weather-station/model/weather_data.go

269 lines
6.8 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 model
import (
"fmt"
"net/url"
"regexp"
"strconv"
"time"
)
// DeviceType 定义设备类型
type DeviceType int
const (
DeviceTypeWIFI DeviceType = iota
DeviceTypeRS485
)
type WeatherData struct {
DeviceType DeviceType
StationID string
Password string
TempF float64
Humidity int
DewpointF float64
WindchillF float64
WindDir int
WindSpeedMph float64
WindGustMph float64
RainIn float64
DailyRainIn float64
WeeklyRainIn float64
MonthlyRainIn float64
YearlyRainIn float64
TotalRainIn float64
SolarRadiation float64
UV int
IndoorTempF float64
IndoorHumidity int
AbsBarometerIn float64
BarometerIn float64
LowBattery bool
SoftwareType string
DateUTC string
Action string
RealTime int
RTFreq int
}
var urlRegex = regexp.MustCompile(`/weatherstation/updateweatherstation\.php\?([^&\s]+(&[^&\s]+)*)`)
// ParseData 根据数据类型解析气象数据
func ParseData(data []byte) (*WeatherData, error) {
// 检查是否为RS485数据
if len(data) == 25 && data[0] == 0x24 {
return ParseRS485WeatherData(data)
}
// 尝试解析为WIFI数据
return ParseWIFIWeatherData(string(data))
}
// ParseWIFIWeatherData 解析WIFI设备数据
func ParseWIFIWeatherData(data string) (*WeatherData, error) {
matches := urlRegex.FindStringSubmatch(data)
if len(matches) < 2 {
return nil, fmt.Errorf("无法找到有效的气象站数据URL")
}
queryString := matches[1]
values, err := url.ParseQuery(queryString)
if err != nil {
return nil, fmt.Errorf("解析查询参数失败: %v", err)
}
wd := &WeatherData{
DeviceType: DeviceTypeWIFI,
DateUTC: time.Now().UTC().Format("2006-01-02 15:04:05"),
}
wd.StationID = values.Get("ID")
wd.Password = values.Get("PASSWORD")
wd.SoftwareType = values.Get("softwaretype")
wd.Action = values.Get("action")
if tempF, err := strconv.ParseFloat(values.Get("tempf"), 64); err == nil {
wd.TempF = tempF
}
if humidity, err := strconv.Atoi(values.Get("humidity")); err == nil {
wd.Humidity = humidity
}
if dewpointF, err := strconv.ParseFloat(values.Get("dewptf"), 64); err == nil {
wd.DewpointF = dewpointF
}
if windchillF, err := strconv.ParseFloat(values.Get("windchillf"), 64); err == nil {
wd.WindchillF = windchillF
}
if windDir, err := strconv.Atoi(values.Get("winddir")); err == nil {
wd.WindDir = windDir
}
if windSpeedMph, err := strconv.ParseFloat(values.Get("windspeedmph"), 64); err == nil {
wd.WindSpeedMph = windSpeedMph
}
if windGustMph, err := strconv.ParseFloat(values.Get("windgustmph"), 64); err == nil {
wd.WindGustMph = windGustMph
}
if rainIn, err := strconv.ParseFloat(values.Get("rainin"), 64); err == nil {
wd.RainIn = rainIn
}
if dailyRainIn, err := strconv.ParseFloat(values.Get("dailyrainin"), 64); err == nil {
wd.DailyRainIn = dailyRainIn
}
if weeklyRainIn, err := strconv.ParseFloat(values.Get("weeklyrainin"), 64); err == nil {
wd.WeeklyRainIn = weeklyRainIn
}
if monthlyRainIn, err := strconv.ParseFloat(values.Get("monthlyrainin"), 64); err == nil {
wd.MonthlyRainIn = monthlyRainIn
}
if yearlyRainIn, err := strconv.ParseFloat(values.Get("yearlyrainin"), 64); err == nil {
wd.YearlyRainIn = yearlyRainIn
}
if totalRainIn, err := strconv.ParseFloat(values.Get("totalrainin"), 64); err == nil {
wd.TotalRainIn = totalRainIn
}
if solarRadiation, err := strconv.ParseFloat(values.Get("solarradiation"), 64); err == nil {
wd.SolarRadiation = solarRadiation
}
if uv, err := strconv.Atoi(values.Get("UV")); err == nil {
wd.UV = uv
}
if indoorTempF, err := strconv.ParseFloat(values.Get("indoortempf"), 64); err == nil {
wd.IndoorTempF = indoorTempF
}
if indoorHumidity, err := strconv.Atoi(values.Get("indoorhumidity")); err == nil {
wd.IndoorHumidity = indoorHumidity
}
if absBarometerIn, err := strconv.ParseFloat(values.Get("absbaromin"), 64); err == nil {
wd.AbsBarometerIn = absBarometerIn
}
if barometerIn, err := strconv.ParseFloat(values.Get("baromin"), 64); err == nil {
wd.BarometerIn = barometerIn
}
if lowBatt, err := strconv.Atoi(values.Get("lowbatt")); err == nil {
wd.LowBattery = lowBatt != 0
}
if realTime, err := strconv.Atoi(values.Get("realtime")); err == nil {
wd.RealTime = realTime
}
if rtFreq, err := strconv.Atoi(values.Get("rtfreq")); err == nil {
wd.RTFreq = rtFreq
}
return wd, nil
}
// ParseRS485WeatherData 解析RS485设备数据
func ParseRS485WeatherData(data []byte) (*WeatherData, error) {
protocol := NewRS485Protocol(data)
rs485Data, err := protocol.ParseRS485Data()
if err != nil {
return nil, err
}
wd := &WeatherData{
DeviceType: DeviceTypeRS485,
DateUTC: time.Now().UTC().Format("2006-01-02 15:04:05"),
StationID: fmt.Sprintf("RS485-%02X%02X", data[1], data[2]), // 使用前两个字节作为设备ID
}
// 转换温度(摄氏度到华氏度)
wd.TempF = rs485Data.Temperature*9/5 + 32
// 转换湿度(直接使用)
wd.Humidity = int(rs485Data.Humidity)
// 转换风向(直接使用)
wd.WindDir = int(rs485Data.WindDirection)
// 转换风速m/s到mph
wd.WindSpeedMph = rs485Data.WindSpeed * 2.23694
// 转换降雨量mm到inch
wd.RainIn = rs485Data.Rainfall / 25.4
// 转换光照(直接使用)
wd.SolarRadiation = rs485Data.Light
// 转换UV直接使用
wd.UV = int(rs485Data.UV)
// 转换气压hPa到inHg
wd.BarometerIn = rs485Data.Pressure / 33.8639
wd.AbsBarometerIn = wd.BarometerIn
return wd, nil
}
func (w *WeatherData) String() string {
return fmt.Sprintf(`
站点ID: %s
温度: %.1f°F (%.1f°C)
湿度: %d%%
露点: %.1f°F (%.1f°C)
风寒指数: %.1f°F (%.1f°C)
风向: %d°
风速: %.2f mph (%.2f km/h)
阵风: %.2f mph (%.2f km/h)
降雨量: %.3f 英寸 (%.2f mm)
日降雨量: %.3f 英寸 (%.2f mm)
周降雨量: %.3f 英寸 (%.2f mm)
月降雨量: %.3f 英寸 (%.2f mm)
年降雨量: %.3f 英寸 (%.2f mm)
总降雨量: %.3f 英寸 (%.2f mm)
太阳辐射: %.2f W/m²
紫外线指数: %d
室内温度: %.1f°F (%.1f°C)
室内湿度: %d%%
绝对气压: %.3f 英寸汞柱 (%.2f hPa)
相对气压: %.3f 英寸汞柱 (%.2f hPa)
低电量: %v
软件类型: %s
日期UTC: %s`,
w.StationID,
w.TempF, (w.TempF-32)*5/9,
w.Humidity,
w.DewpointF, (w.DewpointF-32)*5/9,
w.WindchillF, (w.WindchillF-32)*5/9,
w.WindDir,
w.WindSpeedMph, w.WindSpeedMph*1.60934,
w.WindGustMph, w.WindGustMph*1.60934,
w.RainIn, w.RainIn*25.4,
w.DailyRainIn, w.DailyRainIn*25.4,
w.WeeklyRainIn, w.WeeklyRainIn*25.4,
w.MonthlyRainIn, w.MonthlyRainIn*25.4,
w.YearlyRainIn, w.YearlyRainIn*25.4,
w.TotalRainIn, w.TotalRainIn*25.4,
w.SolarRadiation,
w.UV,
w.IndoorTempF, (w.IndoorTempF-32)*5/9,
w.IndoorHumidity,
w.AbsBarometerIn, w.AbsBarometerIn*33.8639,
w.BarometerIn, w.BarometerIn*33.8639,
w.LowBattery,
w.SoftwareType,
w.DateUTC,
)
}