242 lines
6.1 KiB
Go
242 lines
6.1 KiB
Go
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)
|
|
rs485Data, err := rs485Protocol.ParseRS485Data()
|
|
if err != nil {
|
|
return nil, DeviceTypeRS485, err
|
|
}
|
|
|
|
// 获取设备ID
|
|
idParts, err := protocol.GetCompleteID()
|
|
if err != nil {
|
|
return nil, DeviceTypeRS485, fmt.Errorf("获取设备ID失败: %v", err)
|
|
}
|
|
|
|
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,
|
|
)
|
|
}
|