Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
82ae3e4ba4 | |||
f0bda0a3bd | |||
1ee231fe30 | |||
3279c6fd38 | |||
268bc7d8a2 | |||
2f83edc426 | |||
80f9c00615 |
1
TODO.md
1
TODO.md
@ -2,6 +2,7 @@
|
||||
- [x] Redis recorder panic
|
||||
|
||||
# TODO
|
||||
- [ ] Make lightning distance unit configurable (kph|mph)
|
||||
- [ ] Set TTL on redis key
|
||||
- [ ] Add json schema to CI and README
|
||||
- [ ] Update README
|
||||
|
@ -15,13 +15,13 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 0.1.8
|
||||
version: 0.1.10
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "v0.14.0"
|
||||
appVersion: "v0.15.6"
|
||||
|
||||
dependencies:
|
||||
- name: hull
|
||||
|
@ -52,10 +52,8 @@ var mockUpdate = &weather.WeatherUpdate{
|
||||
TempHumiditySensors: []*weather.TempHumiditySensor{
|
||||
{Name: "sensor1", TempF: ptr.To(99.999), Humidity: nil},
|
||||
},
|
||||
LightningData: &weather.LightningData{
|
||||
LightningDay: ptr.To(1),
|
||||
LightningDistance: ptr.To(20),
|
||||
},
|
||||
LightningDay: ptr.To(1),
|
||||
LightningDistance: ptr.To(20),
|
||||
}
|
||||
|
||||
func TestUpdateToPbUpdate(t *testing.T) {
|
||||
@ -107,7 +105,9 @@ func TestUpdateToPbUpdate(t *testing.T) {
|
||||
Humidity: nil,
|
||||
},
|
||||
},
|
||||
UpdateTimestamp: timestamppb.New(now),
|
||||
UpdateTimestamp: timestamppb.New(now),
|
||||
LightningDay: ptr.To(int32(1)),
|
||||
LightningDistance: ptr.To(int32(20)),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -143,11 +143,9 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
|
||||
{Name: THSensor + "7", TempF: awnUpdate.Temp7F, Humidity: awnUpdate.Humidity7},
|
||||
{Name: THSensor + "8", TempF: awnUpdate.Temp8F, Humidity: awnUpdate.Humidity8},
|
||||
},
|
||||
LightningData: &weather.LightningData{
|
||||
LightningDay: awnUpdate.LightningDay,
|
||||
LightningDistance: awnUpdate.LightningDistance,
|
||||
LightningTime: awnUpdate.LightningTime,
|
||||
},
|
||||
LightningDay: awnUpdate.LightningDay,
|
||||
LightningDistance: awnUpdate.LightningDistance,
|
||||
LightningTime: awnUpdate.LightningTime,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ type WeatherMetrics struct {
|
||||
// Lightning Sensor
|
||||
LightningCountDay metric.Int64Gauge
|
||||
LightningLastDistance metric.Int64Gauge
|
||||
LightningLastTime metric.Int64Gauge
|
||||
|
||||
// Temp and Humidity Sensors
|
||||
SensorTempF metric.Float64Gauge
|
||||
@ -79,9 +80,9 @@ func (wm *WeatherMetrics) Update(u *WeatherUpdate) {
|
||||
wm.recorder.Record(&RecordOpts{Float64Gauge: wm.DewPointF, FloatVal: u.DewPointF, Field: FieldDewPointF, Attributes: attributes, Station: u.StationConfig})
|
||||
wm.recorder.Record(&RecordOpts{Float64Gauge: wm.WindChillF, FloatVal: u.WindChillF, Field: FieldWindChillF, Attributes: attributes, Station: u.StationConfig})
|
||||
|
||||
lightningAttributes := append(attributes, attribute.String("unit", "km"))
|
||||
wm.recorder.Record(&RecordOpts{Int64Gauge: wm.LightningLastDistance, IntVal: u.LightningDistance, Field: FieldLightningDistance, Attributes: lightningAttributes, Station: u.StationConfig})
|
||||
wm.recorder.Record(&RecordOpts{Int64Gauge: wm.LightningLastDistance, IntVal: u.LightningDistance, Field: FieldLightningDistance, Attributes: attributes, Station: u.StationConfig})
|
||||
wm.recorder.Record(&RecordOpts{Int64Gauge: wm.LightningCountDay, IntVal: u.LightningDay, Field: FieldLightningDay, Attributes: attributes, Station: u.StationConfig})
|
||||
wm.recorder.Record(&RecordOpts{Int64Gauge: wm.LightningLastTime, IntVal: u.LightningTime, Field: FieldLightningLastTime, Attributes: attributes, Station: u.StationConfig})
|
||||
|
||||
wm.RecordBatteries(u, attributes)
|
||||
wm.RecordTempHumiditySensors(u, attributes)
|
||||
|
@ -70,7 +70,11 @@ func MustInitMetrics(appCtx context.Context) *WeatherMetrics {
|
||||
wm.LightningCountDay, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_day",
|
||||
metric.WithDescription("Count of lightning strikes for current day"))
|
||||
wm.LightningLastDistance, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_last_distance",
|
||||
metric.WithDescription("Last measured lightning distance"))
|
||||
metric.WithDescription("Last measured lightning distance"),
|
||||
metric.WithUnit("kph"))
|
||||
wm.LightningLastTime, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_last_time",
|
||||
metric.WithDescription("Last lightning time (epoch)"),
|
||||
metric.WithUnit("s"))
|
||||
|
||||
// Temp and Humidity Sensors
|
||||
wm.SensorTempF, _ = wm.meter.Float64Gauge(MetricPrefix+"_sensor_temp_f",
|
||||
|
@ -3,6 +3,7 @@ package weather
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"slices"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@ -19,6 +20,7 @@ type MetricRecorder struct {
|
||||
type RecordOpts struct {
|
||||
Float64Gauge metric.Float64Gauge
|
||||
Int64Gauge metric.Int64Gauge
|
||||
Int64Counter metric.Int64Counter
|
||||
IntVal *int
|
||||
FloatVal *float64
|
||||
Attributes []attribute.KeyValue
|
||||
@ -58,26 +60,39 @@ func (r *MetricRecorder) Record(opts *RecordOpts) {
|
||||
return
|
||||
}
|
||||
r.recordFloat(opts.Float64Gauge, *opts.FloatVal, opts.Attributes...)
|
||||
} else if opts.Int64Counter != nil {
|
||||
if opts.IntVal == nil {
|
||||
log := r.l.Trace().Str("field", string(opts.Field))
|
||||
if opts.Station != nil {
|
||||
log = log.Str("station", opts.Station.Name)
|
||||
}
|
||||
log.Msg("Dropping nil float metric")
|
||||
return
|
||||
}
|
||||
r.recordCounter(opts.Int64Counter, *opts.IntVal, opts.Attributes...)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *RecordOpts) keep() bool {
|
||||
// If keep fields are given, only check keep fields
|
||||
if len(o.Station.KeepMetrics) > 0 {
|
||||
for _, f := range o.Station.KeepMetrics {
|
||||
if f == o.Field {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(o.Station.KeepMetrics, o.Field)
|
||||
}
|
||||
|
||||
for _, f := range o.Station.DropMetrics {
|
||||
if f == o.Field {
|
||||
return false
|
||||
}
|
||||
return !slices.Contains(o.Station.DropMetrics, o.Field)
|
||||
}
|
||||
|
||||
func (r *MetricRecorder) recordCounter(
|
||||
m metric.Int64Counter, value int, attributes ...attribute.KeyValue,
|
||||
) {
|
||||
// Prepare metric attributes
|
||||
options := make([]metric.AddOption, 0, len(attributes))
|
||||
if len(attributes) > 0 {
|
||||
options = append(options, metric.WithAttributes(attributes...))
|
||||
}
|
||||
return true
|
||||
|
||||
val := int64(value)
|
||||
m.Add(r.ctx, val, options...)
|
||||
}
|
||||
|
||||
func (r *MetricRecorder) recordInt(
|
||||
|
@ -9,56 +9,52 @@ import (
|
||||
// Stable intermediate struct containing superset of fields
|
||||
// between AWN and Wunderground style updates from Ambient devices
|
||||
type WeatherUpdate struct {
|
||||
DateUTC *time.Time
|
||||
StationConfig *config.WeatherStation
|
||||
StationID *string
|
||||
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
|
||||
DateUTC *time.Time `json:"dateUTC,omitempty"`
|
||||
StationConfig *config.WeatherStation `json:"stationConfig,omitempty"`
|
||||
StationID *string `json:"stationID,omitempty"`
|
||||
StationType *string `json:"stationType,omitempty"`
|
||||
TempOutdoorF *float64 `json:"tempOutdoorF,omitempty"`
|
||||
TempIndoorF *float64 `json:"tempIndoorF,omitempty"`
|
||||
HumidityOudoor *int `json:"humidityOudoor,omitempty"`
|
||||
HumidityIndoor *int `json:"humidityIndoor,omitempty"`
|
||||
WindSpeedMPH *float64 `json:"windSpeedMPH,omitempty"`
|
||||
WindGustMPH *float64 `json:"windGustMPH,omitempty"`
|
||||
MaxDailyGust *float64 `json:"maxDailyGust,omitempty"`
|
||||
WindDir *int `json:"windDir,omitempty"`
|
||||
WindDirAvg10m *int `json:"windDirAvg10M,omitempty"`
|
||||
UV *int `json:"uv,omitempty"`
|
||||
SolarRadiation *float64 `json:"solarRadiation,omitempty"`
|
||||
HourlyRainIn *float64 `json:"hourlyRainIn,omitempty"`
|
||||
EventRainIn *float64 `json:"eventRainIn,omitempty"`
|
||||
DailyRainIn *float64 `json:"dailyRainIn,omitempty"`
|
||||
WeeklyRainIn *float64 `json:"weeklyRainIn,omitempty"`
|
||||
MonthlyRainIn *float64 `json:"monthlyRainIn,omitempty"`
|
||||
YearlyRainIn *float64 `json:"yearlyRainIn,omitempty"`
|
||||
TotalRainIn *float64 `json:"totalRainIn,omitempty"`
|
||||
Batteries []BatteryStatus `json:"batteries,omitempty"`
|
||||
BaromRelativeIn *float64 `json:"baromRelativeIn,omitempty"`
|
||||
BaromAbsoluteIn *float64 `json:"baromAbsoluteIn,omitempty"`
|
||||
// These fields may be calculated
|
||||
// if not otherwise set
|
||||
DewPointF *float64
|
||||
WindChillF *float64
|
||||
DewPointF *float64 `json:"dewPointF,omitempty"`
|
||||
WindChillF *float64 `json:"windChillF,omitempty"`
|
||||
// Extra Temp+Humidity Sensors
|
||||
TempHumiditySensors []*TempHumiditySensor
|
||||
TempHumiditySensors []*TempHumiditySensor `json:"tempHumiditySensors,omitempty"`
|
||||
// Lightning Data
|
||||
*LightningData
|
||||
}
|
||||
|
||||
type LightningData struct {
|
||||
LightningDay *int // Count of detections
|
||||
LightningDistance *int // Last detection distance [kilometers]
|
||||
LightningTime *int // Last detection time
|
||||
LightningDay *int `json:"lightningDay,omitempty"` // Count of detections
|
||||
LightningDistance *int `json:"lightningDistance,omitempty"` // Last detection distance [kilometers]
|
||||
LightningTime *int `json:"lightningTime,omitempty"` // Last detection time
|
||||
}
|
||||
|
||||
type TempHumiditySensor struct {
|
||||
Name string
|
||||
TempF *float64
|
||||
Humidity *int
|
||||
Name string `json:"name,omitempty"`
|
||||
TempF *float64 `json:"tempF,omitempty"`
|
||||
Humidity *int `json:"humidity,omitempty"`
|
||||
}
|
||||
|
||||
type BatteryStatus struct {
|
||||
Component string
|
||||
Status *int
|
||||
Component string `json:"component,omitempty"`
|
||||
Status *int `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// CHORE: Maintain this, used to check against
|
||||
@ -94,6 +90,7 @@ const (
|
||||
FieldSensorHumidity = "SensorHumidity"
|
||||
FieldLightningDay = "LightningDay"
|
||||
FieldLightningDistance = "LightningDistance"
|
||||
FieldLightningLastTime = "LightningLastTime"
|
||||
)
|
||||
|
||||
func (u *WeatherUpdate) GetStationName() string {
|
||||
|
Reference in New Issue
Block a user