172 lines
4.7 KiB
Go

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 BIGSERIAL PRIMARY KEY,
station_id VARCHAR(50) NOT NULL,
timestamp TIMESTAMPTZ NOT NULL,
temperature DOUBLE PRECISION,
humidity DOUBLE PRECISION,
wind_speed DOUBLE PRECISION,
wind_direction DOUBLE PRECISION,
rainfall DOUBLE PRECISION,
light DOUBLE PRECISION,
uv DOUBLE PRECISION,
pressure DOUBLE PRECISION,
raw_data TEXT,
FOREIGN KEY (station_id) REFERENCES stations(station_id),
UNIQUE (station_id, timestamp)
)`)
if err != nil {
return err
}
// 支持性索引(若已存在则不重复创建)
if _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_rwd_time ON rs485_weather_data (timestamp)`); err != nil {
return err
}
if _, err = db.Exec(`CREATE INDEX IF NOT EXISTS idx_rwd_station_time ON rs485_weather_data (station_id, timestamp)`); err != nil {
return err
}
return nil
}
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 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
}
_, 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, 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),
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 *RS485WeatherData) error {
stationID := fmt.Sprintf("RS485-%s", data.DeviceID)
err := ensureStationExists(stationID, "")
if err != nil {
return err
}
_, 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)`,
stationID, data.ReceivedAt,
data.Temperature, data.Humidity, data.WindSpeed,
data.WindDirection, data.Rainfall, data.Light,
data.UV, data.Pressure, data.RawDataHex)
if err != nil {
return fmt.Errorf("保存RS485气象数据失败: %v", err)
}
return nil
}