diff --git a/main.go b/main.go index 984fb29..767fc1f 100644 --- a/main.go +++ b/main.go @@ -128,24 +128,36 @@ func startUDP() { asciiDump := asciiDump(rawData) log.Printf("ASCII码:\n%s", asciiDump) - weatherData, err := model.ParseData(rawData) + data, deviceType, err := model.ParseData(rawData) if err != nil { log.Printf("解析数据失败: %v", err) continue } log.Println("成功解析气象站数据:") - log.Printf("设备类型: %s", getDeviceTypeString(weatherData.DeviceType)) - log.Println(weatherData) + log.Printf("设备类型: %s", getDeviceTypeString(deviceType)) + log.Println(data) - if weatherData.StationID != "" { - model.RegisterDevice(weatherData.StationID, addr) - log.Printf("设备 %s 已注册,IP: %s", weatherData.StationID, addr.String()) + var stationID string + switch v := data.(type) { + case *model.WeatherData: + stationID = v.StationID + case *model.RS485WeatherData: + // 设备ID格式: HSB(21) MSB(22) LSB(1) + hsb := rawData[21] // HSB: bit 168-175 (索引21) + msb := rawData[22] // MSB: bit 176-183 (索引22) + lsb := rawData[1] // LSB: bit 8-15 (索引1) + stationID = fmt.Sprintf("RS485-%02X%02X%02X", hsb, msb, lsb) + } + + if stationID != "" { + model.RegisterDevice(stationID, addr) + log.Printf("设备 %s 已注册,IP: %s", stationID, addr.String()) } else { log.Printf("警告: 收到的数据没有站点ID") } - err = model.SaveWeatherData(weatherData, string(rawData)) + err = model.SaveWeatherData(data, string(rawData)) if err != nil { log.Printf("保存数据到数据库失败: %v", err) } else { diff --git a/model/db.go b/model/db.go index d970d82..f152ef4 100644 --- a/model/db.go +++ b/model/db.go @@ -92,32 +92,28 @@ func ensureStationExists(stationID, password string) error { return nil } -func SaveWeatherData(data *WeatherData, rawData string) error { +func SaveWeatherData(data interface{}, rawData string) error { if db == nil { return fmt.Errorf("数据库未初始化") } + switch v := data.(type) { + case *WeatherData: + return saveWIFIWeatherData(v, rawData) + case *RS485WeatherData: + return saveRS485WeatherData(v) + default: + return fmt.Errorf("未知的数据类型") + } +} + +func saveWIFIWeatherData(data *WeatherData, rawData string) error { err := ensureStationExists(data.StationID, data.Password) if err != nil { return err } - cst := time.FixedZone("CST", 8*60*60) - timestamp := time.Now().In(cst) - - // 根据设备类型选择不同的保存方法 - switch data.DeviceType { - case DeviceTypeWIFI: - return saveWIFIWeatherData(data, rawData, timestamp) - case DeviceTypeRS485: - return saveRS485WeatherData(data, rawData, timestamp) - default: - return fmt.Errorf("未知的设备类型") - } -} - -func saveWIFIWeatherData(data *WeatherData, rawData string, timestamp time.Time) error { - _, err := db.Exec(` + _, err = db.Exec(` INSERT INTO weather_data ( station_id, timestamp, temp_f, humidity, dewpoint_f, windchill_f, wind_dir, wind_speed_mph, wind_gust_mph, rain_in, daily_rain_in, @@ -125,7 +121,7 @@ func saveWIFIWeatherData(data *WeatherData, rawData string, timestamp time.Time) solar_radiation, uv, indoor_temp_f, indoor_humidity, abs_barometer_in, barometer_in, low_battery, raw_data ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)`, - data.StationID, timestamp, + data.StationID, time.Now(), int(data.TempF*10), data.Humidity, int(data.DewpointF*10), int(data.WindchillF*10), data.WindDir, int(data.WindSpeedMph*100), int(data.WindGustMph*100), int(data.RainIn*1000), int(data.DailyRainIn*1000), int(data.WeeklyRainIn*1000), @@ -139,25 +135,21 @@ func saveWIFIWeatherData(data *WeatherData, rawData string, timestamp time.Time) return nil } -func saveRS485WeatherData(data *WeatherData, rawData string, timestamp time.Time) error { - // 将华氏度转换回摄氏度 - tempC := (data.TempF - 32) * 5 / 9 - // 将mph转换回m/s - windSpeedMS := data.WindSpeedMph / 2.23694 - // 将inch转换回mm - rainfallMM := data.RainIn * 25.4 - // 将inHg转换回hPa - pressureHPa := data.BarometerIn * 33.8639 +func saveRS485WeatherData(data *RS485WeatherData) error { + err := ensureStationExists(data.StationID, "") + if err != nil { + return err + } - _, err := db.Exec(` + _, err = db.Exec(` INSERT INTO rs485_weather_data ( station_id, timestamp, temperature, humidity, wind_speed, wind_direction, rainfall, light, uv, pressure, raw_data ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`, - data.StationID, timestamp, - tempC, data.Humidity, windSpeedMS, - data.WindDir, rainfallMM, data.SolarRadiation, - data.UV, pressureHPa, rawData) + data.StationID, data.Timestamp, + data.Temperature, data.Humidity, data.WindSpeed, + data.WindDirection, data.Rainfall, data.Light, + data.UV, data.Pressure, data.RawData) if err != nil { return fmt.Errorf("保存RS485气象数据失败: %v", err) diff --git a/model/weather_data.go b/model/weather_data.go index 30ef3c7..3223cd4 100644 --- a/model/weather_data.go +++ b/model/weather_data.go @@ -16,8 +16,8 @@ const ( DeviceTypeRS485 ) +// WeatherData 存储WIFI设备的气象数据 type WeatherData struct { - DeviceType DeviceType StationID string Password string TempF float64 @@ -47,17 +47,52 @@ type WeatherData struct { RTFreq int } +// RS485WeatherData 存储RS485设备的气象数据 +type RS485WeatherData struct { + StationID string // 站点ID + Timestamp time.Time // 时间戳 + Temperature float64 // 温度 + Humidity float64 // 湿度 + WindSpeed float64 // 风速 + WindDirection float64 // 风向 + Rainfall float64 // 雨量 + Light float64 // 光照 + UV float64 // 紫外线 + Pressure float64 // 气压 + RawData string // 原始数据 +} + var urlRegex = regexp.MustCompile(`/weatherstation/updateweatherstation\.php\?([^&\s]+(&[^&\s]+)*)`) // ParseData 根据数据类型解析气象数据 -func ParseData(data []byte) (*WeatherData, error) { +func ParseData(data []byte) (interface{}, DeviceType, error) { // 检查是否为RS485数据 if len(data) == 25 && data[0] == 0x24 { - return ParseRS485WeatherData(data) + protocol := NewRS485Protocol(data) + rs485Data, err := protocol.ParseRS485Data() + if err != nil { + return nil, DeviceTypeRS485, err + } + + weatherData := &RS485WeatherData{ + StationID: fmt.Sprintf("RS485-%02X%02X", data[1], data[2]), + Timestamp: time.Now(), + Temperature: rs485Data.Temperature, + Humidity: rs485Data.Humidity, + WindSpeed: rs485Data.WindSpeed, + WindDirection: rs485Data.WindDirection, + Rainfall: rs485Data.Rainfall, + Light: rs485Data.Light, + UV: rs485Data.UV, + Pressure: rs485Data.Pressure, + RawData: fmt.Sprintf("%X", data), + } + return weatherData, DeviceTypeRS485, nil } // 尝试解析为WIFI数据 - return ParseWIFIWeatherData(string(data)) + wifiData, err := ParseWIFIWeatherData(string(data)) + return wifiData, DeviceTypeWIFI, err } // ParseWIFIWeatherData 解析WIFI设备数据 @@ -73,10 +108,7 @@ func ParseWIFIWeatherData(data string) (*WeatherData, error) { return nil, fmt.Errorf("解析查询参数失败: %v", err) } - wd := &WeatherData{ - DeviceType: DeviceTypeWIFI, - DateUTC: time.Now().UTC().Format("2006-01-02 15:04:05"), - } + wd := &WeatherData{} wd.StationID = values.Get("ID") wd.Password = values.Get("PASSWORD") @@ -174,48 +206,6 @@ func ParseWIFIWeatherData(data string) (*WeatherData, error) { 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 @@ -266,3 +256,28 @@ func (w *WeatherData) String() string { w.DateUTC, ) } + +func (w *RS485WeatherData) String() string { + return fmt.Sprintf(` +站点ID: %s +温度: %.1f°C +湿度: %.1f%% +风向: %.1f° +风速: %.2f m/s +降雨量: %.2f mm +光照: %.2f lux +紫外线: %.2f +气压: %.2f hPa +时间: %s`, + w.StationID, + w.Temperature, + w.Humidity, + w.WindDirection, + w.WindSpeed, + w.Rainfall, + w.Light, + w.UV, + w.Pressure, + w.Timestamp.Format("2006-01-02 15:04:05"), + ) +}