Merge 'dev' into 'eto'
This commit is contained in:
@@ -1,27 +1,26 @@
|
||||
import { GeoCoordinates, WateringData } from "../../types";
|
||||
import { BaseWateringData, GeoCoordinates, PWS } from "../../types";
|
||||
import { WeatherProvider } from "../weatherProviders/WeatherProvider";
|
||||
|
||||
|
||||
export interface AdjustmentMethod {
|
||||
/**
|
||||
* Calculates the percentage that should be used to scale watering time.
|
||||
* @param adjustmentOptions The user-specified options for the calculation, or undefined/null if no custom values
|
||||
* are to be used. No checks will be made to ensure the AdjustmentOptions are the correct type that the function
|
||||
* is expecting or to ensure that any of its fields are valid.
|
||||
* @param wateringData The basic weather information of the watering site. This may be undefined if an error occurred
|
||||
* while retrieving the data.
|
||||
* @param adjustmentOptions The user-specified options for the calculation. No checks will be made to ensure the
|
||||
* AdjustmentOptions are the correct type that the function is expecting or to ensure that any of its fields are valid.
|
||||
* @param coordinates The coordinates of the watering site.
|
||||
* @param weatherProvider The WeatherProvider that should be used if the adjustment method needs to obtain any more
|
||||
* @param weatherProvider The WeatherProvider that should be used if the adjustment method needs to obtain any
|
||||
* weather data.
|
||||
* @param pws The PWS to retrieve weather data from, or undefined if a PWS should not be used. If the implementation
|
||||
* of this method does not have PWS support, this parameter may be ignored and coordinates may be used instead.
|
||||
* @return A Promise that will be resolved with the result of the calculation, or rejected with an error message if
|
||||
* the watering scale cannot be calculated.
|
||||
* @throws An error message can be thrown if an error occurs while calculating the watering scale.
|
||||
*/
|
||||
calculateWateringScale(
|
||||
adjustmentOptions: AdjustmentOptions,
|
||||
wateringData: WateringData | undefined,
|
||||
coordinates: GeoCoordinates,
|
||||
weatherProvider: WeatherProvider
|
||||
weatherProvider: WeatherProvider,
|
||||
pws?: PWS
|
||||
): Promise< AdjustmentMethodResponse >;
|
||||
}
|
||||
|
||||
@@ -53,6 +52,8 @@ export interface AdjustmentMethodResponse {
|
||||
* user-configured watering scale instead of using the one returned by the AdjustmentMethod.
|
||||
*/
|
||||
errorMessage?: string;
|
||||
/** The data that was used to calculate the watering scale, or undefined if no data was used. */
|
||||
wateringData: BaseWateringData;
|
||||
}
|
||||
|
||||
export interface AdjustmentOptions {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as SunCalc from "suncalc";
|
||||
import * as moment from "moment";
|
||||
import { AdjustmentMethod, AdjustmentMethodResponse, AdjustmentOptions } from "./AdjustmentMethod";
|
||||
import { GeoCoordinates, WateringData, WeatherProviderId } from "../../types";
|
||||
import { BaseWateringData, GeoCoordinates, PWS } from "../../types";
|
||||
import { WeatherProvider } from "../weatherProviders/WeatherProvider";
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@ import { WeatherProvider } from "../weatherProviders/WeatherProvider";
|
||||
*/
|
||||
async function calculateEToWateringScale(
|
||||
adjustmentOptions: EToScalingAdjustmentOptions,
|
||||
wateringData: WateringData | undefined,
|
||||
coordinates: GeoCoordinates,
|
||||
weatherProvider: WeatherProvider
|
||||
weatherProvider: WeatherProvider,
|
||||
pws?: PWS
|
||||
): Promise< AdjustmentMethodResponse > {
|
||||
|
||||
// Temporarily disabled since OWM forecast data is checking if rain is forecasted for 3 hours in the future.
|
||||
@@ -56,8 +56,9 @@ async function calculateEToWateringScale(
|
||||
minH: Math.round( etoData.minHumidity ),
|
||||
maxH: Math.round( etoData.maxHumidity ),
|
||||
wind: Math.round( etoData.windSpeed * 10 ) / 10,
|
||||
p: Math.round( wateringData.precip * 100 ) / 100
|
||||
}
|
||||
p: Math.round( etoData.precip * 100 ) / 100
|
||||
},
|
||||
wateringData: etoData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,9 +206,7 @@ export interface CloudCoverInfo {
|
||||
/**
|
||||
* Data used to calculate ETo. This data should be taken from a 24 hour time window.
|
||||
*/
|
||||
export interface EToData {
|
||||
/** The WeatherProvider that generated this data. */
|
||||
weatherProvider: WeatherProviderId;
|
||||
export interface EToData extends BaseWateringData {
|
||||
/** The Unix epoch seconds timestamp of the start of this 24 hour time window. */
|
||||
periodStartTime: number;
|
||||
/** The minimum temperature over the time period (in Fahrenheit). */
|
||||
@@ -225,8 +224,6 @@ export interface EToData {
|
||||
* different height can be standardized to 2m using the `standardizeWindSpeed` function in EToAdjustmentMethod.
|
||||
*/
|
||||
windSpeed: number;
|
||||
/** The total precipitation over the time period (in inches). */
|
||||
precip: number;
|
||||
}
|
||||
|
||||
const EToAdjustmentMethod: AdjustmentMethod = {
|
||||
|
||||
@@ -6,7 +6,8 @@ import { AdjustmentMethod, AdjustmentMethodResponse } from "./AdjustmentMethod";
|
||||
*/
|
||||
async function calculateManualWateringScale( ): Promise< AdjustmentMethodResponse > {
|
||||
return {
|
||||
scale: undefined
|
||||
scale: undefined,
|
||||
wateringData: undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { AdjustmentMethod, AdjustmentMethodResponse, AdjustmentOptions } from "./AdjustmentMethod";
|
||||
import { WateringData } from "../../types";
|
||||
import { GeoCoordinates, ZimmermanWateringData } from "../../types";
|
||||
import { WeatherProvider } from "../weatherProviders/WeatherProvider";
|
||||
|
||||
|
||||
/**
|
||||
* Only delays watering if it is currently raining and does not adjust the watering scale.
|
||||
*/
|
||||
async function calculateRainDelayWateringScale( adjustmentOptions: RainDelayAdjustmentOptions, wateringData: WateringData | undefined ): Promise< AdjustmentMethodResponse > {
|
||||
async function calculateRainDelayWateringScale( adjustmentOptions: RainDelayAdjustmentOptions, coordinates: GeoCoordinates, weatherProvider: WeatherProvider ): Promise< AdjustmentMethodResponse > {
|
||||
const wateringData: ZimmermanWateringData = await weatherProvider.getWateringData( coordinates );
|
||||
const raining = wateringData && wateringData.raining;
|
||||
const d = adjustmentOptions && adjustmentOptions.hasOwnProperty( "d" ) ? adjustmentOptions.d : 24;
|
||||
const d = adjustmentOptions.hasOwnProperty( "d" ) ? adjustmentOptions.d : 24;
|
||||
return {
|
||||
scale: undefined,
|
||||
rawData: { raining: raining ? 1 : 0 },
|
||||
rainDelay: raining ? d : undefined
|
||||
rainDelay: raining ? d : undefined,
|
||||
wateringData: wateringData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import { AdjustmentMethod, AdjustmentMethodResponse, AdjustmentOptions } from "./AdjustmentMethod";
|
||||
import { WateringData } from "../../types";
|
||||
import { GeoCoordinates, PWS, ZimmermanWateringData } from "../../types";
|
||||
import { validateValues } from "../weather";
|
||||
import { WeatherProvider } from "../weatherProviders/WeatherProvider";
|
||||
|
||||
|
||||
/**
|
||||
* Calculates how much watering should be scaled based on weather and adjustment options using the Zimmerman method.
|
||||
* (https://github.com/rszimm/sprinklers_pi/wiki/Weather-adjustments#formula-for-setting-the-scale)
|
||||
*/
|
||||
async function calculateZimmermanWateringScale( adjustmentOptions: ZimmermanAdjustmentOptions, wateringData: WateringData | undefined ): Promise< AdjustmentMethodResponse > {
|
||||
async function calculateZimmermanWateringScale(
|
||||
adjustmentOptions: ZimmermanAdjustmentOptions,
|
||||
coordinates: GeoCoordinates,
|
||||
weatherProvider: WeatherProvider,
|
||||
pws?: PWS
|
||||
): Promise< AdjustmentMethodResponse > {
|
||||
const wateringData: ZimmermanWateringData = await weatherProvider.getWateringData( coordinates, pws );
|
||||
|
||||
// Temporarily disabled since OWM forecast data is checking if rain is forecasted for 3 hours in the future.
|
||||
/*
|
||||
@@ -15,7 +22,8 @@ async function calculateZimmermanWateringScale( adjustmentOptions: ZimmermanAdju
|
||||
if ( wateringData && wateringData.raining ) {
|
||||
return {
|
||||
scale: 0,
|
||||
rawData: { raining: 1 }
|
||||
rawData: { raining: 1 },
|
||||
wateringData: wateringData
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -33,42 +41,40 @@ async function calculateZimmermanWateringScale( adjustmentOptions: ZimmermanAdju
|
||||
return {
|
||||
scale: 100,
|
||||
rawData: rawData,
|
||||
errorMessage: "Necessary field(s) were missing from WateringData."
|
||||
errorMessage: "Necessary field(s) were missing from ZimmermanWateringData.",
|
||||
wateringData: wateringData
|
||||
};
|
||||
}
|
||||
|
||||
let humidityBase = 30, tempBase = 70, precipBase = 0;
|
||||
|
||||
// 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;
|
||||
}
|
||||
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( "h" ) ) {
|
||||
humidityFactor = humidityFactor * ( adjustmentOptions.h / 100 );
|
||||
}
|
||||
|
||||
if ( adjustmentOptions.hasOwnProperty( "t" ) ) {
|
||||
tempFactor = tempFactor * ( adjustmentOptions.t / 100 );
|
||||
}
|
||||
if ( adjustmentOptions.hasOwnProperty( "t" ) ) {
|
||||
tempFactor = tempFactor * ( adjustmentOptions.t / 100 );
|
||||
}
|
||||
|
||||
if ( adjustmentOptions.hasOwnProperty( "r" ) ) {
|
||||
precipFactor = precipFactor * ( adjustmentOptions.r / 100 );
|
||||
}
|
||||
if ( adjustmentOptions.hasOwnProperty( "r" ) ) {
|
||||
precipFactor = precipFactor * ( adjustmentOptions.r / 100 );
|
||||
}
|
||||
|
||||
return {
|
||||
// Apply all of the weather modifying factors and clamp the result between 0 and 200%.
|
||||
scale: Math.floor( Math.min( Math.max( 0, 100 + humidityFactor + tempFactor + precipFactor ), 200 ) ),
|
||||
rawData: rawData
|
||||
rawData: rawData,
|
||||
wateringData: wateringData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user