From 044330ee8d69fe00dfd062ba94fdff15975f99d9 Mon Sep 17 00:00:00 2001 From: Bob Florian Date: Thu, 20 Dec 2018 11:33:10 -0800 Subject: [PATCH] WWST-2091 Converted SmartWeather Station to TWC APIs (#3802) --- .../smartweather-station-tile.groovy | 569 +++++++++--------- 1 file changed, 288 insertions(+), 281 deletions(-) diff --git a/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy b/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy index aa1a9391..854314d8 100644 --- a/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy +++ b/devicetypes/smartthings/smartweather-station-tile.src/smartweather-station-tile.groovy @@ -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 +} \ No newline at end of file