feat: 新增 485 的解析

This commit is contained in:
yarnom 2025-08-03 13:50:07 +08:00
parent bc3290c501
commit 6e643497a1
2 changed files with 237 additions and 40 deletions

146
main.go
View File

@ -128,45 +128,43 @@ func startUDP() {
asciiDump := asciiDump(rawData)
log.Printf("ASCII码:\n%s", asciiDump)
data, deviceType, err := model.ParseData(rawData)
if err != nil {
log.Printf("解析数据失败: %v", err)
continue
}
// 检查数据是否为RS485格式
if len(rawData) == 25 && rawData[0] == 0x24 {
// 解析RS485数据
hexStr := strings.ReplaceAll(hexDump, "\n", " ")
parseHexData(hexStr)
log.Println("成功解析气象站数据:")
log.Printf("设备类型: %s", getDeviceTypeString(deviceType))
log.Println(data)
// 如果是RS485数据打印更详细的信息
if deviceType == model.DeviceTypeRS485 {
if rs485Data, ok := data.(*model.RS485WeatherData); ok {
log.Println("RS485数据详情:")
log.Printf("设备ID: %s", rs485Data.DeviceID)
log.Printf("温度: %.2f°C", rs485Data.Temperature)
log.Printf("湿度: %.2f%%", rs485Data.Humidity)
log.Printf("风向: %.2f°", rs485Data.WindDirection)
log.Printf("风速: %.2f m/s", rs485Data.WindSpeed)
log.Printf("降雨量: %.2f mm", rs485Data.Rainfall)
log.Printf("光照: %.2f lux", rs485Data.Light)
log.Printf("紫外线: %.2f", rs485Data.UV)
log.Printf("气压: %.2f hPa", rs485Data.Pressure)
// 注册设备
protocol := model.NewProtocol(rawData)
idParts, err := protocol.GetCompleteID()
if err == nil {
stationID := fmt.Sprintf("RS485-%s", idParts.Complete.Hex)
model.RegisterDevice(stationID, addr)
log.Printf("设备 %s 已注册IP: %s", stationID, addr.String())
}
}
var stationID string
switch v := data.(type) {
case *model.WeatherData:
stationID = v.StationID
case *model.RS485WeatherData:
stationID = fmt.Sprintf("RS485-%s", v.DeviceID)
}
if stationID != "" {
model.RegisterDevice(stationID, addr)
log.Printf("设备 %s 已注册IP: %s", stationID, addr.String())
} else {
log.Printf("警告: 收到的数据没有站点ID")
// 尝试解析WIFI数据
data, deviceType, err := model.ParseData(rawData)
if err != nil {
log.Printf("解析数据失败: %v", err)
continue
}
log.Println("成功解析气象站数据:")
log.Printf("设备类型: %s", getDeviceTypeString(deviceType))
log.Println(data)
if deviceType == model.DeviceTypeWIFI {
if wifiData, ok := data.(*model.WeatherData); ok {
stationID := wifiData.StationID
if stationID != "" {
model.RegisterDevice(stationID, addr)
log.Printf("设备 %s 已注册IP: %s", stationID, addr.String())
} else {
log.Printf("警告: 收到的数据没有站点ID")
}
}
}
}
// 暂时不保存到数据库
@ -191,8 +189,21 @@ func getDeviceTypeString(deviceType model.DeviceType) string {
}
func main() {
setupLogger()
startUDP()
// 检查是否有命令行参数
if len(os.Args) > 1 && os.Args[1] == "parse" {
if len(os.Args) > 2 {
// 解析指定的十六进制数据
hexData := os.Args[2]
parseHexData(hexData)
} else {
fmt.Println("用法: ./weatherstation parse <十六进制数据>")
fmt.Println("示例: ./weatherstation parse \"24 F2 10 02 C7 48 10 03 00 6A 03 E8 05 F5 96 10 3F 01 83 2D B1 00 29 9B A4\"")
}
} else {
// 正常启动服务器
setupLogger()
startUDP()
}
}
func hexDump(data []byte) string {
@ -234,3 +245,62 @@ func asciiDump(data []byte) string {
}
return result.String()
}
// parseHexData 解析十六进制字符串数据
func parseHexData(hexStr string) {
// 移除所有空格
hexStr = strings.ReplaceAll(hexStr, " ", "")
// 将十六进制字符串转换为字节数组
data, err := hex.DecodeString(hexStr)
if err != nil {
log.Printf("解析十六进制字符串失败: %v", err)
return
}
// 检查数据有效性
if !model.ValidateRS485Data(data) {
log.Printf("无效的RS485数据格式: 长度=%d, 起始字节=%02X", len(data), data[0])
return
}
// 创建协议解析器
protocol := model.NewProtocol(data)
rs485Protocol := model.NewRS485Protocol(data)
// 获取设备ID
idParts, err := protocol.GetCompleteID()
if err != nil {
log.Printf("获取设备ID失败: %v", err)
return
}
// 解析RS485数据
rs485Data, err := rs485Protocol.ParseRS485Data()
if err != nil {
log.Printf("解析RS485数据失败: %v", err)
return
}
// 添加设备ID和时间戳
rs485Data.DeviceID = idParts.Complete.Hex
rs485Data.ReceivedAt = time.Now()
rs485Data.RawDataHex = fmt.Sprintf("%X", data)
// 打印解析结果
log.Println("=== RS485数据解析结果 ===")
log.Printf("原始数据: %s", hexStr)
log.Printf("设备ID: %s (HSB=%s, MSB=%s, LSB=%s)",
idParts.Complete.Hex,
idParts.HSB.Hex,
idParts.MSB.Hex,
idParts.LSB.Hex)
log.Printf("温度: %.2f°C", rs485Data.Temperature)
log.Printf("湿度: %.1f%%", rs485Data.Humidity)
log.Printf("风向: %.1f°", rs485Data.WindDirection)
log.Printf("风速: %.2f m/s", rs485Data.WindSpeed)
log.Printf("降雨量: %.2f mm", rs485Data.Rainfall)
log.Printf("光照: %.2f lux", rs485Data.Light)
log.Printf("紫外线: %.2f", rs485Data.UV)
log.Printf("气压: %.2f hPa", rs485Data.Pressure)
}

View File

@ -549,8 +549,8 @@ func TestGetPressure(t *testing.T) {
func TestParseNewData(t *testing.T) {
// 新的测试数据24 F2 30 02 AF 51 03 01 00 08 00 00 00 00 00 6E C2 01 82 D8 5B 00 29 87 EA
data := []byte{0x24, 0xF2, 0x30, 0x02, 0xAF, 0x51, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xC2, 0x01, 0x82, 0xD8, 0x5B, 0x00, 0x29, 0x87, 0xEA}
//data := []byte{0x24, 0xF2, 0x30, 0x02, 0xAF, 0x51, 0x03, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0xC2, 0x01, 0x82, 0xD8, 0x5B, 0x00, 0x29, 0x87, 0xEA}
data := []byte{0x24, 0xF2, 0x10, 0x02, 0xC7, 0x48, 0x10, 0x03, 0x00, 0x6A, 0x03, 0xE8, 0x05, 0xF5, 0x96, 0x10, 0x3F, 0x01, 0x83, 0x2D, 0xB1, 0x00, 0x29, 0x9B, 0xA4}
protocol := NewProtocol(data)
// 1. 解析风速
@ -686,3 +686,130 @@ func TestParseNewDataWithDetails(t *testing.T) {
t.Logf("设备ID: %02X %02X %02X", id.HSB.Dec, id.MSB.Dec, id.LSB.Dec)
t.Logf("原始字节: HSB=%02X, MSB=%02X, LSB=%02X", data[21], data[22], data[1])
}
func TestParseSpecificData(t *testing.T) {
// 测试数据24 F2 10 02 C7 48 10 03 00 6A 03 E8 05 F5 96 10 3F 01 83 2D B1 00 29 9B A4
data := []byte{0x24, 0xF2, 0x10, 0x02, 0xC7, 0x48, 0x10, 0x03, 0x00, 0x6A, 0x03, 0xE8, 0x05, 0xF5, 0x96, 0x10, 0x3F, 0x01, 0x83, 0x2D, 0xB1, 0x00, 0x29, 0x9B, 0xA4}
protocol := NewProtocol(data)
t.Log("\n=== 特定数据解析测试 ===")
// 1. 设备ID解析
t.Log("\n=== 设备ID解析 ===")
id, err := protocol.GetCompleteID()
if err != nil {
t.Fatalf("获取设备ID失败: %v", err)
}
t.Logf("设备ID: %s", id.Complete.Hex)
t.Logf("原始字节: HSB=%02X, MSB=%02X, LSB=%02X", data[21], data[22], data[1])
// 2. 温度解析
t.Log("\n=== 温度解析 ===")
temp, err := protocol.GetTemperature()
if err != nil {
t.Fatalf("获取温度失败: %v", err)
}
t.Logf("温度: %.2f °C (raw: 0x%X)", temp.Complete.Value, temp.Complete.RawValue)
t.Logf("TMP_H: %s (0x%X), TMP_M: %s (0x%X), TMP_L: %s (0x%X)",
temp.TmpH.Binary, temp.TmpH.Value,
temp.TmpM.Binary, temp.TmpM.Value,
temp.TmpL.Binary, temp.TmpL.Value)
// 3. 湿度解析
t.Log("\n=== 湿度解析 ===")
humidity, err := protocol.GetHumidity()
if err != nil {
t.Fatalf("获取湿度失败: %v", err)
}
t.Logf("湿度: %d%% (raw: 0x%X)", humidity.Complete.Value, humidity.Complete.RawValue)
t.Logf("HM_H: %s (0x%X), HM_L: %s (0x%X)",
humidity.HmH.Binary, humidity.HmH.Value,
humidity.HmL.Binary, humidity.HmL.Value)
// 4. 风速解析
t.Log("\n=== 风速解析 ===")
windSpeed, err := protocol.GetWindSpeed()
if err != nil {
t.Fatalf("获取风速失败: %v", err)
}
t.Logf("风速: %.5f m/s (raw: 0x%X)", windSpeed.Complete.Value, windSpeed.Complete.RawValue)
t.Logf("WSP_FLAG: %v", windSpeed.WspFlag.Value)
t.Logf("WSP_H: %s (0x%X), WSP_L: %s (0x%X)",
windSpeed.WspH.Binary, windSpeed.WspH.Value,
windSpeed.WspL.Binary, windSpeed.WspL.Value)
// 5. 风向解析
t.Log("\n=== 风向解析 ===")
windDir, err := protocol.GetWindDirection()
if err != nil {
t.Fatalf("获取风向失败: %v", err)
}
t.Logf("风向: %.1f° (raw: 0x%X)", windDir.Complete.Degree, windDir.Complete.Value)
t.Logf("DirH: %s (0x%X), DirM: %s (0x%X), DirL: %s (0x%X)",
windDir.DirH.Binary, windDir.DirH.Value,
windDir.DirM.Binary, windDir.DirM.Value,
windDir.DirL.Binary, windDir.DirL.Value)
// 6. 降雨量解析
t.Log("\n=== 降雨量解析 ===")
rainfall, err := protocol.GetRainfall()
if err != nil {
t.Fatalf("获取降雨量失败: %v", err)
}
t.Logf("降雨量: %.3f mm (raw: 0x%X)", rainfall.Complete.Value, rainfall.Complete.RawValue)
t.Logf("原始字节: %02X %02X", data[8], data[9])
// 7. 光照解析
t.Log("\n=== 光照解析 ===")
light, err := protocol.GetLight()
if err != nil {
t.Fatalf("获取光照失败: %v", err)
}
t.Logf("光照: %.1f lux (raw: 0x%X)", light.Complete.Value, light.Complete.RawValue)
t.Logf("原始字节: %02X %02X %02X", data[12], data[13], data[14])
// 8. UV指数解析
t.Log("\n=== UV指数解析 ===")
uv, err := protocol.GetUVIndex()
if err != nil {
t.Fatalf("获取UV指数失败: %v", err)
}
t.Logf("UV指数: %.1f uW/c㎡ (raw: 0x%X)", uv.Complete.Value, uv.Complete.RawValue)
t.Logf("原始字节: %02X %02X", data[10], data[11])
// 9. 气压解析
t.Log("\n=== 气压解析 ===")
pressure, err := protocol.GetPressure()
if err != nil {
t.Fatalf("获取气压失败: %v", err)
}
t.Logf("气压: %.2f hPa (raw: 0x%X)", pressure.Complete.Value, pressure.Complete.RawValue)
t.Logf("原始字节: %02X %02X %02X", data[17], data[18], data[19])
// 10. 阵风速度解析
t.Log("\n=== 阵风速度解析 ===")
gust, err := protocol.GetGustSpeed()
if err != nil {
t.Fatalf("获取阵风速度失败: %v", err)
}
t.Logf("阵风速度: %.2f m/s (raw: 0x%X)", gust.Complete.Value, gust.Complete.RawValue)
t.Logf("原始字节: %02X", data[7])
// 11. 创建RS485协议解析器并解析数据
t.Log("\n=== RS485协议解析 ===")
rs485Protocol := NewRS485Protocol(data)
rs485Data, err := rs485Protocol.ParseRS485Data()
if err != nil {
t.Fatalf("RS485数据解析失败: %v", err)
}
t.Logf("温度: %.2f°C", rs485Data.Temperature)
t.Logf("湿度: %.1f%%", rs485Data.Humidity)
t.Logf("风速: %.2f m/s", rs485Data.WindSpeed)
t.Logf("风向: %.1f°", rs485Data.WindDirection)
t.Logf("降雨量: %.3f mm", rs485Data.Rainfall)
t.Logf("光照: %.1f lux", rs485Data.Light)
t.Logf("紫外线: %.1f", rs485Data.UV)
t.Logf("气压: %.2f hPa", rs485Data.Pressure)
}