From d58e48293d88b61334127137491cd74ef3aa637b Mon Sep 17 00:00:00 2001 From: Matthew Oslan Date: Mon, 20 May 2019 16:34:26 -0400 Subject: [PATCH 1/5] Use rolling 24 hour window for watering scale --- routes/weatherProviders/DarkSky.ts | 45 ++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/routes/weatherProviders/DarkSky.ts b/routes/weatherProviders/DarkSky.ts index c934d94..47fabc5 100644 --- a/routes/weatherProviders/DarkSky.ts +++ b/routes/weatherProviders/DarkSky.ts @@ -5,25 +5,52 @@ import { httpJSONRequest } from "../weather"; async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< WateringData > { // The Unix timestamp of 24 hours ago. - const timestamp: number = moment().subtract( 1, "day" ).unix(); + const yesterdayTimestamp: number = moment().subtract( 1, "day" ).unix(); + const todayTimestamp: number = moment().unix(); const DARKSKY_API_KEY = process.env.DARKSKY_API_KEY, - historicUrl = `https://api.darksky.net/forecast/${DARKSKY_API_KEY}/${coordinates[0]},${coordinates[1]},${timestamp}`; + yesterdayUrl = `https://api.darksky.net/forecast/${DARKSKY_API_KEY}/${coordinates[0]},${coordinates[1]},${yesterdayTimestamp}?exclude=currently,minutely,daily,alerts,flags`, + todayUrl = `https://api.darksky.net/forecast/${DARKSKY_API_KEY}/${coordinates[0]},${coordinates[1]},${todayTimestamp}?exclude=currently,minutely,daily,alerts,flags`; - let historicData; + let yesterdayData, todayData; try { - historicData = await httpJSONRequest( historicUrl ); + yesterdayData = await httpJSONRequest( yesterdayUrl ); + todayData = await httpJSONRequest( todayUrl ); } catch (err) { // Indicate watering data could not be retrieved if an API error occurs. return undefined; } + if ( !todayData.hourly || !todayData.hourly.data || !yesterdayData.hourly || !yesterdayData.hourly.data ) { + return undefined; + } + + // Fail if not enough data is available. + if ( yesterdayData.hourly.data.length + todayData.hourly.data.length < 24 ) { + return undefined; + } + + const totals = { temp: 0, humidity: 0, precip: 0 }; + // Sum data from the current calendar day. + const todayPeriods = Math.min( 24, todayData.hourly.data.length ); + for ( let index = todayPeriods - 1; index >= 0; index-- ) { + totals.temp += todayData.hourly.data[ index ].temperature; + totals.humidity += todayData.hourly.data[ index ].humidity; + totals.precip += todayData.hourly.data[ index ].precipIntensity + } + + // Sum data from yesterday. + for ( let index = 24 - todayPeriods - 1; index >= 0; index-- ) { + totals.temp += yesterdayData.hourly.data[ index ].temperature; + totals.humidity += yesterdayData.hourly.data[ index ].humidity; + totals.precip += yesterdayData.hourly.data[ index ].precipIntensity + } + return { - // Calculate average temperature for the day using hourly data. - temp : historicData.hourly.data.reduce( ( sum, hourlyData ) => sum + hourlyData.temperature, 0 ) / historicData.hourly.data.length, - humidity: historicData.daily.data[ 0 ].humidity * 100, - precip: historicData.daily.data[ 0 ].precipIntensity * 24, - raining: historicData.currently.precipType === "rain" + temp : totals.temp / 24, + humidity: totals.humidity / 24 * 100, + precip: totals.precip, + raining: todayData.hourly.data[ todayData.hourly.data.length - 1 ].precipIntensity > 0 }; } From 56bf8a59627884e47c3fa074236e239bd0109e47 Mon Sep 17 00:00:00 2001 From: Matthew Oslan Date: Mon, 20 May 2019 16:41:12 -0400 Subject: [PATCH 2/5] Cleanup getWeatherData in DarkSky.ts --- routes/weatherProviders/DarkSky.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/routes/weatherProviders/DarkSky.ts b/routes/weatherProviders/DarkSky.ts index 47fabc5..452b0ff 100644 --- a/routes/weatherProviders/DarkSky.ts +++ b/routes/weatherProviders/DarkSky.ts @@ -56,13 +56,17 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W async function getDarkSkyWeatherData( coordinates: GeoCoordinates ): Promise< WeatherData > { const DARKSKY_API_KEY = process.env.DARKSKY_API_KEY, - forecastUrl = `https://api.darksky.net/forecast/${DARKSKY_API_KEY}/${coordinates[0]},${coordinates[1]}`; + forecastUrl = `https://api.darksky.net/forecast/${DARKSKY_API_KEY}/${coordinates[0]},${coordinates[1]}?exclude=minutely,alerts,flags`; let forecast; try { forecast = await httpJSONRequest( forecastUrl ); } catch (err) { - // Indicate watering data could not be retrieved if an API error occurs. + // Indicate weather data could not be retrieved if an API error occurs. + return undefined; + } + + if ( !forecast.currently || !forecast.daily || !forecast.daily.data ) { return undefined; } @@ -76,16 +80,16 @@ async function getDarkSkyWeatherData( coordinates: GeoCoordinates ): Promise< We region: "", city: "", - minTemp: Math.floor( forecast.daily.data[ 0 ].temperatureLow ), - maxTemp: Math.floor( forecast.daily.data[ 0 ].temperatureHigh ), + minTemp: Math.floor( forecast.daily.data[ 0 ].temperatureMin ), + maxTemp: Math.floor( forecast.daily.data[ 0 ].temperatureMax ), precip: forecast.daily.data[ 0 ].precipIntensity * 24, - forecast: [] + forecast: [ ] }; for ( let index = 0; index < forecast.daily.data.length; index++ ) { weather.forecast.push( { - temp_min: Math.floor( forecast.daily.data[ index ].temperatureLow ), - temp_max: Math.floor( forecast.daily.data[ index ].temperatureHigh ), + temp_min: Math.floor( forecast.daily.data[ index ].temperatureMin ), + temp_max: Math.floor( forecast.daily.data[ index ].temperatureMax ), date: forecast.daily.data[ index ].time, // TODO set this icon: "", From c181d12992c16270fe8b514fe6d412cea0cdd570 Mon Sep 17 00:00:00 2001 From: Matthew Oslan Date: Wed, 22 May 2019 15:10:26 -0400 Subject: [PATCH 3/5] Ignore forecast data when calculating Dark Sky watering scale --- routes/weatherProviders/DarkSky.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/routes/weatherProviders/DarkSky.ts b/routes/weatherProviders/DarkSky.ts index 452b0ff..7622b09 100644 --- a/routes/weatherProviders/DarkSky.ts +++ b/routes/weatherProviders/DarkSky.ts @@ -31,8 +31,11 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W } const totals = { temp: 0, humidity: 0, precip: 0 }; + // The number of hourly forecasts from today's data that use historic data (not forecast data). + // Find the first element that contains forecast data. + const todayHistoricElements = todayData.hourly.data.findIndex( ( data ) => data.time > todayTimestamp - 60 * 60 ); // Sum data from the current calendar day. - const todayPeriods = Math.min( 24, todayData.hourly.data.length ); + const todayPeriods = Math.min( 24, todayHistoricElements ); for ( let index = todayPeriods - 1; index >= 0; index-- ) { totals.temp += todayData.hourly.data[ index ].temperature; totals.humidity += todayData.hourly.data[ index ].humidity; @@ -50,7 +53,7 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W temp : totals.temp / 24, humidity: totals.humidity / 24 * 100, precip: totals.precip, - raining: todayData.hourly.data[ todayData.hourly.data.length - 1 ].precipIntensity > 0 + raining: todayData.hourly.data[ todayHistoricElements - 1 ].precipIntensity > 0 }; } From 31e443620cf941166f4e109b27bbf07589dadba4 Mon Sep 17 00:00:00 2001 From: Matthew Oslan Date: Sun, 26 May 2019 00:54:15 -0400 Subject: [PATCH 4/5] Use most recent data and cleanup code --- routes/weatherProviders/DarkSky.ts | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/routes/weatherProviders/DarkSky.ts b/routes/weatherProviders/DarkSky.ts index 7622b09..f3e7aa4 100644 --- a/routes/weatherProviders/DarkSky.ts +++ b/routes/weatherProviders/DarkSky.ts @@ -25,35 +25,37 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W return undefined; } + // The number of hourly forecasts to use from today's data. This will only include elements that contain historic + // data (not forecast data). + // Find the first element that contains forecast data. + const todayElements = Math.min( 24, todayData.hourly.data.findIndex( ( data ) => data.time > todayTimestamp - 60 * 60 ) ); + + const samples = [ + // Take as much data as possible from the first elements of today's data. + ...todayData.hourly.data.slice( 0, todayElements ), + // Take the remaining data from the last elements of yesterday's data. + ...yesterdayData.hourly.data.slice( todayElements - 24 ), + ]; + // Fail if not enough data is available. - if ( yesterdayData.hourly.data.length + todayData.hourly.data.length < 24 ) { + if ( samples.length !== 24 ) { return undefined; } const totals = { temp: 0, humidity: 0, precip: 0 }; - // The number of hourly forecasts from today's data that use historic data (not forecast data). - // Find the first element that contains forecast data. - const todayHistoricElements = todayData.hourly.data.findIndex( ( data ) => data.time > todayTimestamp - 60 * 60 ); - // Sum data from the current calendar day. - const todayPeriods = Math.min( 24, todayHistoricElements ); - for ( let index = todayPeriods - 1; index >= 0; index-- ) { + for ( let index = 0; index < samples.length; index++ ) { totals.temp += todayData.hourly.data[ index ].temperature; totals.humidity += todayData.hourly.data[ index ].humidity; totals.precip += todayData.hourly.data[ index ].precipIntensity } - // Sum data from yesterday. - for ( let index = 24 - todayPeriods - 1; index >= 0; index-- ) { - totals.temp += yesterdayData.hourly.data[ index ].temperature; - totals.humidity += yesterdayData.hourly.data[ index ].humidity; - totals.precip += yesterdayData.hourly.data[ index ].precipIntensity - } - + const mostRecentSample = todayElements > 0 ? + todayData.hourly.data[ todayElements - 1 ] : yesterdayData.hourly.data[ yesterdayData.hourly.data.length - 1 ]; return { temp : totals.temp / 24, humidity: totals.humidity / 24 * 100, precip: totals.precip, - raining: todayData.hourly.data[ todayHistoricElements - 1 ].precipIntensity > 0 + raining: mostRecentSample.precipIntensity > 0 }; } From e115343cb95e54d3cf655f19d6498f733ff5ae67 Mon Sep 17 00:00:00 2001 From: Matthew Oslan Date: Sun, 26 May 2019 12:42:37 -0400 Subject: [PATCH 5/5] Actually use most recent data --- routes/weatherProviders/DarkSky.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/routes/weatherProviders/DarkSky.ts b/routes/weatherProviders/DarkSky.ts index f3e7aa4..6153dd5 100644 --- a/routes/weatherProviders/DarkSky.ts +++ b/routes/weatherProviders/DarkSky.ts @@ -25,16 +25,16 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W return undefined; } - // The number of hourly forecasts to use from today's data. This will only include elements that contain historic - // data (not forecast data). + /* The number of hourly forecasts to use from today's data. This will only include elements that contain historic + data (not forecast data). */ // Find the first element that contains forecast data. const todayElements = Math.min( 24, todayData.hourly.data.findIndex( ( data ) => data.time > todayTimestamp - 60 * 60 ) ); + /* Take as much data as possible from the first elements of today's data and take the remaining required data from + the remaining data from the last elements of yesterday's data. */ const samples = [ - // Take as much data as possible from the first elements of today's data. - ...todayData.hourly.data.slice( 0, todayElements ), - // Take the remaining data from the last elements of yesterday's data. ...yesterdayData.hourly.data.slice( todayElements - 24 ), + ...todayData.hourly.data.slice( 0, todayElements ) ]; // Fail if not enough data is available. @@ -43,19 +43,17 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W } const totals = { temp: 0, humidity: 0, precip: 0 }; - for ( let index = 0; index < samples.length; index++ ) { - totals.temp += todayData.hourly.data[ index ].temperature; - totals.humidity += todayData.hourly.data[ index ].humidity; - totals.precip += todayData.hourly.data[ index ].precipIntensity + for ( const sample of samples ) { + totals.temp += sample.temperature; + totals.humidity += sample.humidity; + totals.precip += sample.precipIntensity } - const mostRecentSample = todayElements > 0 ? - todayData.hourly.data[ todayElements - 1 ] : yesterdayData.hourly.data[ yesterdayData.hourly.data.length - 1 ]; return { temp : totals.temp / 24, humidity: totals.humidity / 24 * 100, precip: totals.precip, - raining: mostRecentSample.precipIntensity > 0 + raining: samples[ samples.length - 1 ].precipIntensity > 0 }; }