Compare commits

..

6 Commits

Author SHA1 Message Date
82ae3e4ba4 add counter support, add lightning time
All checks were successful
Build and Publish / check-chart (push) Successful in 11s
Build and Publish / helm-release (push) Has been skipped
Build and Publish / release (push) Successful in 3m49s
2025-04-03 15:16:42 -04:00
f0bda0a3bd bump helm chart
All checks were successful
Build and Publish / check-chart (push) Successful in 14s
Build and Publish / helm-release (push) Successful in 34s
Build and Publish / release (push) Successful in 3m48s
2025-04-03 13:49:11 -04:00
1ee231fe30 Fix embedded lightning data
All checks were successful
Build and Publish / release (push) Has been skipped
Build and Publish / check-chart (push) Successful in 10s
Build and Publish / helm-release (push) Has been skipped
2025-04-03 13:48:41 -04:00
3279c6fd38 add json tags
All checks were successful
Build and Publish / check-chart (push) Successful in 14s
Build and Publish / helm-release (push) Has been skipped
Build and Publish / release (push) Successful in 3m55s
2025-04-03 13:35:32 -04:00
268bc7d8a2 code tweaks
All checks were successful
Build and Publish / release (push) Has been skipped
Build and Publish / check-chart (push) Successful in 10s
Build and Publish / helm-release (push) Has been skipped
2025-04-03 10:44:43 -04:00
2f83edc426 bump chart
Some checks are pending
Build and Publish / release (push) Waiting to run
Build and Publish / check-chart (push) Successful in 15s
Build and Publish / helm-release (push) Successful in 47s
2025-04-02 20:45:36 -04:00
8 changed files with 79 additions and 65 deletions

View File

@ -2,6 +2,7 @@
- [x] Redis recorder panic - [x] Redis recorder panic
# TODO # TODO
- [ ] Make lightning distance unit configurable (kph|mph)
- [ ] Set TTL on redis key - [ ] Set TTL on redis key
- [ ] Add json schema to CI and README - [ ] Add json schema to CI and README
- [ ] Update README - [ ] Update README

View File

@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # 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. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # 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 # 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 # 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. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "v0.14.0" appVersion: "v0.15.6"
dependencies: dependencies:
- name: hull - name: hull

View File

@ -52,10 +52,8 @@ var mockUpdate = &weather.WeatherUpdate{
TempHumiditySensors: []*weather.TempHumiditySensor{ TempHumiditySensors: []*weather.TempHumiditySensor{
{Name: "sensor1", TempF: ptr.To(99.999), Humidity: nil}, {Name: "sensor1", TempF: ptr.To(99.999), Humidity: nil},
}, },
LightningData: &weather.LightningData{ LightningDay: ptr.To(1),
LightningDay: ptr.To(1), LightningDistance: ptr.To(20),
LightningDistance: ptr.To(20),
},
} }
func TestUpdateToPbUpdate(t *testing.T) { func TestUpdateToPbUpdate(t *testing.T) {

View File

@ -143,11 +143,9 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
{Name: THSensor + "7", TempF: awnUpdate.Temp7F, Humidity: awnUpdate.Humidity7}, {Name: THSensor + "7", TempF: awnUpdate.Temp7F, Humidity: awnUpdate.Humidity7},
{Name: THSensor + "8", TempF: awnUpdate.Temp8F, Humidity: awnUpdate.Humidity8}, {Name: THSensor + "8", TempF: awnUpdate.Temp8F, Humidity: awnUpdate.Humidity8},
}, },
LightningData: &weather.LightningData{ LightningDay: awnUpdate.LightningDay,
LightningDay: awnUpdate.LightningDay, LightningDistance: awnUpdate.LightningDistance,
LightningDistance: awnUpdate.LightningDistance, LightningTime: awnUpdate.LightningTime,
LightningTime: awnUpdate.LightningTime,
},
} }
} }

View File

@ -40,6 +40,7 @@ type WeatherMetrics struct {
// Lightning Sensor // Lightning Sensor
LightningCountDay metric.Int64Gauge LightningCountDay metric.Int64Gauge
LightningLastDistance metric.Int64Gauge LightningLastDistance metric.Int64Gauge
LightningLastTime metric.Int64Gauge
// Temp and Humidity Sensors // Temp and Humidity Sensors
SensorTempF metric.Float64Gauge 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.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}) 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: attributes, Station: u.StationConfig})
wm.recorder.Record(&RecordOpts{Int64Gauge: wm.LightningLastDistance, IntVal: u.LightningDistance, Field: FieldLightningDistance, Attributes: lightningAttributes, 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.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.RecordBatteries(u, attributes)
wm.RecordTempHumiditySensors(u, attributes) wm.RecordTempHumiditySensors(u, attributes)

View File

@ -70,7 +70,11 @@ func MustInitMetrics(appCtx context.Context) *WeatherMetrics {
wm.LightningCountDay, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_day", wm.LightningCountDay, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_day",
metric.WithDescription("Count of lightning strikes for current day")) metric.WithDescription("Count of lightning strikes for current day"))
wm.LightningLastDistance, _ = wm.meter.Int64Gauge(MetricPrefix+"_lightning_last_distance", 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 // Temp and Humidity Sensors
wm.SensorTempF, _ = wm.meter.Float64Gauge(MetricPrefix+"_sensor_temp_f", wm.SensorTempF, _ = wm.meter.Float64Gauge(MetricPrefix+"_sensor_temp_f",

View File

@ -3,6 +3,7 @@ package weather
import ( import (
"context" "context"
"errors" "errors"
"slices"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/attribute"
@ -19,6 +20,7 @@ type MetricRecorder struct {
type RecordOpts struct { type RecordOpts struct {
Float64Gauge metric.Float64Gauge Float64Gauge metric.Float64Gauge
Int64Gauge metric.Int64Gauge Int64Gauge metric.Int64Gauge
Int64Counter metric.Int64Counter
IntVal *int IntVal *int
FloatVal *float64 FloatVal *float64
Attributes []attribute.KeyValue Attributes []attribute.KeyValue
@ -58,26 +60,39 @@ func (r *MetricRecorder) Record(opts *RecordOpts) {
return return
} }
r.recordFloat(opts.Float64Gauge, *opts.FloatVal, opts.Attributes...) 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 { func (o *RecordOpts) keep() bool {
// If keep fields are given, only check keep fields // If keep fields are given, only check keep fields
if len(o.Station.KeepMetrics) > 0 { if len(o.Station.KeepMetrics) > 0 {
for _, f := range o.Station.KeepMetrics { return slices.Contains(o.Station.KeepMetrics, o.Field)
if f == o.Field {
return true
}
}
return false
} }
for _, f := range o.Station.DropMetrics { return !slices.Contains(o.Station.DropMetrics, o.Field)
if f == o.Field { }
return false
} 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( func (r *MetricRecorder) recordInt(

View File

@ -9,56 +9,52 @@ import (
// Stable intermediate struct containing superset of fields // Stable intermediate struct containing superset of fields
// between AWN and Wunderground style updates from Ambient devices // between AWN and Wunderground style updates from Ambient devices
type WeatherUpdate struct { type WeatherUpdate struct {
DateUTC *time.Time DateUTC *time.Time `json:"dateUTC,omitempty"`
StationConfig *config.WeatherStation StationConfig *config.WeatherStation `json:"stationConfig,omitempty"`
StationID *string StationID *string `json:"stationID,omitempty"`
StationType *string StationType *string `json:"stationType,omitempty"`
TempOutdoorF *float64 TempOutdoorF *float64 `json:"tempOutdoorF,omitempty"`
TempIndoorF *float64 TempIndoorF *float64 `json:"tempIndoorF,omitempty"`
HumidityOudoor *int HumidityOudoor *int `json:"humidityOudoor,omitempty"`
HumidityIndoor *int HumidityIndoor *int `json:"humidityIndoor,omitempty"`
WindSpeedMPH *float64 WindSpeedMPH *float64 `json:"windSpeedMPH,omitempty"`
WindGustMPH *float64 WindGustMPH *float64 `json:"windGustMPH,omitempty"`
MaxDailyGust *float64 MaxDailyGust *float64 `json:"maxDailyGust,omitempty"`
WindDir *int WindDir *int `json:"windDir,omitempty"`
WindDirAvg10m *int WindDirAvg10m *int `json:"windDirAvg10M,omitempty"`
UV *int UV *int `json:"uv,omitempty"`
SolarRadiation *float64 SolarRadiation *float64 `json:"solarRadiation,omitempty"`
HourlyRainIn *float64 HourlyRainIn *float64 `json:"hourlyRainIn,omitempty"`
EventRainIn *float64 EventRainIn *float64 `json:"eventRainIn,omitempty"`
DailyRainIn *float64 DailyRainIn *float64 `json:"dailyRainIn,omitempty"`
WeeklyRainIn *float64 WeeklyRainIn *float64 `json:"weeklyRainIn,omitempty"`
MonthlyRainIn *float64 MonthlyRainIn *float64 `json:"monthlyRainIn,omitempty"`
YearlyRainIn *float64 YearlyRainIn *float64 `json:"yearlyRainIn,omitempty"`
TotalRainIn *float64 TotalRainIn *float64 `json:"totalRainIn,omitempty"`
Batteries []BatteryStatus Batteries []BatteryStatus `json:"batteries,omitempty"`
BaromRelativeIn *float64 BaromRelativeIn *float64 `json:"baromRelativeIn,omitempty"`
BaromAbsoluteIn *float64 BaromAbsoluteIn *float64 `json:"baromAbsoluteIn,omitempty"`
// These fields may be calculated // These fields may be calculated
// if not otherwise set // if not otherwise set
DewPointF *float64 DewPointF *float64 `json:"dewPointF,omitempty"`
WindChillF *float64 WindChillF *float64 `json:"windChillF,omitempty"`
// Extra Temp+Humidity Sensors // Extra Temp+Humidity Sensors
TempHumiditySensors []*TempHumiditySensor TempHumiditySensors []*TempHumiditySensor `json:"tempHumiditySensors,omitempty"`
// Lightning Data // Lightning Data
*LightningData 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 LightningData struct {
LightningDay *int // Count of detections
LightningDistance *int // Last detection distance [kilometers]
LightningTime *int // Last detection time
} }
type TempHumiditySensor struct { type TempHumiditySensor struct {
Name string Name string `json:"name,omitempty"`
TempF *float64 TempF *float64 `json:"tempF,omitempty"`
Humidity *int Humidity *int `json:"humidity,omitempty"`
} }
type BatteryStatus struct { type BatteryStatus struct {
Component string Component string `json:"component,omitempty"`
Status *int Status *int `json:"status,omitempty"`
} }
// CHORE: Maintain this, used to check against // CHORE: Maintain this, used to check against
@ -94,6 +90,7 @@ const (
FieldSensorHumidity = "SensorHumidity" FieldSensorHumidity = "SensorHumidity"
FieldLightningDay = "LightningDay" FieldLightningDay = "LightningDay"
FieldLightningDistance = "LightningDistance" FieldLightningDistance = "LightningDistance"
FieldLightningLastTime = "LightningLastTime"
) )
func (u *WeatherUpdate) GetStationName() string { func (u *WeatherUpdate) GetStationName() string {