From aa4e01afafab23f74a5fbdf9040488abc4aece40 Mon Sep 17 00:00:00 2001 From: Nick Berardi Date: Wed, 18 Jan 2023 05:06:21 -0500 Subject: [PATCH] feat(inputs.openweathermap): Add snow parameter (#12466) --- plugins/inputs/openweathermap/README.md | 1 + .../inputs/openweathermap/openweathermap.go | 13 + .../openweathermap/openweathermap_test.go | 304 ++++++++++++++++++ 3 files changed, 318 insertions(+) diff --git a/plugins/inputs/openweathermap/README.md b/plugins/inputs/openweathermap/README.md index 2548e92b0..4bb5de169 100644 --- a/plugins/inputs/openweathermap/README.md +++ b/plugins/inputs/openweathermap/README.md @@ -67,6 +67,7 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. - humidity (int, percent) - pressure (float, atmospheric pressure hPa) - rain (float, rain volume for the last 1-3 hours (depending on API response) in mm) + - snow (float, snow volume for the last 1-3 hours (depending on API response) in mm) - sunrise (int, nanoseconds since unix epoch) - sunset (int, nanoseconds since unix epoch) - temperature (float, degrees) diff --git a/plugins/inputs/openweathermap/openweathermap.go b/plugins/inputs/openweathermap/openweathermap.go index 3c4b79eff..ac4d01f8c 100644 --- a/plugins/inputs/openweathermap/openweathermap.go +++ b/plugins/inputs/openweathermap/openweathermap.go @@ -152,6 +152,10 @@ type WeatherEntry struct { Rain1 float64 `json:"1h"` Rain3 float64 `json:"3h"` } `json:"rain"` + Snow struct { + Snow1 float64 `json:"1h"` + Snow3 float64 `json:"3h"` + } `json:"snow"` Sys struct { Country string `json:"country"` Sunrise int64 `json:"sunrise"` @@ -198,6 +202,13 @@ func gatherWeatherURL(r io.Reader) (*Status, error) { return status, nil } +func gatherSnow(e WeatherEntry) float64 { + if e.Snow.Snow1 > 0 { + return e.Snow.Snow1 + } + return e.Snow.Snow3 +} + func gatherRain(e WeatherEntry) float64 { if e.Rain.Rain1 > 0 { return e.Rain.Rain1 @@ -214,6 +225,7 @@ func gatherWeather(acc telegraf.Accumulator, status *Status) { "humidity": e.Main.Humidity, "pressure": e.Main.Pressure, "rain": gatherRain(e), + "snow": gatherSnow(e), "sunrise": time.Unix(e.Sys.Sunrise, 0).UnixNano(), "sunset": time.Unix(e.Sys.Sunset, 0).UnixNano(), "temperature": e.Main.Temp, @@ -254,6 +266,7 @@ func gatherForecast(acc telegraf.Accumulator, status *Status) { "humidity": e.Main.Humidity, "pressure": e.Main.Pressure, "rain": gatherRain(e), + "snow": gatherSnow(e), "temperature": e.Main.Temp, "feels_like": e.Main.Feels, "wind_degrees": e.Wind.Deg, diff --git a/plugins/inputs/openweathermap/openweathermap_test.go b/plugins/inputs/openweathermap/openweathermap_test.go index 5684ef39b..16067e823 100644 --- a/plugins/inputs/openweathermap/openweathermap_test.go +++ b/plugins/inputs/openweathermap/openweathermap_test.go @@ -149,6 +149,150 @@ const groupWeatherResponse = ` } ` +const snowWeatherResponse = ` +{ + "cnt": 2, + "list": [{ + "dt": 1544194800, + "id": 111, + "main": { + "humidity": 87, + "pressure": 1007, + "temp": 9.25, + "feels_like": 8.25 + }, + "name": "Paris", + "sys": { + "country": "FR", + "id": 6550, + "message": 0.002, + "sunrise": 1544167818, + "sunset": 1544198047, + "type": 1 + }, + "visibility": 10000, + "weather": [ + { + "description": "light intensity drizzle", + "icon": "09d", + "id": 300, + "main": "Drizzle" + } + ], + "snow": { + "1h": 1.000 + }, + "wind": { + "deg": 290, + "speed": 8.7 + } + }, + { + "dt": 1544194800, + "id": 222, + "main": { + "humidity": 87, + "pressure": 1007, + "temp": 9.25, + "feels_like": 8.25 + }, + "name": "Paris", + "sys": { + "country": "FR", + "id": 6550, + "message": 0.002, + "sunrise": 1544167818, + "sunset": 1544198047, + "type": 1 + }, + "visibility": 10000, + "weather": [ + { + "description": "light intensity drizzle", + "icon": "09d", + "id": 300, + "main": "Drizzle" + } + ], + "snow": { + "3h": 3.000 + }, + "wind": { + "deg": 290, + "speed": 8.7 + } + }, + { + "dt": 1544194800, + "id": 333, + "main": { + "humidity": 87, + "pressure": 1007, + "temp": 9.25, + "feels_like": 8.25 + }, + "name": "Paris", + "sys": { + "country": "FR", + "id": 6550, + "message": 0.002, + "sunrise": 1544167818, + "sunset": 1544198047, + "type": 1 + }, + "visibility": 10000, + "weather": [ + { + "description": "light intensity drizzle", + "icon": "09d", + "id": 300, + "main": "Drizzle" + } + ], + "snow": { + "1h": 1.300, + "3h": 999 + }, + "wind": { + "deg": 290, + "speed": 8.7 + } + }, + { + "dt": 1544194800, + "id": 444, + "main": { + "humidity": 87, + "pressure": 1007, + "temp": 9.25, + "feels_like": 8.25 + }, + "name": "Paris", + "sys": { + "country": "FR", + "id": 6550, + "message": 0.002, + "sunrise": 1544167818, + "sunset": 1544198047, + "type": 1 + }, + "visibility": 10000, + "weather": [ + { + "description": "light intensity drizzle", + "icon": "09d", + "id": 300, + "main": "Drizzle" + } + ], + "wind": { + "deg": 290, + "speed": 8.7 + } + }] +} +` + const rainWeatherResponse = ` { "cnt": 2, @@ -457,6 +601,7 @@ func TestForecastGeneratesMetrics(t *testing.T) { "temperature": 6.71, "feels_like": 5.71, "rain": 0.035, + "snow": 0.0, "wind_degrees": 228.501, "wind_speed": 3.76, "condition_description": "light rain", @@ -481,6 +626,7 @@ func TestForecastGeneratesMetrics(t *testing.T) { "temperature": 6.38, "feels_like": 5.38, "rain": 0.049999999999997, + "snow": 0.0, "wind_degrees": 335.005, "wind_speed": 2.66, "condition_description": "light rain", @@ -543,6 +689,157 @@ func TestWeatherGeneratesMetrics(t *testing.T) { "temperature": 9.25, "feels_like": 8.25, "rain": 0.0, + "snow": 0.0, + "sunrise": int64(1544167818000000000), + "sunset": int64(1544198047000000000), + "wind_degrees": 290.0, + "wind_speed": 8.7, + "visibility": 10000, + "condition_description": "light intensity drizzle", + "condition_icon": "09d", + }, + time.Unix(1544194800, 0), + ), + } + testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics()) +} + +// Ensure that results containing "1h", "3h", both, or no snow values are parsed correctly +func TestSnowMetrics(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var rsp string + if r.URL.Path == "/data/2.5/group" { + rsp = snowWeatherResponse + w.Header()["Content-Type"] = []string{"application/json"} + } else { + require.Fail(t, "Cannot handle request") + } + + _, err := fmt.Fprintln(w, rsp) + require.NoError(t, err) + })) + defer ts.Close() + + n := &OpenWeatherMap{ + BaseURL: ts.URL, + AppID: "noappid", + CityID: []string{"111", "222", "333", "444"}, + Fetch: []string{"weather"}, + Units: "metric", + } + require.NoError(t, n.Init()) + + var acc testutil.Accumulator + + require.NoError(t, n.Gather(&acc)) + + expected := []telegraf.Metric{ + // City with 1h rain value + testutil.MustMetric( + "weather", + map[string]string{ + "city_id": "111", + "forecast": "*", + "city": "Paris", + "country": "FR", + "condition_id": "300", + "condition_main": "Drizzle", + }, + map[string]interface{}{ + "cloudiness": int64(0), + "humidity": int64(87), + "pressure": 1007.0, + "temperature": 9.25, + "feels_like": 8.25, + "rain": 0.0, + "snow": 1.0, + "sunrise": int64(1544167818000000000), + "sunset": int64(1544198047000000000), + "wind_degrees": 290.0, + "wind_speed": 8.7, + "visibility": 10000, + "condition_description": "light intensity drizzle", + "condition_icon": "09d", + }, + time.Unix(1544194800, 0), + ), + // City with 3h snow value + testutil.MustMetric( + "weather", + map[string]string{ + "city_id": "222", + "forecast": "*", + "city": "Paris", + "country": "FR", + "condition_id": "300", + "condition_main": "Drizzle", + }, + map[string]interface{}{ + "cloudiness": int64(0), + "humidity": int64(87), + "pressure": 1007.0, + "temperature": 9.25, + "feels_like": 8.25, + "rain": 0.0, + "snow": 3.0, + "sunrise": int64(1544167818000000000), + "sunset": int64(1544198047000000000), + "wind_degrees": 290.0, + "wind_speed": 8.7, + "visibility": 10000, + "condition_description": "light intensity drizzle", + "condition_icon": "09d", + }, + time.Unix(1544194800, 0), + ), + // City with both 1h and 3h snow values, prefer the 1h value + testutil.MustMetric( + "weather", + map[string]string{ + "city_id": "333", + "forecast": "*", + "city": "Paris", + "country": "FR", + "condition_id": "300", + "condition_main": "Drizzle", + }, + map[string]interface{}{ + "cloudiness": int64(0), + "humidity": int64(87), + "pressure": 1007.0, + "temperature": 9.25, + "feels_like": 8.25, + "rain": 0.0, + "snow": 1.3, + "sunrise": int64(1544167818000000000), + "sunset": int64(1544198047000000000), + "wind_degrees": 290.0, + "wind_speed": 8.7, + "visibility": 10000, + "condition_description": "light intensity drizzle", + "condition_icon": "09d", + }, + time.Unix(1544194800, 0), + ), + // City with no snow values + testutil.MustMetric( + "weather", + map[string]string{ + "city_id": "444", + "forecast": "*", + "city": "Paris", + "country": "FR", + "condition_id": "300", + "condition_main": "Drizzle", + }, + map[string]interface{}{ + "cloudiness": int64(0), + "humidity": int64(87), + "pressure": 1007.0, + "temperature": 9.25, + "feels_like": 8.25, + "rain": 0.0, + "snow": 0.0, "sunrise": int64(1544167818000000000), "sunset": int64(1544198047000000000), "wind_degrees": 290.0, @@ -605,6 +902,7 @@ func TestRainMetrics(t *testing.T) { "temperature": 9.25, "feels_like": 8.25, "rain": 1.0, + "snow": 0.0, "sunrise": int64(1544167818000000000), "sunset": int64(1544198047000000000), "wind_degrees": 290.0, @@ -633,6 +931,7 @@ func TestRainMetrics(t *testing.T) { "temperature": 9.25, "feels_like": 8.25, "rain": 3.0, + "snow": 0.0, "sunrise": int64(1544167818000000000), "sunset": int64(1544198047000000000), "wind_degrees": 290.0, @@ -661,6 +960,7 @@ func TestRainMetrics(t *testing.T) { "temperature": 9.25, "feels_like": 8.25, "rain": 1.3, + "snow": 0.0, "sunrise": int64(1544167818000000000), "sunset": int64(1544198047000000000), "wind_degrees": 290.0, @@ -689,6 +989,7 @@ func TestRainMetrics(t *testing.T) { "temperature": 9.25, "feels_like": 8.25, "rain": 0.0, + "snow": 0.0, "sunrise": int64(1544167818000000000), "sunset": int64(1544198047000000000), "wind_degrees": 290.0, @@ -753,6 +1054,7 @@ func TestBatchWeatherGeneratesMetrics(t *testing.T) { "wind_degrees": 60.0, "wind_speed": 5.0, "rain": 0.0, + "snow": 0.0, "sunrise": int64(1556416455000000000), "sunset": int64(1556470779000000000), "visibility": 10000, @@ -780,6 +1082,7 @@ func TestBatchWeatherGeneratesMetrics(t *testing.T) { "wind_degrees": 0.0, "wind_speed": 1.0, "rain": 0.0, + "snow": 0.0, "sunrise": int64(1556419155000000000), "sunset": int64(1556471486000000000), "visibility": 10000, @@ -807,6 +1110,7 @@ func TestBatchWeatherGeneratesMetrics(t *testing.T) { "wind_degrees": 290.0, "wind_speed": 6.2, "rain": 0.072, + "snow": 0.0, "sunrise": int64(1556426319000000000), "sunset": int64(1556479032000000000), "visibility": 10000,