/*
* WSM4Hubitat
* Weather Service Monitor (WSM) for Hubitat that can use a few different services.
*
* Description:
* This Hubitat driver polls Weather Service APIs primarily for forecast data but in some cases also gets current conditions.
*
* Required information depends on service:
* US - No information is required for the US weather.gov service
* UK - An API Key must be hard coded on line # 412 of the driver for the UK's Met Office API (Includes United Kingdom & Australia)
* Legacy UK - A ClientID and ClientSecret are needed for the UK's Met Office API (Includes United Kingdom & Australia)
* - These can be obtained at https://metoffice.apiconnect.ibmcloud.com/metoffice/production/
* OW - An API Key is needed for OpenWeather's API
* WA - An API Key is needed for Weather API
* WU - An API Key is needed for Weather Underground API
* WWO - An API Key is needed for World Weather Online's API
*
* Features List:
* Ability to have current conditions for OW, WA, WWO, & WU
* Ability to have child devices be for each forecasted day for OW, US NWS, & WU
* Ability to check min/max temp for today and tomorrow from Weather API, World Weather Online API, OpenWeather API,
* and UK Met Office API
* Ability to have current conditions for UK Met Office, US NWS, OW, WA, WWO, & WU
* Ability to check a website (mine) to notify user if there is a newer version of the driver available
*
* Licensing:
* Copyright 2024 David Snell
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
* Version Control:
* 0.9.7 - Correction to ProcessEvent function and removal of old driver-specific attributes when Preferences are saved
* 0.9.6 - Initial changes to support UK Met Office migration to new API and API Keys, also updated driver specific attribute names
* 0.9.5 - Made a check if child devices for week were already created
* 0.9.4 - Correction to OpenWeather so rain.1h is no longer required
* 0.9.3 - Correction so UK is no longer fix in Uxbridge, changes to newer method for version checking
* 0.9.2 - Additional current conditions applicable to WU
* 0.9.1 - Added attributes for current conditions from OW, WA, WU & WWO
* 0.9.0 - Added child devices for forecasts for US NWS, OW, & WU, requires the WeatherSensorChild.groovy driver to also be installed
* 0.8.4 - Added a "Data as of" attribute to identify the date/time the Hubitat received a successful data return,
* replaced ProcessData with ProcessEvent and added ProcessState (consistency between my drivers)
* 0.8.3 - Added ValidTime attributes to indicate when the API said the weather was valid as of,
* added 5 minute refresh option, changed logging at data retrieval to be info level
* 0.8.2 - Added additional refresh rates
* 0.8.1 - Corrected error in refresh times and added support for Weather tile using "Today's" attributes when available
* 0.8.0 - Addition of Weather Underground API and some corrections to other areas
* 0.7.0 - Rework to match semver, changes to logging, updating, and other areas
* 0.06 - Major rework of how data is processed
* 0.05 - Additional weather services added (World Weather Online & Weather API)
* 0.04 - More attributes including URLs for icons and parsing US detailed forecast for unreported fields.
* 0.03 - Addition of more attributes and checks
* 0.02 - Inclusion of OpenWeather API
* 0.01 - Initial design based on my Ambient Weather driver
*
* Thank you(s):
* Thank you to @Cobra for inspiration of how I perform driver version checking.
*/
// Returns the driver name
def DriverName(){
return "WSM4Hubitat"
}
// Returns the driver version
def DriverVersion(){
return "0.9.7"
}
// Driver Metadata
metadata{
definition( name: "WSM4Hubitat", namespace: "Snell", author: "David Snell", importUrl: "https://www.drdsnell.com/projects/hubitat/drivers/WSM4Hubitat.groovy" ) {
// Indicate what capabilities the device should be capable of
capability "Sensor"
capability "Refresh"
capability "PressureMeasurement"
capability "RelativeHumidityMeasurement"
capability "TemperatureMeasurement"
capability "UltravioletIndex"
capability "IlluminanceMeasurement"
// Commands
//command "UK_API_Key_Submission", [
// [ name: "UKAPIKEY*", type: "STRING", description: "Enter the API Key to use (UK Met Office Only)" ]
//] // Field to submit the API Key needed for the UK's Met Office
// Attributes for the driver itself
attribute "DriverName", "string" // Identifies the driver being used for update purposes
attribute "DriverVersion", "string" // Handles version for driver
attribute "DriverStatus", "string" // Handles version notices for driver
// Attributes needed for US NWS
attribute "CWA", "string"
attribute "GridX", "string"
attribute "GridY", "string"
// Attributes for the values returned that Hubitat supports normally
attribute "temperature", "number"
attribute "humidity", "number"
attribute "pressure", "number"
attribute "windSpeed", "number"
attribute "windDir", "number"
attribute "windDirection", "number"
// Attributes for general purpose
attribute "Updated", "string" // AttributeID = 0 - Date/time that the API says the data was "as of"
attribute "Data as of", "string" // Date/time that the data was successfully retrieved as of Hubitat's Date() function
// Attributes for Today's forecast
attribute "Today_Temperature", "number" // AttributeID = 1 - US NWS, UK Met Office, & OpenWeather
attribute "Today_WindSpeed", "number" // AttributeID = 11 - US NWS, UK Met Office, & OpenWeather
attribute "Today_WindDirection", "number" // AttributeID = 21 - US NWS, UK Met Office, & OpenWeather
attribute "Today_WindDirectionString", "string" // AttributeID = 91 - This attribute was created to use words for the direction of the wind
attribute "Today_WindGust", "number" // AttributeID = 31 - UK Met Office & Parsed from US NWS Detailed Forecast
attribute "Today_ShortForecast", "string" // AttributeID = 41 - US NWS, UK Met Office "Significant Weather Code"
attribute "Today_DetailedForecast", "string" // AttributeID = 51 - US NWS
attribute "Today_ChanceRain", "number" // AttributeID = 61 - OpenWeather, UK Met Office, & Parsed from US NWS Detailed Forecast
attribute "Today_ChanceClouds", "number" // AttributeID = 71 - OpenWeather
attribute "Today_ChanceSnow", "number" // AttributeID = 81 - OpenWeather, UK Met Office, & Parsed from US NWS Detailed Forecast
attribute "Today_FeelsLike", "number" // AttributeID = 101 - OpenWeather
attribute "Today_SunriseEpoch", "number" // AttributeID = 111 - OpenWeather
attribute "Today_SunsetEpoch", "string" // AttributeID = 121 - OpenWeather
attribute "Today_Sunrise", "string" // AttributeID = 131 - Calculated from OpenWeather
attribute "Today_Sunset", "string" // AttributeID = 141 - Calculated from OpenWeather
attribute "Today_IconURL", "string" // AttributeID = 151 - US NWS & OpenWeather
attribute "Today_Humidity", "number" // AttributeID = 161 - OpenWeather
attribute "Today_Pressure", "number" // AttributeID = 171 - OpenWeather
attribute "Today_UVI", "number" // AttributeID = 181 - OpenWeather
attribute "Today_MinTemp", "number" // AttributeID = 191 -
attribute "Today_MaxTemp", "number" // AttributeID = 201 -
attribute "Today_ValidTime", "string" // AttributeID = 211 - WeatherUnderground "validTimeLocal[ 0 ]"
// Attributes for Tonight's forecast
attribute "Tonight_Temperature", "number" // AttributeID = 2 - US NWS, UK Met Office, & OpenWeather
attribute "Tonight_WindSpeed", "number" // AttributeID = 12 - US NWS & UK Met Office
attribute "Tonight_WindDirection", "number" // AttributeID = 22 - US NWS & UK Met Office
attribute "Tonight_WindDirectionString", "string" // AttributeID = 92 - This attribute was created to use words for the direction of the wind
attribute "Tonight_WindGust", "number" // AttributeID = 32 - UK Met Office & Parsed from US NWS Detailed Forecast
attribute "Tonight_ShortForecast", "string" // AttributeID = 42 - US NWS
attribute "Tonight_DetailedForecast", "string" // AttributeID = 52 - US NWS
attribute "Tonight_ChanceRain", "number" // AttributeID = 62 - UK Met Office "ProbabilityOfRain" & Parsed from US NWS Detailed Forecast
attribute "Tonight_ChanceSnow", "number" // AttributeID = 82 - Parsed from US NWS Detailed Forecast
attribute "Tonight_FeelsLike", "number" // AttributeID = 102 - OpenWeather
attribute "Tonight_SunriseEpoch", "number" // AttributeID = 112 - OpenWeather
attribute "Tonight_SunsetEpoch", "string" // AttributeID = 122 - OpenWeather
attribute "Tonight_Sunrise", "string" // AttributeID = 132 - Calculated from OpenWeather
attribute "Tonight_Sunset", "string" // AttributeID = 142 - Calculated from OpenWeather
attribute "Tonight_IconURL", "string" // AttributeID = 152 - US NWS & OpenWeather
attribute "Tonight_Humidity", "number" // AttributeID = 162 - OpenWeather
attribute "Tonight_Pressure", "number" // AttributeID = 172 - OpenWeather
//attribute "Tonight_UVI", "number" // AttributeID = 182 - OpenWeather
// Attributes for Tomorrow's forecast
attribute "Tomorrow_Temperature", "number" // AttributeID = 3 - US NWS, UK Met Office, & OpenWeather
attribute "Tomorrow_WindSpeed", "number" // AttributeID = 13 - US NWS, UK Met Office, & OpenWeather
attribute "Tomorrow_WindDirection", "number" // AttributeID = 23 - US NWS, UK Met Office, & OpenWeather
attribute "Tomorrow_WindDirectionString", "string" // AttributeID = 93 - This attribute was created to use words for the direction of the wind
attribute "Tomorrow_WindGust", "number" // AttributeID = 33 - UK Met Office & Parsed from US NWS Detailed Forecast
attribute "Tomorrow_ShortForecast", "string" // AttributeID = 43 - US NWS, UK Met Office "Significant Weather Code"
attribute "Tomorrow_DetailedForecast", "string" // AttributeID = 53 - US NWS
attribute "Tomorrow_ChanceRain", "number" // AttributeID = 63 - OpenWeather, UK Met Office, & Parsed from US NWS Detailed Forecast
attribute "Tomorrow_ChanceClouds", "number" // AttributeID = 73 - OpenWeather
attribute "Tomorrow_ChanceSnow", "number" // AttributeID = 83 - OpenWeather, UK Met Office, & Parsed from US NWS Detailed Forecast
attribute "Tomorrow_FeelsLike", "number" // AttributeID = 103 - OpenWeather
attribute "Tomorrow_Sunrise", "string" // AttributeID = 113 - Calculated from OpenWeather
attribute "Tomorrow_Sunset", "string" // AttributeID = 123 - Calculated from OpenWeather
attribute "Tomorrow_SunriseEpoch", "number" // AttributeID = 133 - OpenWeather
attribute "Tomorrow_SunsetEpoch", "string" // AttributeID = 143 - OpenWeather
attribute "Tomorrow_IconURL", "string" // AttributeID = 153 - US NWS & OpenWeather
attribute "Tomorrow_Humidity", "number" // AttributeID = 163 - OpenWeather
attribute "Tomorrow_Pressure", "number" // AttributeID = 173 - OpenWeather
attribute "Tomorrow_UVI", "number" // AttributeID = 183 - OpenWeather
attribute "Tomorrow_MinTemp", "number" // AttributeID = 193 -
attribute "Tomorrow_MaxTemp", "number" // AttributeID = 203 -
attribute "Tomorrow_ValidTime", "string" // AttributeID = 213 - WeatherUnderground "validTimeLocal[ 1 ]"
// Attributes for Tomorrow night's forecast
attribute "Tomorrownight_Temperature", "number" // AttributeID = 4 - US NWS, UK Met Office, & OpenWeather
attribute "Tomorrownight_WindSpeed", "number" // AttributeID = 14 - US NWS & UK Met Office
attribute "Tomorrownight_WindDirection", "number" // AttributeID = 24 - US NWS & UK Met Office
attribute "Tomorrownight_WindDirectionString", "string" // AttributeID = 94 - This attribute was created to use words for the direction of the wind
attribute "Tomorrownight_WindGust", "number" // AttributeID = 34 - UK Met Office & Parsed from US NWS Detailed Forecast
attribute "Tomorrownight_ShortForecast", "string" // AttributeID = 44 - US NWS
attribute "Tomorrownight_DetailedForecast", "string" // AttributeID = 54 - US NWS
attribute "Tomorrownight_ChanceRain", "number" // AttributeID = 64 - UK Met Office "ProbabilityOfRain" & Parsed from US NWS Detailed Forecast
attribute "Tomorrownight_ChanceSnow", "number" // AttributeID = 84 - Parsed from US NWS Detailed Forecast
attribute "Tomorrownight_FeelsLike", "number" // AttributeID = 104 - OpenWeather
attribute "Tomorrownight_IconURL", "string" // AttributeID = 154 - US NWS & OpenWeather
attribute "Tomorrownight_Humidity", "number" // AttributeID = 164 - OpenWeather
attribute "Tomorrownight_Pressure", "number" // AttributeID = 174 - OpenWeather
//attribute "Tomorrownight_UVI", "number" // AttributeID = 184 - OpenWeather
// Current condition attributes that have been added as of 0.9.1
attribute "Conditions", "string" //
attribute "solarradiation", "number" //
attribute "uv", "number" //
attribute "winddir", "number" //
attribute "dewPoint", "number" //
attribute "feelsLike", "number" // //
attribute "hourlyRain", "number" //
attribute "WindDirectionString", "string" //
attribute "HeatIndex", "number" //
attribute "WindChill", "number" //
attribute "Neighborhood", "string" //
attribute "Quality Control", "number" //
attribute "PWS Software Type", "string" //
attribute "Elevation", "number" //
}
preferences{
section{
if( ShowAllPreferences ){
if( Region == "US" ){
input( type: "bool", name: "ChildrenEnabled", title: "Enable Forecast Child Devices?", description: "Once enabled, child devices will be made for daily forecasting.", required: false, defaultValue: false )
//} else if( Region == "UK" ){
// input( type: "string", name: "APIKEY", title: "APIKEY for UK Met Office?", defaultValue: null )
} else if( Region == "Legacy UK" ){
input( type: "string", name: "ClientID", title: "Client ID for Legacy UK Met Office?", defaultValue: null )
input( type: "string", name: "ClientSecret", title: "Client Secret for Legacy UK Met Office?", defaultValue: null )
} else if( Region == "OW" ){
input( type: "string", name: "APIKey", title: "API Key for OpenWeather?", defaultValue: null )
input( type: "bool", name: "ChildrenEnabled", title: "Enable Forecast Child Devices?", description: "Once enabled, child devices will be made for daily forecasting.", required: false, defaultValue: false )
} else if( Region == "WA" ){
input( type: "string", name: "APIKey", title: "API Key for Weather API?", defaultValue: null )
} else if( Region == "WU" ){
input( type: "string", name: "StationID", title: "Station ID?", defaultValue: null )
input( type: "string", name: "APIKey", title: "API Key for Weather Underground?", defaultValue: null )
input( type: "bool", name: "ChildrenEnabled", title: "Enable Forecast Child Devices?", description: "Once enabled, child devices will be made for daily forecasting.", required: false, defaultValue: false )
} else if( Region == "WWO" ){
input( type: "string", name: "APIKey", title: "API Key for World Weather Online?", defaultValue: null )
}
input( type: "enum", name: "Region", title: "Service to Query", required: true, multiple: false, options: [ [ "US" : "United States NWS" ], [ "UK" : "United Kingdom Met Office" ], [ "Legacy UK" : "Legacy United Kingdom Met Office" ], [ "OW" : "OpenWeather" ], [ "WA" : "Weather API" ], [ "WU" : "Weather Underground" ], [ "WWO" : "World Weather Online" ] ], defaultValue: "US" )
input( type: "enum", name: "RefreshRate", title: "Refresh Rate", required: true, multiple: false, options: [ "5 Minutes", "10 Minutes", "15 Minutes", "30 Minutes", "1 Hour", "3 Hours", "Daily", "Manual" ], defaultValue: "1 Hour" )
input( type: "enum", name: "LogType", title: "Enable Logging?", required: false, multiple: false, options: [ "None", "Info", "Debug", "Trace" ], defaultValue: "Info" )
input( type: "bool", name: "ShowAllPreferences", title: "Show All Preferences?", defaultValue: true )
} else {
input( type: "bool", name: "ShowAllPreferences", title: "Show All Preferences?", defaultValue: true )
}
}
}
}
// updated is called whenever device parameters are saved
def updated(){
unschedule()
switch( RefreshRate ){
case "5 Minutes":
runEvery5Minutes( refresh )
break
case "10 Minutes":
runEvery10Minutes( refresh )
break
case "15 Minutes":
runEvery15Minutes( refresh )
break
case "30 Minutes":
runEvery30Minutes( refresh )
break
case "1 Hour":
runEvery1Hour( refresh )
break
case "3 Hours":
runEvery3Hours( refresh )
break
case "Daily":
schedule( new Date(), refresh )
break
case "Manual":
break
}
Logging( "Refresh rate of ${ RefreshRate }", 3 )
// Set the driver name and version before update checking is scheduled
if( state."Driver Name" != null ){
state.remove( "Driver Name" )
state.remove( "Driver Version" )
device.deleteCurrentState( "Driver Name" )
device.deleteCurrentState( "Driver Version" )
}
ProcessState( "DriverName", "${ DriverName() }" )
ProcessState( "DriverVersion", "${ DriverVersion() }" )
// Schedule the daily driver version check
schedule( new Date(), CheckForUpdate )
if( !ChildrenEnabled ){
getChildDevices().each{
Logging( "Children disabled, deleting ${ it.deviceNetworkId }", 3 )
deleteChildDevice( it.deviceNetworkId )
}
} else {
switch( Region ){
case "UK":
case "Legacy UK":
case "WA":
case "WWO":
break
case "US":
case "OW":
case "WU":
if( getChildDevice( "${ device.name } Sunday" ) == null ){
addChild( "${ device.name } Sunday" )
}
if( getChildDevice( "${ device.name } Monday" ) == null ){
addChild( "${ device.name } Monday" )
}
if( getChildDevice( "${ device.name } Tuesday" ) == null ){
addChild( "${ device.name } Tuesday" )
}
if( getChildDevice( "${ device.name } Wednesday" ) == null ){
addChild( "${ device.name } Wednesday" )
}
if( getChildDevice( "${ device.name } Thursday" ) == null ){
addChild( "${ device.name } Thursday" )
}
if( getChildDevice( "${ device.name } Friday" ) == null ){
addChild( "${ device.name } Friday" )
}
if( getChildDevice( "${ device.name } Saturday" ) == null ){
addChild( "${ device.name } Saturday" )
}
break
default:
break
}
}
Logging( "Updated", 2 )
}
//
def UK_API_Key_Submission( String Key ){
if( Key != null ){
Logging( "Setting UKAPIKey to = ${ Key }", 4 )
ProcessState( "UKAPIKey", Key )
Logging( "UKAPIKey was set to = ${ state.UKAPIKey }", 4 )
} else {
Logging( "No key provided for UK API Key Submission", 5 )
}
}
// refresh performs a poll of data
def refresh(){
Logging( "Refreshing weather information...", 3 )
// Backup required values if they exist
def TempCWA
def TempGridX
def TempGridY
if( Region == "US" && state.CWA != null && state.GridX != null && state.GridY != null ){
TempCWA = state.CWA
TempGridX = state.GridX
TempGridY = state.GridY
}
// Clear current state values
state.clear()
//
if( Region == "US" ){
state.CWA = TempCWA
state.GridX = TempGridX
state.GridY = TempGridY
}
// Poll the weather service
PollNWS()
}
// installed is called when the device is installed, all it really does is run updated
def installed(){
Logging( "Installed", 2 )
updated()
}
// initialize is called when the device is initialized, all it really does is run updated
def initialize(){
Logging( "Initialized", 2 )
updated()
}
// parse
def parse( String description ){
Logging( "Something came in on parse... ${ description }", 3 )
}
//Poll NWS for data, method depends on regional service being used
def PollNWS() {
if( Region == "US" ){
if( state.CWA != null && state.GridX != null && state.GridY != null ){
Logging( "Checking for forecast", 2 )
def Params = [ uri: "https://api.weather.gov/gridpoints/${ state.CWA }/${ state.GridX },${ state.GridY }/forecast", contentType: "application/json", requestContentType: "application/json" ]
asynchttpGet( "GetUSForecast", Params )
} else {
Logging( "Getting specific location for US NWS", 2 )
def Params = [ uri: "https://api.weather.gov/points/${ location.latitude },${ location.longitude }", contentType: "application/json", requestContentType: "application/json" ]
asynchttpGet( "GetUSGrid", Params )
}
} else if( Region == "UK" ){
//if( state.UKAPIKey != null ){
TempLat = location.latitude
TempLong = location.longitude
// Uxbridge UK
//TempLat = "51.5558492"
//TempLong = "-0.4824408"
// Syndey AU - Prospect Nature Reserve
//TempLat = -33.8387391
//TempLong = 150.8904717
//TempAPIKEY = state.UKAPIKey
TempAPIKEY = "ENTER_UK_API_KEY_HERE"
Headers = [ 'Apikey': "${ TempAPIKEY }", 'accept': "application/json" ]
def Params = [ uri: "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/daily?latitude=${ TempLat }&longitude=${ TempLong }", headers: Headers, contentType: "application/json", requestContentType: "application/json" ]
asynchttpGet( "GetUKForecast", Params )
//} else {
//Logging( "UK API Key Submission required for UK method to work properly.", 5 )
//}
} else if( Region == "Legacy UK" ){
TempLat = location.latitude
TempLong = location.longitude
// Uxbridge UK
//TempLat = "51.5558492"
//TempLong = "-0.4824408"
// Syndey AU - Prospect Nature Reserve
//TempLat = -33.8387391
//TempLong = 150.8904717
Headers = [ 'x-ibm-client-id': "${ ClientID }", 'x-ibm-client-secret': "${ ClientSecret }", 'accept': "application/json" ]
def Params = [ uri: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/daily?latitude=${ TempLat }&longitude=${ TempLong }", headers: Headers, contentType: "application/json", requestContentType: "application/json" ]
asynchttpGet( "GetUKForecast", Params )
} else if( Region == "OW" ){
// https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&appid={YOUR API KEY}
def Params
if( location.temperatureScale == "F" ){
Params = [ uri: "https://api.openweathermap.org/data/2.5/onecall?lat=${ location.latitude }&lon=${ location.longitude }&appid=${ APIKey }&units=imperial" ]
} else {
Params = [ uri: "https://api.openweathermap.org/data/2.5/onecall?lat=${ location.latitude }&lon=${ location.longitude }&appid=${ APIKey }&units=metric" ]
}
asynchttpGet( "GetOWForecast", Params )
} else if( Region == "WA" ){ // WeatherAPI
// http://api.weatherapi.com/v1/forecast.json?key=&q=${ location.latitude },${ location.longitude }&days=2
def Params
Params = [ uri: "http://api.weatherapi.com/v1/forecast.json?key=${ APIKey }&q=${ location.latitude },${ location.longitude }&days=2" ]
asynchttpGet( "GetWAForecast", Params )
} else if( Region == "WU" ){ // Weather Underground API
// https://api.weather.com/v2/pws/observations/current?stationId=KMAHANOV10&format=json&units=e&apiKey=yourApiKey
def Params
if( location.temperatureScale == "F" ){
Params = [ uri: "https://api.weather.com/v2/pws/observations/current?stationId=${ StationID }&format=json&units=e&apiKey=${ APIKey }" ]
} else {
Params = [ uri: "https://api.weather.com/v2/pws/observations/current?stationId=${ StationID }&format=json&units=m&apiKey=${ APIKey }" ]
}
asynchttpGet( "GetWUCurrent", Params )
// https://api.weather.com/v3/wx/forecast/daily/5day?geocode=33.74,-84.39&format=json&units=e&language=en-US&apiKey=yourApiKey
if( location.temperatureScale == "F" ){
Params = [ uri: "https://api.weather.com/v3/wx/forecast/daily/5day?geocode=${ location.latitude },${ location.longitude }&format=json&units=e&language=en-US&apiKey=${ APIKey }" ]
} else {
Params = [ uri: "https://api.weather.com/v3/wx/forecast/daily/5day?geocode=${ location.latitude },${ location.longitude }&format=json&units=m&language=en-US&apiKey=${ APIKey }" ]
}
asynchttpGet( "GetWUForecast", Params )
} else if( Region == "WWO" ){ // World Weather Online Premium API
// http://api.worldweatheronline.com/premium/v1/weather.ashx?key=xxxxxxxxxxxxx&q=${ location.latitude },${ location.longitude }&num_of_days=2&tp=24&format=json
def Params
Params = [ uri: "http://api.worldweatheronline.com/premium/v1/weather.ashx?key=${ APIKey }&q=${ location.latitude },${ location.longitude }&num_of_days=2&tp=24&format=json" ]
asynchttpGet( "GetWWOForecast", Params )
}
}
// Handles the response from NWS for Grid coordinates
def GetUSGrid( resp, data ) {
if( resp.getStatus() == 200 ) {
Json = parseJson( resp.data )
//Logging( "GetGrid attempt ${ Json }", 3 )
if( Json.properties.cwa != null ){
state.CWA = Json.properties.cwa // US-NWS Office
Logging( "state.CWA ${ state.CWA }", 3 )
}
if( Json.properties.gridX != null ){
state.GridX = Json.properties.gridX // US-NWS Grid X Value
Logging( "state.GridX ${ state.GridX }", 3 )
}
if( Json.properties.gridY != null ){
state.GridY = Json.properties.gridY // US-NWS Grid Y Value
Logging( "state.GridY ${ state.GridY }", 3 )
}
} else {
Logging( "Error connecting to US NWS: ${ resp.status }", 4 )
}
}
// Get the US forecast returned, output events and populate attributes as needed
def GetUSForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
// Updated
if( Json.properties.updated != null ){
ProcessEvent( "Updated", Json.properties.updated )
//state.Updated = Json.properties.updated // Date/Time of update
}
// Units
if( Json.properties.units != null ){
state.Units = Json.properties.units // Units that information is in
}
// Today's Forecast
// Today's temperature
if( Json.properties.periods[ 0 ].temperature != null ){
ProcessEvent( "Today_Temperature", Json.properties.periods[ 0 ].temperature, Json.properties.periods[ 0 ].temperatureUnit )
ProcessEvent( "temperature", Json.properties.periods[ 0 ].temperature, Json.properties.periods[ 0 ].temperatureUnit )
}
// Today's wind speed
if( Json.properties.periods[ 0 ].windSpeed != null ){
def Split = Json.properties.periods[ 0 ].windSpeed.split()
if( Split.size() > 2 ){
ProcessEvent( "Today_WindSpeed", Split[ 2 ] as int, "mph" )
ProcessEvent( "windSpeed", Split[ 2 ] as int, "mph" )
} else {
ProcessEvent( "Today_WindSpeed", Split[ 0 ] as int, "mph" )
ProcessEvent( "windSpeed", Split[ 0 ] as int, "mph" )
}
}
// Today's wind direction
if( Json.properties.periods[ 0 ].windDirection != null ){
ProcessEvent( "Today_WindDirection", USWindDirection( Json.properties.periods[ 0 ].windDirection ), "°" )
ProcessEvent( "Today_WindDirectionString", Json.properties.periods[ 0 ].windDirection )
ProcessEvent( "windDirection", USWindDirection( Json.properties.periods[ 0 ].windDirection ), "°" )
}
// Today's short forecast
if( Json.properties.periods[ 0 ].shortForecast != null ){
ProcessEvent( "Today_ShortForecast", Json.properties.periods[ 0 ].shortForecast )
}
// Today's detailed forecast
if( Json.properties.periods[ 0 ].detailedForecast != null ){
ProcessEvent( "Today_DetailedForecast", Json.properties.periods[ 0 ].detailedForecast )
ProcessUSDetailedForecast( 1, state.Today_DetailedForecast )
}
// Today's icon
if( Json.properties.periods[ 0 ].icon != null ){
ProcessEvent( "Today_IconURL", Json.properties.periods[ 0 ].icon )
}
// Tonight's Forecast
// Tonight's temperature
if( Json.properties.periods[ 1 ].temperature != null ){
ProcessEvent( "Tonight_Temperature", Json.properties.periods[ 1 ].temperature, Json.properties.periods[ 1 ].temperatureUnit )
}
// Tonight's wind speed
if( Json.properties.periods[ 1 ].windSpeed != null ){
def Split = Json.properties.periods[ 1 ].windSpeed.split()
if( Split.size() > 2 ){
ProcessEvent( "Tonight_WindSpeed", Split[ 2 ] as int, "mph" )
} else {
ProcessEvent( "Tonight_WindSpeed", Split[ 0 ] as int, "mph" )
}
}
// Tonight's wind direction
if( Json.properties.periods[ 1 ].windDirection != null ){
ProcessEvent( "Tonight_WindDirection", USWindDirection( Json.properties.periods[ 1 ].windDirection ), "°" )
ProcessEvent( "Tonight_WindDirectionString", Json.properties.periods[ 1 ].windDirection )
}
// Tonight's short forecast
if( Json.properties.periods[ 1 ].shortForecast != null ){
ProcessEvent( "Tonight_ShortForecast", Json.properties.periods[ 1 ].shortForecast )
}
// Tonight's detailed forecast
if( Json.properties.periods[ 1 ].detailedForecast != null ){
ProcessEvent( "Tonight_DetailedForecast", Json.properties.periods[ 1 ].detailedForecast )
ProcessUSDetailedForecast( 2, state.Tonight_DetailedForecast )
}
// Tonight's icon
if( Json.properties.periods[ 1 ].icon != null ){
ProcessEvent( "Tonight_IconURL", Json.properties.periods[ 1 ].icon )
}
// Tomorrow's Forecast
// Tomorrow's temperature
if( Json.properties.periods[ 2 ].temperature != null ){
ProcessEvent( "Tomorrow_Temperature", Json.properties.periods[ 2 ].temperature, Json.properties.periods[ 2 ].temperatureUnit )
}
// Tomorrow's wind speed
if( Json.properties.periods[ 2 ].windSpeed != null ){
def Split = Json.properties.periods[ 2 ].windSpeed.split()
if( Split.size() > 2 ){
ProcessEvent( "Tomorrow_WindSpeed", Split[ 2 ] as int, "mph" )
} else {
ProcessEvent( "Tomorrow_WindSpeed", Split[ 0 ] as int, "mph" )
}
}
// Tomorrow's wind direction
if( Json.properties.periods[ 2 ].windDirection != null ){
ProcessEvent( "Tomorrow_WindDirection", USWindDirection( Json.properties.periods[ 2 ].windDirection ), "°" )
ProcessEvent( "Tomorrow_WindDirectionString", Json.properties.periods[ 2 ].windDirection )
}
// Tomorrow's short forecast
if( Json.properties.periods[ 2 ].shortForecast != null ){
ProcessEvent( "Tomorrow_ShortForecast", Json.properties.periods[ 2 ].shortForecast )
}
// Tomorrow's detailed forecast
if( Json.properties.periods[ 2 ].detailedForecast != null ){
ProcessEvent( "Tomorrow_DetailedForecast", Json.properties.periods[ 2 ].detailedForecast )
ProcessUSDetailedForecast( 3, state.Tomorrow_DetailedForecast )
}
// Tomorrow's icon
if( Json.properties.periods[ 2 ].icon != null ){
ProcessEvent( "Tomorrow_IconURL", Json.properties.periods[ 2 ].icon )
}
// Tomorrow Night's Forecast
// Tomorrow night's temperature
if( Json.properties.periods[ 3 ].temperature != null ){
ProcessEvent( "Tomorrownight_Temperature", Json.properties.periods[ 3 ].temperature, Json.properties.periods[ 3 ].temperatureUnit )
}
// Tomorrow night's wind speed
if( Json.properties.periods[ 3 ].windSpeed != null ){
def Split = Json.properties.periods[ 3 ].windSpeed.split()
if( Split.size() > 2 ){
ProcessEvent( "Tomorrownight_WindSpeed", Split[ 2 ] as int, "mph" )
} else {
ProcessEvent( "Tomorrownight_WindSpeed", Split[ 0 ] as int, "mph" )
}
}
// Tomorrow night's wind direction
if( Json.properties.periods[ 3 ].windDirection != null ){
ProcessEvent( "Tomorrownight_WindDirection", USWindDirection( Json.properties.periods[ 3 ].windDirection ), "°" )
ProcessEvent( "Tomorrownight_WindDirectionString", Json.properties.periods[ 3 ].windDirection )
}
// Tomorrow night's short forecast
if( Json.properties.periods[ 3 ].shortForecast != null ){
ProcessEvent( "Tomorrownight_ShortForecast", Json.properties.periods[ 3 ].shortForecast )
}
// Tomorrow night's detailed forecast
if( Json.properties.periods[ 3 ].detailedForecast != null ){
ProcessEvent( "Tomorrownight_DetailedForecast", Json.properties.periods[ 3 ].detailedForecast )
ProcessUSDetailedForecast( 4, state.Tomorrownight_DetailedForecast )
}
// Tomorrow night's icon
if( Json.properties.periods[ 3 ].icon != null ){
ProcessEvent( "Tomorrownight_IconURL", Json.properties.periods[ 3 ].icon )
}
// Section for the forecast child devices
if( ChildrenEnabled ){
ClearForecastChildren()
Json.properties.periods.each(){
switch( it.name ){
case "Sunday":
case "Monday":
case "Tuesday":
case "Wednesday":
case "Thursday":
case "Friday":
case "Saturday":
if( it.temperature != null ){
PostEventToChild( "${ device.name } ${ it.name }", "temperature", it.temperature, "${ location.temperatureScale }" )
}
if( it.windDirection != null ){
PostEventToChild( "${ device.name } ${ it.name }", "WindDirectionString", "${ it.windDirection }" )
}
if( it.startTime != null ){
PostEventToChild( "${ device.name } ${ it.name }", "Forecast Valid as of", "${ it.startTime }" )
}
if( it.detailedForecast != null ){
PostEventToChild( "${ device.name } ${ it.name }", "Conditions", "${ it.detailedForecast }" )
}
break
}
}
}
Logging( "US NWS data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else {
Logging( "Error connecting to US NWS: ${ resp.status }", 4 )
return
}
}
// Get the forecast returned, output events and populate attributes as needed
def GetUKForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
if( Json.features[ 0 ].properties.modelRunDate != null ){
ProcessEvent( "Updated", Json.features[ 0 ].properties.modelRunDate )
}
// Today's Forecast
// Today's temperature
if( Json.features[ 0 ].properties.timeSeries[ 0 ].dayMaxScreenTemperature != null ){
ProcessEvent( "Today_Temperature", Json.features[ 0 ].properties.timeSeries[ 0 ].dayMaxScreenTemperature, "C" )
ProcessEvent( "temperature", Json.features[ 0 ].properties.timeSeries[ 0 ].dayMaxScreenTemperature, "C" )
}
// Today's min temperature
if( Json.features[ 0 ].properties.timeSeries[ 0 ].nightLowerBoundMinTemp != null ){
ProcessEvent( "Today_MinTemp", Json.features[ 0 ].properties.timeSeries[ 0 ].nightLowerBoundMinTemp, "C" )
}
// Today's max temperature
if( Json.features[ 0 ].properties.timeSeries[ 0 ].dayUpperBoundMaxTemp != null ){
ProcessEvent( "Today_MaxTemp", Json.features[ 0 ].properties.timeSeries[ 0 ].dayUpperBoundMaxTemp, "C" )
}
// Today's wind speed
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindSpeed != null ){
ProcessEvent( "Today_WindSpeed", Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindSpeed, "knots" )
ProcessEvent( "windSpeed", Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindSpeed, "knots" )
}
// Today's wind direction
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindDirection != null ){
ProcessEvent( "Today_WindDirection", Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindDirection, "°" )
ProcessEvent( "windDirection", Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindDirection, "°" )
}
// Today's wind gust
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindGust != null ){
ProcessEvent( "Today_WindGust", Json.features[ 0 ].properties.timeSeries[ 0 ].midday10MWindGust, "knots" )
}
// Today's chance of rain
if( Json.features[ 0 ].properties.timeSeries[ 0 ].dayProbabilityOfRain != null ){
ProcessEvent( "Today_ChanceRain", Json.features[ 0 ].properties.timeSeries[ 0 ].dayProbabilityOfRain, "%" )
}
// Today's UVI
if( Json.features[ 0 ].properties.timeSeries[ 0 ].maxUvIndex != null ){
ProcessEvent( "Today_UVI", Json.features[ 0 ].properties.timeSeries[ 0 ].maxUvIndex, "" )
}
// Today's short forecast
if( Json.features[ 0 ].properties.timeSeries[ 0 ].daySignificantWeatherCode != null ){
ProcessEvent( "Today_ShortForecast", UKSignificantWeather( Json.features[ 0 ].properties.timeSeries[ 0 ].daySignificantWeatherCode ) )
}
// Tonight's Forecast
// Tonight's temperature
if( Json.features[ 0 ].properties.timeSeries[ 0 ].nightMinScreenTemperature != null ){
ProcessEvent( "Tonight_Temperature", Json.features[ 0 ].properties.timeSeries[ 0 ].nightMinScreenTemperature, "C" )
}
// Tonight's wind speed
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindSpeed != null ){
ProcessEvent( "Tonight_WindSpeed", Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindSpeed, "knots" )
}
// Tonight's wind direction
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindDirection != null ){
ProcessEvent( "Tonight_WindDirection", Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindDirection, "°" )
}
// Tonight's wind gust
if( Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindGust != null ){
ProcessEvent( "Tonight_WindGust", Json.features[ 0 ].properties.timeSeries[ 0 ].midnight10MWindGust, "knots" )
}
// Tonight's chance of rain
if( Json.features[ 0 ].properties.timeSeries[ 0 ].nightProbabilityOfRain != null ){
ProcessEvent( "Tonight_ChanceRain", Json.features[ 0 ].properties.timeSeries[ 0 ].nightProbabilityOfRain, "%" )
}
// Tonight's short forecast
if( Json.features[ 0 ].properties.timeSeries[ 0 ].nightSignificantWeatherCode != null ){
ProcessEvent( "Tonight_ShortForecast", UKSignificantWeather( Json.features[ 0 ].properties.timeSeries[ 0 ].nightSignificantWeatherCode ) )
}
// Tomorrow's Forecast
// Tomorrow's temperature
if( Json.features[ 0 ].properties.timeSeries[ 1 ].dayMaxScreenTemperature != null ){
ProcessEvent( "Tomorrow_Temperature", Json.features[ 0 ].properties.timeSeries[ 1 ].dayMaxScreenTemperature, "C" )
}
// Today's min temperature
if( Json.features[ 0 ].properties.timeSeries[ 1 ].nightLowerBoundMinTemp != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.features[ 0 ].properties.timeSeries[ 1 ].nightLowerBoundMinTemp, "C" )
}
// Today's max temperature
if( Json.features[ 0 ].properties.timeSeries[ 1 ].dayUpperBoundMaxTemp != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.features[ 0 ].properties.timeSeries[ 1 ].dayUpperBoundMaxTemp, "C" )
}
// Tomorrow's wind speed
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindSpeed != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindSpeed, "knots" )
}
// Tomorrow's wind direction
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindDirection != null ){
ProcessEvent( "Tomorrow_WindDirection", Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindDirection, "°" )
}
// Tomorrow's wind gust
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindGust != null ){
ProcessEvent( "Tomorrow_WindGust", Json.features[ 0 ].properties.timeSeries[ 1 ].midday10MWindGust, "knots" )
}
// Tomorrow's chance of rain
if( Json.features[ 0 ].properties.timeSeries[ 1 ].dayProbabilityOfRain != null ){
ProcessEvent( "Tomorrow_ChanceRain", Json.features[ 0 ].properties.timeSeries[ 1 ].dayProbabilityOfRain, "%" )
}
// Tomorrow's UVI
if( Json.features[ 0 ].properties.timeSeries[ 1 ].maxUvIndex != null ){
ProcessEvent( "Tomorrow_UVI", Json.features[ 0 ].properties.timeSeries[ 1 ].maxUvIndex, "" )
}
// Tomorrow's short forecast
if( Json.features[ 0 ].properties.timeSeries[ 1 ].daySignificantWeatherCode != null ){
ProcessEvent( "Tomorrow_ShortForecast", UKSignificantWeather( Json.features[ 0 ].properties.timeSeries[ 1 ].daySignificantWeatherCode ) )
}
// Tomorrow night's Forecast
// Tomorrow night's temperature
if( Json.features[ 0 ].properties.timeSeries[ 1 ].nightMinScreenTemperature != null ){
ProcessEvent( "Tomorrownight_Temperature", Json.features[ 0 ].properties.timeSeries[ 1 ].nightMinScreenTemperature, "C" )
}
// Tomorrow night's wind speed
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindSpeed != null ){
ProcessEvent( "Tomorrownight_WindSpeed", Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindSpeed, "knots" )
}
// Tomorrow night's wind direction
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindDirection != null ){
ProcessEvent( "Tomorrownight_WindDirection", Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindDirection, "°" )
}
// Tomorrow night's wind gust
if( Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindGust != null ){
ProcessEvent( "Tomorrownight_WindGust", Json.features[ 0 ].properties.timeSeries[ 1 ].midnight10MWindGust, "knots" )
}
// Tomorrow night's chance of rain
if( Json.features[ 0 ].properties.timeSeries[ 1 ].nightProbabilityOfRain != null ){
ProcessEvent( "Tomorrownight_ChanceRain", Json.features[ 0 ].properties.timeSeries[ 1 ].nightProbabilityOfRain, "%" )
}
// Tomorrow night's short forecast
if( Json.features[ 0 ].properties.timeSeries[ 1 ].nightSignificantWeatherCode != null ){
ProcessEvent( "Tomorrownight_ShortForecast", UKSignificantWeather( Json.features[ 0 ].properties.timeSeries[ 1 ].nightSignificantWeatherCode ) )
}
Logging( "UK/Australia Met Office data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid API credentials provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to UK Met Office: ${ resp.status }", 4 )
}
}
// Get the forecast returned, output events and populate attributes as needed from OpenWeather
def GetOWForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
// Updated date
if( Json.current.dt != null ){
ProcessEvent( "Updated", ConvertEpochToDate( Json.current.dt ) )
}
// Current temperature
if( Json.current.temp != null ){
ProcessEvent( "temperature", Json.current.temp, location.temperatureScale )
}
// Current feelsLike
if( Json.current.feels_like != null ){
ProcessEvent( "feelsLike", Json.current.feels_like, location.temperatureScale )
}
// Current pressure
if( Json.current.pressure != null ){
ProcessEvent( "pressure", Json.current.pressure, "hPa" )
}
// Current humidity
if( Json.current.humidity != null ){
ProcessEvent( "humidity", Json.current.humidity, "%" )
}
// Current dewPoint
if( Json.current.dew_point != null ){
ProcessEvent( "dewPoint", Json.current.dew_point, location.temperatureScale )
}
// Current uvi
if( Json.current.uvi != null ){
ProcessEvent( "uv", Json.current.uvi )
}
// Current hourlyRain
if( Json.current.rain != null ){
if( Json.current.rain.'1h' != null ){
ProcessEvent( "hourlyRain", Json.current.rain.'1h', "mm" )
}
}
// Current Conditions
if( Json.current.weather.description != null ){
ProcessEvent( "Conditions", Json.current.weather.description )
}
// Current wind speed
if( Json.current.wind_speed != null ){
ProcessEvent( "windSpeed", Json.current.wind_speed, "" )
}
// Current wind gust
if( Json.current.wind_gust != null ){
ProcessEvent( "windGust", Json.current.wind_gust, "" )
}
// Current wind direction
if( Json.current.wind_deg != null ){
ProcessEvent( "winddir", Json.current.wind_deg, "°" )
}
// Today's temperature
if( Json.daily[ 0 ].temp.day != null ){
ProcessEvent( "Today_Temperature", Json.daily[ 0 ].temp.day, location.temperatureScale )
}
// Today's min temperature
if( Json.daily[ 0 ].temp.min != null ){
ProcessEvent( "Today_MinTemp", Json.daily[ 0 ].temp.min, location.temperatureScale )
}
// Today's max temperature
if( Json.daily[ 0 ].temp.max != null ){
ProcessEvent( "Today_MaxTemp", Json.daily[ 0 ].temp.max, location.temperatureScale )
}
// Tonight's temperature
if( Json.daily[ 0 ].temp.night != null ){
ProcessEvent( "Tonight_Temperature", Json.daily[ 0 ].temp.night, location.temperatureScale )
}
// Today's "feels like" temperature
if( Json.daily[ 0 ].feels_like.day != null ){
ProcessEvent( "Today_FeelsLike", Json.daily[ 0 ].feels_like.day, location.temperatureScale )
}
// Tonight's "feels like" temperature
if( Json.daily[ 0 ].feels_like.night != null ){
ProcessEvent( "Tonight_FeelsLike", Json.daily[ 0 ].feels_like.night, location.temperatureScale )
}
// Today's humidity
if( Json.daily[ 0 ].humidity != null ){
ProcessEvent( "Today_Humidity", Json.daily[ 1 ].humidity, "%" )
ProcessEvent( "humidity", Json.daily[ 1 ].humidity, "%" )
}
// Today's air pressure
if( Json.daily[ 0 ].pressure != null ){
ProcessEvent( "Today_Pressure", Json.daily[ 0 ].pressure, "" )
}
// Today's wind speed
if( Json.daily[ 0 ].wind_speed != null ){
ProcessEvent( "Today_WindSpeed", Json.daily[ 0 ].wind_speed, "" )
}
// Today's wind direction
if( Json.daily[ 0 ].wind_deg != null ){
ProcessEvent( "Today_WindDirection", Json.daily[ 0 ].wind_deg, "°" )
}
// Today's chance of rain
if( Json.daily[ 0 ].rain != null ){
ProcessEvent( "Today_ChanceRain", Json.daily[ 0 ].rain, "%" )
} else {
ProcessEvent( "Today_ChanceRain", 0, "%" )
}
// Today's chance of clouds
if( Json.daily[ 0 ].clouds != null ){
ProcessEvent( "Today_ChanceClouds", Json.daily[ 0 ].clouds, "%" )
} else { // OpenWeather appears not to list the variable if the chance is 0 (at least fo rain, so I am making sure here)
ProcessEvent( "Today_ChanceClouds", 0, "%" )
}
// Today's chance of snow
if( Json.daily[ 0 ].snow != null ){
ProcessEvent( "Today_ChanceSnow", Json.daily[ 0 ].snow, "%" )
} else {
ProcessEvent( "Today_ChanceSnow", 0, "%" )
}
// Today's UVI
if( Json.daily[ 0 ].uvi != null ){
ProcessEvent( "Today_UVI", Json.daily[ 0 ].uvi )
}
// Today's sunrise
if( Json.daily[ 0 ].sunrise != null ){
ProcessEvent( "Today_SunriseEpoch", Json.daily[ 0 ].sunrise )
ProcessEvent( "Today_Sunrise", ConvertEpochToDate( Json.daily[ 0 ].sunrise ) )
}
// Today's sunset
if( Json.daily[ 0 ].sunset != null ){
ProcessEvent( "Today_SunsetEpoch", Json.daily[ 0 ].sunset )
ProcessEvent( "Today_Sunset", ConvertEpochToDate( Json.daily[ 0 ].sunset ) )
}
// Today's icon
if( Json.daily[ 0 ].weather[ 0 ].icon != null ){
ProcessEvent( "Today_IconURL", "http://openweathermap.org/img/wn/${ Json.daily[ 0 ].weather[ 0 ].icon }@2x.png" )
}
// Tomorrow's Forecast
// Tomorrow's temperature
if( Json.daily[ 1 ].temp.day != null ){
ProcessEvent( "Tomorrow_Temperature", Json.daily[ 1 ].temp.day, location.temperatureScale )
}
// Tomorrow's min temperature
if( Json.daily[ 1 ].temp.min != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.daily[ 1 ].temp.min, location.temperatureScale )
}
// Today's max temperature
if( Json.daily[ 1 ].temp.max != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.daily[ 1 ].temp.max, location.temperatureScale )
}
// Tomorrow night's temperature
if( Json.daily[ 1 ].temp.night != null ){
ProcessEvent( "Tomorrownight_Temperature", Json.daily[ 1 ].temp.night, location.temperatureScale )
}
// Tomorrow's "feels like" temperature
if( Json.daily[ 1 ].feels_like.day != null ){
ProcessEvent( "Tomorrow_FeelsLike", Json.daily[ 1 ].feels_like.day, location.temperatureScale )
}
// Tomorrow night's "feels like" temperature
if( Json.daily[ 1 ].feels_like.night != null ){
ProcessEvent( "Tomorrownight_FeelsLike", Json.daily[ 1 ].feels_like.night, location.temperatureScale )
}
// Tomorrow's humidity
if( Json.daily[ 1 ].humidity != null ){
ProcessEvent( "Tomorrow_Humidity", Json.daily[ 1 ].humidity, "%" )
}
// Tomorrow's air pressure
if( Json.daily[ 1 ].pressure != null ){
ProcessEvent( "Tomorrow_Pressure", Json.daily[ 1 ].pressure, "" )
}
// Tomorrow's wind speed
if( Json.daily[ 1 ].wind_speed != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.daily[ 1 ].wind_speed, "" )
}
// Tomorrow's wind direction
if( Json.daily[ 1 ].wind_deg != null ){
ProcessEvent( "Tomorrow_WindDirection", Json.daily[ 1 ].wind_deg, "" )
}
// Tomorrow's chance of rain
if( Json.daily[ 1 ].rain != null ){
ProcessEvent( "Tomorrow_ChanceRain", Json.daily[ 1 ].rain, "%" )
} else {
ProcessEvent( "Tomorrow_ChanceRain", 0, "%" )
}
// Tomorrow's chance of clouds
if( Json.daily[ 1 ].clouds != null ){
ProcessEvent( "Tomorrow_ChanceClouds", Json.daily[ 1 ].clouds, "%" )
} else {
ProcessEvent( "Tomorrow_ChanceClouds", 0, "%" )
}
// Tomorrow's chance of snow
if( Json.daily[ 1 ].snow != null ){
ProcessEvent( "Tomorrow_ChanceSnow", Json.daily[ 1 ].snow, "%" )
} else {
ProcessEvent( "Tomorrow_ChanceSnow", 0, "%" )
}
// Tomorrow's UVI
if( Json.daily[ 1 ].uvi != null ){
ProcessEvent( "Tomorrow_UVI", Json.daily[ 1 ].uvi )
}
// Tomorrow's sunrise
if( Json.daily[ 1 ].sunrise != null ){
ProcessEvent( "Tomorrow_SunriseEpoch", Json.daily[ 1 ].sunrise )
ProcessEvent( "Tomorrow_Sunrise", ConvertEpochToDate( Json.daily[ 1 ].sunrise ) )
}
// Tomorrow's sunset
if( Json.daily[ 1 ].sunset != null ){
ProcessEvent( "Tomorrow_SunsetEpoch", Json.daily[ 1 ].sunset )
ProcessEvent( "Tomorrow_Sunset", ConvertEpochToDate( Json.daily[ 1 ].sunset ) )
}
// Tomorrow's icon
if( Json.daily[ 1 ].weather[ 0 ].icon != null ){
ProcessEvent( "Tomorrow_IconURL", "http://openweathermap.org/img/wn/${ Json.daily[ 1 ].weather[ 0 ].icon }@2x.png" )
}
// Section for the forecast child devices
if( ChildrenEnabled ){
ClearForecastChildren()
for( i = 0; i <= 5; i++ ){
def TempDate = ConvertEpochToDate( Json.daily[ i ].dt )
def day = TempDate[ Calendar.DAY_OF_WEEK ]
Day = ReturnDayName( day )
if( Json.daily[ i ].temp.min != null ){
PostEventToChild( "${ device.name } ${ Day }", "Min Temperature", Json.daily[ i ].temp.min, "${ location.temperatureScale }" )
}
if( Json.daily[ i ].temp.max != null ){
PostEventToChild( "${ device.name } ${ Day }", "Max Temperature", Json.daily[ i ].temp.max, "${ location.temperatureScale }" )
}
if( Json.daily[ i ].feels_like.day != null ){
PostEventToChild( "${ device.name } ${ Day }", "feelsLike", Json.daily[ i ].feels_like.day, "${ location.temperatureScale }" )
}
if( Json.daily[ i ].pop != null ){
PostEventToChild( "${ device.name } ${ Day }", "Chance Precipitation", Json.daily[ i ].pop, "%" )
}
if( Json.daily[ i ].pressure != null ){
PostEventToChild( "${ device.name } ${ Day }", "pressure", Json.daily[ i ].pressure )
}
if( Json.daily[ i ].humidity != null ){
PostEventToChild( "${ device.name } ${ Day }", "humidity", Json.daily[ i ].humidity )
}
if( Json.daily[ i ].dew_point != null ){
PostEventToChild( "${ device.name } ${ Day }", "dewPoint", Json.daily[ i ].dew_point )
}
if( Json.daily[ i ].wind_speed != null ){
PostEventToChild( "${ device.name } ${ Day }", "windSpeed", Json.daily[ i ].wind_speed )
}
if( Json.daily[ i ].wind_gust != null ){
PostEventToChild( "${ device.name } ${ Day }", "windGust", Json.daily[ i ].wind_gust )
}
if( Json.daily[ i ].wind_deg != null ){
PostEventToChild( "${ device.name } ${ Day }", "windDirection", Json.daily[ i ].wind_dir )
}
if( Json.daily[ i ].clouds != null ){
PostEventToChild( "${ device.name } ${ Day }", "Cloud Cover", Json.daily[ i ].clouds, "%" )
}
if( Json.daily[ i ].uvi != null ){
PostEventToChild( "${ device.name } ${ Day }", "uv", Json.daily[ i ].uvi )
}
if( Json.daily[ i ].sunrise != null ){
PostEventToChild( "${ device.name } ${ Day }", "Sunrise", "${ ConvertEpochToDate( Json.daily[ i ].sunrise ) }" )
}
if( Json.daily[ i ].sunset != null ){
PostEventToChild( "${ device.name } ${ Day }", "Sunset", "${ ConvertEpochToDate( Json.daily[ i ].sunset ) }" )
}
if( Json.daily[ i ].moon_phase != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moon Phase", "${ Json.daily[ i ].moon_phase }" )
}
if( Json.daily[ i ].moonrise != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moonrise", "${ ConvertEpochToDate( Json.daily[ i ].moonrise ) }" )
}
if( Json.daily[ i ].moonset != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moonset", "${ ConvertEpochToDate( Json.daily[ i ].moonset ) }" )
}
if( Json.daily[ i ].weather[ 0 ].description != null ){
PostEventToChild( "${ device.name } ${ Day }", "Conditions", "${ Json.daily[ i ].weather[ 0 ].description }" )
}
}
}
Logging( "OpenWeather data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid APIKey provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to OpenWeather: ${ resp.status }", 4 )
}
}
// Get the WA forecast returned, output events and populate attributes as needed
def GetWAForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
// Updated
if( Json.current.last_updated != null ){
ProcessEvent( "Updated", Json.current.last_updated )
}
// uv
if( Json.current.uv != null ){
ProcessEvent( "uv", Json.current.uv )
}
// humidity
if( Json.current.humidity != null ){
ProcessEvent( "humidity", Json.current.humidity, "%" )
}
if( location.temperatureScale == "F" ){
// temperature
if( Json.current.temp_f != null ){
ProcessEvent( "temperature", Json.current.temp_f, "F" )
}
// feelsLike
if( Json.current.feelslike_f != null ){
ProcessEvent( "feelsLike", Json.current.feelslike_f, "F" )
}
// pressure
if( Json.current.pressure_in != null ){
ProcessEvent( "pressure", Json.current.pressure_in, "in" )
}
// wind speed
if( Json.current.windspeedMiles != null ){
ProcessEvent( "windSpeed", Json.current.windspeedMiles, "mph" )
}
// Today's temperature
if( Json.forecast.forecastday[ 0 ].day.avgtemp_f != null ){
ProcessEvent( "Today_Temperature", Json.forecast.forecastday[ 0 ].day.avgtemp_f, "F" )
}
// Today's min temperature
if( Json.forecast.forecastday[ 0 ].day.mintemp_f != null ){
ProcessEvent( "Today_MinTemp", Json.forecast.forecastday[ 0 ].day.mintemp_f, "F" )
}
// Today's max temperature
if( Json.forecast.forecastday[ 0 ].day.maxtemp_f != null ){
ProcessEvent( "Today_MaxTemp", Json.forecast.forecastday[ 0 ].day.maxtemp_f, "F" )
}
// Today's wind gust
if( Json.forecast.forecastday[ 0 ].day.maxwind_mph != null ){
ProcessEvent( "Today_WindGust", Json.forecast.forecastday[ 0 ].day.maxwind_mph, "mph" )
}
// Tomorrow's temperature
if( Json.forecast.forecastday[ 1 ].day.avgtemp_f != null ){
ProcessEvent( "Tomorrow_Temperature", Json.forecast.forecastday[ 1 ].day.avgtemp_f, "F" )
}
// Tomorrow's min temperature
if( Json.forecast.forecastday[ 1 ].day.mintemp_f != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.forecast.forecastday[ 1 ].day.mintemp_f, "F" )
}
// Tomorrow's max temperature
if( Json.forecast.forecastday[ 1 ].day.maxtemp_f != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.forecast.forecastday[ 1 ].day.maxtemp_f, "F" )
}
// Tomorrow's wind gust
if( Json.forecast.forecastday[ 1 ].day.maxwind_mph != null ){
ProcessEvent( "Tomorrow_WindGust", Json.forecast.forecastday[ 1 ].day.maxwind_mph, "mph" )
}
} else {
// temperature
if( Json.current.temp_c != null ){
ProcessEvent( "temperature", Json.current.temp_c, "C" )
}
// feelsLike
if( Json.current.feelslike_c != null ){
ProcessEvent( "feelsLike", Json.current.feelslike_c, "C" )
}
// pressure
if( Json.current.pressure_mb != null ){
ProcessEvent( "pressure", Json.current.pressure_mb, "mb" )
}
// wind speed
if( Json.current.windspeedKmph != null ){
ProcessEvent( "windSpeed", Json.current.windspeedKmph, "kmph" )
}
// Today's temperature
if( Json.forecast.forecastday[ 0 ].day.avgtemp_f != null ){
ProcessEvent( "Today_Temperature", Json.forecast.forecastday[ 0 ].day.avgtemp_c, "C" )
}
// Today's min temperature
if( Json.forecast.forecastday[ 0 ].day.mintemp_c != null ){
ProcessEvent( "Today_MinTemp", Json.forecast.forecastday[ 0 ].day.mintemp_c, "C" )
}
// Today's max temperature
if( Json.forecast.forecastday[ 0 ].day.maxtemp_c != null ){
ProcessEvent( "Today_MaxTemp", Json.forecast.forecastday[ 0 ].day.maxtemp_c, "C" )
}
// Today's wind gust
if( Json.forecast.forecastday[ 0 ].day.maxwind_kph != null ){
ProcessEvent( "Today_WindGust", Json.forecast.forecastday[ 0 ].day.maxwind_kph, "kph" )
}
// Tomorrow's temperature
if( Json.forecast.forecastday[ 1 ].day.avgtemp_c != null ){
ProcessEvent( "Tomorrow_Temperature", Json.forecast.forecastday[ 1 ].day.avgtemp_c, "C" )
}
// Tomorrow's min temperature
if( Json.forecast.forecastday[ 1 ].day.mintemp_c != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.forecast.forecastday[ 1 ].day.mintemp_c, "C" )
}
// Tomorrow's max temperature
if( Json.forecast.forecastday[ 1 ].day.maxtemp_c != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.forecast.forecastday[ 1 ].day.maxtemp_c, "C" )
}
// Tomorrow's wind gust
if( Json.forecast.forecastday[ 1 ].day.maxwind_kph != null ){
ProcessEvent( "Tomorrow_WindGust", Json.forecast.forecastday[ 1 ].day.maxwind_kph, "kph" )
}
}
// Today's short forecast
if( Json.forecast.forecastday[ 0 ].day.condition.text != null ){
ProcessEvent( "Today_ShortForecast", Json.forecast.forecastday[ 0 ].day.condition.text )
}
// Today's sunrise
if( Json.forecast.forecastday[ 0 ].astro.sunrise != null ){
ProcessEvent( "Today_Sunrise", "${ Json.forecast.forecastday[ 0 ].date }T${ Json.forecast.forecastday[ 0 ].astro.sunrise }" )
}
// Today's sunset
if( Json.forecast.forecastday[ 0 ].astro.sunset != null ){
ProcessEvent( "Today_Sunset", "${ Json.forecast.forecastday[ 0 ].date }T${ Json.forecast.forecastday[ 0 ].astro.sunset }" )
}
// Today's weather icon
if( Json.forecast.forecastday[ 0 ].day.condition.icon != null ){
def Temp = Json.forecast.forecastday[ 0 ].day.condition.icon.split( "//" )
ProcessEvent( "Today_IconURL", Temp[ 1 ] )
}
// Today's humidity
if( Json.forecast.forecastday[ 0 ].day.avghumidity != null ){
ProcessEvent( "Today_Humidity", Json.forecast.forecastday[ 0 ].day.avghumidity, "%" )
ProcessEvent( "humidity", Json.forecast.forecastday[ 0 ].day.avghumidity, "%" )
}
// Today's UVI
if( Json.forecast.forecastday[ 0 ].day.uv != null ){
ProcessEvent( "Today_UVI", Json.forecast.forecastday[ 0 ].day.uv )
}
// Tomorrow's short forecast
if( Json.forecast.forecastday[ 1 ].day.condition.text != null ){
ProcessEvent( "Tomorrow_ShortForecast", Json.forecast.forecastday[ 1 ].day.condition.text )
}
// Tomorrow's sunrise
if( Json.forecast.forecastday[ 1 ].astro.sunrise != null ){
ProcessEvent( "Tomorrow_Sunrise", "${ Json.forecast.forecastday[ 1 ].date }T${ Json.forecast.forecastday[ 1 ].astro.sunrise }" )
}
// Tomorrow's sunset
if( Json.forecast.forecastday[ 1 ].astro.sunset != null ){
ProcessEvent( "Tomorrow_Sunset", "${ Json.forecast.forecastday[ 1 ].date }T${ Json.forecast.forecastday[ 1 ].astro.sunset }" )
}
// Tomorrow's weather icon
if( Json.forecast.forecastday[ 1 ].day.condition.icon != null ){
def Temp = Json.forecast.forecastday[ 1 ].day.condition.icon.split( "//" )
ProcessEvent( "Tomorrow_IconURL", Temp[ 1 ] )
}
// Tomorrow's humidity
if( Json.forecast.forecastday[ 1 ].day.avghumidity != null ){
ProcessEvent( "Tomorrow_Humidity", Json.forecast.forecastday[ 1 ].day.avghumidity, "%" )
}
// Tomorrow's UVI
if( Json.forecast.forecastday[ 1 ].day.uv != null ){
ProcessEvent( "Tomorrow_UVI", Json.forecast.forecastday[ 1 ].day.uv )
}
Logging( "WeatherAPI.com data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid APIKey provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to WeatherAPI.com: ${ resp.status }", 4 )
}
}
// Get the WU Current, output events and populate attributes as needed
def GetWUCurrent( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
// Updated
if( Json.observations[ 0 ].obsTimeLocal != null ){
ProcessEvent( "Updated", Json.observations[ 0 ].obsTimeLocal )
}
if( location.temperatureScale == "F" ){
// Today's temperature
if( Json.observations[ 0 ].imperial.temp != null ){
ProcessEvent( "Today_Temperature", Json.observations[ 0 ].imperial.temp, "F" )
ProcessEvent( "temperature", Json.observations[ 0 ].imperial.temp, "F" )
}
// Today's wind gust
if( Json.observations[ 0 ].imperial.windGust != null ){
ProcessEvent( "Today_WindGust", Json.observations[ 0 ].imperial.windGust, "mph" )
}
// Today's wind speed
if( Json.observations[ 0 ].imperial.windSpeed != null ){
ProcessEvent( "Today_WindSpeed", Json.observations[ 0 ].imperial.windSpeed, "mph" )
ProcessEvent( "windSpeed", Json.observations[ 0 ].imperial.windSpeed, "mph" )
}
// Today's pressure
if( Json.observations[ 0 ].imperial.pressure != null ){
ProcessEvent( "Today_Pressure", Json.observations[ 0 ].imperial.pressure )
}
// Dew Point
if( Json.observations[ 0 ].imperial.dewpt != null ){
ProcessEvent( "dewPoint", Json.observations[ 0 ].imperial.dewpt )
}
// Heat Index
if( Json.observations[ 0 ].imperial.heatIndex != null ){
ProcessEvent( "feelsLike", Json.observations[ 0 ].imperial.heatIndex )
}
// Wind Chill
if( Json.observations[ 0 ].imperial.windChill != null ){
ProcessEvent( "WindChill", Json.observations[ 0 ].imperial.windChill )
}
} else {
// Today's temperature
if( Json.observations[ 0 ].metric.temp != null ){
ProcessEvent( "Today_Temperature", Json.observations[ 0 ].metric.temp, "C" )
ProcessEvent( "temperature", Json.observations[ 0 ].metric.temp, "C" )
}
// Today's wind gust
if( Json.observations[ 0 ].metric.windGust != null ){
ProcessEvent( "Today_WindGust", Json.observations[ 0 ].metric.windGust, "kph" )
}
// Today's wind speed
if( Json.observations[ 0 ].metric.windSpeed != null ){
ProcessEvent( "Today_WindSpeed", Json.observations[ 0 ].metric.windSpeed, "kph" )
ProcessEvent( "windSpeed", Json.observations[ 0 ].metric.windSpeed, "kph" )
}
// Today's pressure
if( Json.observations[ 0 ].metric.pressure != null ){
ProcessEvent( "Today_Pressure", Json.observations[ 0 ].metric.pressure )
}
// Dew Point
if( Json.observations[ 0 ].metric.dewpt != null ){
ProcessEvent( "dewPoint", Json.observations[ 0 ].metric.dewpt )
}
// Heat Index
if( Json.observations[ 0 ].metric.heatIndex != null ){
ProcessEvent( "feelsLike", Json.observations[ 0 ].metric.heatIndex )
}
// Wind Chill
if( Json.observations[ 0 ].metric.windChill != null ){
ProcessEvent( "WindChill", Json.observations[ 0 ].metric.windChill )
}
}
// Neighborhood
if( Json.observations[ 0 ].neighborhood != null ){
ProcessEvent( "Neighborhood", Json.observations[ 0 ].neighborhood )
}
// Quality Control Indicator
if( Json.observations[ 0 ].qcStatus != null ){
ProcessEvent( "Quality Control", Json.observations[ 0 ].qcStatus )
}
// PWS Software Type
if( Json.observations[ 0 ].softwareType != null ){
ProcessEvent( "PWS Software Type", Json.observations[ 0 ].softwareType )
}
// Elevation
if( Json.observations[ 0 ].elev != null ){
ProcessEvent( "Elevation", Json.observations[ 0 ].elev )
}
// Today's humidity
if( Json.observations[ 0 ].humidity != null ){
ProcessEvent( "Today_Humidity", Json.observations[ 0 ].humidity, "%" )
ProcessEvent( "humidity", Json.observations[ 0 ].humidity, "%" )
}
// Today's wind direction
if( Json.observations[ 0 ].winddir != null ){
ProcessEvent( "Today_WindDirection", Json.observations[ 0 ].winddir, "°" )
ProcessEvent( "windDirection", Json.observations[ 0 ].winddir, "°" )
}
// Today's UVI
if( Json.observations[ 0 ].uv != null ){
ProcessEvent( "uv", Json.observations[ 0 ].uv )
}
// Today's Solar Radiation
if( Json.observations[ 0 ].solarRadiation != null ){
ProcessEvent( "solarradiation", Json.observations[ 0 ].solarRadiation )
}
Logging( "Weather Underground observation data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid APIKey provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to Weather Underground: ${ resp.status }", 4 )
}
}
// Get the WU forecast, output events and populate attributes as needed
def GetWUForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
if( location.temperatureScale == "F" ){
// Tonight's temperature
if( Json.daypart[ 0 ].temperature[ 1 ] != null ){
ProcessEvent( "Tonight_Temperature", Json.daypart[ 0 ].temperature[ 1 ] , "F" )
}
// Tomorrow's temperature
if( Json.daypart[ 0 ].temperature[ 2 ] != null ){
ProcessEvent( "Tomorrow_Temperature", Json.daypart[ 0 ].temperature[ 2 ] , "F" )
}
// Tomorrow night's temperature
if( Json.daypart[ 0 ].temperature[ 2 ] != null ){
ProcessEvent( "Tomorrownight_Temperature", Json.daypart[ 0 ].temperature[ 3 ] , "F" )
}
// Today's min temperature
if( Json.temperatureMin[ 0 ] != null ){
ProcessEvent( "Today_MinTemp", Json.temperatureMin[ 0 ] , "F" )
}
// Tomorrow's min temperature
if( Json.temperatureMin[ 1 ] != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.temperatureMin[ 1 ] , "F" )
}
// Today's max temperature
if( Json.temperatureMax[ 0 ] != null ){
ProcessEvent( "Today_MaxTemp", Json.temperatureMax[ 0 ] , "F" )
}
// Tomorrow's max temperature
if( Json.temperatureMax[ 1 ] != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.temperatureMax[ 1 ] , "F" )
}
// Tonight's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tonight_WindSpeed", Json.daypart[ 0 ].windSpeed[ 1 ] , "mph" )
}
// Tomorrow's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.daypart[ 0 ].windSpeed[ 2 ] , "mph" )
}
// Tomorrow night's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tomorrownight_WindSpeed", Json.daypart[ 0 ].windSpeed[ 3 ] , "mph" )
}
} else {
// Tonight's temperature
if( Json.daypart[ 0 ].temperature[ 1 ] != null ){
ProcessEvent( "Tonight_Temperature", Json.daypart[ 0 ].temperature[ 1 ] , "C" )
}
// Tomorrow's temperature
if( Json.daypart[ 0 ].temperature[ 2 ] != null ){
ProcessEvent( "Tomorrow_Temperature", Json.daypart[ 0 ].temperature[ 2 ] , "C" )
}
// Tomorrow night's temperature
if( Json.daypart[ 0 ].temperature[ 2 ] != null ){
ProcessEvent( "Tomorrownight_Temperature", Json.daypart[ 0 ].temperature[ 3 ] , "C" )
}
// Today's min temperature
if( Json.temperatureMin[ 0 ] != null ){
ProcessEvent( "Today_MinTemp", Json.temperatureMin[ 0 ] , "C" )
}
// Tomorrow's min temperature
if( Json.temperatureMin[ 1 ] != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.temperatureMin[ 1 ] , "C" )
}
// Today's max temperature
if( Json.temperatureMax[ 0 ] != null ){
ProcessEvent( "Today_MaxTemp", Json.temperatureMax[ 0 ] , "C" )
}
// Tomorrow's max temperature
if( Json.temperatureMax[ 1 ] != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.temperatureMax[ 1 ] , "C" )
}
// Tonight's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tonight_WindSpeed", Json.daypart[ 0 ].windSpeed[ 1 ] , "kph" )
}
// Tomorrow's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.daypart[ 0 ].windSpeed[ 2 ] , "kph" )
}
// Tomorrow night's wind speed
if( Json.daypart[ 0 ].windSpeed[ 1 ] != null ){
ProcessEvent( "Tomorrownight_WindSpeed", Json.daypart[ 0 ].windSpeed[ 3 ] , "kph" )
}
}
// Today's sunrise
if( Json.sunriseTimeLocal[ 0 ] != null ){
ProcessEvent( "Today_Sunrise", Json.sunriseTimeLocal[ 0 ] )
}
// Today's sunset
if( Json.sunsetTimeLocal[ 0 ] != null ){
ProcessEvent( "Today_Sunset", Json.sunsetTimeLocal[ 0 ] )
}
// Today's Detailed Forecast
if( Json.narrative[ 0 ] != null ){
ProcessEvent( "Today_DetailedForecast", Json.narrative[ 0 ] )
}
// Today's Valid Time
if( Json.validTimeLocal[ 0 ] != null ){
ProcessEvent( "Today_ValidTime", Json.validTimeLocal[ 0 ] )
}
// Tonight's wind direction
if( Json.daypart[ 0 ].windDirection[ 1 ] != null ){
ProcessEvent( "Tonight_WindDirection", Json.daypart[ 0 ].windDirection[ 1 ] , "°" )
}
// Tomorrow's wind direction
if( Json.daypart[ 0 ].windDirection[ 1 ] != null ){
ProcessEvent( "Tomorrow_WindDirection", Json.daypart[ 0 ].windDirection[ 2 ] , "°" )
}
// Tomorrow night's wind direction
if( Json.daypart[ 0 ].windDirection[ 1 ] != null ){
ProcessEvent( "Tomorrownight_WindDirection", Json.daypart[ 0 ].windDirection[ 3 ] , "°" )
}
// Tomorrow's sunrise
if( Json.sunriseTimeLocal[ 1 ] != null ){
ProcessEvent( "Tomorrow_Sunrise", Json.sunriseTimeLocal[ 1 ] )
}
// Tomorrow's sunset
if( Json.sunsetTimeLocal[ 1 ] != null ){
ProcessEvent( "Tomorrow_Sunset", Json.sunsetTimeLocal[ 1 ] )
}
// Tomorrow's Detailed Forecast
if( Json.narrative[ 1 ] != null ){
ProcessEvent( "Tomorrow_DetailedForecast", Json.narrative[ 1 ] )
}
// Tomorrow's Valid Time
if( Json.validTimeLocal[ 1 ] != null ){
ProcessEvent( "Tomorrow_ValidTime", Json.validTimeLocal[ 1 ] )
}
Logging( "Weather Underground forecast data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
// Section for the forecast child devices
if( ChildrenEnabled ){
ClearForecastChildren()
for( i = 0; i <= 5; i++ ){
def Day = Json.dayOfWeek[ i ]
if( Json.temperatureMin[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Min Temperature", Json.temperatureMin[ i ], "${ location.temperatureScale }" )
}
if( Json.temperatureMax[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Max Temperature", Json.temperatureMax[ i ], "${ location.temperatureScale }" )
}
if( Json.qpf[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Chance Precipitation", ( Json.qpf[ i ] * 100 ), "%" )
}
if( Json.qpfSnow[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Chance Snow", ( Json.qpfSnow[ i ] * 100 ), "%" )
}
if( Json.sunriseTimeLocal[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Sunrise", "${ Json.sunriseTimeLocal[ i ] }" )
}
if( Json.sunsetTimeLocal[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Sunset", "${ Json.sunsetTimeLocal[ i ] }" )
}
if( Json.moonPhase[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moon Phase", "${ Json.moonPhase[ i ] }" )
}
if( Json.moonriseTimeLocal[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moonrise", "${ Json.moonriseTimeLocal[ i ] }" )
}
if( Json.moonsetTimeLocal[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Moonset", "${ Json.moonsetTimeLocal[ i ] }" )
}
if( Json.validTimeLocal[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Forecast Valid as of", "${ Json.validTimeLocal[ i ] }" )
}
if( Json.narrative[ i ] != null ){
PostEventToChild( "${ device.name } ${ Day }", "Conditions", "${ Json.narrative[ i ] }" )
}
}
}
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid APIKey provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to Weather Underground: ${ resp.status }", 4 )
}
}
// Get the WWO forecast returned, output events and populate attributes as needed
def GetWWOForecast( resp, data ){
if( resp.getStatus() == 200 ){
Logging( "${ Region } = ${ resp.data }", 4 )
Json = parseJson( resp.data )
if( Json != null ){
// Updated
if( Json.data.current_condition[ 0 ].observation_time != null ){
ProcessEvent( "Updated", "${ Json.data.weather[ 0 ].date }T${ Json.data.current_condition[ 0 ].observation_time }" )
}
// wind direction
if( Json.data.current_condition[ 0 ].winddirDegree != null ){
ProcessEvent( "windDirection", Json.data.current_condition[ 0 ].winddirDegree, "°" )
}
if( Json.data.current_condition[ 0 ].winddir16Point != null ){
ProcessEvent( "WindDirectionString", Json.data.current_condition[ 0 ].winddir16Point )
}
// Conditions
if( Json.data.current_condition[ 0 ].weatherDesc != null ){
ProcessEvent( "Conditions", Json.data.current_condition[ 0 ].weatherDesc )
}
if( location.temperatureScale == "F" ){
// temperature
if( Json.data.current_condition[ 0 ].temp_F != null ){
ProcessEvent( "temperature", Json.data.current_condition[ 0 ].temp_F, "°F" )
}
// feelsLike
if( Json.data.current_condition[ 0 ].FeelsLikeF != null ){
ProcessEvent( "feelsLike", Json.data.current_condition[ 0 ].FeelsLikeF, "°F" )
}
// Rain
if( Json.data.current_condition[ 0 ].precipInches != null ){
ProcessEvent( "hourlyRain", Json.data.current_condition[ 0 ].precipInches, "in" )
}
// windSpeed
if( Json.data.current_condition[ 0 ].windspeedMiles != null ){
ProcessEvent( "windSpeed", Json.data.current_condition[ 0 ].windspeedMiles, "mph" )
}
// pressure
if( Json.data.current_condition[ 0 ].pressureInches != null ){
ProcessEvent( "pressure", Json.data.current_condition[ 0 ].pressureInches, "in" )
}
} else {
// temperature
if( Json.data.current_condition[ 0 ].temp_C != null ){
ProcessEvent( "temperature", Json.data.current_condition[ 0 ].temp_C, "°C" )
}
// feelsLike
if( Json.data.current_condition[ 0 ].FeelsLikeC != null ){
ProcessEvent( "feelsLike", Json.data.current_condition[ 0 ].FeelsLikeC, "°C" )
}
// Rain
if( Json.data.current_condition[ 0 ].precipMM != null ){
ProcessEvent( "hourlyRain", Json.data.current_condition[ 0 ].precipMM, "mm" )
}
// windSpeed
if( Json.data.current_condition[ 0 ].windspeedKmph != null ){
ProcessEvent( "windSpeed", Json.data.current_condition[ 0 ].windspeedKmph, "kmph" )
}
// pressure
if( Json.data.current_condition[ 0 ].pressure != null ){
ProcessEvent( "pressure", Json.data.current_condition[ 0 ].pressure, "mbar" )
}
}
// Today's temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].hourly[ 0 ].tempF != null ){
ProcessEvent( "Today_Temperature", Json.data.weather[ 0 ].hourly[ 0 ].tempF, "F" )
}
} else {
if( Json.data.weather[ 0 ].hourly[ 0 ].tempC != null ){
ProcessEvent( "Today_Temperature", Json.data.weather[ 0 ].hourly[ 0 ].tempC, "C" )
}
}
// Today's min temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].mintempF != null ){
ProcessEvent( "Today_MinTemp", Json.data.weather[ 0 ].mintempF, "F" )
}
} else {
if( Json.data.weather[ 0 ].mintempC != null ){
ProcessEvent( "Today_MinTemp", Json.data.weather[ 0 ].mintempC, "C" )
}
}
// Today's max temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].maxtempF!= null ){
ProcessEvent( "Today_MaxTemp", Json.data.weather[ 0 ].maxtempF, "F" )
}
} else {
if( Json.data.weather[ 0 ].maxtempC != null ){
ProcessEvent( "Today_MaxTemp", Json.data.weather[ 0 ].maxtempC, "C" )
}
}
// Today's wind speed
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].hourly[ 0 ].windspeedMiles != null ){
ProcessEvent( "Today_WindSpeed", Json.data.weather[ 0 ].hourly[ 0 ].windspeedMiles, "mph" )
}
} else {
if( Json.data.weather[ 0 ].hourly[ 0 ].windspeedKmph != null ){
ProcessEvent( "Today_WindSpeed", Json.data.weather[ 0 ].hourly[ 0 ].windspeedKmph, "kph" )
}
}
// Today's wind direction
if( Json.data.weather[ 0 ].hourly[ 0 ].winddirDegree != null ){
ProcessEvent( "Today_WindDirection", Json.data.weather[ 0 ].hourly[ 0 ].winddirDegree, "°" )
}
// Today's wind gust
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].hourly[ 0 ].WindGustMiles != null ){
ProcessEvent( "Today_WindGust", Json.data.weather[ 0 ].hourly[ 0 ].WindGustMiles, "mph" )
}
} else {
if( Json.data.weather[ 0 ].hourly[ 0 ].WindGustKmph != null ){
ProcessEvent( "Today_WindGust", Json.data.weather[ 0 ].hourly[ 0 ].WindGustKmph, "kph" )
}
}
// Today's short forecast
if( Json.data.weather[ 0 ].hourly[ 0 ].weatherDesc[ 0 ].value != null ){
ProcessEvent( "Today_ShortForecast", Json.data.weather[ 0 ].hourly[ 0 ].weatherDesc[ 0 ].value )
}
// Today's chance of rain
if( Json.data.weather[ 0 ].hourly[ 0 ].chanceofrain != null ){
ProcessEvent( "Today_ChanceRain", Json.data.weather[ 0 ].hourly[ 0 ].chanceofrain )
}
// Today's chance of clouds
if( Json.data.weather[ 0 ].hourly[ 0 ].chanceofovercast != null ){
ProcessEvent( "Today_ChanceClouds", Json.data.weather[ 0 ].hourly[ 0 ].chanceofovercast )
}
// Today's chance of snow
if( Json.data.weather[ 0 ].hourly[ 0 ].chanceofsnow != null ){
ProcessEvent( "Today_ChanceSnow", Json.data.weather[ 0 ].hourly[ 0 ].chanceofsnow )
}
// Today's wind string
if( Json.data.weather[ 0 ].hourly[ 0 ].winddir16Point != null ){
ProcessEvent( "Today_WindDirectionString", Json.data.weather[ 0 ].hourly[ 0 ].winddir16Point )
}
// Today's feels like
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 0 ].hourly[ 0 ].FeelsLikeF != null ){
ProcessEvent( "Today_FeelsLike", Json.data.weather[ 0 ].hourly[ 0 ].FeelsLikeF, "F" )
}
} else {
if( Json.data.weather[ 0 ].hourly[ 0 ].FeelsLikeC != null ){
ProcessEvent( "Today_FeelsLike", Json.data.weather[ 0 ].hourly[ 0 ].FeelsLikeC, "C" )
}
}
// Today's sunrise
if( Json.data.weather[ 0 ].astronomy[ 0 ].sunrise != null ){
ProcessEvent( "Today_Sunrise", "${ Json.data.weather[ 0 ].date }T${ Json.data.weather[ 0 ].astronomy[ 0 ].sunrise }" )
}
// Today's sunset
if( Json.data.weather[ 0 ].astronomy[ 0 ].sunset != null ){
ProcessEvent( "Tomorrownight_WindSpeed", "${ Json.data.weather[ 0 ].date }T${ Json.data.weather[ 0 ].astronomy[ 0 ].sunset }" )
}
// Today's weather icon
if( Json.data.weather[ 0 ].hourly[ 0 ].weatherIconUrl[ 0 ].value != null ){
ProcessEvent( "Today_IconURL", Json.data.weather[ 0 ].hourly[ 0 ].weatherIconUrl[ 0 ].value )
}
// Today's humidity
if( Json.data.weather[ 0 ].hourly[ 0 ].humidity != null ){
ProcessEvent( "Today_Humidity", Json.data.weather[ 0 ].hourly[ 0 ].humidity, "%" )
}
// Today's pressure
if( Json.data.weather[ 0 ].hourly[ 0 ].pressure != null ){
ProcessEvent( "Today_Pressure", Json.data.weather[ 0 ].hourly[ 0 ].pressure )
}
// Today's UVI
if( Json.data.weather[ 0 ].hourly[ 0 ].uvIndex != null ){
ProcessEvent( "Today_UVI", Json.data.weather[ 0 ].hourly[ 0 ].uvIndex )
}
// Tomorrow's temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].hourly[ 0 ].tempF != null ){
ProcessEvent( "Tomorrow_Temperature", Json.data.weather[ 1 ].hourly[ 0 ].tempF, "F" )
}
} else {
if( Json.data.weather[ 1 ].hourly[ 0 ].tempC != null ){
ProcessEvent( "Tomorrow_Temperature", Json.data.weather[ 1 ].hourly[ 0 ].tempC, "C" )
}
}
// Tomorrow's min temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].mintempF != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.data.weather[ 1 ].mintempF, "F" )
}
} else {
if( Json.data.weather[ 1 ].mintempC != null ){
ProcessEvent( "Tomorrow_MinTemp", Json.data.weather[ 1 ].mintempC, "C" )
}
}
// Tomorrow's max temperature
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].maxtempF!= null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.data.weather[ 1 ].maxtempF, "F" )
}
} else {
if( Json.data.weather[ 1 ].maxtempC != null ){
ProcessEvent( "Tomorrow_MaxTemp", Json.data.weather[ 1 ].maxtempC, "C" )
}
}
// Tomorrow's wind speed
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].hourly[ 0 ].windspeedMiles != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.data.weather[ 1 ].hourly[ 0 ].windspeedMiles, "mph" )
}
} else {
if( Json.data.weather[ 1 ].hourly[ 0 ].windspeedKmph != null ){
ProcessEvent( "Tomorrow_WindSpeed", Json.data.weather[ 1 ].hourly[ 0 ].windspeedKmph, "kph" )
}
}
// Tomorrow's wind direction
if( Json.data.weather[ 1 ].hourly[ 0 ].winddirDegree != null ){
ProcessEvent( "Tomorrow_WindDirection", Json.data.weather[ 1 ].hourly[ 0 ].winddirDegree, "°" )
}
// Tomorrow's wind gust
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].hourly[ 0 ].WindGustMiles != null ){
ProcessEvent( "Tomorrow_WindGust", Json.data.weather[ 1 ].hourly[ 0 ].WindGustMiles, "mph" )
}
} else {
if( Json.data.weather[ 1 ].hourly[ 0 ].WindGustKmph != null ){
ProcessEvent( "Tomorrow_WindGust", Json.data.weather[ 1 ].hourly[ 0 ].WindGustKmph, "kph" )
}
}
// Tomorrow's short forecast
if( Json.data.weather[ 1 ].hourly[ 0 ].weatherDesc[ 0 ].value != null ){
ProcessEvent( "Tomorrow_ShortForecast", Json.data.weather[ 1 ].hourly[ 0 ].weatherDesc[ 0 ].value )
}
// Tomorrow's chance of rain
if( Json.data.weather[ 1 ].hourly[ 0 ].chanceofrain != null ){
ProcessEvent( "Tomorrow_ChanceRain", Json.data.weather[ 1 ].hourly[ 0 ].chanceofrain )
}
// Tomorrow's chance of clouds
if( Json.data.weather[ 1 ].hourly[ 0 ].chanceofovercast != null ){
ProcessEvent( "Tomorrow_ChanceClouds", Json.data.weather[ 1 ].hourly[ 0 ].chanceofovercast )
}
// Tomorrow's chance of snow
if( Json.data.weather[ 1 ].hourly[ 0 ].chanceofsnow != null ){
ProcessEvent( "Tomorrow_ChanceSnow", Json.data.weather[ 1 ].hourly[ 0 ].chanceofsnow )
}
// Tomorrow's wind string
if( Json.data.weather[ 1 ].hourly[ 0 ].winddir16Point != null ){
ProcessEvent( "Tomorrow_WindDirectionString", Json.data.weather[ 1 ].hourly[ 0 ].winddir16Point )
}
// Tomorrow's feels like
if( location.temperatureScale == "F" ){
if( Json.data.weather[ 1 ].hourly[ 0 ].FeelsLikeF != null ){
ProcessEvent( "Tomorrow_FeelsLike", Json.data.weather[ 1 ].hourly[ 0 ].FeelsLikeF, "F" )
}
} else {
if( Json.data.weather[ 1 ].hourly[ 0 ].FeelsLikeC != null ){
ProcessEvent( "Tomorrow_FeelsLike", Json.data.weather[ 1 ].hourly[ 0 ].FeelsLikeC, "C" )
}
}
// Tomorrow's sunrise
if( Json.data.weather[ 1 ].astronomy[ 0 ].sunrise != null ){
ProcessEvent( "Tomorrow_Sunrise", "${ Json.data.weather[ 1 ].date }T${ Json.data.weather[ 1 ].astronomy[ 0 ].sunrise }" )
}
// Tomorrow's sunset
if( Json.data.weather[ 1 ].astronomy[ 0 ].sunset != null ){
ProcessEvent( "Tomorrownight_WindSpeed", "${ Json.data.weather[ 1 ].date }T${ Json.data.weather[ 1 ].astronomy[ 0 ].sunset }" )
}
// Tomorrow's weather icon
if( Json.data.weather[ 1 ].hourly[ 0 ].weatherIconUrl[ 0 ].value != null ){
ProcessEvent( "Tomorrow_IconURL", Json.data.weather[ 1 ].hourly[ 0 ].weatherIconUrl[ 0 ].value )
}
// Tomorrow's humidity
if( Json.data.weather[ 1 ].hourly[ 0 ].humidity != null ){
ProcessEvent( "Tomorrow_Humidity", Json.data.weather[ 1 ].hourly[ 0 ].humidity, "%" )
}
// Today's pressure
if( Json.data.weather[ 1 ].hourly[ 0 ].pressure != null ){
ProcessEvent( "Tomorrow_Pressure", Json.data.weather[ 1 ].hourly[ 0 ].pressure )
}
// Tomorrow's UVI
if( Json.data.weather[ 1 ].hourly[ 0 ].uvIndex != null ){
ProcessEvent( "Tomorrow_UVI", Json.data.weather[ 1 ].hourly[ 0 ].uvIndex )
}
Logging( "World Weather Online forecast data as of ${ new Date() }.", 2 )
ProcessEvent( "Data as of", "${ new Date() }" )
} else {
Logging( "No data returned by API", 4 )
}
} else if( resp.getStatus() == 401 ){
Logging( "Invalid APIKey provided", 4 )
} else if( resp.getStatus() == 429 ){
Logging( "Maximum API calls per day", 4 )
} else {
Logging( "Error connecting to World Weather Online: ${ resp.status }", 4 )
}
}
// Process data to check against current state value and then send an event if it has changed
def ProcessEvent( Name, Value, Unit = null ){
if( state."${ Name }" != Value ){
state."${ Name }" = Value
if( Unit != null ){
Logging( "Event ${ Name } = ${ Value }${ Unit }", 4 )
sendEvent( name: "${ Name }", value: Value, unit: Unit, isStateChange: true )
} else {
Logging( "Event ${ Name } = ${ Value }", 4 )
sendEvent( name: "${ Name }", value: Value, isStateChange: true )
}
}
}
// Check data to against current state value and change the state if needed
def ProcessState( Name, Value ){
if( state."${ Name }" != Value ){
state."${ Name }" = Value
Logging( "state.${ Name } = ${ Value }", 4 )
}
}
// Significant weather code check for UK Met Office codes
def UKSignificantWeather( Code ){
def WeatherString
switch( Code ){
case "NA":
WeatherString = "Not available"
break
case "0":
WeatherString = "Clear night"
break
case "1":
WeatherString = "Sunny day"
break
case "2":
WeatherString = "Partly cloudy (night)"
break
case "3":
WeatherString = "Partly cloudy (day)"
break
case "4":
WeatherString = "Not used"
break
case "5":
WeatherString = "Mist"
break
case "6":
WeatherString = "Fog"
break
case "7":
WeatherString = "Cloudy"
break
case "8":
WeatherString = "Overcast"
break
case "9":
WeatherString = "Light rain shower (night)"
break
case "10":
WeatherString = "Light rain shower (day)"
break
case "11":
WeatherString = "Drizzle"
break
case "12":
WeatherString = "Light rain"
break
case "13":
WeatherString = "Heavy rain shower (night)"
break
case "14":
WeatherString = "Heavy rain shower (day)"
break
case "15":
WeatherString = "Heavy rain"
break
case "16":
WeatherString = "Sleet shower (night)"
break
case "17":
WeatherString = "Sleet shower (day)"
break
case "18":
WeatherString = "Sleet"
break
case "19":
WeatherString = "Hail shower (night)"
break
case "20":
WeatherString = "Hail shower (day)"
break
case "21":
WeatherString = "Hail"
break
case "22":
WeatherString = "Light snow shower (night)"
break
case "23":
WeatherString = "Light snow shower (day)"
break
case "24":
WeatherString = "Light snow"
break
case "25":
WeatherString = "Heavy snow shower (night)"
break
case "26":
WeatherString = "Heavy snow shower (day)"
break
case "27":
WeatherString = "Heavy snow"
break
case "28":
WeatherString = "Thunder shower (night)"
break
case "29":
WeatherString = "Thunder shower (day)"
break
case "30":
WeatherString = "Thunder"
break
default:
WeatherString = "Not available"
break
}
return WeatherString
}
// Provide a number based on US Wind Direction string
def USWindDirection( WindDirection ){
def WindDegrees
switch( WindDirection ){
case "N":
WindDegrees = 0
break
case "NE":
WindDegrees = 45
break
case "E":
WindDegrees = 90
break
case "SE":
WindDegrees = 135
break
case "S":
WindDegrees = 180
break
case "SW":
WindDegrees = 225
break
case "W":
WindDegrees = 270
break
case "NW":
WindDegrees = 315
break
}
return WindDegrees
}
// Process the US detailed forecast for Chance of Precipitation and Type
def ProcessUSDetailedForecast( Which, DetailedForecast ){
def Split = DetailedForecast.split( "Chance of precipitation is " )
if( Split.size() > 1 ){
Split = Split[ 1 ].split( "%" )
def Percent = Split[ 0 ]
//Logging( "Detailed = ${ DetailedForecast }", 3 )
if( DetailedForecast.contains( "Rain" ) || DetailedForecast.contains( "rain" ) ){
switch( Which ){
case 1:
ProcessEvent( "Today_ChanceRain", Percent, "%" )
break
case 2:
ProcessEvent( "Tonight_ChanceRain", Percent, "%" )
break
case 3:
ProcessEvent( "Tomorrow_ChanceRain", Percent, "%" )
break
case 4:
ProcessEvent( "Tomorrownight_ChanceRain", Percent, "%" )
break
}
} else if( DetailedForecast.contains( "Snow" ) || DetailedForecast.contains( "snow" ) ){
switch( Which ){
case 1:
ProcessEvent( "Today_ChanceSnow", Percent, "%" )
break
case 2:
ProcessEvent( "Tonight_ChanceSnow", Percent, "%" )
break
case 3:
ProcessEvent( "Tomorrow_ChanceSnow", Percent, "%" )
break
case 4:
ProcessEvent( "Tomorrownight_ChanceSnow", Percent, "%" )
break
}
}
} else {
switch( Which ){
case 1:
ProcessEvent( "Today_ChanceRain", 0, "%" )
ProcessEvent( "Today_ChanceSnow", 0, "%" )
break
case 2:
ProcessEvent( "Tonight_ChanceRain", 0, "%" )
ProcessEvent( "Tonight_ChanceSnow", 0, "%" )
break
case 3:
ProcessEvent( "Tomorrow_ChanceRain", 0, "%" )
ProcessEvent( "Tomorrow_ChanceSnow", 0, "%" )
break
case 4:
ProcessEvent( "Tomorrownight_ChanceRain", 0, "%" )
ProcessEvent( "Tomorrownight_ChanceSnow", 0, "%" )
break
}
}
Split = DetailedForecast.split( "gusts as high as " )
if( Split.size() > 1 ){
Split = Split[ 1 ].split( " mph" )
def WindGust = Split[ 0 ]
switch( Which ){
case 1:
ProcessEvent( "Today_WindGust", WindGust, "mph" )
break
case 2:
ProcessEvent( "Tonight_WindGust", WindGust, "mph" )
break
case 3:
ProcessEvent( "Tomorrow_WindGust", WindGust, "mph" )
break
case 4:
ProcessEvent( "Tomorrownight_WindGust", WindGust, "mph" )
break
}
}
}
// Checks the location.getTemperatureScale() to convert temperature values
def ConvertTemperature( Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( location.getTemperatureScale() == "C" ){
ReturnValue = ( ( ( Value - 32 ) * 5 ) / 9 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Checks the location.getTemperatureScale() to convert in to mm
def ConvertInches( Number Value ){
if( Value != null ){
def TempInt
def ReturnValue = Value as double
if( location.getTemperatureScale() == "C" ){
ReturnValue = ( Value * 25.4 )
TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
}
TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Checks the location.getTemperatureScale() to convert mph to kph
def ConvertMPH( Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( location.getTemperatureScale() == "C" ){
ReturnValue = ( Value * 1.609 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Used to convert epoch values to text dates
def ConvertEpochToDate( Number Epoch ){
def date = use( groovy.time.TimeCategory ) {
new Date( 0 ) + Epoch.seconds
}
return date
}
String ReturnDayName( Number Day ){
def map=[
1:"Sunday",
2:"Monday",
3:"Tuesday",
4:"Wednesday",
5:"Thursday",
6:"Friday",
7:"Saturday" ]
return map[ Day ]
}
// Clears forecast data from child devices
def ClearForecastChildren(){
for( i = 0; i <= 6; i++ ){
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Min Temperature", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Max Temperature", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Chance Precipitation", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Chance Snow", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Sunrise", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Sunset", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Moon Phase", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Moonrise", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Moonset", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Forecast Valid as of", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Conditions", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "temperature", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "windSpeed", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "windDirection", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "WindDirectionString", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "windGust", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "humidity", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "pressure", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "uv", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "feelsLike", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "dewPoint", null )
PostEventToChild( "${ device.name } ${ ReturnDayName( i + 1 ) }", "Cloud Cover", null )
}
}
// Post data to child device
def PostEventToChild( Child, Variable, Value, Unit = null, ForceEvent = false ){
if( ChildrenEnabled ){
if( Child != null ){
if( getChildDevice( "${ Child }" ) == null ){
addSensor( "${ Child }" )
}
if( getChildDevice( "${ Child }" ) != null ){
if( Unit != null ){
if( ForceEvent ){
getChildDevice( "${ Child }" ).ProcessEvent( "${ Variable }", Value, "${ Unit }", ForceEvent )
Logging( "Child Event: ${ Variable } = ${ Value }${ Unit }", 4 )
} else {
getChildDevice( "${ Child }" ).ProcessEvent( "${ Variable }", Value, "${ Unit }" )
Logging( "Child Event: ${ Variable } = ${ Value }", 4 )
}
} else {
if( ForceEvent ){
getChildDevice( "${ Child }" ).ProcessEvent( "${ Variable }", Value, null, ForceEvent )
Logging( "Child Event: ${ Variable } = ${ Value }${ Unit }", 4 )
} else {
getChildDevice( "${ Child }" ).ProcessEvent( "${ Variable }", Value )
Logging( "Child Event: ${ Variable } = ${ Value }", 4 )
}
}
} else {
if( Unit != null ){
Logging( "Failure to add ${ Child } and post ${ Variable }=${ Value }${ Unit }", 5 )
} else {
Logging( "Failure to add ${ Child } and post ${ Variable }=${ Value }", 5 )
}
}
} else {
Logging( "Failure to add child because child name was null", 5 )
}
}
}
// Post data to child device
def PostStateToChild( Child, Variable, Value ){
def ChildParent = "${ Child }"
if( ChildrenEnabled ){
if( ChildParent != null ){
if( getChildDevice( "${ ChildParent }" ) == null ){
addChild( "${ ChildParent }" )
}
if( getChildDevice( "${ ChildParent }" ) != null ){
Logging( "${ ChildParent } State: ${ Variable } = ${ Value }", 4 )
getChildDevice( "${ ChildParent }" ).ProcessState( "${ Variable }", Value )
} else {
Logging( "${ ChildParent } does not exist so could not post ${ Variable }=${ Value }", 5 )
}
} else {
Logging( "Failure to add child because child name was null", 5 )
}
}
}
// Adds a WeatherSensorChild child device
// Based on @mircolino's method for child sensors
def addChild( String DNI ){
try{
Logging( "addChild(${ DNI })", 3 )
addChildDevice( "WeatherSensorChild", DNI, [ name: "${ DNI }" ] )
}
catch( Exception e ){
def Temp = e as String
if( Temp.contains( "not found" ) ){
Logging( "WeatherSensorChild driver is not loaded, this is required for child devices.\n Disabling children for rest of refresh.", 5 )
ChildrenEnabled = false
} else {
Logging( "Exception in addChild: ${ Temp }", 5 )
}
}
}
// uninstalling device so make sure to clean up children
void uninstalled() {
// Delete all children
getChildDevices().each{
deleteChildDevice( it.deviceNetworkId )
}
Logging( "Uninstalled", 2 )
}
// Handles whether logging is enabled and thus what to put there.
def Logging( LogMessage, LogLevel ){
// Add all messages as info logging
if( ( LogLevel == 2 ) && ( LogType != "None" ) ){
log.info( "${ device.displayName } - ${ LogMessage }" )
} else if( ( LogLevel == 3 ) && ( ( LogType == "Debug" ) || ( LogType == "Trace" ) ) ){
log.debug( "${ device.displayName } - ${ LogMessage }" )
} else if( ( LogLevel == 4 ) && ( LogType == "Trace" ) ){
log.trace( "${ device.displayName } - ${ LogMessage }" )
} else if( LogLevel == 5 ){
log.error( "${ device.displayName } - ${ LogMessage }" )
}
}
// Checks drdsnell.com for the latest version of the driver
// Original inspiration from @cobra's version checking
def CheckForUpdate(){
ProcessEvent( "DriverName", DriverName() )
ProcessEvent( "DriverVersion", DriverVersion() )
httpGet( uri: "https://www.drdsnell.com/projects/hubitat/drivers/versions.json", contentType: "application/json" ){ resp ->
switch( resp.status ){
case 200:
if( resp.data."${ DriverName() }" ){
CurrentVersion = DriverVersion().split( /\./ )
if( resp.data."${ DriverName() }".version == "REPLACED" ){
ProcessEvent( "DriverStatus", "Driver replaced, please use ${ resp.data."${ state.DriverName }".file }" )
} else if( resp.data."${ DriverName() }".version == "REMOVED" ){
ProcessEvent( "DriverStatus", "Driver removed and no longer supported." )
} else {
SiteVersion = resp.data."${ DriverName() }".version.split( /\./ )
if( CurrentVersion == SiteVersion ){
Logging( "Driver version up to date", 3 )
ProcessEvent( "DriverStatus", "Up to date" )
} else if( ( CurrentVersion[ 0 ] as int ) > ( SiteVersion [ 0 ] as int ) ){
Logging( "Major development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 )
ProcessEvent( "DriverStatus", "Major development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" )
} else if( ( CurrentVersion[ 1 ] as int ) > ( SiteVersion [ 1 ] as int ) ){
Logging( "Minor development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 )
ProcessEvent( "DriverStatus", "Minor development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" )
} else if( ( CurrentVersion[ 2 ] as int ) > ( SiteVersion [ 2 ] as int ) ){
Logging( "Patch development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 )
ProcessEvent( "DriverStatus", "Patch development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" )
} else if( ( SiteVersion[ 0 ] as int ) > ( CurrentVersion[ 0 ] as int ) ){
Logging( "New major release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 )
ProcessEvent( "DriverStatus", "New major release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" )
} else if( ( SiteVersion[ 1 ] as int ) > ( CurrentVersion[ 1 ] as int ) ){
Logging( "New minor release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 )
ProcessEvent( "DriverStatus", "New minor release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" )
} else if( ( SiteVersion[ 2 ] as int ) > ( CurrentVersion[ 2 ] as int ) ){
Logging( "New patch ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 )
ProcessEvent( "DriverStatus", "New patch ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" )
}
}
} else {
Logging( "${ DriverName() } is not published on drdsnell.com", 2 )
ProcessEvent( "DriverStatus", "${ DriverName() } is not published on drdsnell.com" )
}
break
default:
Logging( "Unable to check drdsnell.com for ${ DriverName() } driver updates.", 2 )
break
}
}
}