/*
* WeatherFlow
*
* Description:
* This Hubitat driver polls the WeatherFlow API for your station's data.
*
* The driver CAN support child devices if the WeatherSensorChild.groovy driver is also installed. This will generate a number of
* children based on the sensors reporting. Children will be automatically created when applicable data is posted. All children are
* deleted if the feature is disabled (it is disabled by default). Child sensors can be useful for Rules or the Dashboard in order to
* focus on particular values, like a specific temperature sensor, or combining temperature and humidity readings.
*
* Required Information:
* 1) Token to allow data to be polled (from account Settings - Data Authorizations)
* 2) Your Station ID (if you do not know, enter a number and run the GetStationList command, then check the Station List state variable)
*
* Features List:
* Child devices generated based on sensors reporting
* Ability to read and report all known values returned from the WeatherFlow API for a particular station
* 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.4.11 - Added preference for Pressure Units and changed conversions and events to handle the unit selected
* 0.4.10 - Correction to ProcessEvent function
* 0.4.9 - Handling for null station data and update to driver specific attribute names
* 0.4.8 - Removing hubs from device-specific data call as WeatherFlow API no longer returns data for them
* 0.4.7 - Added a command to "ClearStateVariables" so events and variables will sync
* 0.4.6 - Added rain + hail for PrecipitationTypeString
* 0.4.5 - Swapped out many areas where a state variable was being referenced to instead use the data for that state
* 0.4.4 - Fix for items being processed as states that should have been events (caused other issues as well)
* 0.4.3 - Additional data points added and updated driver version checking
* 0.4.2 - Converting lightning strike distance from km if needed
* 0.4.1 - Added 1 minute refresh back in, added extra checks around device labeling
* 0.4.0 - Added support for Forecast data, changed refresh interval (removed 1 minute added 1 hour),
* now using Token instead of API Key, added GetStationList command, reworked child naming
* 0.3.5 - Replaced boolean attributes with string attributes because boolean attributes are not valid
* 0.3.4 - Handle devices reported without Serial #
* 0.3.3 - Rework of logging and expanding value range when converting inches
* 0.3.2 - Some rework of data processing and adding missed attributes
* 0.3.1 - Rework of version control and state/event processing
* 0.02 - Rework child naming convention
* 0.01 - Initial version based on my AmbientEcowittWeather driver
*
* Thank you(s):
* Thank you to @Cobra for inspiration of how I perform driver version checking.
* Thank you to @mircolino for working out a parent/child method and pointing out other areas for significant improvement.
*/
// Returns the driver name
def DriverName(){
return "WeatherFlow"
}
// Returns the driver version
def DriverVersion(){
return "0.4.11"
}
// Driver Metadata
metadata{
definition( name: "WeatherFlow", namespace: "Snell", author: "David Snell", importUrl: "https://www.drdsnell.com/projects/hubitat/drivers/WeatherFlow.groovy" ) {
// Indicate what capabilities the device should be capable of
capability "Sensor"
capability "Refresh"
capability "Battery"
capability "PressureMeasurement"
capability "RelativeHumidityMeasurement"
capability "CarbonDioxideMeasurement"
capability "TemperatureMeasurement"
capability "UltravioletIndex"
capability "IlluminanceMeasurement"
capability "pHMeasurement"
// Commands from the driver
command "PollForecast"
command "GetStationList"
command "ClearStateVariables"
// 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 status information/notices for driver
// Special attributes
attribute "Station List", "list" //
// Station attributes
attribute "StationName", "string"
attribute "PublicName", "string"
attribute "Elevation", "number"
attribute "Latitude", "number"
attribute "Longitude", "number"
attribute "TimeZone", "string"
attribute "Public", "string"
attribute "LocalMode", "string"
attribute "Units_Temp", "string"
attribute "Units_Wind", "string"
attribute "Units Precip", "string"
attribute "Units Pressure", "string"
attribute "Units Distance", "string"
attribute "Units Direction", "string"
attribute "Units Other", "string"
attribute "Status Code", "number"
attribute "Status Message", "string"
attribute "Shared With WeatherFlow", "string"
attribute "Shared With WeatherUnderground", "string"
attribute "LastModifiedEpoch", "number"
attribute "LastModifiedString", "string"
attribute "Messages", "string"
attribute "SensorIDs", "number"
// Attributes for observational data
attribute "TimestampEpoch", "number"
attribute "TimestampString", "string"
attribute "AirTemperature", "number"
attribute "AirTemperatureIndoor", "number"
attribute "temperature", "number"
attribute "temperatureIndoor", "number"
attribute "BarometricPressure", "number"
attribute "BarometricPressureIndoor", "number"
attribute "StationPressure", "number"
attribute "StationPressureIndoor", "number"
attribute "pressure", "number"
attribute "pressureIndoor", "number"
attribute "SeaLevelPressure", "number"
attribute "SeaLevelPressureIndoor", "number"
attribute "RelativeHumidity", "number"
attribute "RelativeHumidityIndoor", "number"
attribute "humidity", "number"
attribute "humidityIndoor", "number"
attribute "Precip", "number"
attribute "PrecipAccumLast1hr", "number"
attribute "PrecipAccumLocalDay", "number"
attribute "PrecipAccumLocalDayFinal", "number"
attribute "PrecipAccumLocalYesterday", "number"
attribute "PrecipAccumLocalYesterdayFinal", "number"
attribute "PrecipMinutesLocalDay", "number"
attribute "PrecipMinutesLocalYesterday", "number"
attribute "PrecipMinutesLocalYesterdayFinal", "number"
attribute "windAvg", "number"
attribute "windSpeed", "number"
attribute "windGust", "number"
attribute "windLull", "number"
attribute "windDirection", "number"
attribute "WindDirectionString", "string"
attribute "SolarRadiation", "number"
attribute "ultravioletIndex", "number"
attribute "ultravioletIndexIndoor", "number"
attribute "illuminance", "number"
attribute "illuminanceIndoor", "number"
attribute "LightningStrikeLastEpoch", "number"
attribute "LightningStrikeLastDate", "string"
attribute "LightningStrikeLastDistance", "number"
attribute "LightningStrikeCount", "number"
attribute "LightningStrikeCountLast1hr", "number"
attribute "LightningStrikeCountLast3hr", "number"
attribute "feelsLike", "number"
attribute "feelsLikein", "number"
attribute "HeatIndex", "number"
attribute "HeatIndexIndoor", "number"
attribute "WindChill", "number"
attribute "WindChillIndoor", "number"
attribute "dewPoint", "number"
attribute "dewPointIndoor", "number"
attribute "WetBulbTemperature", "number"
attribute "WetBulbTemperatureIndoor", "number"
attribute "WetBulbGlobeTemperature", "number"
attribute "DeltaT", "number"
attribute "AirDensity", "number"
attribute "PrecipAnalysisTypeYesterday", "number"
attribute "PrecipAccumLocalYesterday", "number"
attribute "PrecipTotal1h", "number"
attribute "PressureTrend", "string"
attribute "PrecipitationType", "number"
attribute "PrecipitationTypeString", "string"
attribute "PrecipitationAnalysisType", "number"
attribute "PrecipitationAnalysisTypeString", "string"
attribute "RainAccumulation", "number"
attribute "RainAccumulationFinal", "number"
attribute "LocalDayRainAccumulation", "number"
attribute "LocalDayRainAccumulationFinal", "number"
// Forecast Attributes
attribute "Today Conditions", "string"
attribute "Today Icon", "string"
attribute "Today Sunrise", "string"
attribute "Today Sunset", "string"
attribute "Today High Temperature", "number"
attribute "Today Low Temperature", "number"
attribute "Today Chance Precipitation", "number"
attribute "Today Precipitation Icon", "string"
attribute "Today Precipitation Type", "string"
attribute "Tomorrow Conditions", "string"
attribute "Tomorrow Icon", "string"
attribute "Tomorrow Sunrise", "string"
attribute "Tomorrow Sunset", "string"
attribute "Tomorrow High Temperature", "number"
attribute "Tomorrow Low Temperature", "number"
attribute "Tomorrow Chance Precipitation", "number"
attribute "Tomorrow Precipitation Icon", "string"
attribute "Tomorrow Precipitation Type", "string"
}
preferences{
section{
if( ShowAllPreferences ){
input( type: "string", name: "Token", title: "Token for WeatherFlow", required: true )
input( type: "string", name: "StationID", title: "Station ID to be checked", required: true )
input( type: "enum", name: "RefreshRate", title: "Data Refresh Rate", required: false, multiple: false, options: [ "1 minute", "5 minutes", "15 minutes", "30 minutes", "Hourly", "Manual" ], defaultValue: "5 minutes" )
input( type: "enum", name: "MeasurementStandard", title: "Measurement Standard?", description: "Metric (as in kilometers) or Imperial (as in miles)", required: false, multiple: false, options: [ "Metric", "Imperial" ], defaultValue: "Metric" )
input( type: "enum", name: "PressureUnits", title:"Pressure Units?", description: "Select unit of pressure, mbar, psi, or inHG", required: false, options: [ "mbar", "psi", "inHG" ] )
input( type: "enum", name: "WindDirMethod", title: "Wind Direction Method?", description: "How do you want wind direction indicated?", required: false, multiple: false, options: [ [ "1" : "Degrees Only" ], [ "2" : "4 Compass Values (Letter Only)" ], [ "3" : "8 Compass Values (Letters Only)" ], [ "4" : "16 Compass Values (Letters Only)" ], [ "5" : "4 Compass Values (Words)" ], [ "6" : "8 Compass Values (Words)" ], [ "7" : "16 Compass Values (Words)" ] ], defaultValue: "1" )
input( type: "bool", name: "ChildrenEnabled", title: "Enable Child Devices?", defaultValue: false, description: "Once enabled, child devices will be made for added sensors.", required: false )
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()
// Schedule automatic checks of things
def Hour = ( new Date().format( "h" ) as int )
def Minute = ( new Date().format( "m" ) as int )
def Second = ( new Date().format( "s" ) as int )
switch( RefreshRate ){
case "1 minute":
schedule( "${ Second } * * ? * *", "refresh" )
break
case "5 minutes":
schedule( "${ Second } 0/5 * ? * *", "refresh" )
break
case "15 minutes":
schedule( "${ Second } 0/15 * ? * *", "refresh" )
break
case "30 minutes":
schedule( "${ Second } 0/30 * ? * *", "refresh" )
break
case "Hourly":
schedule( "${ Second } ${ Minute } * ? * *", "refresh" )
break
case "Manual":
break
}
Logging( "Refresh rate: ${ RefreshRate }", 4 )
// Set the driver name and version before update checking is scheduled
if( state."Driver Status" != null ){
state.remove( "Driver Name" )
state.remove( "Driver Version" )
state.remove( "Driver Status" )
device.deleteCurrentState( "Driver Status" )
device.deleteCurrentState( "Driver Name" )
device.deleteCurrentState( "Driver Version" )
}
ProcessEvent( "DriverName", DriverName() )
ProcessEvent( "DriverVersion", DriverVersion() )
// Schedule the things to check daily
schedule( "${ Second } ${ Minute } ${ Hour } ? * *", "CheckForUpdate" )
schedule( "${ Second } ${ Minute } 0 ? * *", "PollForecast" )
if( MeasurementStandard == null ){
MeasurementStandard = "Metric"
}
if( WindDirMethod == null ){
WindDirMethod = "1"
}
if( LogType == null ){
LogType = "2"
}
if( !ChildrenEnabled ){
getChildDevices().each{
Logging( "Children disabled, deleting ${ it.deviceNetworkId }", 3 )
deleteChildDevice( it.deviceNetworkId )
}
}
Logging( "Saved preferences", 2 )
}
// Clears all the current state variables
def ClearStateVariables(){
state.clear()
}
// refresh performs a poll of data
def refresh(){
PollWeatherFlow()
}
// 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()
}
// uninstalling device so make sure to clean up children
void uninstalled() {
// Delete all children
getChildDevices().each{
deleteChildDevice( it.deviceNetworkId )
}
Logging( "Uninstalled", 2 )
}
// parse is one of those "special" methods for when data is returned.
// Nothing should trigger it in this driver so a logging if something DOES show up.
def parse( String description ){
Logging( "Something arrived for parse: ${ description }", 3 )
}
//Poll WeatherFlow for station data
def PollWeatherFlow(){
if( Token != null ){
def Params
Params = [ uri: "https://swd.weatherflow.com/swd/rest/stations/${ StationID }?token=${ Token }", contentType: "application/json" ]
asynchttpGet( "GetStationData", Params )
} else {
Logging( "Token is required for WeatherFlow API.", 5 )
}
}
//Poll WeatherFlow for list of stations
def GetStationList(){
if( Token != null ){
def Params
Params = [ uri: "https://swd.weatherflow.com/swd/rest/stations?token=${ Token }", contentType: "application/json" ]
asynchttpGet( "HandleStationList", Params )
} else {
Logging( "Token is required for WeatherFlow API.", 5 )
}
}
// Handles the response from WeatherFlow and triggers more checks for specific device and observation data
def HandleStationList( resp, data ){
switch( resp.getStatus() ){
case 200:
Data = parseJson( resp.data )
Logging( "GetStationList response: ${ Data }", 4 )
def TempStations = []
Data.stations.each(){
TempStations.add( it.station_id as int )
}
ProcessState( "Station List", TempStations )
break
case 401:
Logging( "Unauthorized, most likely due to invalid token.", 5 )
break
case 404:
Logging( "Station not found.", 5 )
break
default:
Logging( "Error connecting to WeatherFlow: ${ resp.status }", 5 )
break
}
}
// Handles the response from WeatherFlow and triggers more checks for specific device and observation data
def GetStationData( resp, data ){
switch( resp.getStatus() ){
case 200:
Logging( "Raw response: ${ resp.data }", 4 )
if( resp.data != null ){
Data = parseJson( resp.data )
ParseStation( Data )
def Params
if( Data.stations != null ){
if( Data.stations[ 0 ].devices != null ){
for( int i = 0; i < Data.stations[ 0 ].devices.size(); i++ ){
if( Data.stations[ 0 ].devices[ i ].device_type != "HB" ){
Logging( "Getting data for device: ${ Data.stations[ 0 ].devices[ i ].device_id }", 4 )
Params = [ uri: "https://swd.weatherflow.com/swd/rest/observations/device/${ Data.stations[ 0 ].devices[ i ].device_id }?token=${ Token }", contentType: "application/json" ]
Logging( "Params for device: ${ Data.stations[ 0 ].devices[ i ].device_id } = ${ Params }", 4 )
asynchttpGet( "GetDeviceData", Params, [ Method: "GetDeviceData", Device: "${ Data.stations[ 0 ].devices[ i ].device_id }" ] )
}
}
}
}
Params = [ uri: "https://swd.weatherflow.com/swd/rest/observations/station/${ StationID }?token=${ Token }", contentType: "application/json" ]
Logging( "Station Obs Params = ${ Params }", 4 )
asynchttpGet( "GetWeatherData", Params, [ Method: "GetWeatherData" ] )
} else {
Logging( "No data returned by WeatherFlow", 5 )
}
break
case 401:
Logging( "Unauthorized, most likely due to invalid token.", 5 )
break
case 404:
Logging( "Station not found.", 5 )
break
default:
Logging( "Error connecting to WeatherFlow: ${ resp.status }", 5 )
break
}
}
// Handles the response from WeatherFlow observational data
def GetWeatherData( resp, data ){
switch( resp.getStatus() ){
case 200:
Logging( "Obs data raw response: ${ resp.data }", 4 )
Data = parseJson( resp.data )
if( Data != null ){
ParseWeather( Data )
} else {
Logging( "No obs data returned by WeatherFlow", 5 )
}
break
case 401:
Logging( "Unauthorized, most likely due to invalid token when getting obs data.", 5 )
break
case 404:
Logging( "Station not found for obs data.", 5 )
break
default:
Logging( "Error connecting to WeatherFlow when getting obs data: ${ resp.status }", 5 )
break
}
}
// Handles the response from WeatherFlow for Device Data
def GetDeviceData( resp, data ){
if( resp != null ){
switch( resp.getStatus() ){
case 200:
Data = parseJson( resp.data )
Logging( "Device ${ data.Device } response: ${ Data }", 4 )
if( Data != null ){
ParseDevice( Data )
} else {
Logging( "No data returned by WeatherFlow for Device ${ data.Device }", 5 )
}
break
case 401:
Logging( "Unauthorized, most likely due to invalid token when getting Device ${ data.Device } data.", 5 )
break
case 404:
Logging( "Device ${ data.Device } not found.", 5 )
break
default:
Logging( "Error connecting to WeatherFlow for Device ${ data.Device } data: ${ resp.status }", 5 )
break
}
}
}
// Parse the station data returned, output events and populate attributes as needed
def ParseStation( Data ){
if( Data != null ){
if( Data.stations != null ){
if( Data.stations[ 0 ] != null ){
if( Data.stations[ 0 ].devices != null ){
def TempInfo = new int[ Data.stations[ 0 ].devices.size() ]
for( int i = 0; i < Data.stations[ 0 ].devices.size(); i++ ){
def DeviceID
if( Data.stations[ 0 ].devices[ i ].device_id != null ){ // device_id
DeviceID = Data.stations[ 0 ].devices[ i ].device_id
TempInfo[ i ] = DeviceID
PostStateToChild( "${ DeviceID }", "device_id", DeviceID )
}
if( Data.stations[ 0 ].devices[ i ].hardware_revision != null ){ // hardware_revision
PostStateToChild( "${ DeviceID }", "hardware_revision", Data.stations[ 0 ].devices[ i ].hardware_revision )
}
if( Data.stations[ 0 ].devices[ i ].firmware_revision != null ){ // firmware_revision
PostStateToChild( "${ DeviceID }", "firmware_revision", Data.stations[ 0 ].devices[ i ].firmware_revision )
}
if( Data.stations[ 0 ].devices[ i ].device_meta.environment != null ){ // Environment
PostStateToChild( "${ DeviceID }", "environment", Data.stations[ 0 ].devices[ i ].device_meta.environment )
}
if( Data.stations[ 0 ].devices[ i ].device_meta.agl != null ){ // agl
PostStateToChild( "${ DeviceID }", "agl", Data.stations[ 0 ].devices[ i ].device_meta.agl )
}
if( Data.stations[ 0 ].devices[ i ].device_meta.wifi_network_name != null ){ // wifi_network_name
PostStateToChild( "${ DeviceID }", "wifi_network_name", Data.stations[ 0 ].devices[ i ].device_meta.wifi_network_name )
}
if( Data.stations[ 0 ].devices[ i ].device_meta.name != null ){ // Device name
PostStateToChild( "${ DeviceID }", "name", Data.stations[ 0 ].devices[ i ].device_meta.name )
}
if( Data.stations[ 0 ].devices[ i ].serial_number != null ){ // serial_number
PostStateToChild( "${ DeviceID }", "serial_number", Data.stations[ 0 ].devices[ i ].serial_number )
}
if( Data.stations[ 0 ].devices[ i ].device_type != null ){ // device_type
PostStateToChild( "${ DeviceID }", "Device Type", Data.stations[ 0 ].devices[ i ].device_type )
if( ChildrenEnabled ){
if( getChildDevice( "${ DeviceID }" ) != null ){
if( getChildDevice( "${ DeviceID }" ).label == null ){
if( Data.stations[ 0 ].devices[ i ].device_type == "HB" ){
getChildDevice( "${ DeviceID }" ).label = "Hub"
} else if( Data.stations[ 0 ].devices[ i ].device_type == "ST" ){
getChildDevice( "${ DeviceID }" ).label = "Station"
} else if( Data.stations[ 0 ].devices[ i ].device_type == "AR" ){
getChildDevice( "${ DeviceID }" ).label = "Air"
} else if( Data.stations[ 0 ].devices[ i ].device_type == "SK" ){
getChildDevice( "${ DeviceID }" ).label = "Sky"
}
}
}
}
}
}
// Copy the TempInfo (array of device_ids) over to the state.SensorIDs
state.SensorIDs = TempInfo
if( Data.stations[ 0 ].timezone != null ){ // timezone
ProcessState( "Timezone", Data.stations[ 0 ].timezone )
}
if( Data.stations[ 0 ].station_meta.elevation != null ){ // elevation
ProcessState( "Elevation", Data.stations[ 0 ].station_meta.elevation )
}
if( Data.stations[ 0 ].station_meta.share_with_wf != null ){ // Shared with WeatherFlow
ProcessState( "Shared with WeatherFlow", Data.stations[ 0 ].station_meta.share_with_wf )
}
if( Data.stations[ 0 ].station_meta.share_with_wu != null ){ // Shared with WeatherUnderground
ProcessState( "Shared with WeatherUnderground", Data.stations[ 0 ].station_meta.share_with_wu )
}
if( Data.stations[ 0 ].latitude != null ){ // latitude
ProcessState( "Latitude", Data.stations[ 0 ].latitude )
}
if( Data.stations[ 0 ].station_items != null ){ // station_items
for( int i = 0; i < Data.stations[ 0 ].station_items.size(); i++ ){
if( ( Data.stations[ 0 ].station_items[ i ].item != "diagnostics" ) && ( Data.stations[ 0 ].station_items[ i ].item != "forecast" ) ){
ProcessState( "${ Data.stations[ 0 ].station_items[ i ].item }_Sensor", Data.stations[ 0 ].station_items[ i ].device_id )
}
if( Data.stations[ 0 ].station_items[ i ].device_id != null ){
PostStateToChild( "${ Data.stations[ 0 ].station_items[ i ].device_id }", "${ Data.stations[ 0 ].station_items[ i ].item }_Sensor", "true" )
PostStateToChild( "${ Data.stations[ 0 ].station_items[ i ].device_id }", "location_item_id", Data.stations[ 0 ].station_items[ i ].location_item_id )
}
}
}
if( Data.stations[ 0 ].is_local_mode != null ){ // is_local_mode
ProcessState( "LocalMode", "${ Data.stations[ 0 ].is_local_mode }" )
}
if( Data.stations[ 0 ].name != null ){ // name
ProcessState( "StationName", Data.stations[ 0 ].name )
}
if( Data.stations[ 0 ].messages != null ){ // station_items
ProcessState( "Messages", Data.stations[ 0 ].messages )
}
if( Data.stations[ 0 ].last_modified_epoch != null ){ // last_modified_epoch
ProcessState( "LastModifiedEpoch", Data.stations[ 0 ].last_modified_epoch )
ProcessState( "LastModifiedString", ConvertEpochToDate( Data.stations[ 0 ].last_modified_epoch ) )
}
if( Data.stations[ 0 ].public_name != null ){ // public_name
ProcessState( "PublicName", Data.stations[ 0 ].public_name )
}
if( Data.stations[ 0 ].longitude != null ){ // longitude
ProcessState( "Longitude", Data.stations[ 0 ].longitude )
}
}
}
}
}
}
// Parse the data returned, output events and populate attributes as needed
def ParseWeather( Data ){
Logging( "Weather data = ${ Data }", 4 ) // For development purposes, to see if new attributes show up
// Station information
if( Data.station_name != null ){ // Station name
ProcessState( "StationName", Data.station_name )
}
if( Data.elevation != null ){ // Station elevation
ProcessState( "Elevation", Data.elevation )
}
if( Data.latitude != null ){ // Station latitude
ProcessState( "Latitude", Data.latitude )
}
if( Data.longitude != null ){ // Station longitude
ProcessState( "Longitude", Data.longitude )
}
if( Data.timezone != null ){ // Station time zone
ProcessState( "TimeZone", Data.timezone )
}
if( Data.is_public != null ){ // Station is public
ProcessState( "Public", "${ Data.is_public }" )
}
if( Data.station_units != null ){
if( Data.station_units.units_temp != null ){ // Station units temp
ProcessState( "UnitsTemp", Data.station_units.units_temp )
}
if( Data.station_units.units_wind != null ){ // Station units wind
ProcessState( "UnitsWind", Data.station_units.units_wind )
}
if( Data.station_units.units_precip != null ){ // Station units precip
ProcessState( "UnitsPrecip", Data.station_units.units_precip )
}
if( Data.station_units.units_pressure != null ){ // Station units pressure
ProcessState( "UnitsPressure", Data.station_units.units_pressure )
}
if( Data.station_units.units_distance != null ){ // Station units distance
ProcessState( "UnitsDistance", Data.station_units.units_distance )
}
if( Data.station_units.units_direction != null ){ // Station units direction
ProcessState( "UnitsDirection", Data.station_units.units_direction )
}
if( Data.station_units.units_other != null ){ // Station units other
ProcessState( "UnitsOther", Data.station_units.units_other )
}
}
if( Data.status != null ){
if( Data.status.status_code != null ){ // Station status code
ProcessState( "StatusCode", Data.status.status_code )
}
if( Data.status.status_message != null ){ // Station status message
ProcessState( "StatusMessage", Data.status.status_message )
}
}
Data.obs[ 0 ].each{
switch( it.key ){
case "timestamp":
ProcessState( "TimestampEpoch", it.value )
ProcessEvent( "TimestampString", ConvertEpochToDate( it.value ) )
break
case "air_temperature":
ProcessEvent( "AirTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
ProcessEvent( "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "air_temperature_indoor":
ProcessEvent( "AirTemperatureIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "Indoor Station", "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "barometric_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "BarometricPressure", it.value, "mb" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "BarometricPressure", it.value, "mb" )
ProcessEvent( "pressure", it.value, "mb" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "pressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "BarometricPressure", ConvertPressure( "Metric", it.value ), "psi" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "BarometricPressure", ConvertPressure( "Metric", it.value ), "psi" )
ProcessEvent( "pressure", ConvertPressure( "Metric", it.value ), "psi" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "pressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "BarometricPressure", ConvertPressure( "Metric", it.value ), "inHG" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "BarometricPressure", ConvertPressure( "Metric", it.value ), "inHG" )
ProcessEvent( "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
PostEventToChild( "${ state.barometric_pressure_Sensor }", "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "barometric_pressure_indoor":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "BarometricPressureIndoor", it.value, "mb" )
PostEventToChild( "Indoor Station", "pressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "BarometricPressureIndoor", ConvertPressure( "Metric", it.value ), "psi" )
PostEventToChild( "Indoor Station", "pressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "BarometricPressureIndoor", ConvertPressure( "Metric", it.value ), "inHG" )
PostEventToChild( "Indoor Station", "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "station_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "StationPressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "sea_level_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "SeaLevelPressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "sea_level_pressure_indoor":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "relative_humidity": // Outdoor relative humidity
ProcessEvent( "RelativeHumidity", it.value, "%" )
ProcessEvent( "humidity", it.value, "%" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "humidity", it.value, "%" )
break
case "relative_humidity_indoor": // Indoor relative humidity
ProcessEvent( "RelativeHumidityIndoor", it.value, "%" )
//PostEventToChild( "Indoor Station", "humidity", state.RelativeHumidityIndoor, "%" )
break
case "precip": // precip
if( MeasurementStandard == "Metric" ){
ProcessEvent( "Precip", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "Precip", it.value, "mm" )
} else {
ProcessEvent( "Precip", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "Precip", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_last_1hr": // precip accum last 1hr
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipAccumLast1hr", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLast1hr", it.value, "mm" )
} else {
ProcessEvent( "PrecipAccumLast1hr", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLast1hr", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_day_final": //
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipAccumLocalDayFinal", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalDayFinal", it.value, "mm" )
} else {
ProcessEvent( "PrecipAccumLocalDayFinal", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalDayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_day": // precip accum local day
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipAccumLocalDay", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalDay", it.value, "mm" )
} else {
ProcessEvent( "PrecipAccumLocalDay", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_yesterday": // precip accum local yesterday
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipAccumLocalYesterday", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalYesterday", it.value, "mm" )
} else {
ProcessEvent( "PrecipAccumLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_yesterday_final": // precip accum local yesterday final
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipAccumLocalYesterdayFinal", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalYesterdayFinal", it.value, "mm" )
} else {
ProcessEvent( "PrecipAccumLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipAccumLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_day": // precip minutes local day
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipMinutesLocalDay", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalDay", it.value, "mm" )
} else {
ProcessEvent( "PrecipMinutesLocalDay", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_yesterday": // precip minutes local yesterday
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipMinutesLocalYesterday", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalYesterday", it.value, "mm" )
} else {
ProcessEvent( "PrecipMinutesLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_yesterday_final": // precip minutes local yesterday final
if( MeasurementStandard == "Metric" ){
ProcessEvent( "PrecipMinutesLocalYesterdayFinal", it.value, "mm" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalYesterdayFinal", it.value, "mm" )
} else {
ProcessEvent( "PrecipMinutesLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
PostEventToChild( "${ state.rain_Sensor }", "PrecipMinutesLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "wind_avg": // wind avg
if( MeasurementStandard == "Metric" ){
ProcessEvent( "WindAvg", it.value, "m/s" )
PostEventToChild( "${ state.wind_Sensor }", "WindAvg", it.value, "m/s" )
ProcessEvent( "windSpeed", it.value, "m/s" )
PostEventToChild( "${ state.wind_Sensor }", "windSpeed", it.value, "m/s" )
} else {
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", it.value ), "mph" )
PostEventToChild( "${ state.wind_Sensor }", "WindAvg", it.value, "mph" )
ProcessEvent( "windSpeed", it.value, "mph" )
PostEventToChild( "${ state.wind_Sensor }", "windSpeed", it.value, "mph" )
}
break
case "wind_gust": // wind gust
if( MeasurementStandard == "Metric" ){
ProcessEvent( "windGust", it.value, "m/s" )
PostEventToChild( "${ state.wind_Sensor }", "windGust", it.value, "m/s" )
} else {
ProcessEvent( "windGust", ConvertMetersSecond( "Metric", it.value ), "mph" )
PostEventToChild( "${ state.wind_Sensor }", "windGust", it.value, "mph" )
}
break
case "wind_lull": // wind lull
if( MeasurementStandard == "Metric" ){
ProcessEvent( "windLull", it.value, "m/s" )
PostEventToChild( "${ state.wind_Sensor }", "windLull", it.value, "m/s" )
} else {
ProcessEvent( "windLull", ConvertMetersSecond( "Metric", it.value ), "mph" )
PostEventToChild( "${ state.wind_Sensor }", "windLull", it.value, "mph" )
}
break
case "wind_direction": // wind direction
ProcessEvent( "windDirection", it.value, "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( it.value ) )
PostEventToChild( "${ state.wind_Sensor }", "windDirection", it.value, "°" )
PostEventToChild( "${ state.wind_Sensor }", "WindDirectionString", MakeWindDirectionString( it.value ) )
break
case "solar_radiation": // solar radiation
ProcessEvent( "SolarRadiation", it.value )
PostEventToChild( "${ state.light_Sensor }", "SolarRadiation", it.value )
break
case "uv": // Outdoor uv
ProcessEvent( "ultravioletIndex", it.value, "uvi" )
PostEventToChild( "${ state.light_Sensor }", "ultravioletIndex", it.value, "uvi" )
break
case "uv_indoor": // Indoor uv
ProcessEvent( "ultravioletIndexIndoor", it.value, "uvi" )
//PostEventToChild( "Indoor Station", "ultravioletIndex", state.ultravioletIndexIndoor, "uvi" )
break
case "brightness": // Outdoor brightness
ProcessEvent( "illuminance", it.value, "lux" )
PostEventToChild( "${ state.light_Sensor }", "illuminance", it.value, "lux" )
break
case "brightness_indoor": // Indoor brightness
ProcessEvent( "illuminanceIndoor", it.value, "lux" )
//PostEventToChild( "Indoor Station", "illuminance", state.illuminanceIndoor, "lux" )
break
case "lightning_strike_last_epoch": // lightning strike last epoch
ProcessState( "LightningStrikeLastEpoch", it.value )
ProcessEvent( "LightningStrikeLastDate", ConvertEpochToDate( it.value ) )
PostStateToChild( "${ state.lightning_Sensor }", "LightningStrikeLastEpoch", it.value )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeLastDate", ConvertEpochToDate( it.value ) )
break
case "lightning_strike_last_distance": // lightning strike last distance
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LightningStrikeLastDistance", it.value, "km" )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeLastDistance", it.value, "km" )
} else {
ProcessEvent( "LightningStrikeLastDistance", ConvertMiles( "Metric", it.value ), "miles" )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeLastDistance", ConvertMiles( "Metric", it.value ), "miles" )
}
break
case "lightning_strike_count": // lightning strike count
ProcessEvent( "LightningStrikeCount", it.value )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeCount", it.value )
break
case "lightning_strike_count_last_1hr": // lightning strike count last 1hr
ProcessEvent( "LightningStrikeCountLast1hr", it.value )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeCountLast1hr", it.value )
break
case "lightning_strike_count_last_3hr": // lightning strike count last 3hr
ProcessEvent( "LightningStrikeCountLast3hr", it.value )
PostEventToChild( "${ state.lightning_Sensor }", "LightningStrikeCountLast3hr", it.value )
break
case "feels_like": // Outdoor feels like
ProcessEvent( "feelsLike", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "feelsLike", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "feels_like_indoor": // Indoor feels like
ProcessEvent( "feelsLikein", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostEventToChild( "Indoor Station", "feelsLikein", state.feelsLikein, "°${ location.getTemperatureScale() }" )
break
case "heat_index": // Outdoor heat index
ProcessEvent( "HeatIndex", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "HeatIndex", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "heat_index_indoor": // Indoor heat index
ProcessEvent( "HeatIndexIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostEventToChild( "Indoor Station", "HeatIndex", state.HeatIndexIndoor, "°${ location.getTemperatureScale() }" )
break
case "wind_chill": // Outdoor wind chill
ProcessEvent( "WindChill", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "WindChill", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "wind_chill_indoor": // Indoor wind chill
ProcessEvent( "WindChillIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostEventToChild( "Indoor Station", "WindChill", state.WindChillIndoor, "°${ location.getTemperatureScale() }" )
break
case "dew_point": // Outdoor dew point
ProcessEvent( "dewPoint", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "dewPoint", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "dew_point_indoor": // Indoor dew point
ProcessEvent( "dewPointIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostEventToChild( "Indoor Station", "dewPoint", state.dewPointIndoor, "°${ location.getTemperatureScale() }" )
break
case "wet_bulb_temperature": // Outdoor wet bulb temperature
ProcessEvent( "WetBulbTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ state.air_temperature_humidity_Sensor }", "WetBulbTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "wet_bulb_temperature_indoor": // Indoor wet bulb temperature
ProcessEvent( "WetBulbTemperatureIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostStateToChild( "Indoor Station", "WetBulbTemperature", state.WetBulbTemperatureIndoor )
break
case "wet_bulb_globe_temperature": //
ProcessEvent( "WetBulbGlobeTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
//PostStateToChild( "Indoor Station", "WetBulbGlobeTemperature", state.WetBulbGlobeTemperature )
break
case "delta_t": // delta t
ProcessState( "DeltaT", it.value )
//PostStateToChild( "Outdoor Station", "DeltaT", state.DeltaT )
break
case "air_density": // air density
ProcessEvent( "AirDensity", it.value )
//PostStateToChild( "Outdoor Station", "AirDensity", state.AirDensity )
break
case "precip_analysis_type_yesterday": // precip_analysis_type_yesterday
ProcessEvent( "PrecipAnalysisTypeYesterday", it.value )
//PostStateToChild( "Outdoor Station", "PrecipAnalysisTypeYesterday", state.PrecipAnalysisTypeYesterday )
break
case "pressure_trend": // pressure_trend
ProcessEvent( "PressureTrend", "${ it.value }" )
//PostStateToChild( "Outdoor Station", "PressureTrend", state."PressureTrend" )
break
default:
Logging( "Unhandled data ${ it.key } = ${ it.value }", 3 )
break
}
}
}
// Parse the station data returned, output events and populate attributes as needed
def ParseDevice( Data ){
Logging( "Device data = ${ Data }", 4 ) // For development purposes, to see if new attributes show up
def TempID
if( Data.device_id != null ){ // device_id
TempID = Data.device_id
}
if( Data.summary != null ){
if( Data.summary.heat_index != null ){ // heat_index
ProcessEvent( "HeatIndex", ConvertTemperature( "C", Data.summary.heat_index ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "HeatIndex", ConvertTemperature( "C", Data.summary.heat_index ), "°${ location.getTemperatureScale() }" )
}
if( Data.summary.pressure_trend != null ){ // pressure_trend
ProcessEvent( "PressureTrend", Data.summary.pressure_trend )
PostEventToChild( "${ TempID }", "PressureTrend", Data.summary.pressure_trend )
}
if( Data.summary.wind_chill != null ){ // wind_chill
ProcessEvent( "WindChill", ConvertTemperature( "C", Data.summary.wind_chill ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "WindChill", ConvertTemperature( "C", Data.summary.wind_chill ), "°${ location.getTemperatureScale() }" )
}
if( Data.summary.strike_last_dist != null ){ // strike_last_dist
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LightningStrikeLastDistance", Data.summary.strike_last_dist, "km" )
PostEventToChild( "${ TempID }", "LightningStrikeLastDistance", Data.summary.strike_last_dist, "km" )
} else {
ProcessEvent( "LightningStrikeLastDistance", ConvertMiles( "Metric", Data.summary.strike_last_dist ), "miles" )
PostEventToChild( "${ TempID }", "LightningStrikeLastDistance", ConvertMiles( "Metric", Data.summary.strike_last_dist ), "miles" )
}
}
if( Data.summary.strike_count_3h != null ){ // strike_count_3h
ProcessEvent( "LightningStrikeCountLast3hr", Data.summary.strike_count_3h )
PostEventToChild( "${ TempID }", "LightningStrikeCountLast3hr", Data.summary.strike_count_3h )
}
if( Data.summary.feels_like != null ){ // feels_like
ProcessEvent( "feelsLike", ConvertTemperature( "C", Data.summary.feels_like ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "feelsLike", ConvertTemperature( "C", Data.summary.feels_like ), "°${ location.getTemperatureScale() }" )
}
if( Data.summary.strike_last_epoch != null ){ // strike_last_epoch
ProcessEvent( "LightningStrikeLastEpoch", Data.summary.strike_last_epoch )
PostEventToChild( "${ TempID }", "LightningStrikeLastEpoch", Data.summary.strike_last_epoch )
ProcessEvent( "LightningStrikeLastDate", ConvertEpochToDate( Data.summary.strike_last_epoch ) )
PostEventToChild( "${ TempID }", "LightningStrikeLastDate", ConvertEpochToDate( Data.summary.strike_last_epoch ) )
}
if( Data.summary.precip_accum_local_yesterday_final != null ){ // precip_accum_local_yesterday_final
ProcessEvent( "PrecipAccumLocalYesterdayFinal", Data.summary.precip_accum_local_yesterday_final )
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterdayFinal", Data.summary.precip_accum_local_yesterday_final )
}
if( Data.summary.precip_analysis_type_yesterday != null ){ // precip_analysis_type_yesterday
ProcessEvent( "PrecipAnalysisTypeYesterday", Data.summary.precip_analysis_type_yesterday )
PostEventToChild( "${ TempID }", "PrecipAnalysisTypeYesterday", Data.summary.precip_analysis_type_yesterday )
}
if( Data.summary.precip_accum_local_yesterday != null ){ // precip_accum_local_yesterday
ProcessEvent( "PrecipAccumLocalYesterday", Data.summary.precip_accum_local_yesterday )
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterday", Data.summary.precip_accum_local_yesterday )
}
if( Data.summary.precip_total_1h != null ){ // precip_total_1h
ProcessEvent( "PrecipTotal1h", Data.summary.precip_total_1h )
PostEventToChild( "${ TempID }", "PrecipTotal1h", Data.summary.precip_total_1h )
}
}
if( Data.type == "obs_air" ){
if( Data.obs[ 0 ][ 0 ] != null ){ // 0 - Epoch (seconds UTC)
ProcessState( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostStateToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
PostEventToChild( "${ TempID }", "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Station Pressure (MB)
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "StationPressure", Data.obs[ 0 ][ 1 ], "mb" )
PostEventToChild( "${ TempID }", "StationPressure", Data.obs[ 0 ][ 1 ], "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "psi" )
PostEventToChild( "${ TempID }", "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "inHG" )
PostEventToChild( "${ TempID }", "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "inHG" )
}
}
if( Data.obs[ 0 ][ 2 ] != null ){ // 2 - Air Temperature (C)
ProcessEvent( "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 2 ] ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 2 ] ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "temperature", ConvertTemperature( "C", Data.obs[ 0 ][ 2 ] ), "°${ location.getTemperatureScale() }" )
}
if( Data.obs[ 0 ][ 3 ] != null ){ // 3 - Relative Humidity (%)
ProcessEvent( "RelativeHumidity", Data.obs[ 0 ][ 3 ], "%" )
PostEventToChild( "${ TempID }", "RelativeHumidity", Data.obs[ 0 ][ 3 ], "%" )
PostEventToChild( "${ TempID }", "humidity", Data.obs[ 0 ][ 3 ], "%" )
}
if( Data.obs[ 0 ][ 4 ] != null ){ // 4 - Lightning Strike Count
ProcessEvent( "LightningStrikeCount", Data.obs[ 0 ][ 4 ] )
PostEventToChild( "${ TempID }", "LightningStrikeCount", Data.obs[ 0 ][ 4 ] )
}
if( Data.obs[ 0 ][ 5 ] != null ){ // 5 - Lightning Strike Average Distance (km)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LightningStrikeAverageDistance", Data.obs[ 0 ][ 5 ], "km" )
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", Data.obs[ 0 ][ 5 ], "km" )
} else {
ProcessEvent( "LightningStrikeAverageDistance", ConvertMiles( "Metric", Data.obs[ 0 ][ 5 ] ), "miles" )
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", ConvertMiles( "Metric", Data.obs[ 0 ][ 5 ] ), "miles" )
}
}
if( Data.obs[ 0 ][ 6 ] != null ){ // 6 - Battery (volts)
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 6 ], "volts" )
PostStateToChild( "${ TempID }", "BatteryVoltage", Data.obs[ 0 ][ 6 ] )
if( Data.obs[ 0 ][ 6 ] >= 2.455 ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 6 ] >= 2.41 ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 6 ] >= 2.375 ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
ProcessEvent( "${ TempID }_battery%", 25, "%" )
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 7 ] != null ){ // 7 - Report Interval (minutes)
ProcessState( "${ TempID }_Interval", Data.obs[ 0 ][ 7 ] )
PostStateToChild( "${ TempID }", "Interval", Data.obs[ 0 ][ 7 ] )
}
} else if( Data.type == "obs_sky" ){
if( Data.obs[ 0 ][ 0 ] != null ){ // 0 - Epoch (seconds UTC)
ProcessState( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostStateToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
PostEventToChild( "${ TempID }", "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Illuminance (lux)
ProcessEvent( "illuminance", Data.obs[ 0 ][ 1 ], "lux" )
PostEventToChild( "${ TempID }", "illuminance", Data.obs[ 0 ][ 1 ], "lux" )
}
if( Data.obs[ 0 ][ 2 ] != null ){ // 2 - UV (index)
ProcessEvent( "ultravioletIndex", Data.obs[ 0 ][ 2 ], "uvi" )
PostEventToChild( "${ TempID }", "ultravioletIndex", Data.obs[ 0 ][ 2 ],, "uvi" )
}
if( Data.obs[ 0 ][ 3 ] != null ){ // 3 - Rain Accumulation (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "RainAccumulation", Data.obs[ 0 ][ 3 ], "mm" )
PostEventToChild( "${ TempID }", "RainAccumulation", Data.obs[ 0 ][ 3 ], "mm" )
} else {
ProcessEvent( "RainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 3 ] ), "inches" )
PostEventToChild( "${ TempID }", "RainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 3 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 4 ] != null ){ // 4 - Wind Lull (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "WindLull", Data.obs[ 0 ][ 4 ], "m/s" )
PostEventToChild( "${ TempID }", "WindLull", Data.obs[ 0 ][ 4 ], "m/s" )
} else {
ProcessEvent( "WindLull", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 4 ] ), "mph" )
PostEventToChild( "${ TempID }", "WindLull", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 4 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 5 ] != null ){ // 5 - Wind Avg (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "WindAvg", Data.obs[ 0 ][ 5 ], "m/s" )
PostEventToChild( "${ TempID }", "WindAvg", Data.obs[ 0 ][ 5 ], "m/s" )
ProcessEvent( "windSpeed", Data.obs[ 0 ][ 5 ], "m/s" )
PostEventToChild( "${ TempID }", "windSpeed", Data.obs[ 0 ][ 5 ], "m/s" )
} else {
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
PostEventToChild( "${ TempID }", "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
ProcessEvent( "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
PostEventToChild( "${ TempID }", "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 6 ] != null ){ // 6 - Wind Gust (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "windGust", Data.obs[ 0 ][ 6 ], "m/s" )
PostEventToChild( "${ TempID }", "windGust", Data.obs[ 0 ][ 6 ], "m/s" )
} else {
ProcessEvent( "windGust", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 6 ] ), "mph" )
PostEventToChild( "${ TempID }", "windGust", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 6 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 7 ] != null ){ // 7 - Wind Direction (degrees)
ProcessEvent( "windDirection", Data.obs[ 0 ][ 7 ], "°" )
PostEventToChild( "${ TempID }", "windDirection", Data.obs[ 0 ][ 7 ], "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 7 ] ) )
PostEventToChild( "${ TempID }", "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 7 ] ) )
}
if( Data.obs[ 0 ][ 8 ] != null ){ // 8 - Battery (volts)
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 8 ], "volts" )
PostStateToChild( "${ TempID }", "BatteryVoltage", Data.obs[ 0 ][ 6 ] )
if( Data.obs[ 0 ][ 8 ] >= 2.455 ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 8 ] >= 2.41 ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 8 ] >= 2.375 ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
ProcessEvent( "${ TempID }_battery%", 25, "%" )
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 9 ] != null ){ // 9 - Report Interval (minutes)
ProcessState( "${ TempID }_Interval", Data.obs[ 0 ][ 9 ] )
PostStateToChild( "${ TempID }", "Interval", Data.obs[ 0 ][ 9 ] )
}
if( Data.obs[ 0 ][ 10 ] != null ){ // 10 - Solar Radiation (W/m^2)
ProcessEvent( "SolarRadiation", Data.obs[ 0 ][ 10 ], "W/m^2" )
PostEventToChild( "${ TempID }", "SolarRadiation", Data.obs[ 0 ][ 10 ], "W/m^2" )
}
if( Data.obs[ 0 ][ 11 ] != null ){ // 11 - Local Day Rain Accumulation (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LocalDayRainAccumulation", Data.obs[ 0 ][ 11 ], "mm" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", Data.obs[ 0 ][ 11 ], "mm" )
} else {
ProcessEvent( "LocalDayRainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 11 ] ), "inches" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 11 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 12 ] != null ){ // 12 - Precipitation Type (0 = none, 1 = rain, 2 = hail, 3 = rain + hail)
ProcessEvent( "PrecipitationType", Data.obs[ 0 ][ 12 ] )
PostEventToChild( "${ TempID }", "PrecipitationType", Data.obs[ 0 ][ 12 ] )
switch( Data.obs[ 0 ][ 12 ] ){
case 0:
ProcessEvent( "PrecipitationTypeString", "none" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "none" )
break
case 1:
ProcessEvent( "PrecipitationTypeString", "rain" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain" )
break
case 2:
ProcessEvent( "PrecipitationTypeString", "hail" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "hail" )
break
case 3:
ProcessEvent( "PrecipitationTypeString", "rain + hail" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain + hail" )
break
}
}
if( Data.obs[ 0 ][ 13 ] != null ){ // 13 - Wind Sample Interval (seconds)
ProcessState( "${ TempID }_WindSampleInterval", Data.obs[ 0 ][ 13 ] )
PostStateToChild( "${ TempID }", "WindSampleInterval", Data.obs[ 0 ][ 13 ] )
}
if( Data.obs[ 0 ][ 14 ] != null ){ // 14 - Rain Accumulation Final (Rain Check) (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "RainAccumulationFinal", Data.obs[ 0 ][ 14 ], "mm" )
PostEventToChild( "${ TempID }", "RainAccumulationFinal", Data.obs[ 0 ][ 14 ], "mm" )
} else {
ProcessEvent( "RainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 14 ] ), "inches" )
PostEventToChild( "${ TempID }", "RainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 14 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 15 ] != null ){ // 15 - Local Day Rain Accumulation Final (Rain Check) (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 15 ], "mm" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 15 ], "mm" )
} else {
ProcessEvent( "LocalDayRainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 15 ] ), "inches" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 15 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 16 ] != null ){ // 16 - Precipitation Analysis Type (0 = none, 1 = Rain Check with user display on, 2 = Rain Check with user display off)
ProcessEvent( "PrecipitationAnalysisType", Data.obs[ 0 ][ 16 ] )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisType", Data.obs[ 0 ][ 16 ] )
switch( Data.obs[ 0 ][ 16 ] ){
case 0:
ProcessEvent( "PrecipitationAnalysisTypeString", "none" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "none" )
break
case 1:
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
break
case 2:
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display off" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display off" )
break
}
}
} else if( Data.type == "obs_st" ){
if( Data.obs[ 0 ][ 0 ] != null ){ // 0 - Epoch (seconds UTC)
ProcessState( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostStateToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
PostEventToChild( "${ TempID }", "TimestampDate", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Wind Lull (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "WindLull", Data.obs[ 0 ][ 1 ], "m/s" )
PostEventToChild( "${ TempID }", "WindLull", Data.obs[ 0 ][ 1 ], "m/s" )
} else {
ProcessEvent( "WindLull", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 1 ] ), "mph" )
PostEventToChild( "${ TempID }", "WindLull", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 1 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 2 ] != null ){ // 2 - Wind Avg (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "WindAvg", Data.obs[ 0 ][ 2 ], "m/s" )
PostEventToChild( "${ TempID }", "WindAvg", Data.obs[ 0 ][ 2 ], "m/s" )
ProcessEvent( "windSpeed", Data.obs[ 0 ][ 2 ], "m/s" )
PostEventToChild( "${ TempID }", "windSpeed", Data.obs[ 0 ][ 2 ], "m/s" )
} else {
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
PostEventToChild( "${ TempID }", "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
ProcessEvent( "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
PostEventToChild( "${ TempID }", "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 3 ] != null ){ // 3 - Wind Gust (m/s)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "windGust", Data.obs[ 0 ][ 3 ], "m/s" )
PostEventToChild( "${ TempID }", "windGust", Data.obs[ 0 ][ 3 ], "m/s" )
} else {
ProcessEvent( "windGust", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 3 ] ), "mph" )
PostEventToChild( "${ TempID }", "windGust", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 3 ] ), "mph" )
}
}
if( Data.obs[ 0 ][ 4 ] != null ){ // 4 - Wind Direction (degrees)
ProcessEvent( "windDirection", Data.obs[ 0 ][ 4 ], "°" )
PostEventToChild( "${ TempID }", "windDirection", Data.obs[ 0 ][ 4 ], "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 4 ] ) )
PostEventToChild( "${ TempID }", "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 4 ] ) )
}
if( Data.obs[ 0 ][ 5 ] != null ){ // 5 - Wind Sample Interval (seconds)
ProcessState( "${ TempID }_WindSampleInterval", Data.obs[ 0 ][ 5 ] )
PostStateToChild( "${ TempID }", "WindSampleInterval", Data.obs[ 0 ][ 5 ] )
}
if( Data.obs[ 0 ][ 6 ] != null ){ // 6 - Pressure (MB)
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
ProcessEvent( "pressure", Data.obs[ 0 ][ 6 ], "mb" )
PostEventToChild( "${ TempID }", "pressure", Data.obs[ 0 ][ 6 ], "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
ProcessEvent( "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "psi" )
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "psi" )
} else if( PressureUnits == "inHG" ){
ProcessEvent( "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "inHG" )
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "inHG" )
}
}
if( Data.obs[ 0 ][ 7 ] != null ){ // 7 - Air Temperature (C)
ProcessEvent( "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 7 ] ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 7 ] ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "temperature", ConvertTemperature( "C", Data.obs[ 0 ][ 7 ] ), "°${ location.getTemperatureScale() }" )
}
if( Data.obs[ 0 ][ 8 ] != null ){ // 8 - Relative Humidity (%)
ProcessEvent( "RelativeHumidity", Data.obs[ 0 ][ 8 ], "%" )
PostEventToChild( "${ TempID }", "RelativeHumidity", Data.obs[ 0 ][ 8 ], "%" )
PostEventToChild( "${ TempID }", "humidity", Data.obs[ 0 ][ 8 ], "%" )
}
if( Data.obs[ 0 ][ 9 ] != null ){ // 9 - Illuminance (lux)
ProcessEvent( "illuminance", Data.obs[ 0 ][ 9 ], "lux" )
PostEventToChild( "${ TempID }", "illuminance", Data.obs[ 0 ][ 9 ], "lux" )
}
if( Data.obs[ 0 ][ 10 ] != null ){ // 10 - UV (index)
ProcessEvent( "ultravioletIndex", Data.obs[ 0 ][ 10 ], "uvi" )
PostEventToChild( "${ TempID }", "ultravioletIndex", Data.obs[ 0 ][ 10 ], "uvi" )
}
if( Data.obs[ 0 ][ 11 ] != null ){ // 11 - Solar Radiation (W/m^2)
ProcessEvent( "SolarRadiation", Data.obs[ 0 ][ 11 ], "W/m^2" )
PostEventToChild( "${ TempID }", "SolarRadiation", Data.obs[ 0 ][ 11 ], "W/m^2" )
}
if( Data.obs[ 0 ][ 12 ] != null ){ // 12 - Rain Accumulation (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "RainAccumulation", Data.obs[ 0 ][ 12 ], "mm" )
PostEventToChild( "${ TempID }", "RainAccumulation", Data.obs[ 0 ][ 12 ], "mm" )
} else {
ProcessEvent( "RainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 12 ] ), "inches" )
PostEventToChild( "${ TempID }", "RainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 12 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 13 ] != null ){ // 13 - Precipitation Type (0 = none, 1 = rain, 2 = hail, 3 = rain + hail)
ProcessEvent( "PrecipitationType", Data.obs[ 0 ][ 13 ] )
PostEventToChild( "${ TempID }", "PrecipitationType", Data.obs[ 0 ][ 13 ] )
switch( Data.obs[ 0 ][ 13 ] ){
case 0:
ProcessEvent( "PrecipitationTypeString", "none" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "none" )
break
case 1:
ProcessEvent( "PrecipitationTypeString", "rain" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain" )
break
case 2:
ProcessEvent( "PrecipitationTypeString", "hail" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "hail" )
break
case 3:
ProcessEvent( "PrecipitationTypeString", "rain + hail" )
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain + hail" )
break
}
}
if( Data.obs[ 0 ][ 14 ] != null ){ // 14 - Average Strike Distance (km)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LightningStrikeAverageDistance", Data.obs[ 0 ][ 14 ], "km" )
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", Data.obs[ 0 ][ 14 ], "km" )
} else {
ProcessEvent( "LightningStrikeAverageDistance", ConvertMiles( "Metric", Data.obs[ 0 ][ 14 ] ), "miles" )
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", ConvertMiles( "Metric", Data.obs[ 0 ][ 14 ] ), "miles" )
}
}
if( Data.obs[ 0 ][ 15 ] != null ){ // 15 - Strike Count
ProcessEvent( "LightningStrikeCount", Data.obs[ 0 ][ 15 ] )
PostEventToChild( "${ TempID }", "LightningStrikeCount", Data.obs[ 0 ][ 15 ] )
}
if( Data.obs[ 0 ][ 16 ] != null ){ // 16 - Battery (volts)
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 16 ], "volts" )
PostStateToChild( "${ TempID }", "Battery Voltage", Data.obs[ 0 ][ 16 ] )
if( Data.obs[ 0 ][ 16 ] >= 2.455 ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 16 ] >= 2.41 ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 16 ] >= 2.375 ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
ProcessEvent( "${ TempID }_battery%", 25, "%" )
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 17 ] != null ){ // 17 - Report Interval (minutes)
ProcessState( "${ TempID }_Interval", Data.obs[ 0 ][ 17 ] )
PostStateToChild( "${ TempID }", "Interval", Data.obs[ 0 ][ 17 ] )
}
if( Data.obs[ 0 ][ 18 ] != null ){ // 18 - Local Day Rain Accumulation (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LocalDayRainAccumulation", Data.obs[ 0 ][ 18 ], "mm" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", Data.obs[ 0 ][ 18 ], "mm" )
} else {
ProcessEvent( "LocalDayRainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 18 ] ), "inches" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", ConvertInches( "Metric", Data.obs[ 0 ][ 18 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 19 ] != null ){ // 19 - Rain Accumulation Final (Rain Check) (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "RainAccumulationFinal", Data.obs[ 0 ][ 19 ], "mm" )
PostEventToChild( "${ TempID }", "RainAccumulationFinal", Data.obs[ 0 ][ 19 ], "mm" )
} else {
ProcessEvent( "RainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 19 ] ), "inches" )
PostEventToChild( "${ TempID }", "RainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 19 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 20 ] != null ){ // 20 - Local Day Rain Accumulation Final (Rain Check) (mm)
if( MeasurementStandard == "Metric" ){
ProcessEvent( "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 20 ], "mm" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 20 ], "mm" )
} else {
ProcessEvent( "LocalDayRainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 20 ] ), "inches" )
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", ConvertInches( "Metric", Data.obs[ 0 ][ 20 ] ), "inches" )
}
}
if( Data.obs[ 0 ][ 21 ] != null ){ // 21 - Precipitation Aanalysis Type (0 = none, 1 = Rain Check with user display on, 2 = Rain Check with user display off)
ProcessEvent( "PrecipitationAnalysisType", Data.obs[ 0 ][ 21 ] )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisType", Data.obs[ 0 ][ 21 ] )
switch( Data.obs[ 0 ][ 21 ] ){
case 0:
ProcessEvent( "PrecipitationAnalysisTypeString", "none" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "none" )
break
case 1:
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
break
case 2:
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display off" )
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display off" )
break
}
}
}
}
//Poll WeatherFlow for forecast
def PollForecast(){
if( Token != null ){
def Params
Params = [ uri: "https://swd.weatherflow.com/swd/rest/better_forecast?station_id=${ StationID }&token=${ Token }", contentType: "application/json" ]
Logging( "Forecast Params = ${ Params }", 4 )
asynchttpGet( "GetForecastData", Params)
} else {
Logging( "Token is required for WeatherFlow API.", 5 )
}
}
// Handles the forecast response from WeatherFlow
def GetForecastData( resp, data ){
switch( resp.getStatus() ){
case 200:
Logging( "Raw response: ${ resp.data }", 4 )
if( resp.data != null ){
Data = parseJson( resp.data )
ProcessForecast( Data.forecast.daily[ 0 ], "Today" )
ProcessForecast( Data.forecast.daily[ 1 ], "Tomorrow" )
} else {
Logging( "No data returned by WeatherFlow", 5 )
}
break
case 401:
Logging( "Unauthorized, most likely due to invalid token.", 5 )
break
case 404:
Logging( "Station not found.", 5 )
break
default:
Logging( "Error connecting to WeatherFlow: ${ resp.status }", 5 )
break
}
}
// ProcessForecast takes the forecast data and sets it for the correct day
def ProcessForecast( Data, Day ){
Data.each{
switch( it.key ){
case "conditions":
ProcessEvent( "${ Day } Conditions", "${ it.value }" )
PostEventToChild( "Forecast", "${ Day } Conditions", "${ it.value }" )
break
case "icon":
ProcessEvent( "${ Day } Icon", it.value )
PostEventToChild( "Forecast", "${ Day } Icon", "${ it.value }" )
break
case "sunrise":
ProcessEvent( "${ Day } Sunrise", ConvertEpochToDate( it.value ) )
PostEventToChild( "Forecast", "${ Day } Sunrise", ConvertEpochToDate( it.value ) )
break
case "sunset":
ProcessEvent( "${ Day } Sunset", ConvertEpochToDate( it.value ) )
PostEventToChild( "Forecast", "${ Day } Sunset", ConvertEpochToDate( it.value ) )
break
case "air_temp_high":
ProcessEvent( "${ Day } High Temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "Forecast", "${ Day } High Temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "air_temp_low":
ProcessEvent( "${ Day } Low Temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "Forecast", "${ Day } Low Temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "precip_probability":
ProcessEvent( "${ Day } Chance Precipitation", it.value, "%" )
PostEventToChild( "Forecast", "${ Day } Chance Precipitation", it.value, "%" )
break
case "precip_icon":
ProcessEvent( "${ Day } Precipitation Icon", "${ it.value }" )
PostEventToChild( "Forecast", "${ Day } Precipitation Icon", "${ it.value }" )
break
case "precip_type":
ProcessEvent( "${ Day } Precipitation Type", "${ it.value }" )
PostEventToChild( "Forecast", "${ Day } Precipitation Type", "${ it.value }" )
break
// Data to ignore
case "day_start_local":
case "day_num":
case "month_num":
break
// Data not handled yet
default:
Logging( "Unhandled data ${ Day } ${ it.key } = ${ it.value } from Weatherflow forecast.", 3 )
PostStateToChild( "Forecast", "${ Day } ${ it.key }", "${ it.value }" )
break
}
}
}
// Makes a string that describes the current wind direction in words (or at least letters)
def String MakeWindDirectionString( Direction ){
def WindDirectionString
switch( WindDirMethod ){
case "1": // Just uses the degree value
WindDirectionString = "${ Direction }°"
break
case "2": // 4 Compass Points - Letters
if( Direction > 315 || Direction <= 45 ){
WindDirectionString = "N"
} else if( Direction > 45 && Direction <= 135 ){
WindDirectionString = "E"
} else if( Direction > 135 && Direction <= 225 ){
WindDirectionString = "S"
} else if( Direction > 225 && Direction <= 315 ){
WindDirectionString = "W"
}
break
case "3": // 8 Compass Points - Letters
if( Direction > 337.5 || Direction <= 22.5 ){
WindDirectionString = "N"
} else if( Direction > 22.5 && Direction <= 67.5 ){
WindDirectionString = "NE"
} else if( Direction > 67.5 && Direction <= 112.5 ){
WindDirectionString = "E"
} else if( Direction > 112.5 && Direction <= 157.5 ){
WindDirectionString = "SE"
} else if( Direction > 157.5 && Direction <= 202.5 ){
WindDirectionString = "S"
} else if( Direction > 202.5 && Direction <= 247.5 ){
WindDirectionString = "SW"
} else if( Direction > 247.5 && Direction <= 292.5 ){
WindDirectionString = "W"
} else if( Direction > 292.5 && Direction <= 337.5 ){
WindDirectionString = "NW"
}
break
case "4": // 16 Compass Points - Letters
if( Direction > 348.75 || Direction <= 11.25 ){
WindDirectionString = "N"
} else if( Direction > 11.25 && Direction <= 33.75 ){
WindDirectionString = "NNE"
} else if( Direction > 33.75 && Direction <= 56.25 ){
WindDirectionString = "NE"
} else if( Direction > 56.25 && Direction <= 78.75 ){
WindDirectionString = "ENE"
} else if( Direction > 78.75 && Direction <= 101.25 ){
WindDirectionString = "E"
} else if( Direction > 101.25 && Direction <= 123.75 ){
WindDirectionString = "ESE"
} else if( Direction > 123.75 && Direction <= 146.25 ){
WindDirectionString = "SE"
} else if( Direction > 146.25 && Direction <= 168.75 ){
WindDirectionString = "SSE"
} else if( Direction > 168.75 && Direction <= 191.25 ){
WindDirectionString = "S"
} else if( Direction > 191.25 && Direction <= 213.75 ){
WindDirectionString = "SSW"
} else if( Direction > 213.75 && Direction <= 236.25 ){
WindDirectionString = "SW"
} else if( Direction > 236.25 && Direction <= 258.75 ){
WindDirectionString = "WSW"
} else if( Direction > 258.75 && Direction <= 281.25 ){
WindDirectionString = "W"
} else if( Direction > 281.25 && Direction <= 303.75 ){
WindDirectionString = "WNW"
} else if( Direction > 303.75 && Direction <= 326.25 ){
WindDirectionString = "NW"
} else if( Direction > 326.25 && Direction <= 348.75 ){
WindDirectionString = "NNW"
}
break
case "5": // 4 Compass Points - Words
if( Direction > 315 || Direction <= 45 ){
WindDirectionString = "North"
} else if( Direction > 45 && Direction <= 135 ){
WindDirectionString = "East"
} else if( Direction > 135 && Direction <= 225 ){
WindDirectionString = "South"
} else if( Direction > 225 && Direction <= 315 ){
WindDirectionString = "West"
}
break
case "6": // 8 Compass Points - Words
if( Direction > 337.5 || Direction <= 22.5 ){
WindDirectionString = "North"
} else if( Direction > 22.5 && Direction <= 67.5 ){
WindDirectionString = "North-East"
} else if( Direction > 67.5 && Direction <= 112.5 ){
WindDirectionString = "East"
} else if( Direction > 112.5 && Direction <= 157.5 ){
WindDirectionString = "South-East"
} else if( Direction > 157.5 && Direction <= 202.5 ){
WindDirectionString = "South"
} else if( Direction > 202.5 && Direction <= 247.5 ){
WindDirectionString = "South-West"
} else if( Direction > 247.5 && Direction <= 292.5 ){
WindDirectionString = "West"
} else if( Direction > 292.5 && Direction <= 337.5 ){
WindDirectionString = "North-West"
}
break
case "7": // 16 Compass Points - Words
if( Direction > 348.75 || Direction <= 11.25 ){
WindDirectionString = "North"
} else if( Direction > 11.25 && Direction <= 33.75 ){
WindDirectionString = "North-North-East"
} else if( Direction > 33.75 && Direction <= 56.25 ){
WindDirectionString = "North-East"
} else if( Direction > 56.25 && Direction <= 78.75 ){
WindDirectionString = "East-North-East"
} else if( Direction > 78.75 && Direction <= 101.25 ){
WindDirectionString = "East"
} else if( Direction > 101.25 && Direction <= 123.75 ){
WindDirectionString = "East-South-East"
} else if( Direction > 123.75 && Direction <= 146.25 ){
WindDirectionString = "South-East"
} else if( Direction > 146.25 && Direction <= 168.75 ){
WindDirectionString = "South-South-East"
} else if( Direction > 168.75 && Direction <= 191.25 ){
WindDirectionString = "South"
} else if( Direction > 191.25 && Direction <= 213.75 ){
WindDirectionString = "South-South-West"
} else if( Direction > 213.75 && Direction <= 236.25 ){
WindDirectionString = "South-West"
} else if( Direction > 236.25 && Direction <= 258.75 ){
WindDirectionString = "West-South-West"
} else if( Direction > 258.75 && Direction <= 281.25 ){
WindDirectionString = "West"
} else if( Direction > 281.25 && Direction <= 303.75 ){
WindDirectionString = "West-North-West"
} else if( Direction > 303.75 && Direction <= 326.25 ){
WindDirectionString = "North-West"
} else if( Direction > 326.25 && Direction <= 348.75 ){
WindDirectionString = "North-North-West"
}
break
}
return WindDirectionString
}
// Used to convert epoch values to text dates
def String ConvertEpochToDate( Number Epoch ){
def date = use( groovy.time.TimeCategory ) {
new Date( 0 ) + Epoch.seconds
}
return date
}
// Checks the location.getTemperatureScale() to convert temperature values
def ConvertTemperature( String Scale, Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( location.getTemperatureScale() == "C" && Scale.toUpperCase() == "F" ){
ReturnValue = ( ( ( Value - 32 ) * 5 ) / 9 )
Logging( "Temperature Conversion ${ Value }°${ Scale.toUpperCase() } to ${ ReturnValue }°${ location.getTemperatureScale() }", 4 )
} else if( location.getTemperatureScale() == "F" && Scale.toUpperCase() == "C" ) {
ReturnValue = ( ( ( Value * 9 ) / 5 ) + 32 )
Logging( "Temperature Conversion ${ Value }°${ Scale.toUpperCase() } to ${ ReturnValue }°${ location.getTemperatureScale() }", 4 )
} else if( location.getTemperatureScale() == Scale.toUpperCase() ){
ReturnValue = Value
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Converts speed between m/s and mph
def ConvertMetersSecond( String BaseScale, Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( BaseScale == "Metric" && MeasurementStandard == "Imperial" ){
ReturnValue = ( Value * 2.237 )
} else if( BaseScale.toUpperCase() == "Imperial" && MeasurementStandard == "Metric" ) {
ReturnValue = ( Value / 2.237 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Converts distances between km and miles or km/h and mph
def ConvertMiles( String BaseScale, Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( BaseScale == "Metric" && MeasurementStandard == "Imperial" ){
ReturnValue = ( Value / 1.609 )
} else if( BaseScale.toUpperCase() == "Imperial" && MeasurementStandard == "Metric" ) {
ReturnValue = ( Value * 1.609 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Converts measurements between inches and mm
def ConvertInches( String BaseScale, Number Value ){
if( Value != null ){
def TempInt
def ReturnValue = Value as double
if( BaseScale == "Metric" && MeasurementStandard == "Imperial" ){
ReturnValue = ( Value / 25.4 )
TempInt = ( ReturnValue * 100000 ) as int
ReturnValue = ( TempInt / 100000 )
} else if( BaseScale.toUpperCase() == "Imperial" && MeasurementStandard == "Metric" ) {
ReturnValue = ( Value * 25.4 )
TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
}
return ReturnValue
}
}
// Converts pressure between mbar and psi
/*
def ConvertPressure( String BaseScale, Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( BaseScale == "Metric" && MeasurementStandard == "Imperial" ){
ReturnValue = ( Value / 68.948 )
} else if( BaseScale.toUpperCase() == "Imperial" && MeasurementStandard == "Metric" ) {
ReturnValue = ( Value * 68.948 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
*/
// Converts pressure between mbar, psi, and inHG based on PressureUnits preference or MeasurementStandard (if PressureUnits not set)
def ConvertPressure( String BaseScale, Number Value ){
if( Value != null ){
def ReturnValue = Value as double
if( ( BaseScale == "Metric" ) && ( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ) ){
ReturnValue = ( Value / 68.948 )
} else if( ( BaseScale == "Imperial" ) && ( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ) ){
ReturnValue = ( Value * 68.948 )
} else if( ( BaseScale == "Metric" ) && ( PressureUnits == "inHG" ) ){
ReturnValue = ( Value / 33.864 )
} else if( ( BaseScale == "Imperial" ) && ( PressureUnits == "inHG" ) ){
ReturnValue = ( Value * 2.036 )
}
def TempInt = ( ReturnValue * 100 ) as int
ReturnValue = ( TempInt / 100 )
return ReturnValue
}
}
// Process data to check against current state value and then send an event if it has changed
def ProcessEvent( Variable, Value, Unit = null ){
if( state."${ Variable }" != Value ){
state."${ Variable }" = Value
if( Unit != null ){
Logging( "Event: ${ Variable } = ${ Value }${ Unit }", 4 )
sendEvent( name: "${ Variable }", value: Value, unit: Unit, isStateChange: true )
} else {
Logging( "Event: ${ Variable } = ${ Value }", 4 )
sendEvent( name: "${ Variable }", value: Value, isStateChange: true )
}
}
}
// Process data to check against current state value and then send an event if it has changed
def ProcessState( Variable, Value ){
if( state."${ Variable }" != Value ){
Logging( "State: ${ Variable } = ${ Value }", 4 )
state."${ Variable }" = Value
}
}
// Post data to child device
def PostEventToChild( Child, Variable, Value, Unit = null ){
if( ChildrenEnabled ){
if( Child != null ){
def ChildParent = "${ Child }"// ${ device.deviceNetworkId }"
if( getChildDevice( "${ ChildParent }" ) == null ){
Logging( "Adding Child ${ ChildParent } with ${ Variable } = ${ Value }", 4 )
addSensor( "${ ChildParent }" )
}
if( getChildDevice( "${ ChildParent }" ) != null ){
if( Unit != null ){
getChildDevice( "${ ChildParent }" ).ProcessEvent( "${ Variable }", Value, "${ Unit }" )
Logging( "Child Event: ${ Variable } = ${ Value }${ Unit }", 4 )
} else {
getChildDevice( "${ ChildParent }" ).ProcessEvent( "${ Variable }", Value )
Logging( "Child Event: ${ Variable } = ${ Value }", 4 )
}
} else {
if( Unit != null ){
Logging( "Failure to add ${ ChildParent } and post ${ Variable }=${ Value }${ Unit }", 5 )
} else {
Logging( "Failure to add ${ ChildParent } 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 ){
if( ChildrenEnabled ){
if( Child != null ){
def ChildParent = "${ Child }"// ${ device.deviceNetworkId }"
if( getChildDevice( "${ ChildParent }" ) == null ){
Logging( "Adding Child ${ ChildParent } with ${ Variable } = ${ Value }", 4 )
addSensor( "${ ChildParent }" )
}
if( getChildDevice( "${ ChildParent }" ) != null ){
Logging( "Child State: ${ Variable } = ${ Value }", 4 )
getChildDevice( "${ ChildParent }" ).ProcessState( "${ Variable }", Value )
} else {
Logging( "Failure to add ${ ChildParent } and 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 addSensor( String DNI ){
try{
Logging( "addSensor(${ 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.", 4 )
ChildrenEnabled = false
} else {
Logging( "Exception in addSensor: ${ Temp }", 4 )
}
}
}
// 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
}
}
}