/*
* 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)
*
* Optional:
* If you have multiple sensors, enter the Sensor ID for the sensor data you want displayed in the parent device
*
* 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.17 - Correction for station observation handling
* 0.4.16 - TimestampDate was being posted instead of TimestampString in some places
* 0.4.15 - TimestampEpoch is now posted as an event
* 0.4.14 - Cleanup of some TempID and Data.device_id points to keep code simpler
* 0.4.13 - Corrected missing humidity value from being copied to parent device and correcting ParentSensorID to an int
* 0.4.12 - Change to data handling for multiple stations and added Preference for Sensor ID to provide data to parent device
* 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.17"
}
// 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: "string", name: "ParentSensorID", title: "Sensor ID for Parent data", description: "If more than one sensor, enter Sensor's ID to copy data to parent device", required: false )
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() )
ProcessEvent( "DriverStatus", null )
// 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( state.ParentSensorID != null ){
ProcessState( "ParentSensorID", ParentSensorID as int )
}
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 ){ // Shared with WeatherFlow
ProcessState( "Shared with WeatherFlow", "true" )
} else {
ProcessState( "Shared with WeatherFlow", "false" )
}
if( Data.stations[ 0 ].station_meta.share_with_wu ){ // Shared with WeatherUnderground
ProcessState( "Shared with WeatherUnderground", "true" )
} else {
ProcessState( "Shared with WeatherUnderground", "false" )
}
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
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 )
}
}
def TempID = null
def ParentSensorID = null
if( Data.device_id != null ){ // device_id
TempID = Data.device_id as int
} else if( Data.station_id != null ){
TempID = Data.station_id as int
}
if( state.ParentSensorID != null ){
ParentSensorID = state.ParentSensorID as int
}
Logging( "TempID = ${ TempID } & ParentSensorID = ${ ParentSensorID }", 4 )
if( TempID != null ){
Data.obs[ 0 ].each{
switch( it.key ){
case "timestamp":
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "TimestampEpoch", it.value )
ProcessEvent( "TimestampString", ConvertEpochToDate( it.value ) )
}
PostEventToChild( "${ TempID }", "TimestampEpoch", it.value )
PostEventToChild( "${ TempID }", "TimestampString", ConvertEpochToDate( it.value ) )
break
case "air_temperature":
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "AirTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
ProcessEvent( "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "AirTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "air_temperature_indoor":
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "AirTemperatureIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "AirTemperatureIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
PostEventToChild( "${ TempID }", "temperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "barometric_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressure", it.value, "mb" )
ProcessEvent( "pressure", it.value, "mb" )
}
PostEventToChild( "${ TempID }", "BarometricPressure", it.value, "mb" )
PostEventToChild( "${ TempID }", "pressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressure", ConvertPressure( "Metric", it.value ), "psi" )
ProcessEvent( "pressure", ConvertPressure( "Metric", it.value ), "psi" )
}
PostEventToChild( "${ TempID }", "BarometricPressure", ConvertPressure( "Metric", it.value ), "psi" )
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressure", ConvertPressure( "Metric", it.value ), "inHG" )
ProcessEvent( "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
PostEventToChild( "${ TempID }", "BarometricPressure", ConvertPressure( "Metric", it.value ), "inHG" )
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "barometric_pressure_indoor":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressureIndoor", it.value, "mb" )
}
PostEventToChild( "${ TempID }", "pressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressureIndoor", ConvertPressure( "Metric", it.value ), "psi" )
}
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "BarometricPressureIndoor", ConvertPressure( "Metric", it.value ), "inHG" )
}
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "station_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "StationPressure", it.value, "mb" )
}
PostEventToChild( "${ TempID }", "StationPressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", it.value ), "psi" )
}
PostEventToChild( "${ TempID }", "StationPressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
PostEventToChild( "${ TempID }", "StationPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "sea_level_pressure":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressure", it.value, "mb" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressure", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "psi" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressure", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "sea_level_pressure_indoor":
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressureIndoor", it.value, "mb" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressureIndoor", it.value, "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "psi" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "inHG" )
}
PostEventToChild( "${ TempID }", "SeaLevelPressureIndoor", ConvertPressure( "Metric", it.value ), "inHG" )
}
break
case "relative_humidity": // Outdoor relative humidity
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RelativeHumidity", it.value, "%" )
ProcessEvent( "humidity", it.value, "%" )
}
PostEventToChild( "${ TempID }", "RelativeHumidity", it.value, "%" )
PostEventToChild( "${ TempID }", "humidity", it.value, "%" )
break
case "relative_humidity_indoor": // Indoor relative humidity
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RelativeHumidityIndoor", it.value, "%" )
}
PostEventToChild( "${ TempID }", "RelativeHumidityIndoor", it.value, "%" )
break
case "precip": // precip
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "Precip", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "Precip", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "Precip", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "Precip", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_last_1hr": // precip accum last 1hr
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLast1hr", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLast1hr", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLast1hr", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLast1hr", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_day_final": //
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalDayFinal", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalDayFinal", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalDayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalDayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_day": // precip accum local day
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalDay", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalDay", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_yesterday": // precip accum local yesterday
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalYesterday", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterday", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_accum_local_yesterday_final": // precip accum local yesterday final
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalYesterdayFinal", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterdayFinal", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAccumLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipAccumLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_day": // precip minutes local day
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalDay", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalDay", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalDay", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_yesterday": // precip minutes local yesterday
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalYesterday", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalYesterday", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalYesterday", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "precip_minutes_local_yesterday_final": // precip minutes local yesterday final
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalYesterdayFinal", it.value, "mm" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalYesterdayFinal", it.value, "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipMinutesLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
PostEventToChild( "${ TempID }", "PrecipMinutesLocalYesterdayFinal", ConvertInches( "Metric", it.value ), "inches" )
}
break
case "wind_avg": // wind avg
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", it.value, "m/s" )
ProcessEvent( "windSpeed", it.value, "m/s" )
}
PostEventToChild( "${ TempID }", "WindAvg", it.value, "m/s" )
PostEventToChild( "${ TempID }", "windSpeed", it.value, "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", it.value ), "mph" )
ProcessEvent( "windSpeed", it.value, "mph" )
}
PostEventToChild( "${ TempID }", "WindAvg", it.value, "mph" )
PostEventToChild( "${ TempID }", "windSpeed", it.value, "mph" )
}
break
case "wind_gust": // wind gust
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windGust", it.value, "m/s" )
}
PostEventToChild( "${ TempID }", "windGust", it.value, "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windGust", ConvertMetersSecond( "Metric", it.value ), "mph" )
}
PostEventToChild( "${ TempID }", "windGust", it.value, "mph" )
}
break
case "wind_lull": // wind lull
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windLull", it.value, "m/s" )
}
PostEventToChild( "${ TempID }", "windLull", it.value, "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windLull", ConvertMetersSecond( "Metric", it.value ), "mph" )
}
PostEventToChild( "${ TempID }", "windLull", it.value, "mph" )
}
break
case "wind_direction": // wind direction
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windDirection", it.value, "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( it.value ) )
}
PostEventToChild( "${ TempID }", "windDirection", it.value, "°" )
PostEventToChild( "${ TempID }", "WindDirectionString", MakeWindDirectionString( it.value ) )
break
case "solar_radiation": // solar radiation
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "SolarRadiation", it.value )
}
PostEventToChild( "${ TempID }", "SolarRadiation", it.value )
break
case "uv": // Outdoor uv
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "ultravioletIndex", it.value, "uvi" )
}
PostEventToChild( "${ TempID }", "ultravioletIndex", it.value, "uvi" )
break
case "uv_indoor": // Indoor uv
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "ultravioletIndexIndoor", it.value, "uvi" )
}
PostEventToChild( "${ TempID }", "ultravioletIndexIndoor", state.ultravioletIndexIndoor, "uvi" )
break
case "brightness": // Outdoor brightness
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "illuminance", it.value, "lux" )
}
PostEventToChild( "${ TempID }", "illuminance", it.value, "lux" )
break
case "brightness_indoor": // Indoor brightness
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "illuminanceIndoor", it.value, "lux" )
}
PostEventToChild( "${ TempID }", "illuminanceIndoor", state.illuminanceIndoor, "lux" )
break
case "lightning_strike_last_epoch": // lightning strike last epoch
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessState( "LightningStrikeLastEpoch", it.value )
ProcessEvent( "LightningStrikeLastDate", ConvertEpochToDate( it.value ) )
}
PostStateToChild( "${ TempID }", "LightningStrikeLastEpoch", it.value )
PostEventToChild( "${ TempID }", "LightningStrikeLastDate", ConvertEpochToDate( it.value ) )
break
case "lightning_strike_last_distance": // lightning strike last distance
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeLastDistance", it.value, "km" )
}
PostEventToChild( "${ TempID }", "LightningStrikeLastDistance", it.value, "km" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeLastDistance", ConvertMiles( "Metric", it.value ), "miles" )
}
PostEventToChild( "${ TempID }", "LightningStrikeLastDistance", ConvertMiles( "Metric", it.value ), "miles" )
}
break
case "lightning_strike_count": // lightning strike count
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeCount", it.value )
}
PostEventToChild( "${ TempID }", "LightningStrikeCount", it.value )
break
case "lightning_strike_count_last_1hr": // lightning strike count last 1hr
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeCountLast1hr", it.value )
}
PostEventToChild( "${ TempID }", "LightningStrikeCountLast1hr", it.value )
break
case "lightning_strike_count_last_3hr": // lightning strike count last 3hr
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeCountLast3hr", it.value )
}
PostEventToChild( "${ TempID }", "LightningStrikeCountLast3hr", it.value )
break
case "feels_like": // Outdoor feels like
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "feelsLike", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "feelsLike", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "feels_like_indoor": // Indoor feels like
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "feelsLikein", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "feelsLikein", state.feelsLikein, "°${ location.getTemperatureScale() }" )
break
case "heat_index": // Outdoor heat index
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "HeatIndex", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "HeatIndex", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "heat_index_indoor": // Indoor heat index
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "HeatIndexIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "HeatIndexIndoor", state.HeatIndexIndoor, "°${ location.getTemperatureScale() }" )
break
case "wind_chill": // Outdoor wind chill
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindChill", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "WindChill", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "wind_chill_indoor": // Indoor wind chill
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindChillIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "WindChillIndoor", state.WindChillIndoor, "°${ location.getTemperatureScale() }" )
break
case "dew_point": // Outdoor dew point
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "dewPoint", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "dewPoint", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "dew_point_indoor": // Indoor dew point
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "dewPointIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "dewPointIndoor", state.dewPointIndoor, "°${ location.getTemperatureScale() }" )
break
case "wet_bulb_temperature": // Outdoor wet bulb temperature
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WetBulbTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostEventToChild( "${ TempID }", "WetBulbTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
break
case "wet_bulb_temperature_indoor": // Indoor wet bulb temperature
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WetBulbTemperatureIndoor", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostStateToChild( "${ TempID }", "WetBulbTemperatureIndoor", state.WetBulbTemperatureIndoor )
break
case "wet_bulb_globe_temperature": //
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WetBulbGlobeTemperature", ConvertTemperature( "C", it.value ), "°${ location.getTemperatureScale() }" )
}
PostStateToChild( "${ TempID }", "WetBulbGlobeTemperature", state.WetBulbGlobeTemperature )
break
case "delta_t": // delta t
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessState( "DeltaT", it.value )
}
PostStateToChild( "${ TempID }", "DeltaT", state.DeltaT )
break
case "air_density": // air density
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "AirDensity", it.value )
}
PostStateToChild( "${ TempID }", "AirDensity", state.AirDensity )
break
case "precip_analysis_type_yesterday": // precip_analysis_type_yesterday
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipAnalysisTypeYesterday", it.value )
}
PostStateToChild( "${ TempID }", "PrecipAnalysisTypeYesterday", state.PrecipAnalysisTypeYesterday )
break
case "pressure_trend": // pressure_trend
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PressureTrend", "${ it.value }" )
}
PostStateToChild( "${ TempID }", "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 = null
def ParentSensorID = null
if( Data.device_id != null ){ // device_id
TempID = Data.device_id as int
}
if( state.ParentSensorID != null ){
ParentSensorID = state.ParentSensorID as int
}
if( TempID != null ){
if( Data.summary != null ){
if( Data.summary.heat_index != null ){ // heat_index
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PressureTrend", Data.summary.pressure_trend )
}
PostEventToChild( "${ TempID }", "PressureTrend", Data.summary.pressure_trend )
}
if( Data.summary.wind_chill != null ){ // wind_chill
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeLastDistance", Data.summary.strike_last_dist, "km" )
}
PostEventToChild( "${ TempID }", "LightningStrikeLastDistance", Data.summary.strike_last_dist, "km" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeCountLast3hr", Data.summary.strike_count_3h )
}
PostEventToChild( "${ TempID }", "LightningStrikeCountLast3hr", Data.summary.strike_count_3h )
}
if( Data.summary.feels_like != null ){ // feels_like
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeLastEpoch", Data.summary.strike_last_epoch )
ProcessEvent( "LightningStrikeLastDate", ConvertEpochToDate( Data.summary.strike_last_epoch ) )
}
PostEventToChild( "${ TempID }", "LightningStrikeLastEpoch", 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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
PostEventToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostEventToChild( "${ TempID }", "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Station Pressure (MB)
if( ( PressureUnits == "mbar" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Metric" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "StationPressure", Data.obs[ 0 ][ 1 ], "mb" )
}
PostEventToChild( "${ TempID }", "StationPressure", Data.obs[ 0 ][ 1 ], "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "psi" )
}
PostEventToChild( "${ TempID }", "StationPressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 1 ] ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 2 ] ), "°${ location.getTemperatureScale() }" )
ProcessEvent( "temperature", 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 (%)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RelativeHumidity", Data.obs[ 0 ][ 3 ], "%" )
ProcessEvent( "humidity", 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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeAverageDistance", Data.obs[ 0 ][ 5 ], "km" )
}
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", Data.obs[ 0 ][ 5 ], "km" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 6 ], "volts" )
}
PostStateToChild( "${ TempID }", "BatteryVoltage", Data.obs[ 0 ][ 6 ] )
if( Data.obs[ 0 ][ 6 ] >= 2.455 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
}
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 6 ] >= 2.41 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
}
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 6 ] >= 2.375 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
}
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 25, "%" )
}
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 7 ] != null ){ // 7 - Report Interval (minutes)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
PostEventToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostEventToChild( "${ TempID }", "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Illuminance (lux)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "illuminance", Data.obs[ 0 ][ 1 ], "lux" )
}
PostEventToChild( "${ TempID }", "illuminance", Data.obs[ 0 ][ 1 ], "lux" )
}
if( Data.obs[ 0 ][ 2 ] != null ){ // 2 - UV (index)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RainAccumulation", Data.obs[ 0 ][ 3 ], "mm" )
}
PostEventToChild( "${ TempID }", "RainAccumulation", Data.obs[ 0 ][ 3 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindLull", Data.obs[ 0 ][ 4 ], "m/s" )
}
PostEventToChild( "${ TempID }", "WindLull", Data.obs[ 0 ][ 4 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", Data.obs[ 0 ][ 5 ], "m/s" )
ProcessEvent( "windSpeed", Data.obs[ 0 ][ 5 ], "m/s" )
}
PostEventToChild( "${ TempID }", "WindAvg", Data.obs[ 0 ][ 5 ], "m/s" )
PostEventToChild( "${ TempID }", "windSpeed", Data.obs[ 0 ][ 5 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
ProcessEvent( "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 5 ] ), "mph" )
}
PostEventToChild( "${ TempID }", "WindAvg", 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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windGust", Data.obs[ 0 ][ 6 ], "m/s" )
}
PostEventToChild( "${ TempID }", "windGust", Data.obs[ 0 ][ 6 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windDirection", Data.obs[ 0 ][ 7 ], "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 7 ] ) )
}
PostEventToChild( "${ TempID }", "windDirection", Data.obs[ 0 ][ 7 ], "°" )
PostEventToChild( "${ TempID }", "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 7 ] ) )
}
if( Data.obs[ 0 ][ 8 ] != null ){ // 8 - Battery (volts)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 8 ], "volts" )
}
PostStateToChild( "${ TempID }", "BatteryVoltage", Data.obs[ 0 ][ 6 ] )
if( Data.obs[ 0 ][ 8 ] >= 2.455 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
}
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 8 ] >= 2.41 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
}
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 8 ] >= 2.375 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
}
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 25, "%" )
}
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 9 ] != null ){ // 9 - Report Interval (minutes)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LocalDayRainAccumulation", Data.obs[ 0 ][ 11 ], "mm" )
}
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", Data.obs[ 0 ][ 11 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationType", Data.obs[ 0 ][ 12 ] )
}
PostEventToChild( "${ TempID }", "PrecipitationType", Data.obs[ 0 ][ 12 ] )
switch( Data.obs[ 0 ][ 12 ] ){
case 0:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "none" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "none" )
break
case 1:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "rain" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain" )
break
case 2:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "hail" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "hail" )
break
case 3:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "rain + hail" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain + hail" )
break
}
}
if( Data.obs[ 0 ][ 13 ] != null ){ // 13 - Wind Sample Interval (seconds)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RainAccumulationFinal", Data.obs[ 0 ][ 14 ], "mm" )
}
PostEventToChild( "${ TempID }", "RainAccumulationFinal", Data.obs[ 0 ][ 14 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 15 ], "mm" )
}
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 15 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisType", Data.obs[ 0 ][ 16 ] )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisType", Data.obs[ 0 ][ 16 ] )
switch( Data.obs[ 0 ][ 16 ] ){
case 0:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisTypeString", "none" )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "none" )
break
case 1:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
break
case 2:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
ProcessEvent( "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
PostEventToChild( "${ TempID }", "TimestampEpoch", Data.obs[ 0 ][ 0 ] )
PostEventToChild( "${ TempID }", "TimestampString", ConvertEpochToDate( Data.obs[ 0 ][ 0 ] ) )
}
if( Data.obs[ 0 ][ 1 ] != null ){ // 1 - Wind Lull (m/s)
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindLull", Data.obs[ 0 ][ 1 ], "m/s" )
}
PostEventToChild( "${ TempID }", "WindLull", Data.obs[ 0 ][ 1 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", Data.obs[ 0 ][ 2 ], "m/s" )
ProcessEvent( "windSpeed", Data.obs[ 0 ][ 2 ], "m/s" )
}
PostEventToChild( "${ TempID }", "WindAvg", Data.obs[ 0 ][ 2 ], "m/s" )
PostEventToChild( "${ TempID }", "windSpeed", Data.obs[ 0 ][ 2 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "WindAvg", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
ProcessEvent( "windSpeed", ConvertMetersSecond( "Metric", Data.obs[ 0 ][ 2 ] ), "mph" )
}
PostEventToChild( "${ TempID }", "WindAvg", 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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windGust", Data.obs[ 0 ][ 3 ], "m/s" )
}
PostEventToChild( "${ TempID }", "windGust", Data.obs[ 0 ][ 3 ], "m/s" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "windDirection", Data.obs[ 0 ][ 4 ], "°" )
ProcessEvent( "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 4 ] ) )
}
PostEventToChild( "${ TempID }", "windDirection", Data.obs[ 0 ][ 4 ], "°" )
PostEventToChild( "${ TempID }", "WindDirectionString", MakeWindDirectionString( Data.obs[ 0 ][ 4 ] ) )
}
if( Data.obs[ 0 ][ 5 ] != null ){ // 5 - Wind Sample Interval (seconds)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "pressure", Data.obs[ 0 ][ 6 ], "mb" )
}
PostEventToChild( "${ TempID }", "pressure", Data.obs[ 0 ][ 6 ], "mb" )
} else if( ( PressureUnits == "psi" ) || ( ( PressureUnits == null ) && ( MeasurementStandard == "Imperial" ) ) ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "psi" )
}
PostEventToChild( "${ TempID }", "pressure", ConvertPressure( "Metric", Data.obs[ 0 ][ 6 ] ), "psi" )
} else if( PressureUnits == "inHG" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "AirTemperature", ConvertTemperature( "C", Data.obs[ 0 ][ 7 ] ), "°${ location.getTemperatureScale() }" )
ProcessEvent( "temperature", 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 (%)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RelativeHumidity", Data.obs[ 0 ][ 8 ], "%" )
ProcessEvent( "humidity", 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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "illuminance", Data.obs[ 0 ][ 9 ], "lux" )
}
PostEventToChild( "${ TempID }", "illuminance", Data.obs[ 0 ][ 9 ], "lux" )
}
if( Data.obs[ 0 ][ 10 ] != null ){ // 10 - UV (index)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RainAccumulation", Data.obs[ 0 ][ 12 ], "mm" )
}
PostEventToChild( "${ TempID }", "RainAccumulation", Data.obs[ 0 ][ 12 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationType", Data.obs[ 0 ][ 13 ] )
}
PostEventToChild( "${ TempID }", "PrecipitationType", Data.obs[ 0 ][ 13 ] )
switch( Data.obs[ 0 ][ 13 ] ){
case 0:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "none" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "none" )
break
case 1:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "rain" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain" )
break
case 2:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "hail" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "hail" )
break
case 3:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationTypeString", "rain + hail" )
}
PostEventToChild( "${ TempID }", "PrecipitationTypeString", "rain + hail" )
break
}
}
if( Data.obs[ 0 ][ 14 ] != null ){ // 14 - Average Strike Distance (km)
if( MeasurementStandard == "Metric" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeAverageDistance", Data.obs[ 0 ][ 14 ], "km" )
}
PostEventToChild( "${ TempID }", "LightningStrikeAverageDistance", Data.obs[ 0 ][ 14 ], "km" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LightningStrikeCount", Data.obs[ 0 ][ 15 ] )
}
PostEventToChild( "${ TempID }", "LightningStrikeCount", Data.obs[ 0 ][ 15 ] )
}
if( Data.obs[ 0 ][ 16 ] != null ){ // 16 - Battery (volts)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_Battery", Data.obs[ 0 ][ 16 ], "volts" )
}
PostStateToChild( "${ TempID }", "Battery Voltage", Data.obs[ 0 ][ 16 ] )
if( Data.obs[ 0 ][ 16 ] >= 2.455 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 100, "%" )
}
PostEventToChild( "${ TempID }", "battery", 100, "%" )
} else if( Data.obs[ 0 ][ 16 ] >= 2.41 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 75, "%" )
}
PostEventToChild( "${ TempID }", "battery", 75, "%" )
} else if( Data.obs[ 0 ][ 16 ] >= 2.375 ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 50, "%" )
}
PostEventToChild( "${ TempID }", "battery", 50, "%" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "${ TempID }_battery%", 25, "%" )
}
PostEventToChild( "${ TempID }", "battery", 25, "%" )
}
}
if( Data.obs[ 0 ][ 17 ] != null ){ // 17 - Report Interval (minutes)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LocalDayRainAccumulation", Data.obs[ 0 ][ 18 ], "mm" )
}
PostEventToChild( "${ TempID }", "LocalDayRainAccumulation", Data.obs[ 0 ][ 18 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "RainAccumulationFinal", Data.obs[ 0 ][ 19 ], "mm" )
}
PostEventToChild( "${ TempID }", "RainAccumulationFinal", Data.obs[ 0 ][ 19 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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" ){
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 20 ], "mm" )
}
PostEventToChild( "${ TempID }", "LocalDayRainAccumulationFinal", Data.obs[ 0 ][ 20 ], "mm" )
} else {
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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)
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisType", Data.obs[ 0 ][ 21 ] )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisType", Data.obs[ 0 ][ 21 ] )
switch( Data.obs[ 0 ][ 21 ] ){
case 0:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisTypeString", "none" )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "none" )
break
case 1:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
ProcessEvent( "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
}
PostEventToChild( "${ TempID }", "PrecipitationAnalysisTypeString", "Rain Check with user display on" )
break
case 2:
if( ( TempID == ParentSensorID ) || ( ParentSensorID == null ) ){
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 ${ ChildParent } Event: ${ Variable } = ${ Value }${ Unit }", 4 )
} else {
getChildDevice( "${ ChildParent }" ).ProcessEvent( "${ Variable }", Value )
Logging( "Child ${ ChildParent } 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 event ${ Variable } 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 ${ ChildParent } 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 state ${ Variable } 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
}
}
}