package model import ( "database/sql" "fmt" "time" "weatherstation/config" _ "github.com/lib/pq" ) var db *sql.DB func InitDB() error { cfg := config.GetConfig() connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", cfg.Database.Host, cfg.Database.Port, cfg.Database.User, cfg.Database.Password, cfg.Database.DBName, cfg.Database.SSLMode) var err error db, err = sql.Open("postgres", connStr) if err != nil { return fmt.Errorf("无法连接到数据库: %v", err) } err = db.Ping() if err != nil { return fmt.Errorf("数据库连接测试失败: %v", err) } // 创建RS485数据表 err = createRS485Table() if err != nil { return fmt.Errorf("创建RS485数据表失败: %v", err) } return nil } func createRS485Table() error { _, err := db.Exec(` CREATE TABLE IF NOT EXISTS rs485_weather_data ( id SERIAL PRIMARY KEY, station_id VARCHAR(50) NOT NULL, timestamp TIMESTAMP NOT NULL, temperature DECIMAL(5,2), -- 温度(摄氏度) humidity DECIMAL(5,2), -- 湿度(%) wind_speed DECIMAL(5,2), -- 风速(m/s) wind_direction DECIMAL(5,2), -- 风向(度) rainfall DECIMAL(5,2), -- 降雨量(mm) light DECIMAL(10,2), -- 光照(lux) uv DECIMAL(5,2), -- 紫外线 pressure DECIMAL(7,2), -- 气压(hPa) raw_data TEXT, -- 原始数据 FOREIGN KEY (station_id) REFERENCES stations(station_id) )`) return err } func CloseDB() { if db != nil { db.Close() } } func ensureStationExists(stationID, password string) error { if db == nil { return fmt.Errorf("数据库未初始化") } var count int err := db.QueryRow("SELECT COUNT(*) FROM stations WHERE station_id = $1", stationID).Scan(&count) if err != nil { return fmt.Errorf("查询站点失败: %v", err) } if count == 0 { _, err = db.Exec("INSERT INTO stations (station_id, password) VALUES ($1, $2)", stationID, password) if err != nil { return fmt.Errorf("添加站点失败: %v", err) } } else { _, err = db.Exec("UPDATE stations SET password = $1, last_update = $2 WHERE station_id = $3", password, time.Now(), stationID) if err != nil { return fmt.Errorf("更新站点失败: %v", err) } } return nil } func SaveWeatherData(data *WeatherData, rawData string) error { if db == nil { return fmt.Errorf("数据库未初始化") } 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(` 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, weekly_rain_in, monthly_rain_in, yearly_rain_in, total_rain_in, 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, 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), int(data.MonthlyRainIn*1000), int(data.YearlyRainIn*1000), int(data.TotalRainIn*1000), int(data.SolarRadiation*100), data.UV, int(data.IndoorTempF*10), data.IndoorHumidity, int(data.AbsBarometerIn*1000), int(data.BarometerIn*1000), data.LowBattery, rawData) if err != nil { return fmt.Errorf("保存WIFI气象数据失败: %v", err) } 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 _, 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) if err != nil { return fmt.Errorf("保存RS485气象数据失败: %v", err) } return nil }