Merge pull request #40 from Derpthemeus/improve-weather-provider-handling
Improve weather provider handling
This commit is contained in:
@@ -5,7 +5,6 @@ import * as SunCalc from "suncalc";
|
|||||||
import * as moment from "moment-timezone";
|
import * as moment from "moment-timezone";
|
||||||
import * as geoTZ from "geo-tz";
|
import * as geoTZ from "geo-tz";
|
||||||
|
|
||||||
import * as local from "./local";
|
|
||||||
import { AdjustmentOptions, GeoCoordinates, TimeData, WateringData, WeatherData, WeatherProvider } from "../types";
|
import { AdjustmentOptions, GeoCoordinates, TimeData, WateringData, WeatherData, WeatherProvider } from "../types";
|
||||||
const weatherProvider: WeatherProvider = require("./weatherProviders/" + ( process.env.WEATHER_PROVIDER || "OWM" ) ).default;
|
const weatherProvider: WeatherProvider = require("./weatherProviders/" + ( process.env.WEATHER_PROVIDER || "OWM" ) ).default;
|
||||||
|
|
||||||
@@ -18,6 +17,13 @@ const filters = {
|
|||||||
timezone: /^()()()()()()([+-])(\d{2})(\d{2})/
|
timezone: /^()()()()()()([+-])(\d{2})(\d{2})/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Enum of available watering scale adjustment methods.
|
||||||
|
const ADJUSTMENT_METHOD = {
|
||||||
|
MANUAL: 0,
|
||||||
|
ZIMMERMAN: 1,
|
||||||
|
RAIN_DELAY: 2
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a location description to geographic coordinates.
|
* Resolves a location description to geographic coordinates.
|
||||||
* @param location A partial zip/city/country or a coordinate pair.
|
* @param location A partial zip/city/country or a coordinate pair.
|
||||||
@@ -52,7 +58,7 @@ async function resolveCoordinates( location: string ): Promise< GeoCoordinates >
|
|||||||
if ( typeof data.RESULTS === "object" && data.RESULTS.length && data.RESULTS[ 0 ].tz !== "MISSING" ) {
|
if ( typeof data.RESULTS === "object" && data.RESULTS.length && data.RESULTS[ 0 ].tz !== "MISSING" ) {
|
||||||
|
|
||||||
// If it is, reply with an array containing the GPS coordinates
|
// If it is, reply with an array containing the GPS coordinates
|
||||||
return [ data.RESULTS[ 0 ].lat, data.RESULTS[ 0 ].lon ];
|
return [ parseFloat( data.RESULTS[ 0 ].lat ), parseFloat( data.RESULTS[ 0 ].lon ) ];
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Otherwise, indicate no data was found
|
// Otherwise, indicate no data was found
|
||||||
@@ -77,16 +83,6 @@ export async function httpJSONRequest(url: string ): Promise< any > {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves weather data necessary for watering level calculations from the a local record.
|
|
||||||
* @param coordinates The coordinates to retrieve the watering data for.
|
|
||||||
* @return A Promise that will be resolved with WateringData.
|
|
||||||
*/
|
|
||||||
async function getLocalWateringData( coordinates: GeoCoordinates ): Promise< WateringData > {
|
|
||||||
// TODO is this type assertion safe?
|
|
||||||
return local.getLocalWeather() as WateringData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates timezone and sunrise/sunset for the specified coordinates.
|
* Calculates timezone and sunrise/sunset for the specified coordinates.
|
||||||
* @param coordinates The coordinates to use to calculate time data.
|
* @param coordinates The coordinates to use to calculate time data.
|
||||||
@@ -110,56 +106,48 @@ function getTimeData( coordinates: GeoCoordinates ): TimeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates how much watering should be scaled based on weather and adjustment options.
|
* Calculates how much watering should be scaled based on weather and adjustment options using the Zimmerman method.
|
||||||
* @param adjustmentMethod The method to use to calculate the watering percentage. The only supported method is 1, which
|
|
||||||
* corresponds to the Zimmerman method. If an invalid adjustmentMethod is used, this method will return -1.
|
|
||||||
* @param adjustmentOptions Options to tweak the calculation, or undefined/null if no custom values are to be used.
|
* @param adjustmentOptions Options to tweak the calculation, or undefined/null if no custom values are to be used.
|
||||||
* @param wateringData The weather to use to calculate watering percentage.
|
* @param wateringData The weather to use to calculate watering percentage.
|
||||||
* @return The percentage that watering should be scaled by, or -1 if an invalid adjustmentMethod was provided.
|
* @return The percentage that watering should be scaled by.
|
||||||
*/
|
*/
|
||||||
function calculateWeatherScale( adjustmentMethod: number, adjustmentOptions: AdjustmentOptions, wateringData: WateringData ): number {
|
function calculateZimmermanWateringScale( adjustmentOptions: AdjustmentOptions, wateringData: WateringData ): number {
|
||||||
|
|
||||||
// Zimmerman method
|
let humidityBase = 30, tempBase = 70, precipBase = 0;
|
||||||
if ( adjustmentMethod === 1 ) {
|
|
||||||
let humidityBase = 30, tempBase = 70, precipBase = 0;
|
|
||||||
|
|
||||||
// Check to make sure valid data exists for all factors
|
// Check to make sure valid data exists for all factors
|
||||||
if ( !validateValues( [ "temp", "humidity", "precip" ], wateringData ) ) {
|
if ( !validateValues( [ "temp", "humidity", "precip" ], wateringData ) ) {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
|
||||||
|
|
||||||
// Get baseline conditions for 100% water level, if provided
|
|
||||||
if ( adjustmentOptions ) {
|
|
||||||
humidityBase = adjustmentOptions.hasOwnProperty( "bh" ) ? adjustmentOptions.bh : humidityBase;
|
|
||||||
tempBase = adjustmentOptions.hasOwnProperty( "bt" ) ? adjustmentOptions.bt : tempBase;
|
|
||||||
precipBase = adjustmentOptions.hasOwnProperty( "br" ) ? adjustmentOptions.br : precipBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
let temp = wateringData.temp,
|
|
||||||
humidityFactor = ( humidityBase - wateringData.humidity ),
|
|
||||||
tempFactor = ( ( temp - tempBase ) * 4 ),
|
|
||||||
precipFactor = ( ( precipBase - wateringData.precip ) * 200 );
|
|
||||||
|
|
||||||
// Apply adjustment options, if provided, by multiplying the percentage against the factor
|
|
||||||
if ( adjustmentOptions ) {
|
|
||||||
if ( adjustmentOptions.hasOwnProperty( "h" ) ) {
|
|
||||||
humidityFactor = humidityFactor * ( adjustmentOptions.h / 100 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( adjustmentOptions.hasOwnProperty( "t" ) ) {
|
|
||||||
tempFactor = tempFactor * ( adjustmentOptions.t / 100 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( adjustmentOptions.hasOwnProperty( "r" ) ) {
|
|
||||||
precipFactor = precipFactor * ( adjustmentOptions.r / 100 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply all of the weather modifying factors and clamp the result between 0 and 200%.
|
|
||||||
return Math.floor( Math.min( Math.max( 0, 100 + humidityFactor + tempFactor + precipFactor ), 200 ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
// Get baseline conditions for 100% water level, if provided
|
||||||
|
if ( adjustmentOptions ) {
|
||||||
|
humidityBase = adjustmentOptions.hasOwnProperty( "bh" ) ? adjustmentOptions.bh : humidityBase;
|
||||||
|
tempBase = adjustmentOptions.hasOwnProperty( "bt" ) ? adjustmentOptions.bt : tempBase;
|
||||||
|
precipBase = adjustmentOptions.hasOwnProperty( "br" ) ? adjustmentOptions.br : precipBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
let humidityFactor = ( humidityBase - wateringData.humidity ),
|
||||||
|
tempFactor = ( ( wateringData.temp - tempBase ) * 4 ),
|
||||||
|
precipFactor = ( ( precipBase - wateringData.precip ) * 200 );
|
||||||
|
|
||||||
|
// Apply adjustment options, if provided, by multiplying the percentage against the factor
|
||||||
|
if ( adjustmentOptions ) {
|
||||||
|
if ( adjustmentOptions.hasOwnProperty( "h" ) ) {
|
||||||
|
humidityFactor = humidityFactor * ( adjustmentOptions.h / 100 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( adjustmentOptions.hasOwnProperty( "t" ) ) {
|
||||||
|
tempFactor = tempFactor * ( adjustmentOptions.t / 100 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( adjustmentOptions.hasOwnProperty( "r" ) ) {
|
||||||
|
precipFactor = precipFactor * ( adjustmentOptions.r / 100 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply all of the weather modifying factors and clamp the result between 0 and 200%.
|
||||||
|
return Math.floor( Math.min( Math.max( 0, 100 + humidityFactor + tempFactor + precipFactor ), 200 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,6 +181,11 @@ function checkWeatherRestriction( adjustmentValue: number, weather: WateringData
|
|||||||
export const getWeatherData = async function( req: express.Request, res: express.Response ) {
|
export const getWeatherData = async function( req: express.Request, res: express.Response ) {
|
||||||
const location: string = getParameter(req.query.loc);
|
const location: string = getParameter(req.query.loc);
|
||||||
|
|
||||||
|
if ( !weatherProvider.getWeatherData ) {
|
||||||
|
res.send( "Error: selected WeatherProvider does not support getWeatherData" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let coordinates: GeoCoordinates;
|
let coordinates: GeoCoordinates;
|
||||||
try {
|
try {
|
||||||
coordinates = await resolveCoordinates( location );
|
coordinates = await resolveCoordinates( location );
|
||||||
@@ -256,53 +249,43 @@ export const getWateringData = async function( req: express.Request, res: expres
|
|||||||
res.send(`Error: Unable to resolve location (${err})`);
|
res.send(`Error: Unable to resolve location (${err})`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
location = coordinates;
|
|
||||||
|
|
||||||
// Continue with the weather request
|
// Continue with the weather request
|
||||||
let timeData: TimeData = getTimeData( coordinates );
|
let timeData: TimeData = getTimeData( coordinates );
|
||||||
let wateringData: WateringData;
|
let wateringData: WateringData;
|
||||||
if ( local.useLocalWeather() ) {
|
if ( adjustmentMethod !== ADJUSTMENT_METHOD.MANUAL ) {
|
||||||
wateringData = await getLocalWateringData( coordinates );
|
if ( !weatherProvider.getWateringData ) {
|
||||||
} else if ( adjustmentMethod !== 0 || checkRestrictions ) {
|
res.send( "Error: selected WeatherProvider does not support getWateringData" );
|
||||||
wateringData = await weatherProvider.getWateringData(coordinates);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Process data to retrieve the resulting scale, sunrise/sunset, timezone,
|
|
||||||
// and also calculate if a restriction is met to prevent watering.
|
|
||||||
|
|
||||||
// Use getTimeData as fallback if a PWS is used but time data is not provided.
|
|
||||||
// This will never occur, but it might become possible in the future when PWS support is re-added.
|
|
||||||
if ( !timeData ) {
|
|
||||||
if ( typeof location[ 0 ] === "number" && typeof location[ 1 ] === "number" ) {
|
|
||||||
timeData = getTimeData( location as GeoCoordinates );
|
|
||||||
} else {
|
|
||||||
res.send( "Error: No weather data found." );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wateringData = await weatherProvider.getWateringData( coordinates );
|
||||||
}
|
}
|
||||||
|
|
||||||
let scale: number = calculateWeatherScale( adjustmentMethod, adjustmentOptions, wateringData ),
|
let scale = -1, rainDelay = -1;
|
||||||
rainDelay: number = -1;
|
|
||||||
|
if ( adjustmentMethod === ADJUSTMENT_METHOD.ZIMMERMAN ) {
|
||||||
|
scale = calculateZimmermanWateringScale( adjustmentOptions, wateringData );
|
||||||
|
}
|
||||||
|
|
||||||
if (wateringData) {
|
if (wateringData) {
|
||||||
// Check for any user-set restrictions and change the scale to 0 if the criteria is met
|
// Check for any user-set restrictions and change the scale to 0 if the criteria is met
|
||||||
if (checkWeatherRestriction(req.params[0], wateringData)) {
|
if (checkWeatherRestriction(req.params[0], wateringData)) {
|
||||||
scale = 0;
|
scale = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If any weather adjustment is being used, check the rain status
|
// If any weather adjustment is being used, check the rain status
|
||||||
if ( adjustmentMethod > 0 && wateringData && wateringData.raining ) {
|
if ( adjustmentMethod > ADJUSTMENT_METHOD.MANUAL && wateringData.raining ) {
|
||||||
|
|
||||||
// If it is raining and the user has weather-based rain delay as the adjustment method then apply the specified delay
|
// If it is raining and the user has weather-based rain delay as the adjustment method then apply the specified delay
|
||||||
if ( adjustmentMethod === 2 ) {
|
if ( adjustmentMethod === ADJUSTMENT_METHOD.RAIN_DELAY ) {
|
||||||
|
|
||||||
rainDelay = ( adjustmentOptions && adjustmentOptions.hasOwnProperty( "d" ) ) ? adjustmentOptions.d : 24;
|
rainDelay = ( adjustmentOptions && adjustmentOptions.hasOwnProperty( "d" ) ) ? adjustmentOptions.d : 24;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// For any other adjustment method, apply a scale of 0 (as the scale will revert when the rain stops)
|
// For any other adjustment method, apply a scale of 0 (as the scale will revert when the rain stops)
|
||||||
scale = 0;
|
scale = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,17 +299,13 @@ export const getWateringData = async function( req: express.Request, res: expres
|
|||||||
rawData: undefined
|
rawData: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( adjustmentMethod > 0 ) {
|
if ( adjustmentMethod > ADJUSTMENT_METHOD.MANUAL ) {
|
||||||
data.rawData = {
|
data.rawData = {
|
||||||
h: wateringData ? Math.round( wateringData.humidity * 100) / 100 : null,
|
h: wateringData ? Math.round( wateringData.humidity * 100) / 100 : null,
|
||||||
p: wateringData ? Math.round( wateringData.precip * 100 ) / 100 : null,
|
p: wateringData ? Math.round( wateringData.precip * 100 ) / 100 : null,
|
||||||
t: wateringData ? Math.round( wateringData.temp * 10 ) / 10 : null,
|
t: wateringData ? Math.round( wateringData.temp * 10 ) / 10 : null,
|
||||||
raining: wateringData ? ( wateringData.raining ? 1 : 0 ) : null
|
raining: wateringData ? ( wateringData.raining ? 1 : 0 ) : null
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if ( local.useLocalWeather() ) {
|
|
||||||
console.log( "OpenSprinkler Weather Response: %s", JSON.stringify( data ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the response to the client in the requested format
|
// Return the response to the client in the requested format
|
||||||
@@ -339,7 +318,7 @@ export const getWateringData = async function( req: express.Request, res: expres
|
|||||||
"&sunrise=" + data.sunrise +
|
"&sunrise=" + data.sunrise +
|
||||||
"&sunset=" + data.sunset +
|
"&sunset=" + data.sunset +
|
||||||
"&eip=" + data.eip +
|
"&eip=" + data.eip +
|
||||||
( adjustmentMethod > 0 ? "&rawData=" + JSON.stringify( data.rawData ) : "" )
|
( data.rawData ? "&rawData=" + JSON.stringify( data.rawData ) : "" )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,6 +371,11 @@ async function httpRequest( url: string ): Promise< string > {
|
|||||||
function validateValues( keys: string[], obj: object ): boolean {
|
function validateValues( keys: string[], obj: object ): boolean {
|
||||||
let key: string;
|
let key: string;
|
||||||
|
|
||||||
|
// Return false if the object is null/undefined.
|
||||||
|
if ( !obj ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for ( key in keys ) {
|
for ( key in keys ) {
|
||||||
if ( !keys.hasOwnProperty( key ) ) {
|
if ( !keys.hasOwnProperty( key ) ) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ async function getDarkSkyWateringData( coordinates: GeoCoordinates ): Promise< W
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
weatherProvider: "DarkSky",
|
||||||
temp : totals.temp / 24,
|
temp : totals.temp / 24,
|
||||||
humidity: totals.humidity / 24 * 100,
|
humidity: totals.humidity / 24 * 100,
|
||||||
precip: totals.precip,
|
precip: totals.precip,
|
||||||
@@ -74,6 +75,7 @@ async function getDarkSkyWeatherData( coordinates: GeoCoordinates ): Promise< We
|
|||||||
}
|
}
|
||||||
|
|
||||||
const weather: WeatherData = {
|
const weather: WeatherData = {
|
||||||
|
weatherProvider: "DarkSky",
|
||||||
temp: Math.floor( forecast.currently.temperature ),
|
temp: Math.floor( forecast.currently.temperature ),
|
||||||
humidity: Math.floor( forecast.currently.humidity * 100 ),
|
humidity: Math.floor( forecast.currently.humidity * 100 ),
|
||||||
wind: Math.floor( forecast.currently.windSpeed ),
|
wind: Math.floor( forecast.currently.windSpeed ),
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ async function getOWMWateringData( coordinates: GeoCoordinates ): Promise< Water
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
weatherProvider: "OWM",
|
||||||
temp: totalTemp / periods,
|
temp: totalTemp / periods,
|
||||||
humidity: totalHumidity / periods,
|
humidity: totalHumidity / periods,
|
||||||
precip: totalPrecip / 25.4,
|
precip: totalPrecip / 25.4,
|
||||||
@@ -58,6 +59,7 @@ async function getOWMWeatherData( coordinates: GeoCoordinates ): Promise< Weathe
|
|||||||
}
|
}
|
||||||
|
|
||||||
const weather: WeatherData = {
|
const weather: WeatherData = {
|
||||||
|
weatherProvider: "OWM",
|
||||||
temp: parseInt( current.main.temp ),
|
temp: parseInt( current.main.temp ),
|
||||||
humidity: parseInt( current.main.humidity ),
|
humidity: parseInt( current.main.humidity ),
|
||||||
wind: parseInt( current.wind.speed ),
|
wind: parseInt( current.wind.speed ),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as express from "express";
|
import * as express from "express";
|
||||||
import { CronJob } from "cron";
|
import { CronJob } from "cron";
|
||||||
|
import { GeoCoordinates, WateringData, WeatherProvider } from "../../types";
|
||||||
|
|
||||||
const count = { temp: 0, humidity: 0 };
|
const count = { temp: 0, humidity: 0 };
|
||||||
|
|
||||||
@@ -42,25 +43,20 @@ export const captureWUStream = function( req: express.Request, res: express.Resp
|
|||||||
res.send( "success\n" );
|
res.send( "success\n" );
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useLocalWeather = function(): boolean {
|
export const getLocalWateringData = function(): WateringData {
|
||||||
return process.env.PWS ? true : false;
|
const result: WateringData = {
|
||||||
};
|
...yesterday as WateringData,
|
||||||
|
// Use today's weather if we dont have information for yesterday yet (i.e. on startup)
|
||||||
export const getLocalWeather = function(): LocalWeather {
|
...today,
|
||||||
const result: LocalWeather = {};
|
// PWS report "buckets" so consider it still raining if last bucket was less than an hour ago
|
||||||
|
raining: last_bucket !== undefined ? ( ( Date.now() - +last_bucket ) / 1000 / 60 / 60 < 1 ) : undefined,
|
||||||
// Use today's weather if we dont have information for yesterday yet (i.e. on startup)
|
weatherProvider: "local"
|
||||||
Object.assign( result, today, yesterday);
|
};
|
||||||
|
|
||||||
if ( "precip" in yesterday && "precip" in today ) {
|
if ( "precip" in yesterday && "precip" in today ) {
|
||||||
result.precip = yesterday.precip + today.precip;
|
result.precip = yesterday.precip + today.precip;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PWS report "buckets" so consider it still raining if last bucket was less than an hour ago
|
|
||||||
if ( last_bucket !== undefined ) {
|
|
||||||
result.raining = ( ( Date.now() - +last_bucket ) / 1000 / 60 / 60 < 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,6 +75,9 @@ interface PWSStatus {
|
|||||||
precip?: number;
|
precip?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LocalWeather extends PWSStatus {
|
const LocalWeatherProvider: WeatherProvider = {
|
||||||
raining?: boolean;
|
getWateringData: async function ( coordinates: GeoCoordinates ) {
|
||||||
}
|
return getLocalWateringData();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default LocalWeatherProvider;
|
||||||
@@ -5,7 +5,7 @@ import * as express from "express";
|
|||||||
import * as cors from "cors";
|
import * as cors from "cors";
|
||||||
|
|
||||||
import * as weather from "./routes/weather";
|
import * as weather from "./routes/weather";
|
||||||
import * as local from "./routes/local";
|
import * as local from "./routes/weatherProviders/local";
|
||||||
|
|
||||||
let host = process.env.HOST || "127.0.0.1",
|
let host = process.env.HOST || "127.0.0.1",
|
||||||
port = parseInt( process.env.PORT ) || 3000;
|
port = parseInt( process.env.PORT ) || 3000;
|
||||||
|
|||||||
10
types.ts
10
types.ts
@@ -13,6 +13,8 @@ export interface TimeData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WeatherData {
|
export interface WeatherData {
|
||||||
|
/** The WeatherProvider that generated this data. */
|
||||||
|
weatherProvider: WeatherProviderId;
|
||||||
/** The current temperature (in Fahrenheit). */
|
/** The current temperature (in Fahrenheit). */
|
||||||
temp: number;
|
temp: number;
|
||||||
/** The current humidity (as a percentage). */
|
/** The current humidity (as a percentage). */
|
||||||
@@ -54,6 +56,8 @@ export interface WeatherDataForecast {
|
|||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
export interface WateringData {
|
export interface WateringData {
|
||||||
|
/** The WeatherProvider that generated this data. */
|
||||||
|
weatherProvider: WeatherProviderId;
|
||||||
/** The average temperature over the window (in Fahrenheit). */
|
/** The average temperature over the window (in Fahrenheit). */
|
||||||
temp: number;
|
temp: number;
|
||||||
/** The average humidity over the window (as a percentage). */
|
/** The average humidity over the window (as a percentage). */
|
||||||
@@ -88,7 +92,7 @@ export interface WeatherProvider {
|
|||||||
* @return A Promise that will be resolved with the WateringData if it is successfully retrieved,
|
* @return A Promise that will be resolved with the WateringData if it is successfully retrieved,
|
||||||
* or resolved with undefined if an error occurs while retrieving the WateringData.
|
* or resolved with undefined if an error occurs while retrieving the WateringData.
|
||||||
*/
|
*/
|
||||||
getWateringData( coordinates : GeoCoordinates ): Promise< WateringData >;
|
getWateringData?( coordinates : GeoCoordinates ): Promise< WateringData >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the current weather data for usage in the mobile app.
|
* Retrieves the current weather data for usage in the mobile app.
|
||||||
@@ -96,5 +100,7 @@ export interface WeatherProvider {
|
|||||||
* @return A Promise that will be resolved with the WeatherData if it is successfully retrieved,
|
* @return A Promise that will be resolved with the WeatherData if it is successfully retrieved,
|
||||||
* or resolved with undefined if an error occurs while retrieving the WeatherData.
|
* or resolved with undefined if an error occurs while retrieving the WeatherData.
|
||||||
*/
|
*/
|
||||||
getWeatherData( coordinates : GeoCoordinates ): Promise< WeatherData >;
|
getWeatherData?( coordinates : GeoCoordinates ): Promise< WeatherData >;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type WeatherProviderId = "OWM" | "DarkSky" | "local";
|
||||||
|
|||||||
Reference in New Issue
Block a user