Proxy support for AWN/Wunderground
This commit is contained in:
parent
849dbfb6ff
commit
7fc1fc9b56
3
go.mod
3
go.mod
@ -4,6 +4,7 @@ go 1.23.4
|
||||
|
||||
require (
|
||||
gitea.libretechconsulting.com/rmcguire/go-app v0.3.1
|
||||
github.com/go-resty/resty/v2 v2.16.3
|
||||
github.com/gorilla/schema v1.4.1
|
||||
github.com/rs/zerolog v1.33.0
|
||||
go.opentelemetry.io/otel v1.33.0
|
||||
@ -22,7 +23,7 @@ require (
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_golang v1.20.5 // indirect
|
||||
|
19
go.sum
19
go.sum
@ -1,5 +1,3 @@
|
||||
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=
|
||||
gitea.libretechconsulting.com/rmcguire/go-app v0.3.1 h1:jydcJ+Vv8sk+Le7nTI2+b6E7FfV+ShBJo7YdxmdaCYc=
|
||||
gitea.libretechconsulting.com/rmcguire/go-app v0.3.1/go.mod h1:wHOWh4O4AMDATQ3WEUYjq5a5bnICPBpu5G6BsNxqN38=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
@ -20,6 +18,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E=
|
||||
github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
@ -39,8 +39,9 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
@ -91,14 +92,10 @@ go.opentelemetry.io/otel/sdk/metric v1.33.0 h1:Gs5VK9/WUJhNXZgn8MR6ITatvAmKeIuCt
|
||||
go.opentelemetry.io/otel/sdk/metric v1.33.0/go.mod h1:dL5ykHZmm1B1nVRk9dDjChwDmt81MjVp3gLkQRwKf/Q=
|
||||
go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s=
|
||||
go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg=
|
||||
go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -108,18 +105,14 @@ golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
||||
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
|
||||
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
||||
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -114,6 +114,26 @@ func (aw *AmbientWeather) handleProviderRequest(
|
||||
Any("update", update).
|
||||
Msg("successfully handled update")
|
||||
w.Write([]byte("ok"))
|
||||
|
||||
// Proxy update to one or both services if configured to do so
|
||||
// Uses a weather update to allow awn to publish to wunderground and
|
||||
// visa versa.
|
||||
if station := aw.config.GetStation(update.GetStationName()); station != nil {
|
||||
if station.ProxyToAWN {
|
||||
err := aw.awnProvider.ProxyReq(ctx, update)
|
||||
if err != nil {
|
||||
zerolog.Ctx(aw.appCtx).Err(err).Msg("failed to proxy to ambient weather")
|
||||
}
|
||||
}
|
||||
if station.ProxyToWunderground {
|
||||
err := aw.awnProvider.ProxyReq(ctx, update)
|
||||
if err != nil {
|
||||
zerolog.Ctx(aw.appCtx).Err(err).Msg("failed to proxy to ambient weather")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (aw *AmbientWeather) InitMetrics() {
|
||||
|
@ -35,3 +35,12 @@ type WeatherStation struct {
|
||||
KeepMetrics []weather.WeatherUpdateField `yaml:"keepMetrics"`
|
||||
DropMetrics []weather.WeatherUpdateField `yaml:"dropMetrics"`
|
||||
}
|
||||
|
||||
func (wc *AmbientLocalExporterConfig) GetStation(name string) *WeatherStation {
|
||||
for _, station := range wc.WeatherStations {
|
||||
if station.Name == name {
|
||||
return &station
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -2,18 +2,27 @@ package awn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/gorilla/schema"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/otel"
|
||||
|
||||
"gitea.libretechconsulting.com/rmcguire/ambient-weather-local-exporter/pkg/weather"
|
||||
)
|
||||
|
||||
type AWNProvider struct{}
|
||||
|
||||
const providerName = "awn"
|
||||
const (
|
||||
providerName = "awn"
|
||||
awnURL = "http://ambientweather.net/data/report"
|
||||
)
|
||||
|
||||
func (awn *AWNProvider) Name() string {
|
||||
return providerName
|
||||
@ -32,6 +41,74 @@ func (awn *AWNProvider) ReqToWeather(_ context.Context, r *http.Request) (
|
||||
return MapAwnUpdate(awnUpdate), nil
|
||||
}
|
||||
|
||||
// Attempts to proxy the weather station update to awn
|
||||
// SAMPLE:
|
||||
// {"PASSKEY":["ABF7E052BC7325A32300ACC89112AA91"],"baromabsin":["28.895"],
|
||||
// "baromrelin":["29.876"],"battin":["1"],"battout":["1"],"battrain":["1"],
|
||||
// "dailyrainin":["0.000"],"dateutc":["2025-01-11 22:07:57"],"eventrainin":["0.000"],
|
||||
// "hourlyrainin":["0.000"],"humidity":["76"],"humidityin":["31"],"maxdailygust":["7.83"],
|
||||
// "monthlyrainin":["0.000"],"solarradiation":["14.21"],"stationtype":["WeatherHub_V1.0.1"],
|
||||
// "tempf":["29.48"],"tempinf":["66.20"],"totalrainin":["0.000"],"uv":["0"],
|
||||
// "weeklyrainin":["0.000"],"winddir":["66"],"winddir_avg10m":["268"],"windgustmph":["2.68"],
|
||||
// "windspeedmph":["0.00"],"yearlyrainin":["0.000"]}
|
||||
func (awn *AWNProvider) ProxyReq(ctx context.Context, update *weather.WeatherUpdate) error {
|
||||
tracer := otel.GetTracer(ctx, "awnProvider", "proxyReq")
|
||||
ctx, span := tracer.Start(ctx, "proxyToAWN")
|
||||
defer span.End()
|
||||
|
||||
if update.WeatherServiceCredentials["PASSKEY"] == "" {
|
||||
err := errors.New("no PASSKEY set in update")
|
||||
span.RecordError(err)
|
||||
return err
|
||||
}
|
||||
|
||||
params := updateToAWNParams(update)
|
||||
|
||||
resp, err := resty.New().R().
|
||||
SetContext(ctx).
|
||||
SetQueryParamsFromValues(*params).
|
||||
Get(awnURL)
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
}
|
||||
|
||||
span.SetAttributes(
|
||||
attribute.Int("statusCode", resp.StatusCode()),
|
||||
attribute.String("body", string(resp.Body())),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func updateToAWNParams(update *weather.WeatherUpdate) *url.Values {
|
||||
params := &url.Values{}
|
||||
params.Set("PASSKEY", update.WeatherServiceCredentials["PASSKEY"])
|
||||
params.Set("dateutc", time.Now().Format(time.DateTime))
|
||||
weather.SetURLVal(params, "baromabsin", update.BaromAbsoluteIn)
|
||||
weather.SetURLVal(params, "baromrelin", update.BaromRelativeIn)
|
||||
weather.SetURLVal(params, "dailyrainin", update.DailyRainIn)
|
||||
weather.SetURLVal(params, "weeklyrainin", update.WeeklyRainIn)
|
||||
weather.SetURLVal(params, "eventrainin", update.EventRainIn)
|
||||
weather.SetURLVal(params, "hourlyrainin", update.HourlyRainIn)
|
||||
weather.SetURLVal(params, "monthlyrainin", update.MonthlyRainIn)
|
||||
weather.SetURLVal(params, "yearlyrainin", update.YearlyRainIn)
|
||||
weather.SetURLVal(params, "totalrainin", update.TotalRainIn)
|
||||
weather.SetURLVal(params, "humidity", update.HumidityOudoor)
|
||||
weather.SetURLVal(params, "humidityin", update.HumidityIndoor)
|
||||
weather.SetURLVal(params, "solarradiation", update.SolarRadiation)
|
||||
weather.SetURLVal(params, "uv", update.UV)
|
||||
weather.SetURLVal(params, "stationtype", update.StationType)
|
||||
weather.SetURLVal(params, "tempf", update.TempOutdoorF)
|
||||
weather.SetURLVal(params, "tempinf", update.TempIndoorF)
|
||||
weather.SetURLVal(params, "winddir", update.WindDir)
|
||||
weather.SetURLVal(params, "winddir_avg10m", update.WindDirAvg10m)
|
||||
weather.SetURLVal(params, "windgustmph", update.WindGustMPH)
|
||||
weather.SetURLVal(params, "windspeedmph", update.WindSpeedMPH)
|
||||
weather.SetURLVal(params, "maxdailygust", update.MaxDailyGust)
|
||||
return params
|
||||
}
|
||||
|
||||
func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
|
||||
updateTime := time.Now()
|
||||
if awnUpdate.DateUTC != nil {
|
||||
@ -41,6 +118,11 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
credentials := make(map[string]string)
|
||||
if awnUpdate.PassKey != nil {
|
||||
credentials["PASSKEY"] = *awnUpdate.PassKey
|
||||
}
|
||||
|
||||
return &weather.WeatherUpdate{
|
||||
DateUTC: &updateTime,
|
||||
StationID: awnUpdate.PassKey,
|
||||
@ -79,10 +161,11 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
|
||||
Status: awnUpdate.BattCO2,
|
||||
},
|
||||
},
|
||||
TempIndoorF: awnUpdate.TempInF,
|
||||
HumidityIndoor: awnUpdate.HumidityIn,
|
||||
BaromRelativeIn: awnUpdate.BaromRelIn,
|
||||
BaromAbsoluteIn: awnUpdate.BaromAbsIn,
|
||||
TempIndoorF: awnUpdate.TempInF,
|
||||
HumidityIndoor: awnUpdate.HumidityIn,
|
||||
BaromRelativeIn: awnUpdate.BaromRelIn,
|
||||
BaromAbsoluteIn: awnUpdate.BaromAbsIn,
|
||||
WeatherServiceCredentials: credentials,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,5 +11,6 @@ import (
|
||||
// Ambient Weather Network HTTP requests to a stable struct
|
||||
type AmbientProvider interface {
|
||||
ReqToWeather(context.Context, *http.Request) (*weather.WeatherUpdate, error)
|
||||
ProxyReq(context.Context, *weather.WeatherUpdate) error
|
||||
Name() string
|
||||
}
|
||||
|
@ -13,7 +13,10 @@ import (
|
||||
|
||||
type WUProvider struct{}
|
||||
|
||||
const providerName = "weatherunderground"
|
||||
const (
|
||||
providerName = "weatherunderground"
|
||||
wuURL = "http://rtupdate.wunderground.com/weatherstation/updateweatherstation.php"
|
||||
)
|
||||
|
||||
func (wu *WUProvider) Name() string {
|
||||
return providerName
|
||||
@ -32,6 +35,29 @@ func (wu *WUProvider) ReqToWeather(_ context.Context, r *http.Request) (
|
||||
return MapWUUpdate(wuUpdate), nil
|
||||
}
|
||||
|
||||
func (wu *WUProvider) ProxyReq(ctx context.Context, update *weather.WeatherUpdate) error {
|
||||
// tracer := otel.GetTracer(ctx, "wuProvider", "proxyReq")
|
||||
// ctx, span := tracer.Start(ctx, "proxyToWunderground")
|
||||
// defer span.End()
|
||||
//
|
||||
// resp, err := resty.New().R().
|
||||
// SetContext(ctx).
|
||||
// SetQueryParamsFromValues(r.URL.Query()).
|
||||
// Get(wuURL)
|
||||
// if err != nil {
|
||||
// span.SetStatus(codes.Error, err.Error())
|
||||
// span.RecordError(err)
|
||||
// }
|
||||
//
|
||||
// span.SetAttributes(
|
||||
// attribute.Int("statusCode", resp.StatusCode()),
|
||||
// attribute.String("body", string(resp.Body())),
|
||||
// )
|
||||
//
|
||||
// return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func MapWUUpdate(wuUpdate *WundergroundUpdate) *weather.WeatherUpdate {
|
||||
updateTime := time.Now()
|
||||
|
||||
@ -42,25 +68,32 @@ func MapWUUpdate(wuUpdate *WundergroundUpdate) *weather.WeatherUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
credentials := make(map[string]string)
|
||||
if wuUpdate.ID != nil && wuUpdate.Password != nil {
|
||||
credentials["ID"] = *wuUpdate.ID
|
||||
credentials["Password"] = *wuUpdate.Password
|
||||
}
|
||||
|
||||
return &weather.WeatherUpdate{
|
||||
DateUTC: &updateTime,
|
||||
StationID: wuUpdate.ID,
|
||||
StationType: wuUpdate.SoftwareType,
|
||||
TempOutdoorF: wuUpdate.Tempf,
|
||||
HumidityOudoor: wuUpdate.Humidity,
|
||||
WindSpeedMPH: wuUpdate.WindGustMPH,
|
||||
WindGustMPH: wuUpdate.WindGustMPH,
|
||||
WindDir: wuUpdate.WindDir,
|
||||
UV: wuUpdate.UV,
|
||||
SolarRadiation: wuUpdate.SolarRadiation,
|
||||
HourlyRainIn: wuUpdate.RainIn,
|
||||
DailyRainIn: wuUpdate.DailyRainIn,
|
||||
WeeklyRainIn: wuUpdate.WeeklyRainIn,
|
||||
MonthlyRainIn: wuUpdate.MonthlyRainIn,
|
||||
YearlyRainIn: wuUpdate.YearlyRainIn,
|
||||
TempIndoorF: wuUpdate.IndoorTempF,
|
||||
HumidityIndoor: wuUpdate.IndoorHumidity,
|
||||
BaromRelativeIn: wuUpdate.BaromIn,
|
||||
DateUTC: &updateTime,
|
||||
StationID: wuUpdate.ID,
|
||||
StationType: wuUpdate.SoftwareType,
|
||||
TempOutdoorF: wuUpdate.Tempf,
|
||||
HumidityOudoor: wuUpdate.Humidity,
|
||||
WindSpeedMPH: wuUpdate.WindGustMPH,
|
||||
WindGustMPH: wuUpdate.WindGustMPH,
|
||||
WindDir: wuUpdate.WindDir,
|
||||
UV: wuUpdate.UV,
|
||||
SolarRadiation: wuUpdate.SolarRadiation,
|
||||
HourlyRainIn: wuUpdate.RainIn,
|
||||
DailyRainIn: wuUpdate.DailyRainIn,
|
||||
WeeklyRainIn: wuUpdate.WeeklyRainIn,
|
||||
MonthlyRainIn: wuUpdate.MonthlyRainIn,
|
||||
YearlyRainIn: wuUpdate.YearlyRainIn,
|
||||
TempIndoorF: wuUpdate.IndoorTempF,
|
||||
HumidityIndoor: wuUpdate.IndoorHumidity,
|
||||
BaromRelativeIn: wuUpdate.BaromIn,
|
||||
WeatherServiceCredentials: credentials,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
package weather
|
||||
|
||||
import "math"
|
||||
import (
|
||||
"math"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Attempts to complete missing fields that may not
|
||||
// be set by a specific provider, such as DewPoint and WindChill
|
||||
@ -53,3 +57,31 @@ func CalculateWindChill(tempF float64, windSpeedMPH float64) float64 {
|
||||
35.75*math.Pow(windSpeedMPH, 0.16) +
|
||||
0.4275*tempF*math.Pow(windSpeedMPH, 0.16)
|
||||
}
|
||||
|
||||
// Helper function to set values from fields
|
||||
// typically from a WeatherUpdate
|
||||
func SetURLVal(vals *url.Values, key string, value any) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch v := value.(type) {
|
||||
case *float64:
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
str := strconv.FormatFloat(*v, 'f', 4, 64)
|
||||
vals.Set(key, str)
|
||||
case *int:
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
str := strconv.FormatInt(int64(*v), 10)
|
||||
vals.Set(key, str)
|
||||
case *string:
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
vals.Set(key, *v)
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ type WeatherUpdate struct {
|
||||
// if not otherwise set
|
||||
DewPointF *float64
|
||||
WindChillF *float64
|
||||
// First URL parameters given to AWN/Wunderground
|
||||
// if proxying is enabled
|
||||
WeatherServiceCredentials map[string]string
|
||||
}
|
||||
|
||||
type StationInfo struct {
|
||||
@ -82,3 +85,17 @@ const (
|
||||
FieldDewPointF WeatherUpdateField = "DewPointF"
|
||||
FieldWindChillF WeatherUpdateField = "WindChillF"
|
||||
)
|
||||
|
||||
func (u *WeatherUpdate) GetStationName() string {
|
||||
if u.StationInfo != nil {
|
||||
return u.StationInfo.GetName()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (si *StationInfo) GetName() string {
|
||||
if si.Name != nil {
|
||||
return *si.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user