diff --git a/go.sum b/go.sum index f17e70d..b51f4c8 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,3 @@ -gitea.libretechconsulting.com/rmcguire/go-app v0.1.3 h1:EwmEJLpN+rQjJ5stGEkZsqEDa5F/YnDAEeqJB9XlFn4= -gitea.libretechconsulting.com/rmcguire/go-app v0.1.3/go.mod h1:wHOWh4O4AMDATQ3WEUYjq5a5bnICPBpu5G6BsNxqN38= -gitea.libretechconsulting.com/rmcguire/go-app v0.2.0 h1:pOm/PysC0IWPuEbmEjNSHHa8Qc5OhuoksYExcuJMFE4= -gitea.libretechconsulting.com/rmcguire/go-app v0.2.0/go.mod h1:wHOWh4O4AMDATQ3WEUYjq5a5bnICPBpu5G6BsNxqN38= gitea.libretechconsulting.com/rmcguire/go-app v0.3.0 h1:TSR6oEDBX+83975gmgGgU/cTFgfG999+9N/1h4RAXq0= gitea.libretechconsulting.com/rmcguire/go-app v0.3.0/go.mod h1:wHOWh4O4AMDATQ3WEUYjq5a5bnICPBpu5G6BsNxqN38= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= diff --git a/main.go b/main.go index 37b9114..dc7d5c0 100644 --- a/main.go +++ b/main.go @@ -12,15 +12,26 @@ import ( "gitea.libretechconsulting.com/rmcguire/ambient-weather-local-exporter/pkg/ambient" ) +const defaultMetricPrefix = "weather" + func main() { ctx, cncl := signal.NotifyContext(context.Background(), os.Kill, unix.SIGTERM) defer cncl() + // Config type for app, which implements go-app/config.AppConfig + awConfig := &ambient.AmbientLocalExporterConfig{ + MetricPrefix: defaultMetricPrefix, + WeatherStations: make([]ambient.WeatherStation, 0), + } + // Read config and environment, set up logging, load up // an appCtx, and prepare ambient weather local exporter - ctx = app.MustSetupConfigAndLogging(ctx) - aw := ambient.New(ctx).Init() + ctx, awConfig = app.MustLoadConfigInto(ctx, awConfig) + // Prepare the exporter + aw := ambient.New(ctx, awConfig).Init() + + // Define and prepare the app awApp := app.App{ AppContext: ctx, HTTP: &app.AppHTTP{ @@ -43,7 +54,7 @@ func main() { }, } + // Run and wait awApp.MustRun() - <-awApp.Done() } diff --git a/pkg/ambient/ambient.go b/pkg/ambient/ambient.go index 42df940..878b839 100644 --- a/pkg/ambient/ambient.go +++ b/pkg/ambient/ambient.go @@ -24,6 +24,7 @@ type AmbientWeather struct { // when either "AmbientWeather" or "Wunderground" are selected // in the "Custom" section of the AWNet app, or the web UI // of an Ambient WeatherHub + config *AmbientLocalExporterConfig awnProvider provider.AmbientProvider wuProvider provider.AmbientProvider appCtx context.Context @@ -31,7 +32,7 @@ type AmbientWeather struct { l *zerolog.Logger } -func New(appCtx context.Context) *AmbientWeather { +func New(appCtx context.Context, awConfig *AmbientLocalExporterConfig) *AmbientWeather { return &AmbientWeather{ appCtx: appCtx, } diff --git a/pkg/ambient/config.go b/pkg/ambient/config.go new file mode 100644 index 0000000..25d5c12 --- /dev/null +++ b/pkg/ambient/config.go @@ -0,0 +1,33 @@ +package ambient + +import ( + "gitea.libretechconsulting.com/rmcguire/go-app/pkg/config" + + "gitea.libretechconsulting.com/rmcguire/ambient-weather-local-exporter/pkg/weather" +) + +// This configuration includes all config from go-app/config.AppConfig +type AmbientLocalExporterConfig struct { + MetricPrefix string `yaml:"metricPrefix" default:"weather" env:"AMBIENT_METRIC_PREFIX"` + WeatherStations []WeatherStation `yaml:"weatherStations"` // No env, too complex, not worth the time + *config.AppConfig // Extends app config +} + +type WeatherStation struct { + Name string `yaml:"name"` // Human Friendly Name (e.g. Back Yard Weather) + Equipment string `yaml:"equipment"` // Equipment Type (e.g. WS-5000) + + // One of these is required, based on the type + // set in the "Custom" weather service on your + // console, weather station, or weather hub + WundergroundID string `yaml:"wundergroundID"` + AWNPassKey string `yaml:"awnPassKey"` + + // Proxy updates to AWN or Wunderground + ProxyToAWN bool `yaml:"proxyToAWN"` + ProxyToWunderground bool `yaml:"proxyToWunderground"` + + // Unreliable / unwanted metrics by name of WeatherUpdate Field + // These fields are mapped from the provider fields + DiscardMetrics []weather.WeatherUpdateField `yaml:"discardMetrics"` +} diff --git a/pkg/weather/types.go b/pkg/weather/types.go index 3387e14..14ed0a0 100644 --- a/pkg/weather/types.go +++ b/pkg/weather/types.go @@ -7,31 +7,27 @@ import ( // Stable intermediate struct containing superset of fields // between AWN and Wunderground style updates from Ambient devices type WeatherUpdate struct { - DateUTC *time.Time - StationType string - TempOutdoorF float64 - TempIndoorF float64 - HumidityOudoor int - HumidityIndoor int - WindSpeedMPH float64 - WindGustMPH float64 - MaxDailyGust float64 - WindDir int - WindDirAvg10m int - UV int - SolarRadiation float64 - HourlyRainIn float64 - EventRainIn float64 - DailyRainIn float64 - WeeklyRainIn float64 - MonthlyRainIn float64 - YearlyRainIn float64 - TotalRainIn float64 - Batteries []BatteryStatus - // BattOutdoorSensor int - // BattIndoorSensor int - // BattRainSensor int - // BattCO2Sensor int + DateUTC *time.Time + StationType string + TempOutdoorF float64 + TempIndoorF float64 + HumidityOudoor int + HumidityIndoor int + WindSpeedMPH float64 + WindGustMPH float64 + MaxDailyGust float64 + WindDir int + WindDirAvg10m int + UV int + SolarRadiation float64 + HourlyRainIn float64 + EventRainIn float64 + DailyRainIn float64 + WeeklyRainIn float64 + MonthlyRainIn float64 + YearlyRainIn float64 + TotalRainIn float64 + Batteries []BatteryStatus BaromRelativeIn float64 BaromAbsoluteIn float64 // These fields may be calculated @@ -44,3 +40,35 @@ type BatteryStatus struct { Component string Status int } + +type WeatherUpdateField string + +// NOTE: Annoyance to avoid string constant comparisons +// CHORE: Maintain this +const ( + FieldDateUTC WeatherUpdateField = "DateUTC" + FieldStationType WeatherUpdateField = "StationType" + FieldTempOutdoorF WeatherUpdateField = "TempOutdoorF" + FieldTempIndoorF WeatherUpdateField = "TempIndoorF" + FieldHumidityOudoor WeatherUpdateField = "HumidityOudoor" + FieldHumidityIndoor WeatherUpdateField = "HumidityIndoor" + FieldWindSpeedMPH WeatherUpdateField = "WindSpeedMPH" + FieldWindGustMPH WeatherUpdateField = "WindGustMPH" + FieldMaxDailyGust WeatherUpdateField = "MaxDailyGust" + FieldWindDir WeatherUpdateField = "WindDir" + FieldWindDirAvg10m WeatherUpdateField = "WindDirAvg10m" + FieldUV WeatherUpdateField = "UV" + FieldSolarRadiation WeatherUpdateField = "SolarRadiation" + FieldHourlyRainIn WeatherUpdateField = "HourlyRainIn" + FieldEventRainIn WeatherUpdateField = "EventRainIn" + FieldDailyRainIn WeatherUpdateField = "DailyRainIn" + FieldWeeklyRainIn WeatherUpdateField = "WeeklyRainIn" + FieldMonthlyRainIn WeatherUpdateField = "MonthlyRainIn" + FieldYearlyRainIn WeatherUpdateField = "YearlyRainIn" + FieldTotalRainIn WeatherUpdateField = "TotalRainIn" + FieldBatteries WeatherUpdateField = "Batteries" + FieldBaromRelativeIn WeatherUpdateField = "BaromRelativeIn" + FieldBaromAbsoluteIn WeatherUpdateField = "BaromAbsoluteIn" + FieldDewPointF WeatherUpdateField = "DewPointF" + FieldWindChillF WeatherUpdateField = "WindChillF" +)