continue working on weather mapping
This commit is contained in:
parent
69fd27916b
commit
220cc818e7
60
main.go
60
main.go
@ -9,36 +9,54 @@ import (
|
|||||||
grpcopts "gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/grpc/opts"
|
grpcopts "gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/grpc/opts"
|
||||||
httpopts "gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/http/opts"
|
httpopts "gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/http/opts"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
|
||||||
weatherpb "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/api/v1alpha1/weather"
|
weatherpb "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/api/v1alpha1/weather"
|
||||||
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient"
|
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient"
|
||||||
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient/ambienthttp"
|
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient/ambienthttp"
|
||||||
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient/config"
|
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/ambient/config"
|
||||||
weathergrpc "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/grpc"
|
weathergrpc "gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/grpc"
|
||||||
|
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMetricPrefix = "weather"
|
const (
|
||||||
|
defaultMetricPrefix = "weather"
|
||||||
|
defaultUpdatesToKeep = 120
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cncl := signal.NotifyContext(context.Background(), os.Kill, os.Interrupt, unix.SIGTERM)
|
ctx, cncl := signal.NotifyContext(context.Background(), os.Kill, os.Interrupt, unix.SIGTERM)
|
||||||
defer cncl()
|
defer cncl()
|
||||||
|
|
||||||
// Config type for app, which implements go-app/config.AppConfig
|
// Read config and environment, prepare an appCtx, and merge
|
||||||
awConfig := &config.AmbientLocalExporterConfig{
|
// go-app config into ambient weather exporter app config
|
||||||
|
ctx, awConfig := app.MustLoadConfigInto(ctx, &config.AmbientLocalExporterConfig{
|
||||||
MetricPrefix: defaultMetricPrefix,
|
MetricPrefix: defaultMetricPrefix,
|
||||||
WeatherStations: make([]config.WeatherStation, 0),
|
WeatherStations: make([]config.WeatherStation, 0),
|
||||||
}
|
})
|
||||||
|
|
||||||
// Read config and environment, set up logging, load up
|
// Prepare the ambient exporter with our prepared config
|
||||||
// an appCtx, and prepare ambient weather local exporter
|
// and set up logging, tracing, etc..
|
||||||
ctx, awConfig = app.MustLoadConfigInto(ctx, awConfig)
|
|
||||||
|
|
||||||
// Prepare the exporter
|
|
||||||
aw := ambient.New(ctx, awConfig).Init()
|
aw := ambient.New(ctx, awConfig).Init()
|
||||||
|
|
||||||
// Define and prepare the app
|
// Load http and grpc routes, prepare the app
|
||||||
awApp := app.App{
|
awApp := prepareApp(ctx, aw)
|
||||||
|
|
||||||
|
// Run app and wait
|
||||||
|
awApp.MustRun()
|
||||||
|
<-awApp.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareApp(ctx context.Context, aw *ambient.AmbientWeather) *app.App {
|
||||||
|
// Config updates / defaults
|
||||||
|
if aw.Config.UpdatesToKeep == nil || *aw.Config.UpdatesToKeep < 1 {
|
||||||
|
aw.Config.UpdatesToKeep = ptr.To(defaultUpdatesToKeep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load ambient routes into app
|
||||||
|
awApp := &app.App{
|
||||||
AppContext: ctx,
|
AppContext: ctx,
|
||||||
|
|
||||||
// HTTP Endpoints for Ambient Weather Stations
|
// HTTP Endpoints for Ambient Weather Stations
|
||||||
HTTP: &httpopts.AppHTTP{
|
HTTP: &httpopts.AppHTTP{
|
||||||
Funcs: []httpopts.HTTPFunc{
|
Funcs: []httpopts.HTTPFunc{
|
||||||
@ -51,8 +69,13 @@ func main() {
|
|||||||
HandlerFunc: aw.GetAWNHandlerFunc(ctx),
|
HandlerFunc: aw.GetAWNHandlerFunc(ctx),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// HTTP Listener that fixes broken requests generated by
|
||||||
|
// some versions of awn firmware
|
||||||
CustomListener: ambienthttp.NewAWNMutatingListener(ctx,
|
CustomListener: ambienthttp.NewAWNMutatingListener(ctx,
|
||||||
awConfig.HTTP.Listen), // Necessary to fix certain bad AWN firmware
|
aw.Config.HTTP.Listen), // Necessary to fix certain bad AWN firmware
|
||||||
|
|
||||||
|
// Health check funcs
|
||||||
HealthChecks: []httpopts.HealthCheckFunc{
|
HealthChecks: []httpopts.HealthCheckFunc{
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
@ -60,19 +83,22 @@ func main() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// GRPC Service for retrieving current weather
|
|
||||||
|
// GRPC Service for retrieving weather
|
||||||
GRPC: &grpcopts.AppGRPC{
|
GRPC: &grpcopts.AppGRPC{
|
||||||
Services: []*grpcopts.GRPCService{
|
Services: []*grpcopts.GRPCService{
|
||||||
{
|
{
|
||||||
Name: "Weather Service",
|
Name: "Weather Service",
|
||||||
Type: &weatherpb.AmbientLocalWeatherService_ServiceDesc,
|
Type: &weatherpb.AmbientLocalWeatherService_ServiceDesc,
|
||||||
Service: weathergrpc.GRPCWeather{},
|
Service: weathergrpc.NewGRPCWeather(ctx, state.NewWeatherState(
|
||||||
|
&state.Opts{
|
||||||
|
Ctx: ctx,
|
||||||
|
KeepLast: *aw.Config.UpdatesToKeep,
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run and wait
|
return awApp
|
||||||
awApp.MustRun()
|
|
||||||
<-awApp.Done()
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ type AmbientWeather struct {
|
|||||||
// when either "AmbientWeather" or "Wunderground" are selected
|
// when either "AmbientWeather" or "Wunderground" are selected
|
||||||
// in the "Custom" section of the AWNet app, or the web UI
|
// in the "Custom" section of the AWNet app, or the web UI
|
||||||
// of an Ambient WeatherHub
|
// of an Ambient WeatherHub
|
||||||
config *config.AmbientLocalExporterConfig
|
Config *config.AmbientLocalExporterConfig
|
||||||
awnProvider provider.AmbientProvider
|
awnProvider provider.AmbientProvider
|
||||||
wuProvider provider.AmbientProvider
|
wuProvider provider.AmbientProvider
|
||||||
appCtx context.Context
|
appCtx context.Context
|
||||||
@ -37,7 +37,7 @@ type AmbientWeather struct {
|
|||||||
|
|
||||||
func New(appCtx context.Context, awConfig *config.AmbientLocalExporterConfig) *AmbientWeather {
|
func New(appCtx context.Context, awConfig *config.AmbientLocalExporterConfig) *AmbientWeather {
|
||||||
return &AmbientWeather{
|
return &AmbientWeather{
|
||||||
config: awConfig,
|
Config: awConfig,
|
||||||
appCtx: appCtx,
|
appCtx: appCtx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ func (aw *AmbientWeather) Init() *AmbientWeather {
|
|||||||
aw.wuProvider = &wunderground.WUProvider{}
|
aw.wuProvider = &wunderground.WUProvider{}
|
||||||
aw.l = zerolog.Ctx(aw.appCtx)
|
aw.l = zerolog.Ctx(aw.appCtx)
|
||||||
|
|
||||||
aw.l.Trace().Any("awConfig", aw.config).Send()
|
aw.l.Trace().Any("awConfig", aw.Config).Send()
|
||||||
return aw
|
return aw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,15 +227,15 @@ func (aw *AmbientWeather) proxyUpdate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AmbientWeather) InitMetrics() {
|
func (aw *AmbientWeather) InitMetrics() {
|
||||||
if aw.config.MetricPrefix != "" {
|
if aw.Config.MetricPrefix != "" {
|
||||||
weather.MetricPrefix = aw.config.MetricPrefix
|
weather.MetricPrefix = aw.Config.MetricPrefix
|
||||||
}
|
}
|
||||||
aw.metrics = weather.MustInitMetrics(aw.appCtx)
|
aw.metrics = weather.MustInitMetrics(aw.appCtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (aw *AmbientWeather) enrichStation(update *weather.WeatherUpdate) {
|
func (aw *AmbientWeather) enrichStation(update *weather.WeatherUpdate) {
|
||||||
if update != nil && update.StationID != nil && *update.StationID != "" {
|
if update != nil && update.StationID != nil && *update.StationID != "" {
|
||||||
for _, station := range aw.config.WeatherStations {
|
for _, station := range aw.Config.WeatherStations {
|
||||||
if *update.StationID == station.AWNPassKey || *update.StationID == station.WundergroundID {
|
if *update.StationID == station.AWNPassKey || *update.StationID == station.WundergroundID {
|
||||||
update.StationConfig = &station
|
update.StationConfig = &station
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import (
|
|||||||
// This configuration includes all config from go-app/config.AppConfig
|
// This configuration includes all config from go-app/config.AppConfig
|
||||||
type AmbientLocalExporterConfig struct {
|
type AmbientLocalExporterConfig struct {
|
||||||
MetricPrefix string `yaml:"metricPrefix" default:"weather" env:"AMBIENT_METRIC_PREFIX"`
|
MetricPrefix string `yaml:"metricPrefix" default:"weather" env:"AMBIENT_METRIC_PREFIX"`
|
||||||
WeatherStations []WeatherStation `yaml:"weatherStations"` // No env, too complex, not worth the time
|
UpdatesToKeep *int `yaml:"updatesToKeep" default:"1" env:"AMBIENT_UPDATES_TO_KEEP"`
|
||||||
|
WeatherStations []WeatherStation `yaml:"weatherStations" env:"weatherStations"` // No env, too complex, not worth the time
|
||||||
*config.AppConfig // Extends app config
|
*config.AppConfig // Extends app config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,25 +25,44 @@ func UpdateToPbUpdate(u *weather.WeatherUpdate) *pb.WeatherUpdate {
|
|||||||
TempIndoorF: u.TempIndoorF,
|
TempIndoorF: u.TempIndoorF,
|
||||||
HumidityOutdoor: ptr.To(int32(*u.HumidityOudoor)),
|
HumidityOutdoor: ptr.To(int32(*u.HumidityOudoor)),
|
||||||
HumidityIndoor: ptr.To(int32(*u.HumidityIndoor)),
|
HumidityIndoor: ptr.To(int32(*u.HumidityIndoor)),
|
||||||
WindSpeedMph: new(float64),
|
WindSpeedMph: ptr.To(*u.WindSpeedMPH),
|
||||||
WindGustMph: new(float64),
|
WindGustMph: ptr.To(*u.WindGustMPH),
|
||||||
MaxDailyGust: new(float64),
|
MaxDailyGust: ptr.To(*u.MaxDailyGust),
|
||||||
WindDir: new(int32),
|
WindDir: ptr.To(int32(*u.WindDir)),
|
||||||
WindDirAvg_10M: new(int32),
|
WindDirAvg_10M: ptr.To(int32(*u.WindDirAvg10m)),
|
||||||
Uv: new(int32),
|
Uv: ptr.To(int32(*u.UV)),
|
||||||
SolarRadiation: new(float64),
|
SolarRadiation: ptr.To(*u.SolarRadiation),
|
||||||
HourlyRainIn: new(float64),
|
HourlyRainIn: ptr.To(*u.HourlyRainIn),
|
||||||
EventRainIn: new(float64),
|
EventRainIn: ptr.To(*u.EventRainIn),
|
||||||
DailyRainIn: new(float64),
|
DailyRainIn: ptr.To(*u.DailyRainIn),
|
||||||
WeeklyRainIn: new(float64),
|
WeeklyRainIn: ptr.To(*u.WeeklyRainIn),
|
||||||
MonthlyRainIn: new(float64),
|
MonthlyRainIn: ptr.To(*u.MonthlyRainIn),
|
||||||
YearlyRainIn: new(float64),
|
YearlyRainIn: ptr.To(*u.YearlyRainIn),
|
||||||
TotalRainIn: new(float64),
|
TotalRainIn: ptr.To(*u.TotalRainIn),
|
||||||
Batteries: []*pb.BatteryStatus{},
|
Batteries: []*pb.BatteryStatus{},
|
||||||
BaromRelativeIn: new(float64),
|
BaromRelativeIn: ptr.To(*u.BaromRelativeIn),
|
||||||
BaromAbsoluteIn: new(float64),
|
BaromAbsoluteIn: ptr.To(*u.BaromAbsoluteIn),
|
||||||
DewPointF: new(float64),
|
DewPointF: ptr.To(*u.DewPointF),
|
||||||
WindChillF: new(float64),
|
WindChillF: ptr.To(*u.WindChillF),
|
||||||
TempHumiditySensors: []*pb.TempHumiditySensor{},
|
TempHumiditySensors: []*pb.TempHumiditySensor{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BatteriesToPbBatteries(batteries []weather.BatteryStatus) []*pb.BatteryStatus {
|
||||||
|
pbBatteries := make([]*pb.BatteryStatus, len(batteries))
|
||||||
|
for i, b := range batteries {
|
||||||
|
pbBatteries[i] = &pb.BatteryStatus{
|
||||||
|
Component: b.Component,
|
||||||
|
Status: ptr.To(int32(*b.Status)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pbBatteries
|
||||||
|
}
|
||||||
|
|
||||||
|
func nilOrValPtr[T *int32 | *float64](v T) *T {
|
||||||
|
switch T.(type) {
|
||||||
|
case *int32:
|
||||||
|
return v.(*int32)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/state"
|
"gitea.libretechconsulting.com/rmcguire/ambient-local-exporter/pkg/weather/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
type GRPCWeather struct {
|
type GRPCWeather struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
state *state.WeatherState
|
state *state.WeatherState
|
||||||
|
Loading…
x
Reference in New Issue
Block a user