Skip to content

Commit

Permalink
Use 1h or 3h rain values as appropriate
Browse files Browse the repository at this point in the history
The OpenWeatherMap API doesn't reliably return "3h" rain values,
so we examine the response for "1h" (preferred) or "3h" values as it
seems to depend on the particular weather station used which value will
be returned (see
https://openweathermap.desk.com/customer/en/portal/questions/17663899-rain-1h-3h-are-mutually-exclusive-?new=17663899).

Closes influxdata#6583
  • Loading branch information
lhanson committed Oct 30, 2019
1 parent 9efc376 commit 96ce385
Show file tree
Hide file tree
Showing 3 changed files with 295 additions and 6 deletions.
2 changes: 1 addition & 1 deletion plugins/inputs/openweathermap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ condition ID, icon, and main is at [weather conditions][].
- cloudiness (int, percent)
- humidity (int, percent)
- pressure (float, atmospheric pressure hPa)
- rain (float, rain volume for the last 3 hours in mm)
- rain (float, rain 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)
Expand Down
12 changes: 10 additions & 2 deletions plugins/inputs/openweathermap/openweathermap.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ type WeatherEntry struct {
Temp float64 `json:"temp"`
} `json:"main"`
Rain struct {
Rain1 float64 `json:"1h"`
Rain3 float64 `json:"3h"`
} `json:"rain"`
Sys struct {
Expand Down Expand Up @@ -227,6 +228,13 @@ func gatherWeatherUrl(r io.Reader) (*Status, error) {
return status, nil
}

func gatherRain(e WeatherEntry) interface{} {
if e.Rain.Rain1 > 0 {
return e.Rain.Rain1
}
return e.Rain.Rain3
}

func gatherWeather(acc telegraf.Accumulator, status *Status) {
for _, e := range status.List {
tm := time.Unix(e.Dt, 0)
Expand All @@ -235,7 +243,7 @@ func gatherWeather(acc telegraf.Accumulator, status *Status) {
"cloudiness": e.Clouds.All,
"humidity": e.Main.Humidity,
"pressure": e.Main.Pressure,
"rain": e.Rain.Rain3,
"rain": gatherRain(e),
"sunrise": time.Unix(e.Sys.Sunrise, 0).UnixNano(),
"sunset": time.Unix(e.Sys.Sunset, 0).UnixNano(),
"temperature": e.Main.Temp,
Expand Down Expand Up @@ -274,7 +282,7 @@ func gatherForecast(acc telegraf.Accumulator, status *Status) {
"cloudiness": e.Clouds.All,
"humidity": e.Main.Humidity,
"pressure": e.Main.Pressure,
"rain": e.Rain.Rain3,
"rain": gatherRain(e),
"temperature": e.Main.Temp,
"wind_degrees": e.Wind.Deg,
"wind_speed": e.Wind.Speed,
Expand Down
287 changes: 284 additions & 3 deletions plugins/inputs/openweathermap/openweathermap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ const groupWeatherResponse = `
{
"cnt": 1,
"list": [{
"clouds": {
"all": 0
},
"clouds": {
"all": 0
},
"coord": {
"lat": 48.85,
"lon": 2.35
Expand Down Expand Up @@ -146,6 +146,145 @@ const groupWeatherResponse = `
}
`

const rainWeatherResponse = `
{
"cnt": 2,
"list": [{
"dt": 1544194800,
"id": 111,
"main": {
"humidity": 87,
"pressure": 1007,
"temp": 9.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"
}
],
"rain": {
"1h": 1.000
},
"wind": {
"deg": 290,
"speed": 8.7
}
},
{
"dt": 1544194800,
"id": 222,
"main": {
"humidity": 87,
"pressure": 1007,
"temp": 9.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"
}
],
"rain": {
"3h": 3.000
},
"wind": {
"deg": 290,
"speed": 8.7
}
},
{
"dt": 1544194800,
"id": 333,
"main": {
"humidity": 87,
"pressure": 1007,
"temp": 9.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"
}
],
"rain": {
"1h": 1.300,
"3h": 999
},
"wind": {
"deg": 290,
"speed": 8.7
}
},
{
"dt": 1544194800,
"id": 444,
"main": {
"humidity": 87,
"pressure": 1007,
"temp": 9.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 batchWeatherResponse = `
{
"cnt": 3,
Expand Down Expand Up @@ -405,6 +544,148 @@ func TestWeatherGeneratesMetrics(t *testing.T) {
testutil.RequireMetricsEqual(t, expected, acc.GetTelegrafMetrics())
}

// Ensure that results containing "1h", "3h", both, or no rain values are parsed correctly
func TestRainMetrics(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 = rainWeatherResponse
w.Header()["Content-Type"] = []string{"application/json"}
} else {
panic("Cannot handle request")
}

fmt.Fprintln(w, rsp)
}))
defer ts.Close()

n := &OpenWeatherMap{
BaseUrl: ts.URL,
AppId: "noappid",
CityId: []string{"111", "222", "333", "444"},
Fetch: []string{"weather"},
Units: "metric",
}
n.Init()

var acc testutil.Accumulator

err := n.Gather(&acc)
require.NoError(t, err)

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,
"rain": 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 rain 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,
"rain": 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 rain 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,
"rain": 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 rain 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,
"rain": 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())
}

func TestBatchWeatherGeneratesMetrics(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var rsp string
Expand Down

0 comments on commit 96ce385

Please sign in to comment.