217 lines
7.1 KiB
Go
217 lines
7.1 KiB
Go
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)
|
||
}
|