rain_monitor/api/api.go
yarnom f6f70a561e Revert "feat:新增EM3395TY设备"
This reverts commit b8819d6a5e3590b145a8c785d16c44b113365e42.
2025-07-21 11:24:52 +08:00

217 lines
7.1 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 api
import (
"encoding/json"
"log"
"net/http"
"rain_monitor/db"
"rain_monitor/modbus"
"rain_monitor/models"
"time"
)
// StartWebServer 启动Web服务器
func StartWebServer() {
http.HandleFunc("/api/status", handleStatus)
http.HandleFunc("/api/raw/latest", handleLatestRawData)
http.HandleFunc("/api/trigger-query", handleTriggerQuery)
http.HandleFunc("/api/data", handleQueryData)
http.HandleFunc("/api/latest", handleLatestData)
// 静态文件服务
http.Handle("/", http.FileServer(http.Dir("static")))
log.Println("Web服务器已启动监听端口 10003")
err := http.ListenAndServe(":10003", nil)
if err != nil {
log.Fatalf("Web服务器启动失败: %v", err)
}
}
// handleStatus 处理连接状态请求
func handleStatus(w http.ResponseWriter, r *http.Request) {
status := modbus.GetConnectionStatus()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(status)
}
// handleLatestRawData 获取最新原始数据
func handleLatestRawData(w http.ResponseWriter, r *http.Request) {
// 从数据库获取最新数据而不是从modbus内存中获取
weatherData, err1 := db.GetLatestWeatherData()
rainData, err2 := db.GetLatestRainGaugeData()
if (weatherData == nil && rainData == nil) || (err1 != nil && err2 != nil) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
json.NewEncoder(w).Encode(map[string]interface{}{
"error": "没有可用的数据",
"details": map[string]interface{}{
"weather_error": err1,
"rain_error": err2,
},
})
return
}
result := map[string]interface{}{}
// 使用数据库中的时间戳,如果可用
if weatherData != nil && !weatherData.Timestamp.IsZero() {
result["timestamp"] = weatherData.Timestamp.Format(time.RFC3339)
result["formatted_time"] = weatherData.Timestamp.Format("2006-01-02 15:04:05")
} else if rainData != nil && !rainData.Timestamp.IsZero() {
result["timestamp"] = rainData.Timestamp.Format(time.RFC3339)
result["formatted_time"] = rainData.Timestamp.Format("2006-01-02 15:04:05")
} else {
// 如果都没有时间戳,则使用当前时间作为 fallback
result["timestamp"] = time.Now().Format(time.RFC3339)
result["formatted_time"] = time.Now().Format("2006-01-02 15:04:05")
}
if weatherData != nil {
result["temperature"] = weatherData.Temperature
result["humidity"] = weatherData.Humidity
result["wind_speed"] = weatherData.WindSpeed
result["wind_direction_8"] = weatherData.WindDirection8
result["wind_direction_360"] = weatherData.WindDirection360
result["atm_pressure"] = weatherData.AtmPressure
result["solar_radiation"] = weatherData.SolarRadiation
result["weather_rainfall"] = weatherData.Rainfall // 区分气象站的雨量
}
if rainData != nil {
result["total_rainfall"] = rainData.TotalRainfall // 使用 total_rainfall 表示累计雨量
result["daily_rainfall"] = rainData.DailyRainfall
result["instant_rainfall"] = rainData.InstantRainfall
}
// 为了兼容旧代码,仍然提供一个 rainfall 字段,优先使用雨量计的数据
if rainData != nil {
result["rainfall"] = rainData.TotalRainfall
} else if weatherData != nil {
result["rainfall"] = weatherData.Rainfall
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
// handleTriggerQuery 触发设备查询(保留手动采集功能)
func handleTriggerQuery(w http.ResponseWriter, r *http.Request) {
err1 := modbus.QueryDevice(modbus.DeviceWeatherStation)
err2 := modbus.QueryDevice(modbus.DeviceRainGauge)
result := map[string]interface{}{
"success": err1 == nil || err2 == nil,
"timestamp": time.Now().Format(time.RFC3339),
}
if err1 != nil {
result["weather_error"] = err1.Error()
}
if err2 != nil {
result["rain_error"] = err2.Error()
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
}
// handleQueryData 查询历史数据
func handleQueryData(w http.ResponseWriter, r *http.Request) {
startStr := r.URL.Query().Get("start")
endStr := r.URL.Query().Get("end")
interval := r.URL.Query().Get("interval")
log.Printf("handleQueryData - 请求参数: start=%s, end=%s, interval=%s", startStr, endStr, interval)
if startStr == "" || endStr == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "缺少必要的时间参数"})
return
}
start, err := time.Parse(time.RFC3339, startStr)
if err != nil {
log.Printf("开始时间解析失败: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "开始时间格式错误"})
return
}
end, err := time.Parse(time.RFC3339, endStr)
if err != nil {
log.Printf("结束时间解析失败: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "结束时间格式错误"})
return
}
data, err := db.GetAggregatedData(start, end)
if err != nil {
log.Printf("查询聚合数据失败: %v", err)
// 返回空数组而不是错误,避免前端报错
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode([]models.AggregatedData{})
return
}
log.Printf("查询成功,返回 %d 条记录", len(data))
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}
// handleLatestData 获取最新聚合数据
func handleLatestData(w http.ResponseWriter, r *http.Request) {
startStr := r.URL.Query().Get("start")
endStr := r.URL.Query().Get("end")
interval := r.URL.Query().Get("interval")
log.Printf("handleLatestData - 请求参数: start=%s, end=%s, interval=%s", startStr, endStr, interval)
if startStr == "" || endStr == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "缺少必要的时间参数"})
return
}
start, err := time.Parse(time.RFC3339, startStr)
if err != nil {
log.Printf("开始时间解析失败: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "开始时间格式错误"})
return
}
end, err := time.Parse(time.RFC3339, endStr)
if err != nil {
log.Printf("结束时间解析失败: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]interface{}{"error": "结束时间格式错误"})
return
}
// 只查数据库,不主动采集
data, err := db.GetAggregatedData(start, end)
if err != nil {
log.Printf("查询聚合数据失败: %v", err)
// 返回空数组而不是错误,避免前端报错
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode([]models.AggregatedData{})
return
}
log.Printf("查询成功,返回 %d 条记录", len(data))
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
}