rain_monitor/api/api.go
fengyarnom 94308d81a0 init
2025-06-27 18:09:37 +08:00

200 lines
6.2 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{}{
"timestamp": time.Now().Format(time.RFC3339),
"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["rainfall"] = weatherData.Rainfall
}
if rainData != nil {
result["rainfall"] = rainData.TotalRainfall
result["daily_rainfall"] = rainData.DailyRainfall
result["instant_rainfall"] = rainData.InstantRainfall
}
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)
}