242 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"encoding/json"
"fmt"
"net/http"
"time"
"go_rain_dtu/internal/dao"
"go_rain_dtu/internal/model"
"go_rain_dtu/internal/tcp"
"go_rain_dtu/pkg/logger"
)
type SensorHandler struct {
dao *dao.SensorDAO
}
func NewSensorHandler(dao *dao.SensorDAO) *SensorHandler {
return &SensorHandler{dao: dao}
}
func (h *SensorHandler) GetAggregatedData(w http.ResponseWriter, r *http.Request) {
interval := r.URL.Query().Get("interval")
if interval == "" {
interval = "1hour"
}
// 获取中国时区
chinaLoc, locErr := time.LoadLocation("Asia/Shanghai")
if locErr != nil {
chinaLoc = time.FixedZone("CST", 8*60*60)
}
endTime := time.Now().In(chinaLoc)
startTime := endTime.Add(-24 * time.Hour) // 默认显示24小时数据
if startStr := r.URL.Query().Get("start"); startStr != "" {
if t, parseErr := time.Parse(time.RFC3339, startStr); parseErr == nil {
startTime = t.In(chinaLoc)
}
}
if endStr := r.URL.Query().Get("end"); endStr != "" {
if t, parseErr := time.Parse(time.RFC3339, endStr); parseErr == nil {
endTime = t.In(chinaLoc)
}
}
var data []model.AggregatedData
var err error
// 判断是否获取原始数据
if interval == "raw" {
data, err = h.dao.GetRawData(startTime, endTime)
} else {
data, err = h.dao.GetAggregatedData(startTime, endTime, interval)
}
if err != nil {
logger.Logger.Printf("获取数据失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
// 使用自定义的编码器,设置时间格式
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
if err := encoder.Encode(data); err != nil {
logger.Logger.Printf("JSON编码失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
}
// 处理静态文件
func (h *SensorHandler) ServeStatic(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
http.ServeFile(w, r, "static/index.html")
return
}
http.FileServer(http.Dir("static")).ServeHTTP(w, r)
}
// GetConnectionStatus 返回当前TCP连接状态
func (h *SensorHandler) GetConnectionStatus(w http.ResponseWriter, r *http.Request) {
connected, ip, port := tcp.GetConnectionStatus()
status := struct {
Connected bool `json:"connected"`
IP string `json:"ip"`
Port string `json:"port"`
Count int `json:"count"` // 添加连接数量
}{
Connected: connected,
IP: ip,
Port: port,
Count: tcp.GetActiveConnectionCount(), // 获取活跃连接数
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(status); err != nil {
logger.Logger.Printf("JSON编码失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
}
}
// GetLatestData 获取最新的聚合数据
func (h *SensorHandler) GetLatestData(w http.ResponseWriter, r *http.Request) {
interval := r.URL.Query().Get("interval")
if interval == "" {
interval = "5min" // 默认使用更细粒度的时间间隔
}
// 默认查询最近1小时的数据
endTime := time.Now()
startTime := endTime.Add(-1 * time.Hour)
// 如果提供了时间范围,则使用提供的范围
if startStr := r.URL.Query().Get("start"); startStr != "" {
if t, err := time.Parse(time.RFC3339, startStr); err == nil {
startTime = t
}
}
if endStr := r.URL.Query().Get("end"); endStr != "" {
if t, err := time.Parse(time.RFC3339, endStr); err == nil {
endTime = t
}
}
// 查询数据库获取数据
var data []model.AggregatedData
var err error
// 判断是否获取原始数据
if interval == "raw" {
data, err = h.dao.GetRawData(startTime, endTime)
} else {
data, err = h.dao.GetAggregatedData(startTime, endTime, interval)
}
if err != nil {
logger.Logger.Printf("获取数据失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
if err := encoder.Encode(data); err != nil {
logger.Logger.Printf("JSON编码失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
}
// GetLatestSensorRawData 获取最新的一条传感器原始数据
func (h *SensorHandler) GetLatestSensorRawData(w http.ResponseWriter, r *http.Request) {
data, err := h.dao.GetLatestSensorData()
if err != nil {
logger.Logger.Printf("获取最新传感器数据失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
if data == nil {
// 没有数据,返回空对象
w.Header().Set("Content-Type", "application/json")
w.Write([]byte("{}"))
return
}
// 将时间调整为中国时区(UTC+8)
chinaLoc, err := time.LoadLocation("Asia/Shanghai")
if err != nil {
// 如果无法加载时区手动创建UTC+8的时区
chinaLoc = time.FixedZone("CST", 8*60*60)
}
chinaTime := data.Timestamp.In(chinaLoc)
// 转换为前端友好的格式
response := struct {
ID int64 `json:"id"`
Timestamp time.Time `json:"timestamp"`
FormattedTime string `json:"formatted_time"`
WindSpeed float64 `json:"wind_speed"` // 风速(m/s)
WindForce int `json:"wind_force"` // 风力(级)
WindDirection8 int `json:"wind_direction_8"` // 8方位风向
WindDirection360 int `json:"wind_direction_360"` // 360度风向
Humidity float64 `json:"humidity"` // 湿度(%)
Temperature float64 `json:"temperature"` // 温度(℃)
AtmPressure float64 `json:"atm_pressure"` // 大气压(kPa)
SolarRadiation int `json:"solar_radiation"` // 太阳辐射(W/m²)
Rainfall float64 `json:"rainfall"` // 累计雨量(mm)
}{
ID: data.ID,
Timestamp: data.Timestamp,
FormattedTime: chinaTime.Format("2006-01-02 15:04:05"),
WindSpeed: float64(data.WindSpeed) / 100.0,
WindForce: data.WindForce,
WindDirection8: data.WindDirection8,
WindDirection360: data.WindDirection360,
Humidity: float64(data.Humidity) / 10.0,
Temperature: float64(data.Temperature) / 10.0,
AtmPressure: float64(data.AtmPressure) / 10.0,
SolarRadiation: data.SolarRadiation,
Rainfall: float64(data.OpticalRain) / 10.0,
}
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
if err := encoder.Encode(response); err != nil {
logger.Logger.Printf("JSON编码失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
return
}
}
// TriggerManualQuery 手动触发向所有设备发送查询指令
func (h *SensorHandler) TriggerManualQuery(w http.ResponseWriter, r *http.Request) {
count := tcp.TriggerManualQuery()
response := struct {
Success bool `json:"success"`
Message string `json:"message"`
Count int `json:"count"`
}{
Success: count > 0,
Message: fmt.Sprintf("成功向%d个设备发送查询指令", count),
Count: count,
}
w.Header().Set("Content-Type", "application/json")
encoder := json.NewEncoder(w)
if err := encoder.Encode(response); err != nil {
logger.Logger.Printf("JSON编码失败: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
}
}