Compare commits
	
		
			21 Commits
		
	
	
		
			v0.2.1
			...
			fa0a9f4ddc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fa0a9f4ddc | |||
| 689790fe86 | |||
| 3af1cc40a5 | |||
| 4ff684abe3 | |||
| 87f0cbac01 | |||
| 4c93303f27 | |||
| e8654e76bc | |||
| 54f725c822 | |||
| c002331fd4 | |||
| 2ed4eca56c | |||
| 2e3cfb44f4 | |||
| be8a4f3bca | |||
| 96dfcf7e53 | |||
| 5fc16b39af | |||
| 1ae58f64ca | |||
| bb4e4aa2af | |||
| f102ef50bf | |||
| d3d251ef30 | |||
| eecaf2a82e | |||
| f0f6c58f0b | |||
| 681c7f703b | 
@@ -79,7 +79,9 @@ jobs:
 | 
			
		||||
        with:
 | 
			
		||||
          context: .
 | 
			
		||||
          push: true
 | 
			
		||||
          tags: ${{ env.DOCKER_IMG }}:${{ github.ref_name }}
 | 
			
		||||
          tags: |
 | 
			
		||||
            ${{ env.DOCKER_IMG }}:${{ github.ref_name }}
 | 
			
		||||
            ${{ env.DOCKER_IMG }}:latest
 | 
			
		||||
          build-args: |
 | 
			
		||||
            VER_PKG={{ env.VER_PKG }}
 | 
			
		||||
            VER_PKG=${{ env.VER_PKG }}
 | 
			
		||||
            VERSION=${{ github.ref_name }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -20,7 +20,11 @@
 | 
			
		||||
 | 
			
		||||
# Go workspace file
 | 
			
		||||
go.work
 | 
			
		||||
go.work.sum
 | 
			
		||||
 | 
			
		||||
.env
 | 
			
		||||
 | 
			
		||||
bin/*
 | 
			
		||||
 | 
			
		||||
config.yaml
 | 
			
		||||
docker-compose.yml
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -3,7 +3,7 @@ CMD_NAME := ambient-local-exporter
 | 
			
		||||
.PHONY: all test build docker install clean
 | 
			
		||||
 | 
			
		||||
VERSION ?= development # Default to "development" if VERSION is not set
 | 
			
		||||
PLATFORMS := linux/amd64 darwin/amd64 darwin/arm64
 | 
			
		||||
PLATFORMS := linux/amd64 linux/arm64 darwin/amd64 darwin/arm64
 | 
			
		||||
OUTPUT_DIR := bin
 | 
			
		||||
VER_PKG := gitea.libretechconsulting.com/rmcguire/go-app/pkg/config.Version
 | 
			
		||||
DOCKER_IMG := gitea.libretechconsulting.com/rmcguire/ambient-local-exporter
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								TODO.md
									
									
									
									
									
								
							@@ -1,10 +1,19 @@
 | 
			
		||||
# TODO
 | 
			
		||||
 | 
			
		||||
- [ ] Fix shutdown
 | 
			
		||||
- [ ] Configuration for app
 | 
			
		||||
- [ ] Makefile
 | 
			
		||||
- [ ] Dockerfile
 | 
			
		||||
- [ ] Configurable metric prefix
 | 
			
		||||
- [ ] Helm Chart
 | 
			
		||||
- [ ] Gitea CI
 | 
			
		||||
- [ ] Update README
 | 
			
		||||
- [ ] Version flag
 | 
			
		||||
- [ ] Add Grafana dashboard
 | 
			
		||||
- [ ] Add device name field with ID/Key mappings
 | 
			
		||||
- [ ] Add device type field with ID/Key mappings
 | 
			
		||||
- [ ] Move EVERYTHING to pointers to support nil
 | 
			
		||||
- [ ] Add proxy to upstream support
 | 
			
		||||
 | 
			
		||||
## Done
 | 
			
		||||
- [x] Consolidate battery status into one metric with device label
 | 
			
		||||
- [x] Fix shutdown
 | 
			
		||||
- [x] Add new fields from WS-2192
 | 
			
		||||
- [x] Gitea CI
 | 
			
		||||
- [x] Version flag
 | 
			
		||||
- [x] Makefile
 | 
			
		||||
- [x] Dockerfile
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,10 @@ services:
 | 
			
		||||
      APP_LOG_FORMAT: json ## console, json
 | 
			
		||||
      APP_LOG_TIME_FORMAT: rfc3339 ## long, short, unix, rfc3339, off
 | 
			
		||||
      APP_HTTP_LISTEN: 0.0.0.0:8080
 | 
			
		||||
      APP_HTTP_READ_TIMEOUT: 10s
 | 
			
		||||
      APP_HTTP_WRITE_TIMEOUT: 10s
 | 
			
		||||
      APP_HTTP_IDLE_TIMEOUT: 30s
 | 
			
		||||
      APP_HTTP_LOG_REQUESTS: true
 | 
			
		||||
      APP_OTEL_STDOUT_ENABLED: false
 | 
			
		||||
      APP_OTEL_METRIC_INTERVAL_SECS: 30
 | 
			
		||||
      OTEL_EXPORTER_OTLP_ENDPOINT: http://otel.libretechconsulting.com:4317 # Set to your otel collector
 | 
			
		||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -3,7 +3,7 @@ module gitea.libretechconsulting.com/rmcguire/ambient-weather-local-exporter
 | 
			
		||||
go 1.23.4
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	gitea.libretechconsulting.com/rmcguire/go-app v0.1.1
 | 
			
		||||
	gitea.libretechconsulting.com/rmcguire/go-app v0.3.0
 | 
			
		||||
	github.com/gorilla/schema v1.4.1
 | 
			
		||||
	github.com/rs/zerolog v1.33.0
 | 
			
		||||
	go.opentelemetry.io/otel v1.33.0
 | 
			
		||||
@@ -13,7 +13,7 @@ require (
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/beorn7/perks v1.0.1 // indirect
 | 
			
		||||
	github.com/caarlos0/env/v9 v9.0.0 // indirect
 | 
			
		||||
	github.com/caarlos0/env/v11 v11.3.1 // indirect
 | 
			
		||||
	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
 | 
			
		||||
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 | 
			
		||||
	github.com/felixge/httpsnoop v1.0.4 // indirect
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.sum
									
									
									
									
									
								
							@@ -1,11 +1,13 @@
 | 
			
		||||
gitea.libretechconsulting.com/rmcguire/go-app v0.1.0 h1:H4TMgQ463oRNOyoi0FAvfGtOoDn651zNZStxM+sdNuU=
 | 
			
		||||
gitea.libretechconsulting.com/rmcguire/go-app v0.1.0/go.mod h1:p0ajkpFvzzD6VZ4xSjuowtwGRb1DjMfo/iG6LyFqFCs=
 | 
			
		||||
gitea.libretechconsulting.com/rmcguire/go-app v0.1.1 h1:Hrxqi1tqz8mf0baBsWgFe/S4jyMtIuPqH2FlanJUMNc=
 | 
			
		||||
gitea.libretechconsulting.com/rmcguire/go-app v0.1.1/go.mod h1:p0ajkpFvzzD6VZ4xSjuowtwGRb1DjMfo/iG6LyFqFCs=
 | 
			
		||||
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=
 | 
			
		||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 | 
			
		||||
github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc=
 | 
			
		||||
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
 | 
			
		||||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
 | 
			
		||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
 | 
			
		||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 | 
			
		||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 | 
			
		||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.go
									
									
									
									
									
								
							@@ -16,10 +16,10 @@ func main() {
 | 
			
		||||
	ctx, cncl := signal.NotifyContext(context.Background(), os.Kill, unix.SIGTERM)
 | 
			
		||||
	defer cncl()
 | 
			
		||||
 | 
			
		||||
	// 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)
 | 
			
		||||
	aw.MustInit()
 | 
			
		||||
	aw := ambient.New(ctx).Init()
 | 
			
		||||
 | 
			
		||||
	awApp := app.App{
 | 
			
		||||
		AppContext: ctx,
 | 
			
		||||
 
 | 
			
		||||
@@ -37,10 +37,12 @@ func New(appCtx context.Context) *AmbientWeather {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (aw *AmbientWeather) MustInit() {
 | 
			
		||||
// Initialize with defaults, set logger from context
 | 
			
		||||
func (aw *AmbientWeather) Init() *AmbientWeather {
 | 
			
		||||
	aw.awnProvider = &awn.AWNProvider{}
 | 
			
		||||
	aw.wuProvider = &wunderground.WUProvider{}
 | 
			
		||||
	aw.l = zerolog.Ctx(aw.appCtx)
 | 
			
		||||
	return aw
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (aw *AmbientWeather) GetAWNHandlerFunc(appCtx context.Context) func(http.ResponseWriter, *http.Request) {
 | 
			
		||||
@@ -55,7 +57,7 @@ func (aw *AmbientWeather) GetWundergroundHandlerFunc(appCtx context.Context) fun
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Takes an HTTP requests and convers it to a
 | 
			
		||||
// Takes an HTTP requests and converts it to a
 | 
			
		||||
// stable type. Enrich is called on the type to complete
 | 
			
		||||
// any missing fields as the two providers supported by Ambient
 | 
			
		||||
// devices (awn/wunderground) produce different fields
 | 
			
		||||
@@ -85,6 +87,7 @@ func (aw *AmbientWeather) handleProviderRequest(
 | 
			
		||||
 | 
			
		||||
		w.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
		w.Write([]byte(err.Error()))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Calculate any fields that may be missing
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
 | 
			
		||||
		DateUTC:        &updateTime,
 | 
			
		||||
		TempOutdoorF:   awnUpdate.TempF,
 | 
			
		||||
		HumidityOudoor: awnUpdate.Humidity,
 | 
			
		||||
		WindSpeedMPH:      awnUpdate.WindGustMPH,
 | 
			
		||||
		WindSpeedMPH:   awnUpdate.WindSpeedMPH,
 | 
			
		||||
		WindGustMPH:    awnUpdate.WindGustMPH,
 | 
			
		||||
		MaxDailyGust:   awnUpdate.MaxDailyGust,
 | 
			
		||||
		WindDir:        awnUpdate.WindDir,
 | 
			
		||||
@@ -57,9 +57,24 @@ func MapAwnUpdate(awnUpdate *AmbientWeatherUpdate) *weather.WeatherUpdate {
 | 
			
		||||
		MonthlyRainIn:  awnUpdate.MonthlyRainIn,
 | 
			
		||||
		YearlyRainIn:   awnUpdate.YearlyRainIn,
 | 
			
		||||
		TotalRainIn:    awnUpdate.TotalRainIn,
 | 
			
		||||
		BattOutdoorSensor: awnUpdate.BattOut,
 | 
			
		||||
		BattIndoorSensor:  awnUpdate.BattIn,
 | 
			
		||||
		BattRainSensor:    awnUpdate.BattRain,
 | 
			
		||||
		Batteries: []weather.BatteryStatus{
 | 
			
		||||
			{
 | 
			
		||||
				Component: "OutdoorSensor",
 | 
			
		||||
				Status:    awnUpdate.BattOut,
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				Component: "IndoorSensor",
 | 
			
		||||
				Status:    awnUpdate.BattIn,
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				Component: "RainSensor",
 | 
			
		||||
				Status:    awnUpdate.BattRain,
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				Component: "CO2Sensor",
 | 
			
		||||
				Status:    awnUpdate.BattCO2,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		TempIndoorF:     awnUpdate.TempInF,
 | 
			
		||||
		HumidityIndoor:  awnUpdate.HumidityIn,
 | 
			
		||||
		BaromRelativeIn: awnUpdate.BaromRelIn,
 | 
			
		||||
 
 | 
			
		||||
@@ -27,4 +27,5 @@ type AmbientWeatherUpdate struct {
 | 
			
		||||
	BaromRelIn     float64 `json:"baromrelin,omitempty" schema:"baromrelin"`
 | 
			
		||||
	BaromAbsIn     float64 `json:"baromabsin,omitempty" schema:"baromabsin"`
 | 
			
		||||
	BattIn         int     `json:"battin,omitempty" schema:"battin"`
 | 
			
		||||
	BattCO2        int     `json:"batt_co2,omitempty" schema:"batt_co2"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,15 @@ import "math"
 | 
			
		||||
// Attempts to complete missing fields that may not
 | 
			
		||||
// be set by a specific provider, such as DewPoint and WindChill
 | 
			
		||||
func (u *WeatherUpdate) Enrich() {
 | 
			
		||||
	if u == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u.WindChillF == 0 {
 | 
			
		||||
		u.WindChillF = CalculateWindChill(u.TempOutdoorF, u.WindSpeedMPH)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if u.DewPointF == 0 {
 | 
			
		||||
	if u.DewPointF == 0 && (u.TempOutdoorF != 0 && u.HumidityOudoor != 0) {
 | 
			
		||||
		u.DewPointF = CalculateDewPoint(u.TempOutdoorF, float64(u.HumidityOudoor))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,9 +30,7 @@ type WeatherMetrics struct {
 | 
			
		||||
	MonthlyRainIn   metric.Float64Gauge
 | 
			
		||||
	YearlyRainIn    metric.Float64Gauge
 | 
			
		||||
	TotalRainIn     metric.Float64Gauge
 | 
			
		||||
	BattOutdoorSensor metric.Int64Gauge
 | 
			
		||||
	BattIndoorSensor  metric.Int64Gauge
 | 
			
		||||
	BattRainSensor    metric.Int64Gauge
 | 
			
		||||
	BatteryStatus   metric.Int64Gauge
 | 
			
		||||
	BaromRelativeIn metric.Float64Gauge
 | 
			
		||||
	BaromAbsoluteIn metric.Float64Gauge
 | 
			
		||||
	DewPointF       metric.Float64Gauge
 | 
			
		||||
@@ -45,6 +43,8 @@ type WeatherMetrics struct {
 | 
			
		||||
	meter           metric.Meter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var MetricPrefix = "weather"
 | 
			
		||||
 | 
			
		||||
func MustInitMetrics(appCtx context.Context) *WeatherMetrics {
 | 
			
		||||
	wm := &WeatherMetrics{
 | 
			
		||||
		appCtx: appCtx,
 | 
			
		||||
@@ -54,59 +54,55 @@ func MustInitMetrics(appCtx context.Context) *WeatherMetrics {
 | 
			
		||||
	wm.meter = otel.GetMeter(appCtx, "weather", "metrics")
 | 
			
		||||
 | 
			
		||||
	// Weather Metrics
 | 
			
		||||
	wm.TempOutdoorF, _ = wm.meter.Float64Gauge("weather_temp_outdoor_f",
 | 
			
		||||
	wm.TempOutdoorF, _ = wm.meter.Float64Gauge(MetricPrefix+"_temp_outdoor_f",
 | 
			
		||||
		metric.WithDescription("Outdoor Temperature in Faherenheit"))
 | 
			
		||||
	wm.TempIndoorF, _ = wm.meter.Float64Gauge("weather_temp_indoor_f",
 | 
			
		||||
	wm.TempIndoorF, _ = wm.meter.Float64Gauge(MetricPrefix+"_temp_indoor_f",
 | 
			
		||||
		metric.WithDescription("Indoor Temperature in Faherenheit"))
 | 
			
		||||
	wm.HumidityOudoor, _ = wm.meter.Int64Gauge("weather_humidity_oudoor",
 | 
			
		||||
	wm.HumidityOudoor, _ = wm.meter.Int64Gauge(MetricPrefix+"_humidity_outdoor",
 | 
			
		||||
		metric.WithDescription("Outdoor Humidity %"))
 | 
			
		||||
	wm.HumidityIndoor, _ = wm.meter.Int64Gauge("weather_humidity_indoor",
 | 
			
		||||
	wm.HumidityIndoor, _ = wm.meter.Int64Gauge(MetricPrefix+"_humidity_indoor",
 | 
			
		||||
		metric.WithDescription("Indoor Humidity %"))
 | 
			
		||||
	wm.WindSpeedMPH, _ = wm.meter.Float64Gauge("weather_wind_speed_mph",
 | 
			
		||||
	wm.WindSpeedMPH, _ = wm.meter.Float64Gauge(MetricPrefix+"_wind_speed_mph",
 | 
			
		||||
		metric.WithDescription("Wind Speed in MPH"))
 | 
			
		||||
	wm.WindGustMPH, _ = wm.meter.Float64Gauge("weather_wind_gust_mph",
 | 
			
		||||
	wm.WindGustMPH, _ = wm.meter.Float64Gauge(MetricPrefix+"_wind_gust_mph",
 | 
			
		||||
		metric.WithDescription("Wind Gust in MPH"))
 | 
			
		||||
	wm.MaxDailyGust, _ = wm.meter.Float64Gauge("weather_max_daily_gust",
 | 
			
		||||
	wm.MaxDailyGust, _ = wm.meter.Float64Gauge(MetricPrefix+"_max_daily_gust",
 | 
			
		||||
		metric.WithDescription("Max Daily Wind Gust"))
 | 
			
		||||
	wm.WindDir, _ = wm.meter.Int64Gauge("weather_wind_dir",
 | 
			
		||||
	wm.WindDir, _ = wm.meter.Int64Gauge(MetricPrefix+"_wind_dir",
 | 
			
		||||
		metric.WithDescription("Wind Direction in Degrees"))
 | 
			
		||||
	wm.WindDirAvg10m, _ = wm.meter.Int64Gauge("weather_wind_dir_avg_10m",
 | 
			
		||||
	wm.WindDirAvg10m, _ = wm.meter.Int64Gauge(MetricPrefix+"_wind_dir_avg_10m",
 | 
			
		||||
		metric.WithDescription("Wind Direction 10m Average"))
 | 
			
		||||
	wm.UV, _ = wm.meter.Int64Gauge("weather_uv",
 | 
			
		||||
	wm.UV, _ = wm.meter.Int64Gauge(MetricPrefix+"_uv",
 | 
			
		||||
		metric.WithDescription("UV Index"))
 | 
			
		||||
	wm.SolarRadiation, _ = wm.meter.Float64Gauge("weather_solar_radiation",
 | 
			
		||||
	wm.SolarRadiation, _ = wm.meter.Float64Gauge(MetricPrefix+"_solar_radiation",
 | 
			
		||||
		metric.WithDescription("Solar Radiation in W/㎡"))
 | 
			
		||||
	wm.HourlyRainIn, _ = wm.meter.Float64Gauge("weather_hourly_rain_in",
 | 
			
		||||
	wm.HourlyRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_hourly_rain_in",
 | 
			
		||||
		metric.WithDescription("Hourly Rain in Inches"))
 | 
			
		||||
	wm.EventRainIn, _ = wm.meter.Float64Gauge("weather_event_rain_in",
 | 
			
		||||
	wm.EventRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_event_rain_in",
 | 
			
		||||
		metric.WithDescription("Event Rain in Inches"))
 | 
			
		||||
	wm.DailyRainIn, _ = wm.meter.Float64Gauge("weather_daily_rain_in",
 | 
			
		||||
	wm.DailyRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_daily_rain_in",
 | 
			
		||||
		metric.WithDescription("Daily Rain in Inches"))
 | 
			
		||||
	wm.WeeklyRainIn, _ = wm.meter.Float64Gauge("weather_weekly_rain_in",
 | 
			
		||||
	wm.WeeklyRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_weekly_rain_in",
 | 
			
		||||
		metric.WithDescription("Weekly Rain in Inches"))
 | 
			
		||||
	wm.MonthlyRainIn, _ = wm.meter.Float64Gauge("weather_monthly_rain_in",
 | 
			
		||||
	wm.MonthlyRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_monthly_rain_in",
 | 
			
		||||
		metric.WithDescription("Monthly Rain in Inches"))
 | 
			
		||||
	wm.YearlyRainIn, _ = wm.meter.Float64Gauge("weather_yearly_rain_in",
 | 
			
		||||
	wm.YearlyRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_yearly_rain_in",
 | 
			
		||||
		metric.WithDescription("Yearly Rain in Inches"))
 | 
			
		||||
	wm.TotalRainIn, _ = wm.meter.Float64Gauge("weather_total_rain_in",
 | 
			
		||||
	wm.TotalRainIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_total_rain_in",
 | 
			
		||||
		metric.WithDescription("Total Rain in Inches"))
 | 
			
		||||
	wm.BattOutdoorSensor, _ = wm.meter.Int64Gauge("weather_batt_outdoor_sensor",
 | 
			
		||||
		metric.WithDescription("Outdoor Equipment Battery"))
 | 
			
		||||
	wm.BattIndoorSensor, _ = wm.meter.Int64Gauge("weather_batt_indoor_sensor",
 | 
			
		||||
		metric.WithDescription("Indoor Equipmenet Battery"))
 | 
			
		||||
	wm.BattRainSensor, _ = wm.meter.Int64Gauge("weather_batt_rain_sensor",
 | 
			
		||||
		metric.WithDescription("Rain Sensor Battery"))
 | 
			
		||||
	wm.BaromRelativeIn, _ = wm.meter.Float64Gauge("weather_barometric_pressure_relative_in",
 | 
			
		||||
	wm.BatteryStatus, _ = wm.meter.Int64Gauge(MetricPrefix+"_battery_status",
 | 
			
		||||
		metric.WithDescription("Per-component battery status"))
 | 
			
		||||
	wm.BaromRelativeIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_barometric_pressure_relative_in",
 | 
			
		||||
		metric.WithDescription("Relative Pressure in Inches of Mercury"))
 | 
			
		||||
	wm.BaromAbsoluteIn, _ = wm.meter.Float64Gauge("weather_barometric_pressure_absolute_in",
 | 
			
		||||
	wm.BaromAbsoluteIn, _ = wm.meter.Float64Gauge(MetricPrefix+"_barometric_pressure_absolute_in",
 | 
			
		||||
		metric.WithDescription("Absolute Pressure in Inches of Mercury"))
 | 
			
		||||
	wm.DewPointF, _ = wm.meter.Float64Gauge("weather_dew_point_f",
 | 
			
		||||
	wm.DewPointF, _ = wm.meter.Float64Gauge(MetricPrefix+"_dew_point_f",
 | 
			
		||||
		metric.WithDescription("Dew Point in Faherenheit"))
 | 
			
		||||
	wm.WindChillF, _ = wm.meter.Float64Gauge("weather_wind_chill_f",
 | 
			
		||||
	wm.WindChillF, _ = wm.meter.Float64Gauge(MetricPrefix+"_wind_chill_f",
 | 
			
		||||
		metric.WithDescription("Wind Chill in Faherenheit"))
 | 
			
		||||
 | 
			
		||||
	// Internal Telemetry
 | 
			
		||||
	wm.UpdatesReceived, _ = wm.meter.Int64Counter("weather_updates_received",
 | 
			
		||||
	wm.UpdatesReceived, _ = wm.meter.Int64Counter(MetricPrefix+"_updates_received",
 | 
			
		||||
		metric.WithDescription("Metric Updates Processed by Exporter"))
 | 
			
		||||
 | 
			
		||||
	return wm
 | 
			
		||||
@@ -136,13 +132,18 @@ func (wm *WeatherMetrics) Update(u *WeatherUpdate) {
 | 
			
		||||
	wm.MonthlyRainIn.Record(wm.appCtx, u.MonthlyRainIn, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.YearlyRainIn.Record(wm.appCtx, u.YearlyRainIn, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.TotalRainIn.Record(wm.appCtx, u.TotalRainIn, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.BattOutdoorSensor.Record(wm.appCtx, int64(u.BattOutdoorSensor), metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.BattIndoorSensor.Record(wm.appCtx, int64(u.BattIndoorSensor), metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.BattRainSensor.Record(wm.appCtx, int64(u.BattRainSensor), metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.BaromRelativeIn.Record(wm.appCtx, u.BaromRelativeIn, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.BaromAbsoluteIn.Record(wm.appCtx, u.BaromAbsoluteIn, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.DewPointF.Record(wm.appCtx, u.DewPointF, metric.WithAttributeSet(attributes))
 | 
			
		||||
	wm.WindChillF.Record(wm.appCtx, u.WindChillF, metric.WithAttributeSet(attributes))
 | 
			
		||||
 | 
			
		||||
	// Batteries
 | 
			
		||||
	for _, battery := range u.Batteries {
 | 
			
		||||
		wm.BatteryStatus.Record(wm.appCtx, int64(battery.Status),
 | 
			
		||||
			metric.WithAttributeSet(attributes),
 | 
			
		||||
			metric.WithAttributes(attribute.String("component", battery.Component)),
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	wm.UpdatesReceived.Add(wm.appCtx, 1)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,9 +27,11 @@ type WeatherUpdate struct {
 | 
			
		||||
	MonthlyRainIn  float64
 | 
			
		||||
	YearlyRainIn   float64
 | 
			
		||||
	TotalRainIn    float64
 | 
			
		||||
	BattOutdoorSensor int
 | 
			
		||||
	BattIndoorSensor  int
 | 
			
		||||
	BattRainSensor    int
 | 
			
		||||
	Batteries      []BatteryStatus
 | 
			
		||||
	// BattOutdoorSensor int
 | 
			
		||||
	// BattIndoorSensor  int
 | 
			
		||||
	// BattRainSensor    int
 | 
			
		||||
	// BattCO2Sensor     int
 | 
			
		||||
	BaromRelativeIn float64
 | 
			
		||||
	BaromAbsoluteIn float64
 | 
			
		||||
	// These fields may be calculated
 | 
			
		||||
@@ -37,3 +39,8 @@ type WeatherUpdate struct {
 | 
			
		||||
	DewPointF  float64
 | 
			
		||||
	WindChillF float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BatteryStatus struct {
 | 
			
		||||
	Component string
 | 
			
		||||
	Status    int
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								unset_env.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								unset_env.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
#!env sh
 | 
			
		||||
unset APP_NAME
 | 
			
		||||
unset APP_LOG_LEVEL
 | 
			
		||||
unset APP_LOG_FORMAT
 | 
			
		||||
unset APP_LOG_TIME_FORMAT
 | 
			
		||||
unset APP_HTTP_LISTEN
 | 
			
		||||
unset APP_OTEL_STDOUT_ENABLED
 | 
			
		||||
unset APP_OTEL_METRIC_INTERVAL_SECS
 | 
			
		||||
		Reference in New Issue
	
	Block a user