242 lines
7.3 KiB
Go
242 lines
7.3 KiB
Go
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)
|
||
}
|
||
}
|