WWST-2091 Converted SmartWeather Station to TWC APIs (#3802)
This commit is contained in:
@@ -17,355 +17,362 @@
|
||||
* Date: 2013-04-30
|
||||
*/
|
||||
metadata {
|
||||
definition (name: "SmartWeather Station Tile", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Illuminance Measurement"
|
||||
capability "Temperature Measurement"
|
||||
capability "Relative Humidity Measurement"
|
||||
capability "Ultraviolet Index"
|
||||
capability "Sensor"
|
||||
definition (name: "SmartWeather Station Tile", namespace: "smartthings", author: "SmartThings") {
|
||||
capability "Illuminance Measurement"
|
||||
capability "Temperature Measurement"
|
||||
capability "Relative Humidity Measurement"
|
||||
capability "Ultraviolet Index"
|
||||
capability "Sensor"
|
||||
capability "Refresh"
|
||||
|
||||
attribute "localSunrise", "string"
|
||||
attribute "localSunset", "string"
|
||||
attribute "city", "string"
|
||||
attribute "timeZoneOffset", "string"
|
||||
attribute "weather", "string"
|
||||
attribute "wind", "string"
|
||||
attribute "weatherIcon", "string"
|
||||
attribute "forecastIcon", "string"
|
||||
attribute "feelsLike", "string"
|
||||
attribute "percentPrecip", "string"
|
||||
attribute "alert", "string"
|
||||
attribute "alertKeys", "string"
|
||||
attribute "sunriseDate", "string"
|
||||
attribute "sunsetDate", "string"
|
||||
attribute "lastUpdate", "string"
|
||||
attribute "localSunrise", "string"
|
||||
attribute "localSunset", "string"
|
||||
attribute "city", "string"
|
||||
attribute "timeZoneOffset", "string"
|
||||
attribute "weather", "string"
|
||||
attribute "wind", "string"
|
||||
attribute "windVector", "string"
|
||||
attribute "weatherIcon", "string"
|
||||
attribute "forecastIcon", "string"
|
||||
attribute "feelsLike", "string"
|
||||
attribute "percentPrecip", "string"
|
||||
attribute "alert", "string"
|
||||
attribute "alertKeys", "string"
|
||||
attribute "sunriseDate", "string"
|
||||
attribute "sunsetDate", "string"
|
||||
attribute "lastUpdate", "string"
|
||||
attribute "uvDescription", "string"
|
||||
attribute "forecastToday", "string"
|
||||
attribute "forecastTonight", "string"
|
||||
attribute "forecastTomorrow", "string"
|
||||
}
|
||||
|
||||
command "refresh"
|
||||
}
|
||||
preferences {
|
||||
input "zipCode", "text", title: "Zip Code (optional)", required: false
|
||||
}
|
||||
|
||||
preferences {
|
||||
input "zipCode", "text", title: "Zip Code (optional)", required: false
|
||||
}
|
||||
tiles {
|
||||
valueTile("temperature", "device.temperature") {
|
||||
state "default", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
}
|
||||
|
||||
tiles {
|
||||
valueTile("temperature", "device.temperature") {
|
||||
state "default", label:'${currentValue}°',
|
||||
backgroundColors:[
|
||||
[value: 31, color: "#153591"],
|
||||
[value: 44, color: "#1e9cbb"],
|
||||
[value: 59, color: "#90d2a7"],
|
||||
[value: 74, color: "#44b621"],
|
||||
[value: 84, color: "#f1d801"],
|
||||
[value: 95, color: "#d04e00"],
|
||||
[value: 96, color: "#bc2323"]
|
||||
]
|
||||
}
|
||||
valueTile("humidity", "device.humidity", decoration: "flat") {
|
||||
state "default", label:'${currentValue}% humidity'
|
||||
}
|
||||
|
||||
valueTile("humidity", "device.humidity", decoration: "flat") {
|
||||
state "default", label:'${currentValue}% humidity'
|
||||
}
|
||||
standardTile("weatherIcon", "device.weatherIcon", decoration: "flat") {
|
||||
state "00", icon:"https://smartthings-twc-icons.s3.amazonaws.com/00.png", label: ""
|
||||
state "01", icon:"https://smartthings-twc-icons.s3.amazonaws.com/01.png", label: ""
|
||||
state "02", icon:"https://smartthings-twc-icons.s3.amazonaws.com/02.png", label: ""
|
||||
state "03", icon:"https://smartthings-twc-icons.s3.amazonaws.com/03.png", label: ""
|
||||
state "04", icon:"https://smartthings-twc-icons.s3.amazonaws.com/04.png", label: ""
|
||||
state "05", icon:"https://smartthings-twc-icons.s3.amazonaws.com/05.png", label: ""
|
||||
state "06", icon:"https://smartthings-twc-icons.s3.amazonaws.com/06.png", label: ""
|
||||
state "07", icon:"https://smartthings-twc-icons.s3.amazonaws.com/07.png", label: ""
|
||||
state "08", icon:"https://smartthings-twc-icons.s3.amazonaws.com/08.png", label: ""
|
||||
state "09", icon:"https://smartthings-twc-icons.s3.amazonaws.com/09.png", label: ""
|
||||
state "10", icon:"https://smartthings-twc-icons.s3.amazonaws.com/10.png", label: ""
|
||||
state "11", icon:"https://smartthings-twc-icons.s3.amazonaws.com/11.png", label: ""
|
||||
state "12", icon:"https://smartthings-twc-icons.s3.amazonaws.com/12.png", label: ""
|
||||
state "13", icon:"https://smartthings-twc-icons.s3.amazonaws.com/13.png", label: ""
|
||||
state "14", icon:"https://smartthings-twc-icons.s3.amazonaws.com/14.png", label: ""
|
||||
state "15", icon:"https://smartthings-twc-icons.s3.amazonaws.com/15.png", label: ""
|
||||
state "16", icon:"https://smartthings-twc-icons.s3.amazonaws.com/16.png", label: ""
|
||||
state "17", icon:"https://smartthings-twc-icons.s3.amazonaws.com/17.png", label: ""
|
||||
state "18", icon:"https://smartthings-twc-icons.s3.amazonaws.com/18.png", label: ""
|
||||
state "19", icon:"https://smartthings-twc-icons.s3.amazonaws.com/19.png", label: ""
|
||||
state "20", icon:"https://smartthings-twc-icons.s3.amazonaws.com/20.png", label: ""
|
||||
state "21", icon:"https://smartthings-twc-icons.s3.amazonaws.com/21.png", label: ""
|
||||
state "22", icon:"https://smartthings-twc-icons.s3.amazonaws.com/22.png", label: ""
|
||||
state "23", icon:"https://smartthings-twc-icons.s3.amazonaws.com/23.png", label: ""
|
||||
state "24", icon:"https://smartthings-twc-icons.s3.amazonaws.com/24.png", label: ""
|
||||
state "25", icon:"https://smartthings-twc-icons.s3.amazonaws.com/25.png", label: ""
|
||||
state "26", icon:"https://smartthings-twc-icons.s3.amazonaws.com/26.png", label: ""
|
||||
state "27", icon:"https://smartthings-twc-icons.s3.amazonaws.com/27.png", label: ""
|
||||
state "28", icon:"https://smartthings-twc-icons.s3.amazonaws.com/28.png", label: ""
|
||||
state "29", icon:"https://smartthings-twc-icons.s3.amazonaws.com/29.png", label: ""
|
||||
state "30", icon:"https://smartthings-twc-icons.s3.amazonaws.com/30.png", label: ""
|
||||
state "31", icon:"https://smartthings-twc-icons.s3.amazonaws.com/31.png", label: ""
|
||||
state "32", icon:"https://smartthings-twc-icons.s3.amazonaws.com/32.png", label: ""
|
||||
state "33", icon:"https://smartthings-twc-icons.s3.amazonaws.com/33.png", label: ""
|
||||
state "34", icon:"https://smartthings-twc-icons.s3.amazonaws.com/34.png", label: ""
|
||||
state "35", icon:"https://smartthings-twc-icons.s3.amazonaws.com/35.png", label: ""
|
||||
state "36", icon:"https://smartthings-twc-icons.s3.amazonaws.com/36.png", label: ""
|
||||
state "37", icon:"https://smartthings-twc-icons.s3.amazonaws.com/37.png", label: ""
|
||||
state "38", icon:"https://smartthings-twc-icons.s3.amazonaws.com/38.png", label: ""
|
||||
state "39", icon:"https://smartthings-twc-icons.s3.amazonaws.com/39.png", label: ""
|
||||
state "40", icon:"https://smartthings-twc-icons.s3.amazonaws.com/40.png", label: ""
|
||||
state "41", icon:"https://smartthings-twc-icons.s3.amazonaws.com/41.png", label: ""
|
||||
state "42", icon:"https://smartthings-twc-icons.s3.amazonaws.com/42.png", label: ""
|
||||
state "43", icon:"https://smartthings-twc-icons.s3.amazonaws.com/43.png", label: ""
|
||||
state "44", icon:"https://smartthings-twc-icons.s3.amazonaws.com/44.png", label: ""
|
||||
state "45", icon:"https://smartthings-twc-icons.s3.amazonaws.com/45.png", label: ""
|
||||
state "46", icon:"https://smartthings-twc-icons.s3.amazonaws.com/46.png", label: ""
|
||||
state "47", icon:"https://smartthings-twc-icons.s3.amazonaws.com/47.png", label: ""
|
||||
state "na", icon:"https://smartthings-twc-icons.s3.amazonaws.com/na.png", label: ""
|
||||
}
|
||||
|
||||
standardTile("weatherIcon", "device.weatherIcon", decoration: "flat") {
|
||||
state "chanceflurries", icon:"st.custom.wu1.chanceflurries", label: ""
|
||||
state "chancerain", icon:"st.custom.wu1.chancerain", label: ""
|
||||
state "chancesleet", icon:"st.custom.wu1.chancesleet", label: ""
|
||||
state "chancesnow", icon:"st.custom.wu1.chancesnow", label: ""
|
||||
state "chancetstorms", icon:"st.custom.wu1.chancetstorms", label: ""
|
||||
state "clear", icon:"st.custom.wu1.clear", label: ""
|
||||
state "cloudy", icon:"st.custom.wu1.cloudy", label: ""
|
||||
state "flurries", icon:"st.custom.wu1.flurries", label: ""
|
||||
state "fog", icon:"st.custom.wu1.fog", label: ""
|
||||
state "hazy", icon:"st.custom.wu1.hazy", label: ""
|
||||
state "mostlycloudy", icon:"st.custom.wu1.mostlycloudy", label: ""
|
||||
state "mostlysunny", icon:"st.custom.wu1.mostlysunny", label: ""
|
||||
state "partlycloudy", icon:"st.custom.wu1.partlycloudy", label: ""
|
||||
state "partlysunny", icon:"st.custom.wu1.partlysunny", label: ""
|
||||
state "rain", icon:"st.custom.wu1.rain", label: ""
|
||||
state "sleet", icon:"st.custom.wu1.sleet", label: ""
|
||||
state "snow", icon:"st.custom.wu1.snow", label: ""
|
||||
state "sunny", icon:"st.custom.wu1.sunny", label: ""
|
||||
state "tstorms", icon:"st.custom.wu1.tstorms", label: ""
|
||||
state "cloudy", icon:"st.custom.wu1.cloudy", label: ""
|
||||
state "partlycloudy", icon:"st.custom.wu1.partlycloudy", label: ""
|
||||
state "nt_chanceflurries", icon:"st.custom.wu1.nt_chanceflurries", label: ""
|
||||
state "nt_chancerain", icon:"st.custom.wu1.nt_chancerain", label: ""
|
||||
state "nt_chancesleet", icon:"st.custom.wu1.nt_chancesleet", label: ""
|
||||
state "nt_chancesnow", icon:"st.custom.wu1.nt_chancesnow", label: ""
|
||||
state "nt_chancetstorms", icon:"st.custom.wu1.nt_chancetstorms", label: ""
|
||||
state "nt_clear", icon:"st.custom.wu1.nt_clear", label: ""
|
||||
state "nt_cloudy", icon:"st.custom.wu1.nt_cloudy", label: ""
|
||||
state "nt_flurries", icon:"st.custom.wu1.nt_flurries", label: ""
|
||||
state "nt_fog", icon:"st.custom.wu1.nt_fog", label: ""
|
||||
state "nt_hazy", icon:"st.custom.wu1.nt_hazy", label: ""
|
||||
state "nt_mostlycloudy", icon:"st.custom.wu1.nt_mostlycloudy", label: ""
|
||||
state "nt_mostlysunny", icon:"st.custom.wu1.nt_mostlysunny", label: ""
|
||||
state "nt_partlycloudy", icon:"st.custom.wu1.nt_partlycloudy", label: ""
|
||||
state "nt_partlysunny", icon:"st.custom.wu1.nt_partlysunny", label: ""
|
||||
state "nt_sleet", icon:"st.custom.wu1.nt_sleet", label: ""
|
||||
state "nt_rain", icon:"st.custom.wu1.nt_rain", label: ""
|
||||
state "nt_sleet", icon:"st.custom.wu1.nt_sleet", label: ""
|
||||
state "nt_snow", icon:"st.custom.wu1.nt_snow", label: ""
|
||||
state "nt_sunny", icon:"st.custom.wu1.nt_sunny", label: ""
|
||||
state "nt_tstorms", icon:"st.custom.wu1.nt_tstorms", label: ""
|
||||
state "nt_cloudy", icon:"st.custom.wu1.nt_cloudy", label: ""
|
||||
state "nt_partlycloudy", icon:"st.custom.wu1.nt_partlycloudy", label: ""
|
||||
}
|
||||
|
||||
valueTile("feelsLike", "device.feelsLike", decoration: "flat") {
|
||||
state "default", label:'feels like ${currentValue}°'
|
||||
}
|
||||
valueTile("feelsLike", "device.feelsLike", decoration: "flat") {
|
||||
state "default", label:'feels like ${currentValue}°'
|
||||
}
|
||||
|
||||
valueTile("wind", "device.wind", decoration: "flat") {
|
||||
state "default", label:'wind ${currentValue} mph'
|
||||
}
|
||||
valueTile("wind", "device.windVector", decoration: "flat") {
|
||||
state "default", label:'wind ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("weather", "device.weather", decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
valueTile("weather", "device.weather", decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("city", "device.city", decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
valueTile("city", "device.city", decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("percentPrecip", "device.percentPrecip", decoration: "flat") {
|
||||
state "default", label:'${currentValue}% precip'
|
||||
}
|
||||
valueTile("percentPrecip", "device.percentPrecip", decoration: "flat") {
|
||||
state "default", label:'${currentValue}% precip'
|
||||
}
|
||||
|
||||
valueTile("ultravioletIndex", "device.ultravioletIndex", decoration: "flat") {
|
||||
state "default", label:'${currentValue} UV index'
|
||||
}
|
||||
valueTile("ultravioletIndex", "device.uvDescription", decoration: "flat") {
|
||||
state "default", label:'UV ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("alert", "device.alert", width: 2, height: 1, decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
|
||||
standardTile("refresh", "device.weather", decoration: "flat") {
|
||||
state "default", label: "", action: "refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
valueTile("alert", "device.alert", width: 2, height: 1, decoration: "flat") {
|
||||
state "default", label:'${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("rise", "device.localSunrise", decoration: "flat") {
|
||||
state "default", label:'Sunrise ${currentValue}'
|
||||
}
|
||||
standardTile("refresh", "device.weather", decoration: "flat") {
|
||||
state "default", label: "", action: "refresh", icon:"st.secondary.refresh"
|
||||
}
|
||||
|
||||
valueTile("set", "device.localSunset", decoration: "flat") {
|
||||
state "default", label:'Sunset ${currentValue}'
|
||||
}
|
||||
valueTile("rise", "device.localSunrise", decoration: "flat") {
|
||||
state "default", label:'Sunrise ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("light", "device.illuminance", decoration: "flat") {
|
||||
state "default", label:'${currentValue} lux'
|
||||
}
|
||||
|
||||
valueTile("lastUpdate", "device.lastUpdate", width: 3, height: 1, decoration: "flat") {
|
||||
state "default", label:'Last update:\n${currentValue}'
|
||||
}
|
||||
valueTile("set", "device.localSunset", decoration: "flat") {
|
||||
state "default", label:'Sunset ${currentValue}'
|
||||
}
|
||||
|
||||
main(["temperature", "weatherIcon","feelsLike"])
|
||||
details(["temperature", "humidity", "weatherIcon", "feelsLike", "wind", "weather", "city", "percentPrecip", "ultravioletIndex", "alert", "refresh", "rise", "set", "light", "lastUpdate"])}
|
||||
valueTile("light", "device.illuminance", decoration: "flat") {
|
||||
state "default", label:'${currentValue} lux'
|
||||
}
|
||||
|
||||
valueTile("city", "device.forecastToday", decoration: "flat") {
|
||||
state "default", label:'Today: ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("city", "device.forecastTonight", decoration: "flat") {
|
||||
state "default", label:'Tonight: ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("city", "device.forecastTomorrow", decoration: "flat") {
|
||||
state "default", label:'Tomorrow: ${currentValue}'
|
||||
}
|
||||
|
||||
valueTile("lastUpdate", "device.lastUpdate", width: 3, height: 1, decoration: "flat") {
|
||||
state "default", label:'Last update:\n${currentValue}'
|
||||
}
|
||||
|
||||
main(["temperature", "weatherIcon","feelsLike"])
|
||||
details(["temperature", "humidity", "weatherIcon", "feelsLike", "wind",
|
||||
"weather", "city", "percentPrecip", "ultravioletIndex", "alert",
|
||||
"refresh", "rise", "set", "light", "lastUpdate"])}
|
||||
}
|
||||
|
||||
// parse events into attributes
|
||||
def parse(String description) {
|
||||
log.debug "Parsing '${description}'"
|
||||
log.debug "Parsing '${description}'"
|
||||
}
|
||||
|
||||
def installed() {
|
||||
poll()
|
||||
runEvery30Minutes(poll)
|
||||
poll()
|
||||
runEvery30Minutes(poll)
|
||||
}
|
||||
|
||||
def uninstalled() {
|
||||
unschedule()
|
||||
unschedule()
|
||||
}
|
||||
|
||||
// handle commands
|
||||
def poll() {
|
||||
log.debug "WUSTATION: Executing 'poll', location: ${location.name}"
|
||||
log.info "WUSTATION: Executing 'poll', location: ${location.name}"
|
||||
|
||||
// Last update time stamp
|
||||
def timeStamp = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
|
||||
sendEvent(name: "lastUpdate", value: timeStamp)
|
||||
// Last update time stamp
|
||||
def timeStamp = new Date().format("yyyy MMM dd EEE h:mm:ss a", location.timeZone)
|
||||
sendEvent(name: "lastUpdate", value: timeStamp)
|
||||
|
||||
// Current conditions
|
||||
def obs = get("conditions")?.current_observation
|
||||
if (obs) {
|
||||
def weatherIcon = obs.icon_url.split("/")[-1].split("\\.")[0]
|
||||
// Current conditions
|
||||
def tempUnits = getTemperatureScale()
|
||||
def obs = getTwcConditions(zipCode)
|
||||
if (obs) {
|
||||
// TODO def weatherIcon = obs.icon_url.split("/")[-1].split("\\.")[0]
|
||||
|
||||
if(getTemperatureScale() == "C") {
|
||||
send(name: "temperature", value: Math.round(obs.temp_c), unit: "C")
|
||||
send(name: "feelsLike", value: Math.round(obs.feelslike_c as Double), unit: "C")
|
||||
} else {
|
||||
send(name: "temperature", value: Math.round(obs.temp_f), unit: "F")
|
||||
send(name: "feelsLike", value: Math.round(obs.feelslike_f as Double), unit: "F")
|
||||
}
|
||||
|
||||
send(name: "humidity", value: obs.relative_humidity[0..-2] as Integer, unit: "%")
|
||||
send(name: "weather", value: obs.weather)
|
||||
send(name: "weatherIcon", value: weatherIcon, displayed: false)
|
||||
send(name: "wind", value: Math.round(obs.wind_mph) as String, unit: "MPH") // as String because of bug in determining state change of 0 numbers
|
||||
send(name: "temperature", value: obs.temperature, unit: tempUnits)
|
||||
send(name: "feelsLike", value: obs.temperatureFeelsLike, unit: tempUnits)
|
||||
|
||||
if (obs.local_tz_offset != device.currentValue("timeZoneOffset")) {
|
||||
send(name: "timeZoneOffset", value: obs.local_tz_offset, isStateChange: true)
|
||||
}
|
||||
send(name: "humidity", value: obs.relativeHumidity, unit: "%")
|
||||
send(name: "weather", value: obs.wxPhraseShort)
|
||||
send(name: "weatherIcon", value: obs.iconCode as String, displayed: false)
|
||||
send(name: "wind", value: obs.windSpeed as String, unit: tempUnits == "C" ? "KPH" : "MPH") // as String because of bug in determining state change of 0 numbers
|
||||
send(name: "windVector", value: "${obs.windDirectionCardinal}@${obs.windSpeed}", unit: tempUnits == "C" ? "KPH" : "MPH")
|
||||
log.trace "Getting location info"
|
||||
def loc = getTwcLocation(zipCode).location
|
||||
def cityValue = "${loc.city}, ${loc.adminDistrictCode} ${loc.countryCode}"
|
||||
if (cityValue != device.currentValue("city")) {
|
||||
send(name: "city", value: cityValue, isStateChange: true)
|
||||
}
|
||||
|
||||
def cityValue = "${obs.display_location.city}, ${obs.display_location.state}"
|
||||
if (cityValue != device.currentValue("city")) {
|
||||
send(name: "city", value: cityValue, isStateChange: true)
|
||||
}
|
||||
send(name: "ultravioletIndex", value: obs.uvIndex)
|
||||
send(name: "uvDescription", value: obs.uvDescription)
|
||||
|
||||
send(name: "ultravioletIndex", value: Math.round(obs.UV as Double))
|
||||
def dtf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
|
||||
// Sunrise / Sunset
|
||||
def a = get("astronomy")?.moon_phase
|
||||
def today = localDate("GMT${obs.local_tz_offset}")
|
||||
def ltf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm")
|
||||
ltf.setTimeZone(TimeZone.getTimeZone("GMT${obs.local_tz_offset}"))
|
||||
def utf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
utf.setTimeZone(TimeZone.getTimeZone("GMT"))
|
||||
def sunriseDate = dtf.parse(obs.sunriseTimeLocal)
|
||||
log.info "'${obs.sunriseTimeLocal}'"
|
||||
|
||||
def sunriseDate = ltf.parse("${today} ${a.sunrise.hour}:${a.sunrise.minute}")
|
||||
def sunsetDate = ltf.parse("${today} ${a.sunset.hour}:${a.sunset.minute}")
|
||||
def sunsetDate = dtf.parse(obs.sunsetTimeLocal)
|
||||
|
||||
def tf = new java.text.SimpleDateFormat("h:mm a")
|
||||
tf.setTimeZone(TimeZone.getTimeZone("GMT${obs.local_tz_offset}"))
|
||||
tf.setTimeZone(TimeZone.getTimeZone(loc.ianaTimeZone))
|
||||
|
||||
def localSunrise = "${tf.format(sunriseDate)}"
|
||||
def localSunset = "${tf.format(sunsetDate)}"
|
||||
send(name: "localSunrise", value: localSunrise, descriptionText: "Sunrise today is at $localSunrise")
|
||||
send(name: "localSunset", value: localSunset, descriptionText: "Sunset today at is $localSunset")
|
||||
|
||||
send(name: "illuminance", value: estimateLux(sunriseDate, sunsetDate, weatherIcon))
|
||||
send(name: "illuminance", value: estimateLux(obs, sunriseDate, sunsetDate))
|
||||
|
||||
// Forecast
|
||||
def f = get("forecast")
|
||||
def f1= f?.forecast?.simpleforecast?.forecastday
|
||||
if (f1) {
|
||||
def icon = f1[0].icon_url.split("/")[-1].split("\\.")[0]
|
||||
def value = f1[0].pop as String // as String because of bug in determining state change of 0 numbers
|
||||
send(name: "percentPrecip", value: value, unit: "%")
|
||||
send(name: "forecastIcon", value: icon, displayed: false)
|
||||
}
|
||||
else {
|
||||
log.warn "Forecast not found"
|
||||
}
|
||||
// Forecast
|
||||
def f = getTwcForecast(zipCode)
|
||||
if (f) {
|
||||
def icon = f.daypart[0].iconCode[0] ?: f.daypart[0].iconCode[1]
|
||||
def value = f.daypart[0].precipChance[0] ?: f.daypart[0].precipChance[1]
|
||||
def narrative = f.daypart[0].narrative
|
||||
send(name: "percentPrecip", value: value, unit: "%")
|
||||
send(name: "forecastIcon", value: icon, displayed: false)
|
||||
send(name: "forecastToday", value: narrative[0])
|
||||
send(name: "forecastTonight", value: narrative[1])
|
||||
send(name: "forecastTomorrow", value: narrative[2])
|
||||
}
|
||||
else {
|
||||
log.warn "Forecast not found"
|
||||
}
|
||||
|
||||
// Alerts
|
||||
def alerts = get("alerts")?.alerts
|
||||
def newKeys = alerts?.collect{it.type + it.date_epoch} ?: []
|
||||
log.debug "WUSTATION: newKeys = $newKeys"
|
||||
log.trace device.currentState("alertKeys")
|
||||
def oldKeys = device.currentState("alertKeys")?.jsonValue
|
||||
log.debug "WUSTATION: oldKeys = $oldKeys"
|
||||
// Alerts
|
||||
def alerts = getTwcAlerts(zipCode)
|
||||
if (alerts) {
|
||||
alerts.each {alert ->
|
||||
def msg = alert.headlineText
|
||||
if (alert.effectiveTimeLocal && !msg.contains(" from ")) {
|
||||
msg += " from ${parseAlertTime(alert.effectiveTimeLocal).format("E hh:mm a", TimeZone.getTimeZone(alert.effectiveTimeLocalTimeZone))}"
|
||||
}
|
||||
if (alert.expireTimeLocal && !msg.contains(" until ")) {
|
||||
msg += " until ${parseAlertTime(alert.expireTimeLocal).format("E hh:mm a", TimeZone.getTimeZone(alert.expireTimeLocalTimeZone))}"
|
||||
}
|
||||
send(name: "alert", value: msg, descriptionText: msg)
|
||||
}
|
||||
}
|
||||
else {
|
||||
send(name: "alert", value: "No current alerts", descriptionText: msg)
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "No response from TWC API"
|
||||
}
|
||||
}
|
||||
|
||||
def noneString = "no current weather alerts"
|
||||
if (!newKeys && oldKeys == null) {
|
||||
send(name: "alertKeys", value: newKeys.encodeAsJSON(), displayed: false)
|
||||
send(name: "alert", value: noneString, descriptionText: "${device.displayName} has no current weather alerts", isStateChange: true)
|
||||
}
|
||||
else if (newKeys != oldKeys) {
|
||||
if (oldKeys == null) {
|
||||
oldKeys = []
|
||||
}
|
||||
send(name: "alertKeys", value: newKeys.encodeAsJSON(), displayed: false)
|
||||
|
||||
def newAlerts = false
|
||||
alerts.each {alert ->
|
||||
if (!oldKeys.contains(alert.type + alert.date_epoch)) {
|
||||
def msg = "${alert.description} from ${alert.date} until ${alert.expires}"
|
||||
send(name: "alert", value: pad(alert.description), descriptionText: msg, isStateChange: true)
|
||||
newAlerts = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!newAlerts && device.currentValue("alert") != noneString) {
|
||||
send(name: "alert", value: noneString, descriptionText: "${device.displayName} has no current weather alerts", isStateChange: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.warn "No response from Weather Underground API"
|
||||
}
|
||||
def parseAlertTime(s) {
|
||||
def dtf = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
def s2 = s.replaceAll(/([0-9][0-9]):([0-9][0-9])$/,'$1$2')
|
||||
dtf.parse(s2)
|
||||
}
|
||||
|
||||
def refresh() {
|
||||
poll()
|
||||
poll()
|
||||
}
|
||||
|
||||
def configure() {
|
||||
poll()
|
||||
poll()
|
||||
}
|
||||
|
||||
private pad(String s, size = 25) {
|
||||
def n = (size - s.size()) / 2
|
||||
if (n > 0) {
|
||||
def sb = ""
|
||||
n.times {sb += " "}
|
||||
sb += s
|
||||
n.times {sb += " "}
|
||||
return sb
|
||||
}
|
||||
else {
|
||||
return s
|
||||
}
|
||||
def n = (size - s.size()) / 2
|
||||
if (n > 0) {
|
||||
def sb = ""
|
||||
n.times {sb += " "}
|
||||
sb += s
|
||||
n.times {sb += " "}
|
||||
return sb
|
||||
}
|
||||
else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private get(feature) {
|
||||
getWeatherFeature(feature, zipCode)
|
||||
getWeatherFeature(feature, zipCode)
|
||||
}
|
||||
|
||||
private localDate(timeZone) {
|
||||
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
|
||||
df.setTimeZone(TimeZone.getTimeZone(timeZone))
|
||||
df.format(new Date())
|
||||
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
|
||||
df.setTimeZone(TimeZone.getTimeZone(timeZone))
|
||||
df.format(new Date())
|
||||
}
|
||||
|
||||
private send(map) {
|
||||
log.debug "WUSTATION: event: $map"
|
||||
sendEvent(map)
|
||||
log.debug "WUSTATION: event: $map"
|
||||
sendEvent(map)
|
||||
}
|
||||
|
||||
private estimateLux(sunriseDate, sunsetDate, weatherIcon) {
|
||||
def lux = 0
|
||||
def now = new Date().time
|
||||
if (now > sunriseDate.time && now < sunsetDate.time) {
|
||||
//day
|
||||
switch(weatherIcon) {
|
||||
case 'tstorms':
|
||||
lux = 200
|
||||
break
|
||||
case ['cloudy', 'fog', 'rain', 'sleet', 'snow', 'flurries',
|
||||
'chanceflurries', 'chancerain', 'chancesleet',
|
||||
'chancesnow', 'chancetstorms']:
|
||||
lux = 1000
|
||||
break
|
||||
case 'mostlycloudy':
|
||||
lux = 2500
|
||||
break
|
||||
case ['partlysunny', 'partlycloudy', 'hazy']:
|
||||
lux = 7500
|
||||
break
|
||||
default:
|
||||
//sunny, clear
|
||||
lux = 10000
|
||||
}
|
||||
private estimateLux(obs, sunriseDate, sunsetDate) {
|
||||
def lux = 0
|
||||
if (obs.dayOrNight == 'N') {
|
||||
lux = 10
|
||||
}
|
||||
else {
|
||||
//day
|
||||
switch(obs.iconCode) {
|
||||
case '04':
|
||||
lux = 200
|
||||
break
|
||||
case ['05', '06', '07', '08', '09', '10',
|
||||
'11', '12', '13','14', '15','17','18','19','20',
|
||||
'21','22','23','24','25','26']:
|
||||
lux = 1000
|
||||
break
|
||||
case ['27', '28']:
|
||||
lux = 2500
|
||||
break
|
||||
case ['29', '30']:
|
||||
lux = 7500
|
||||
break
|
||||
default:
|
||||
//sunny, clear
|
||||
lux = 10000
|
||||
}
|
||||
|
||||
//adjust for dusk/dawn
|
||||
def afterSunrise = now - sunriseDate.time
|
||||
def beforeSunset = sunsetDate.time - now
|
||||
def oneHour = 1000 * 60 * 60
|
||||
//adjust for dusk/dawn
|
||||
def now = new Date().time
|
||||
def afterSunrise = now - sunriseDate.time
|
||||
def beforeSunset = sunsetDate.time - now
|
||||
def oneHour = 1000 * 60 * 60
|
||||
|
||||
if(afterSunrise < oneHour) {
|
||||
//dawn
|
||||
lux = (long)(lux * (afterSunrise/oneHour))
|
||||
} else if (beforeSunset < oneHour) {
|
||||
//dusk
|
||||
lux = (long)(lux * (beforeSunset/oneHour))
|
||||
}
|
||||
}
|
||||
else {
|
||||
//night - always set to 10 for now
|
||||
//could do calculations for dusk/dawn too
|
||||
lux = 10
|
||||
}
|
||||
|
||||
lux
|
||||
}
|
||||
if(afterSunrise < oneHour) {
|
||||
//dawn
|
||||
lux = (long)(lux * (afterSunrise/oneHour))
|
||||
} else if (beforeSunset < oneHour) {
|
||||
//dusk
|
||||
lux = (long)(lux * (beforeSunset/oneHour))
|
||||
}
|
||||
}
|
||||
lux
|
||||
}
|
||||
Reference in New Issue
Block a user