package model import ( "fmt" "net/url" "regexp" "strconv" "time" ) // DeviceType 定义设备类型 type DeviceType int const ( DeviceTypeWIFI DeviceType = iota DeviceTypeRS485 ) // WeatherData 存储WIFI设备的气象数据 type WeatherData struct { 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) (interface{}, DeviceType, error) { // 检查是否为RS485数据 if len(data) == 25 && data[0] == 0x24 { // 创建协议解析器 protocol := NewProtocol(data) rs485Protocol := NewRS485Protocol(data) // 获取设备ID idParts, err := protocol.GetCompleteID() if err != nil { return nil, DeviceTypeRS485, fmt.Errorf("获取设备ID失败: %v", err) } // 解析RS485数据 rs485Data, err := rs485Protocol.ParseRS485Data() if err != nil { return nil, DeviceTypeRS485, err } // 添加设备ID和时间戳 rs485Data.DeviceID = idParts.Complete.Hex rs485Data.ReceivedAt = time.Now() rs485Data.RawDataHex = fmt.Sprintf("%X", data) return rs485Data, DeviceTypeRS485, nil } // 尝试解析为WIFI数据 wifiData, err := ParseWIFIWeatherData(string(data)) return wifiData, DeviceTypeWIFI, err } // 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{} 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 } 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, ) }