package config import ( "errors" "os" "time" "gopkg.in/yaml.v3" ) type Config struct { LogLevel string `yaml:"log_level"` MQTT struct { Broker string `yaml:"broker"` ClientID string `yaml:"client_id"` Username string `yaml:"username"` Password string `yaml:"password"` Topic string `yaml:"topic"` QoS byte `yaml:"qos"` } `yaml:"mqtt"` DB struct { ConnString string `yaml:"conn_string"` } `yaml:"db"` Site struct { Name string `yaml:"name"` Latitude float64 `yaml:"latitude"` Longitude float64 `yaml:"longitude"` ElevationM float64 `yaml:"elevation_m"` } `yaml:"site"` Pollers struct { OpenMeteo struct { Enabled bool `yaml:"enabled"` Interval time.Duration `yaml:"interval"` Model string `yaml:"model"` } `yaml:"open_meteo"` } `yaml:"pollers"` Wunderground struct { Enabled bool `yaml:"enabled"` StationID string `yaml:"station_id"` StationKey string `yaml:"station_key"` Interval time.Duration `yaml:"interval"` } `yaml:"wunderground"` } func Load(path string) (*Config, error) { b, err := os.ReadFile(path) if err != nil { return nil, err } var c Config if err := yaml.Unmarshal(b, &c); err != nil { return nil, err } // Minimal validation if c.MQTT.Broker == "" || c.MQTT.Topic == "" { return nil, errors.New("mqtt broker and topic are required") } if c.DB.ConnString == "" { return nil, errors.New("db conn_string is required") } if c.Site.Name == "" { c.Site.Name = "default" } if c.Pollers.OpenMeteo.Model == "" { c.Pollers.OpenMeteo.Model = "ecmwf" } if c.Pollers.OpenMeteo.Interval == 0 { c.Pollers.OpenMeteo.Interval = 30 * time.Minute } if c.Wunderground.Interval == 0 { c.Wunderground.Interval = 60 * time.Second } // If enabled, require creds if c.Wunderground.Enabled && (c.Wunderground.StationID == "" || c.Wunderground.StationKey == "") { return nil, errors.New("wunderground enabled but station_id/station_key not set") } return &c, nil }