diff --git a/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy b/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy index 91694c9e8ce..853b15f8e59 100644 --- a/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-ki-thermostat.src/stelpro-ki-thermostat.groovy @@ -4,7 +4,7 @@ * 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 + * 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 @@ -19,214 +19,214 @@ import physicalgraph.zwave.commands.* metadata { - definition (name: "Stelpro Ki Thermostat", namespace: "stelpro", author: "Stelpro", ocfDeviceType: "oic.d.thermostat") { - capability "Actuator" - capability "Temperature Measurement" - capability "Temperature Alarm" - capability "Thermostat" - capability "Thermostat Mode" - capability "Thermostat Operating State" - capability "Thermostat Heating Setpoint" - capability "Configuration" - capability "Sensor" - capability "Refresh" - capability "Health Check" - - // Right now this can disrupt device health if the device is currently offline -- it would be erroneously marked online. - //attribute "outsideTemp", "number" - - command "setOutdoorTemperature" - command "quickSetOutTemp" // Maintain backward compatibility with self published versions of the "Stelpro Get Remote Temperature" SmartApp - command "increaseHeatSetpoint" - command "decreaseHeatSetpoint" - command "eco" // Command does not exist in "Thermostat Mode" - command "updateWeather" - - fingerprint deviceId: "0x0806", inClusters: "0x5E,0x86,0x72,0x40,0x43,0x31,0x85,0x59,0x5A,0x73,0x20,0x42", mfr: "0239", prod: "0001", model: "0001", deviceJoinName: "Stelpro Ki Thermostat" - } - - // simulator metadata - simulator { } - - preferences { - input("heatdetails", "enum", title: "Do you want a detailed operating state notification?", options: ["No", "Yes"], defaultValue: "No", required: true, displayDuringSetup: true) - input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "[Do not use space](Blank = No Forecast)") - } - - tiles(scale : 2) { - multiAttributeTile(name:"thermostatMulti", type:"thermostat", width:6, height:4, canChangeIcon: true) { - tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { - attributeState("temperature", label:'${currentValue}°', icon: "st.alarm.temperature.normal") - } - tileAttribute("device.heatingSetpoint", key: "VALUE_CONTROL") { - attributeState("VALUE_UP", action: "increaseHeatSetpoint") - attributeState("VALUE_DOWN", action: "decreaseHeatSetpoint") - } - tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { - attributeState("idle", backgroundColor:"#44b621") - attributeState("heating", backgroundColor:"#ffa81e") - } - tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { - attributeState("heat", label:'${name}') - attributeState("eco", label:'${name}') - } - tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { - attributeState("heatingSetpoint", label:'${currentValue}°') - } - } - standardTile("mode", "device.thermostatMode", width: 2, height: 2) { - state "heat", label:'${name}', action:"eco", nextState:"eco", icon:"st.Home.home29" - state "eco", label:'${name}', action:"heat", nextState:"heat", icon:"st.Outdoor.outdoor3" - } - valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2) { - state "heatingSetpoint", label:'Setpoint ${currentValue}°', backgroundColors:[ - // Celsius - [value: 0, color: "#153591"], - [value: 7, color: "#1e9cbb"], - [value: 15, color: "#90d2a7"], - [value: 23, color: "#44b621"], - [value: 28, color: "#f1d801"], - [value: 35, color: "#d04e00"], - [value: 37, color: "#bc2323"], - // Fahrenheit - [value: 40, 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"] - ] - } - standardTile("temperatureAlarm", "device.temperatureAlarm", decoration: "flat", width: 2, height: 2) { - state "default", label: 'No Alarm', icon: "st.alarm.temperature.normal", backgroundColor: "#ffffff" - state "cleared", label: 'No Alarm', icon: "st.alarm.temperature.normal", backgroundColor: "#ffffff" - state "freeze", label: 'Freeze', icon: "st.alarm.temperature.freeze", backgroundColor: "#bc2323" - state "heat", label: 'Overheat', icon: "st.alarm.temperature.overheat", backgroundColor: "#bc2323" - } - standardTile("refresh", "device.refresh", decoration: "flat", width: 2, height: 2) { - state "default", action:"refresh.refresh", icon:"st.secondary.refresh" - } - - main ("thermostatMulti") - details(["thermostatMulti", "mode", "heatingSetpoint", "temperatureAlarm", "refresh"]) - } + definition (name: "Stelpro Ki Thermostat", namespace: "stelpro", author: "Stelpro", ocfDeviceType: "oic.d.thermostat") { + capability "Actuator" + capability "Temperature Measurement" + capability "Temperature Alarm" + capability "Thermostat" + capability "Thermostat Mode" + capability "Thermostat Operating State" + capability "Thermostat Heating Setpoint" + capability "Configuration" + capability "Sensor" + capability "Refresh" + capability "Health Check" + + // Right now this can disrupt device health if the device is currently offline -- it would be erroneously marked online. + //attribute "outsideTemp", "number" + + command "setOutdoorTemperature" + command "quickSetOutTemp" // Maintain backward compatibility with self published versions of the "Stelpro Get Remote Temperature" SmartApp + command "increaseHeatSetpoint" + command "decreaseHeatSetpoint" + command "eco" // Command does not exist in "Thermostat Mode" + command "updateWeather" + + fingerprint deviceId: "0x0806", inClusters: "0x5E,0x86,0x72,0x40,0x43,0x31,0x85,0x59,0x5A,0x73,0x20,0x42", mfr: "0239", prod: "0001", model: "0001", deviceJoinName: "Stelpro Ki Thermostat" + } + + // simulator metadata + simulator { } + + preferences { + input("heatdetails", "enum", title: "Do you want a detailed operating state notification?", options: ["No", "Yes"], defaultValue: "No", required: true, displayDuringSetup: true) + input("zipcode", "text", title: "ZipCode (Outdoor Temperature)", description: "[Do not use space](Blank = No Forecast)") + } + + tiles(scale : 2) { + multiAttributeTile(name:"thermostatMulti", type:"thermostat", width:6, height:4, canChangeIcon: true) { + tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { + attributeState("temperature", label:'${currentValue}°', icon: "st.alarm.temperature.normal") + } + tileAttribute("device.heatingSetpoint", key: "VALUE_CONTROL") { + attributeState("VALUE_UP", action: "increaseHeatSetpoint") + attributeState("VALUE_DOWN", action: "decreaseHeatSetpoint") + } + tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { + attributeState("idle", backgroundColor:"#44b621") + attributeState("heating", backgroundColor:"#ffa81e") + } + tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { + attributeState("heat", label:'${name}') + attributeState("eco", label:'${name}') + } + tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { + attributeState("heatingSetpoint", label:'${currentValue}°') + } + } + standardTile("mode", "device.thermostatMode", width: 2, height: 2) { + state "heat", label:'${name}', action:"eco", nextState:"eco", icon:"st.Home.home29" + state "eco", label:'${name}', action:"heat", nextState:"heat", icon:"st.Outdoor.outdoor3" + } + valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2) { + state "heatingSetpoint", label:'Setpoint ${currentValue}°', backgroundColors:[ + // Celsius + [value: 0, color: "#153591"], + [value: 7, color: "#1e9cbb"], + [value: 15, color: "#90d2a7"], + [value: 23, color: "#44b621"], + [value: 28, color: "#f1d801"], + [value: 35, color: "#d04e00"], + [value: 37, color: "#bc2323"], + // Fahrenheit + [value: 40, 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"] + ] + } + standardTile("temperatureAlarm", "device.temperatureAlarm", decoration: "flat", width: 2, height: 2) { + state "default", label: 'No Alarm', icon: "st.alarm.temperature.normal", backgroundColor: "#ffffff" + state "cleared", label: 'No Alarm', icon: "st.alarm.temperature.normal", backgroundColor: "#ffffff" + state "freeze", label: 'Freeze', icon: "st.alarm.temperature.freeze", backgroundColor: "#bc2323" + state "heat", label: 'Overheat', icon: "st.alarm.temperature.overheat", backgroundColor: "#bc2323" + } + standardTile("refresh", "device.refresh", decoration: "flat", width: 2, height: 2) { + state "default", action:"refresh.refresh", icon:"st.secondary.refresh" + } + + main ("thermostatMulti") + details(["thermostatMulti", "mode", "heatingSetpoint", "temperatureAlarm", "refresh"]) + } } def getSupportedThermostatModes() { - ["heat", "eco"] + ["heat", "eco"] } def getMinSetpointIndex() { - 0 + 0 } def getMaxSetpointIndex() { - 1 + 1 } def getThermostatSetpointRange() { - (getTemperatureScale() == "C") ? [5, 30] : [41, 86] + (getTemperatureScale() == "C") ? [5, 30] : [41, 86] } def getHeatingSetpointRange() { - thermostatSetpointRange + thermostatSetpointRange } def getSetpointStep() { - (getTemperatureScale() == "C") ? 0.5 : 1.0 + (getTemperatureScale() == "C") ? 0.5 : 1.0 } def setupHealthCheck() { - // Device-Watch simply pings if no device events received for 32min(checkInterval) - sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) + // Device-Watch simply pings if no device events received for 32min(checkInterval) + sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) } def configureSupportedRanges() { - sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) - sendEvent(name: "thermostatSetpointRange", value: thermostatSetpointRange, displayed: false) - sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) + sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false) + sendEvent(name: "thermostatSetpointRange", value: thermostatSetpointRange, displayed: false) + sendEvent(name: "heatingSetpointRange", value: heatingSetpointRange, displayed: false) } def installed() { - sendEvent(name: "temperatureAlarm", value: "cleared", displayed: false) + sendEvent(name: "temperatureAlarm", value: "cleared", displayed: false) - setupHealthCheck() + setupHealthCheck() - configureSupportedRanges() + configureSupportedRanges() } def updated() { - setupHealthCheck() + setupHealthCheck() - configureSupportedRanges() + configureSupportedRanges() - unschedule(scheduledUpdateWeather) - if (settings.zipcode) { - runEvery1Hour(scheduledUpdateWeather) - scheduledUpdateWeather() - } + unschedule(scheduledUpdateWeather) + if (settings.zipcode) { + runEvery1Hour(scheduledUpdateWeather) + scheduledUpdateWeather() + } } def parse(String description) { - // If the user installed with an old DTH version, update so that the new mobile client will work - if (!device.currentValue("supportedThermostatModes")) { - configureSupportedRanges() - } - - if (description == "updated") { - return null - } - - // Class, version - def map = createEvent(zwaveEvent(zwave.parse(description, [0x40:2, 0x43:2, 0x31:3, 0x42:1, 0x20:1, 0x85: 2]))) - if (!map) { - return null - } - - def result = [map] - // This logic is to appease the (now deprecated but still sort-of used) consolidated - // Thermostat capability gods. - if (map.isStateChange && map.name == "heatingSetpoint") { - result << createEvent([ - name: "thermostatSetpoint", - value: map.value, - unit: map.unit, - data: [thermostatSetpointRange: thermostatSetpointRange] - ]) - } - - log.debug "Parse returned $result" - result + // If the user installed with an old DTH version, update so that the new mobile client will work + if (!device.currentValue("supportedThermostatModes")) { + configureSupportedRanges() + } + + if (description == "updated") { + return null + } + + // Class, version + def map = createEvent(zwaveEvent(zwave.parse(description, [0x40:2, 0x43:2, 0x31:3, 0x42:1, 0x20:1, 0x85: 2]))) + if (!map) { + return null + } + + def result = [map] + // This logic is to appease the (now deprecated but still sort-of used) consolidated + // Thermostat capability gods. + if (map.isStateChange && map.name == "heatingSetpoint") { + result << createEvent([ + name: "thermostatSetpoint", + value: map.value, + unit: map.unit, + data: [thermostatSetpointRange: thermostatSetpointRange] + ]) + } + + log.debug "Parse returned $result" + result } def updateWeather() { - log.debug "updating weather" - def weather - // If there is a zipcode defined, weather forecast will be sent. Otherwise, no weather forecast. - if (settings.zipcode) { - log.debug "ZipCode: ${settings.zipcode}" - weather = getWeatherFeature("conditions", settings.zipcode) - - // Check if the variable is populated, otherwise return. - if (!weather) { - log.debug("Something went wrong, no data found.") - return false - } - - def locationScale = getTemperatureScale() - def tempToSend = (locationScale == "C") ? weather.current_observation.temp_c : weather.current_observation.temp_f - log.debug("Outdoor Temperature: ${tempToSend} ${locationScale}") - // Right now this can disrupt device health if the device is - // currently offline -- it would be erroneously marked online. - //sendEvent(name: 'outsideTemp', value: tempToSend) - setOutdoorTemperature(tempToSend) - } + log.debug "updating weather" + def weather + // If there is a zipcode defined, weather forecast will be sent. Otherwise, no weather forecast. + if (settings.zipcode) { + log.debug "ZipCode: ${settings.zipcode}" + weather = getTwcConditions(settings.zipcode) + + // Check if the variable is populated, otherwise return. + if (!weather) { + log.debug("Something went wrong, no data found.") + return false + } + + def locationScale = getTemperatureScale() + def tempToSend = weather.temperature + log.debug("Outdoor Temperature: ${tempToSend} ${locationScale}") + // Right now this can disrupt device health if the device is + // currently offline -- it would be erroneously marked online. + //sendEvent(name: 'outsideTemp', value: tempToSend) + setOutdoorTemperature(tempToSend) + } } def scheduledUpdateWeather() { - def actions = updateWeather() + def actions = updateWeather() - if (actions) { - sendHubCommand(actions) - } + if (actions) { + sendHubCommand(actions) + } } // Command Implementations @@ -235,281 +235,281 @@ def scheduledUpdateWeather() { * PING is used by Device-Watch in attempt to reach the Device **/ def ping() { - log.debug "ping()" - zwave.sensorMultilevelV3.sensorMultilevelGet().format() + log.debug "ping()" + zwave.sensorMultilevelV3.sensorMultilevelGet().format() } def poll() { - log.debug "poll()" - delayBetween([ - updateWeather(), - zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(), - zwave.thermostatModeV2.thermostatModeGet().format(), - zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: 1).format(), - zwave.sensorMultilevelV3.sensorMultilevelGet().format() // current temperature - ], 100) + log.debug "poll()" + delayBetween([ + updateWeather(), + zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(), + zwave.thermostatModeV2.thermostatModeGet().format(), + zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: 1).format(), + zwave.sensorMultilevelV3.sensorMultilevelGet().format() // current temperature + ], 100) } // Event Generation def zwaveEvent(thermostatsetpointv2.ThermostatSetpointReport cmd) { - def cmdScale = cmd.scale == 1 ? "F" : "C" - def temp; - float tempfloat; - def map = [:] + def cmdScale = cmd.scale == 1 ? "F" : "C" + def temp; + float tempfloat; + def map = [:] - if (cmd.scaledValue >= 327 || - cmd.setpointType != thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1) { - return [:] - } - temp = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision) - tempfloat = (Math.round(temp.toFloat() * 2)) / 2 - map.value = tempfloat + if (cmd.scaledValue >= 327 || + cmd.setpointType != thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1) { + return [:] + } + temp = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision) + tempfloat = (Math.round(temp.toFloat() * 2)) / 2 + map.value = tempfloat - map.unit = getTemperatureScale() - map.displayed = false - map.name = "heatingSetpoint" - map.data = [heatingSetpointRange: heatingSetpointRange] + map.unit = getTemperatureScale() + map.displayed = false + map.name = "heatingSetpoint" + map.data = [heatingSetpointRange: heatingSetpointRange] - // So we can respond with same format - state.size = cmd.size - state.scale = cmd.scale - state.precision = cmd.precision + // So we can respond with same format + state.size = cmd.size + state.scale = cmd.scale + state.precision = cmd.precision - map + map } def zwaveEvent(sensormultilevelv3.SensorMultilevelReport cmd) { - def temp - float tempfloat - def format - def map = [:] - - if (cmd.sensorType == sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_TEMPERATURE_VERSION_1) { - map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision) - map.unit = getTemperatureScale() - map.name = "temperature" - - temp = map.value - // The specific values checked below represent ambient temperature alarm indicators - if (temp == "32765") { // 0x7FFD - map.name = "temperatureAlarm" - map.value = "freeze" - map.unit = "" - } else if (temp == "32767") { // 0x7FFF - map.name = "temperatureAlarm" - map.value = "heat" - map.unit = "" - } else if (temp == "-32768"){ // 0x8000 - map.name = "temperatureAlarm" - map.value = "cleared" - map.unit = "" - } else { - tempfloat = (Math.round(temp.toFloat() * 2)) / 2 - map.value = tempfloat - } - } else if (cmd.sensorType == sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_RELATIVE_HUMIDITY_VERSION_2) { - map.value = cmd.scaledSensorValue - map.unit = "%" - map.name = "humidity" - } - - map + def temp + float tempfloat + def format + def map = [:] + + if (cmd.sensorType == sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_TEMPERATURE_VERSION_1) { + map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision) + map.unit = getTemperatureScale() + map.name = "temperature" + + temp = map.value + // The specific values checked below represent ambient temperature alarm indicators + if (temp == "32765") { // 0x7FFD + map.name = "temperatureAlarm" + map.value = "freeze" + map.unit = "" + } else if (temp == "32767") { // 0x7FFF + map.name = "temperatureAlarm" + map.value = "heat" + map.unit = "" + } else if (temp == "-32768"){ // 0x8000 + map.name = "temperatureAlarm" + map.value = "cleared" + map.unit = "" + } else { + tempfloat = (Math.round(temp.toFloat() * 2)) / 2 + map.value = tempfloat + } + } else if (cmd.sensorType == sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_RELATIVE_HUMIDITY_VERSION_2) { + map.value = cmd.scaledSensorValue + map.unit = "%" + map.name = "humidity" + } + + map } def zwaveEvent(thermostatoperatingstatev1.ThermostatOperatingStateReport cmd) { - def map = [:] - def operatingState = zwaveOperatingStateToString(cmd.operatingState) + def map = [:] + def operatingState = zwaveOperatingStateToString(cmd.operatingState) - if (operatingState) { - map.name = "thermostatOperatingState" - map.value = operatingState + if (operatingState) { + map.name = "thermostatOperatingState" + map.value = operatingState - if (settings.heatdetails == "No") { - map.displayed = false - } - } else { - log.trace "${device.displayName} sent invalid operating state $value" - } + if (settings.heatdetails == "No") { + map.displayed = false + } + } else { + log.trace "${device.displayName} sent invalid operating state $value" + } - map + map } def zwaveEvent(thermostatmodev2.ThermostatModeReport cmd) { - def map = [:] - def mode = zwaveModeToString(cmd.mode) + def map = [:] + def mode = zwaveModeToString(cmd.mode) - if (mode) { - map.name = "thermostatMode" - map.value = mode - map.data = [supportedThermostatModes: supportedThermostatModes] - } else { - log.trace "${device.displayName} sent invalid mode $value" - } + if (mode) { + map.name = "thermostatMode" + map.value = mode + map.data = [supportedThermostatModes: supportedThermostatModes] + } else { + log.trace "${device.displayName} sent invalid mode $value" + } - map + map } def zwaveEvent(associationv2.AssociationReport cmd) { - delayBetween([ - zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:0).format(), - zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(), - poll() - ], 2300) + delayBetween([ + zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:0).format(), + zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(), + poll() + ], 2300) } def zwaveEvent(thermostatmodev2.ThermostatModeSupportedReport cmd) { - log.debug "Zwave event received: $cmd" + log.debug "Zwave event received: $cmd" } def zwaveEvent(physicalgraph.zwave.Command cmd) { - log.warn "Unexpected zwave command $cmd" + log.warn "Unexpected zwave command $cmd" } def refresh() { - poll() + poll() } def configure() { - unschedule(scheduledUpdateWeather) - if (settings.zipcode) { - runEvery1Hour(scheduledUpdateWeather) - } - poll() + unschedule(scheduledUpdateWeather) + if (settings.zipcode) { + runEvery1Hour(scheduledUpdateWeather) + } + poll() } def setHeatingSetpoint(preciseDegrees) { - float minSetpoint = thermostatSetpointRange[minSetpointIndex] - float maxSetpoint = thermostatSetpointRange[maxSetpointIndex] - - if (preciseDegrees >= minSetpoint && preciseDegrees <= maxSetpoint) { - def degrees = new BigDecimal(preciseDegrees).setScale(1, BigDecimal.ROUND_HALF_UP) - log.trace "setHeatingSetpoint($degrees)" - def deviceScale = state.scale ?: 1 - def deviceScaleString = deviceScale == 2 ? "C" : "F" - def locationScale = getTemperatureScale() - def p = (state.precision == null) ? 1 : state.precision - def setpointType = thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1 - - def convertedDegrees = degrees - if (locationScale == "C" && deviceScaleString == "F") { - convertedDegrees = celsiusToFahrenheit(degrees) - } else if (locationScale == "F" && deviceScaleString == "C") { - convertedDegrees = fahrenheitToCelsius(degrees) - } - - delayBetween([ - zwave.thermostatSetpointV2.thermostatSetpointSet(setpointType: setpointType, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(), - zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: setpointType).format() - ], 1000) - } else { - log.debug "heatingSetpoint $preciseDegrees out of range! (supported: $minSetpoint - $maxSetpoint ${getTemperatureScale()})" - } + float minSetpoint = thermostatSetpointRange[minSetpointIndex] + float maxSetpoint = thermostatSetpointRange[maxSetpointIndex] + + if (preciseDegrees >= minSetpoint && preciseDegrees <= maxSetpoint) { + def degrees = new BigDecimal(preciseDegrees).setScale(1, BigDecimal.ROUND_HALF_UP) + log.trace "setHeatingSetpoint($degrees)" + def deviceScale = state.scale ?: 1 + def deviceScaleString = deviceScale == 2 ? "C" : "F" + def locationScale = getTemperatureScale() + def p = (state.precision == null) ? 1 : state.precision + def setpointType = thermostatsetpointv2.ThermostatSetpointReport.SETPOINT_TYPE_HEATING_1 + + def convertedDegrees = degrees + if (locationScale == "C" && deviceScaleString == "F") { + convertedDegrees = celsiusToFahrenheit(degrees) + } else if (locationScale == "F" && deviceScaleString == "C") { + convertedDegrees = fahrenheitToCelsius(degrees) + } + + delayBetween([ + zwave.thermostatSetpointV2.thermostatSetpointSet(setpointType: setpointType, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(), + zwave.thermostatSetpointV2.thermostatSetpointGet(setpointType: setpointType).format() + ], 1000) + } else { + log.debug "heatingSetpoint $preciseDegrees out of range! (supported: $minSetpoint - $maxSetpoint ${getTemperatureScale()})" + } } // Maintain backward compatibility with self published versions of the "Stelpro Get Remote Temperature" SmartApp def quickSetOutTemp(outsideTemp) { - setOutdoorTemperature(outsideTemp) + setOutdoorTemperature(outsideTemp) } def setOutdoorTemperature(outsideTemp) { - def degrees = outsideTemp as Double - def locationScale = getTemperatureScale() - def p = (state.precision == null) ? 1 : state.precision - def deviceScale = (locationScale == "C") ? 0 : 1 - def sensorType = sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_TEMPERATURE_VERSION_1 + def degrees = outsideTemp as Double + def locationScale = getTemperatureScale() + def p = (state.precision == null) ? 1 : state.precision + def deviceScale = (locationScale == "C") ? 0 : 1 + def sensorType = sensormultilevelv3.SensorMultilevelReport.SENSOR_TYPE_TEMPERATURE_VERSION_1 - log.debug "setOutdoorTemperature: ${degrees}" - zwave.sensorMultilevelV3.sensorMultilevelReport(sensorType: sensorType, scale: deviceScale, precision: p, scaledSensorValue: degrees).format() + log.debug "setOutdoorTemperature: ${degrees}" + zwave.sensorMultilevelV3.sensorMultilevelReport(sensorType: sensorType, scale: deviceScale, precision: p, scaledSensorValue: degrees).format() } def increaseHeatSetpoint() { - float currentSetpoint = device.currentValue("heatingSetpoint") + float currentSetpoint = device.currentValue("heatingSetpoint") - currentSetpoint = currentSetpoint + setpointStep - setHeatingSetpoint(currentSetpoint) + currentSetpoint = currentSetpoint + setpointStep + setHeatingSetpoint(currentSetpoint) } def decreaseHeatSetpoint() { - float currentSetpoint = device.currentValue("heatingSetpoint") + float currentSetpoint = device.currentValue("heatingSetpoint") - currentSetpoint = currentSetpoint - setpointStep - setHeatingSetpoint(currentSetpoint) + currentSetpoint = currentSetpoint - setpointStep + setHeatingSetpoint(currentSetpoint) } def getModeNumericMap() {[ - "heat": thermostatmodev2.ThermostatModeReport.MODE_HEAT, - "eco": thermostatmodev2.ThermostatModeReport.MODE_ENERGY_SAVE_HEAT + "heat": thermostatmodev2.ThermostatModeReport.MODE_HEAT, + "eco": thermostatmodev2.ThermostatModeReport.MODE_ENERGY_SAVE_HEAT ]} def zwaveModeToString(mode) { - if (thermostatmodev2.ThermostatModeReport.MODE_HEAT == mode) { - return "heat" - } else if (thermostatmodev2.ThermostatModeReport.MODE_ENERGY_SAVE_HEAT == mode) { - return "eco" - } - return null + if (thermostatmodev2.ThermostatModeReport.MODE_HEAT == mode) { + return "heat" + } else if (thermostatmodev2.ThermostatModeReport.MODE_ENERGY_SAVE_HEAT == mode) { + return "eco" + } + return null } def zwaveOperatingStateToString(state) { - if (thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE == state) { - return "idle" - } else if (thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING == state) { - return "heating" - } - return null + if (thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE == state) { + return "idle" + } else if (thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING == state) { + return "heating" + } + return null } def setCoolingSetpoint(coolingSetpoint) { - log.trace "${device.displayName} does not support cool setpoint" + log.trace "${device.displayName} does not support cool setpoint" } def heat() { - log.trace "heat mode applied" - setThermostatMode("heat") + log.trace "heat mode applied" + setThermostatMode("heat") } def eco() { - log.trace "eco mode applied" - setThermostatMode("eco") + log.trace "eco mode applied" + setThermostatMode("eco") } def off() { - log.trace "${device.displayName} does not support off mode" + log.trace "${device.displayName} does not support off mode" } def auto() { - log.trace "${device.displayName} does not support auto mode" + log.trace "${device.displayName} does not support auto mode" } def emergencyHeat() { - log.trace "${device.displayName} does not support emergency heat mode" + log.trace "${device.displayName} does not support emergency heat mode" } def cool() { - log.trace "${device.displayName} does not support cool mode" + log.trace "${device.displayName} does not support cool mode" } def setThermostatMode(value) { - if (supportedThermostatModes.contains(value)) { - delayBetween([ - zwave.thermostatModeV2.thermostatModeSet(mode: modeNumericMap[value]).format(), - zwave.thermostatModeV2.thermostatModeGet().format() - ], 1000) - } else { - log.trace "${device.displayName} does not support $value mode" - } + if (supportedThermostatModes.contains(value)) { + delayBetween([ + zwave.thermostatModeV2.thermostatModeSet(mode: modeNumericMap[value]).format(), + zwave.thermostatModeV2.thermostatModeGet().format() + ], 1000) + } else { + log.trace "${device.displayName} does not support $value mode" + } } def fanOn() { - log.trace "${device.displayName} does not support fan on" + log.trace "${device.displayName} does not support fan on" } def fanAuto() { - log.trace "${device.displayName} does not support fan auto" + log.trace "${device.displayName} does not support fan auto" } def fanCirculate() { - log.trace "${device.displayName} does not support fan circulate" + log.trace "${device.displayName} does not support fan circulate" } def setThermostatFanMode() { - log.trace "${device.displayName} does not support fan mode" + log.trace "${device.displayName} does not support fan mode" } diff --git a/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy b/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy index f1f7c19af86..e29d2bf128a 100644 --- a/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-ki-zigbee-thermostat.src/stelpro-ki-zigbee-thermostat.groovy @@ -337,16 +337,16 @@ def updateWeather() { // If there is a zipcode defined, weather forecast will be sent. Otherwise, no weather forecast. if (settings.zipcode) { log.debug "ZipCode: ${settings.zipcode}" - weather = getWeatherFeature("conditions", settings.zipcode) + weather = getTwcConditions(settings.zipcode) // Check if the variable is populated, otherwise return. if (!weather) { log.debug("Something went wrong, no data found.") return false } - + def locationScale = getTemperatureScale() - def tempToSend = (locationScale == "C") ? weather.current_observation.temp_c : weather.current_observation.temp_f + def tempToSend = weather.temperature log.debug("Outdoor Temperature: ${tempToSend} ${locationScale}") // Right now this can disrupt device health if the device is // currently offline -- it would be erroneously marked online. @@ -569,5 +569,3 @@ def auto() { def fanAuto() { log.debug "${device.displayName} does not support fan auto" } - - diff --git a/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy b/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy index b18253d4705..0996843a6a2 100644 --- a/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy +++ b/devicetypes/stelpro/stelpro-maestro-thermostat.src/stelpro-maestro-thermostat.groovy @@ -60,7 +60,7 @@ metadata { input("away_setpoint", "enum", title: "Away Setpoint", options: ["5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.5", "10", "10.5", "11", "11.5", "12", "12.5", "13", "13.5", "14", "14.5", "15", "5.5", "15.5", "16", "16.5", "17", "17.5", "18", "18.5", "19", "19.5", "20", "20.5", "21", "21.5", "22", "22.5", "23", "24", "24.5", "25", "25.5", "26", "26.5", "27", "27.5", "28", "28.5", "29", "29.5", "30"], defaultValue: "17", required: true) input("vacation_setpoint", "enum", title: "Vacation Setpoint", options: ["5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.5", "10", "10.5", "11", "11.5", "12", "12.5", "13", "13.5", "14", "14.5", "15", "5.5", "15.5", "16", "16.5", "17", "17.5", "18", "18.5", "19", "19.5", "20", "20.5", "21", "21.5", "22", "22.5", "23", "24", "24.5", "25", "25.5", "26", "26.5", "27", "27.5", "28", "28.5", "29", "29.5", "30"], defaultValue: "13", required: true) input("standby_setpoint", "enum", title: "Standby Setpoint", options: ["5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.5", "10", "10.5", "11", "11.5", "12", "12.5", "13", "13.5", "14", "14.5", "15", "5.5", "15.5", "16", "16.5", "17", "17.5", "18", "18.5", "19", "19.5", "20", "20.5", "21", "21.5", "22", "22.5", "23", "24", "24.5", "25", "25.5", "26", "26.5", "27", "27.5", "28", "28.5", "29", "29.5", "30"], defaultValue: "5", required: true) - */ + */ } tiles(scale : 2) { @@ -326,16 +326,16 @@ def updateWeather() { // If there is a zipcode defined, weather forecast will be sent. Otherwise, no weather forecast. if (settings.zipcode) { log.debug "ZipCode: ${settings.zipcode}" - weather = getWeatherFeature("conditions", settings.zipcode) + weather = getTwcConditions(settings.zipcode) // Check if the variable is populated, otherwise return. if (!weather) { log.debug("Something went wrong, no data found.") return false } - + def locationScale = getTemperatureScale() - def tempToSend = (locationScale == "C") ? weather.current_observation.temp_c : weather.current_observation.temp_f + def tempToSend = weather.temperature log.debug("Outdoor Temperature: ${tempToSend} ${locationScale}") // Right now this can disrupt device health if the device is // currently offline -- it would be erroneously marked online. @@ -534,5 +534,3 @@ def auto() { def fanAuto() { log.debug "${device.displayName} does not support fan auto" } - - diff --git a/smartapps/michaelstruck/talking-alarm-clock.src/talking-alarm-clock.groovy b/smartapps/michaelstruck/talking-alarm-clock.src/talking-alarm-clock.groovy index a773d9f740d..3113bb172c8 100644 --- a/smartapps/michaelstruck/talking-alarm-clock.src/talking-alarm-clock.groovy +++ b/smartapps/michaelstruck/talking-alarm-clock.src/talking-alarm-clock.groovy @@ -7,7 +7,7 @@ * Version - 1.3.0 5/29/15 - Further code optimizations and addition of alarm summary action * Version - 1.3.1 5/30/15 - Fixed one small code syntax issue in Scenario D * Version - 1.4.0 6/7/15 - Revised About screen, enhanced the weather forecast voice summary, added a mode change option with alarm, and added secondary alarm options - * Version - 1.4.1 6/9/15 - Changed the mode change speech to make it clear when the mode change is taking place + * Version - 1.4.1 6/9/15 - Changed the mode change speech to make it clear when the mode change is taking place * Version - 1.4.2 6/10/15 - To prevent accidental triggering of summary, put in a mode switch restriction * Version - 1.4.3 6/12/15 - Syntax issues and minor GUI fixes * Version - 1.4.4 6/15/15 - Fixed a bug with Phrase change at alarm time @@ -25,7 +25,7 @@ * for the specific language governing permissions and limitations under the License. * */ - + definition( name: "Talking Alarm Clock", namespace: "MichaelStruck", @@ -39,48 +39,48 @@ definition( ) preferences { - page name:"pageMain" - page name:"pageSetupScenarioA" - page name:"pageSetupScenarioB" - page name:"pageSetupScenarioC" - page name:"pageSetupScenarioD" - page name:"pageWeatherSettingsA" //technically, these 4 pages should not be dynamic, but are here to work around a crash on the Andriod app - page name:"pageWeatherSettingsB" - page name:"pageWeatherSettingsC" - page name:"pageWeatherSettingsD" + page name:"pageMain" + page name:"pageSetupScenarioA" + page name:"pageSetupScenarioB" + page name:"pageSetupScenarioC" + page name:"pageSetupScenarioD" + page name:"pageWeatherSettingsA" //technically, these 4 pages should not be dynamic, but are here to work around a crash on the Andriod app + page name:"pageWeatherSettingsB" + page name:"pageWeatherSettingsC" + page name:"pageWeatherSettingsD" } // Show setup page def pageMain() { - dynamicPage(name: "pageMain", install: true, uninstall: true) { + dynamicPage(name: "pageMain", install: true, uninstall: true) { section ("Alarms") { href "pageSetupScenarioA", title: getTitle(ScenarioNameA, 1), description: getDesc(A_timeStart, A_sonos, A_day, A_mode), state: greyOut(ScenarioNameA, A_sonos, A_timeStart, A_alarmOn, A_alarmType) if (ScenarioNameA && A_sonos && A_timeStart && A_alarmType){ - input "A_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "true", submitOnChange:true + input "A_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "true", submitOnChange:true } } section { href "pageSetupScenarioB", title: getTitle(ScenarioNameB, 2), description: getDesc(B_timeStart, B_sonos, B_day, B_mode), state: greyOut(ScenarioNameB, B_sonos, B_timeStart, B_alarmOn, B_alarmType) if (ScenarioNameB && B_sonos && B_timeStart && B_alarmType){ - input "B_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true - } + input "B_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true + } } section { href "pageSetupScenarioC", title: getTitle(ScenarioNameC, 3), description: getDesc(C_timeStart, C_sonos, C_day, C_mode), state: greyOut(ScenarioNameC, C_sonos, C_timeStart, C_alarmOn, C_alarmType) if (ScenarioNameC && C_sonos && C_timeStart && C_alarmType){ - input "C_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true - } + input "C_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true + } } section { href "pageSetupScenarioD", title: getTitle(ScenarioNameD, 4), description: getDesc(D_timeStart, D_sonos, D_day, D_mode), state: greyOut(ScenarioNameD, D_sonos, D_timeStart, D_alarmOn, D_alarmType) if (ScenarioNameD && D_sonos && D_timeStart && D_alarmType){ - input "D_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true + input "D_alarmOn", "bool", title: "Enable this alarm?", defaultValue: "false", submitOnChange:true } } section([title:"Options", mobileOnly:true]) { input "alarmSummary", "bool", title: "Enable Alarm Summary", defaultValue: "false", submitOnChange:true if (alarmSummary) { - href "pageAlarmSummary", title: "Alarm Summary Settings", description: "Tap to configure alarm summary settings", state: "complete" + href "pageAlarmSummary", title: "Alarm Summary Settings", description: "Tap to configure alarm summary settings", state: "complete" } input "zipCode", "text", title: "Zip Code", required: false label title:"Assign a name", required: false @@ -90,385 +90,385 @@ def pageMain() { } page(name: "pageAlarmSummary", title: "Alarm Summary Settings") { - section { - input "summarySonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: false + section { + input "summarySonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: false input "summaryVolume", "number", title: "Set the summary volume", description: "0-100%", required: false input "summaryDisabled", "bool", title: "Include disabled or unconfigured alarms in summary", defaultValue: "false" input "summaryMode", "mode", title: "Speak summary only during the following modes...", multiple: true, required: false - } + } } //Show "pageSetupScenarioA" page def pageSetupScenarioA() { dynamicPage(name: "pageSetupScenarioA") { - section("Alarm settings") { - input "ScenarioNameA", "text", title: "Scenario Name", multiple: false, required: true - input "A_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true + section("Alarm settings") { + input "ScenarioNameA", "text", title: "Scenario Name", multiple: false, required: true + input "A_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true input "A_volume", "number", title: "Alarm volume", description: "0-100%", required: false - input "A_timeStart", "time", title: "Time to trigger alarm", required: true - input "A_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false - input "A_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false - input "A_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true - + input "A_timeStart", "time", title: "Time to trigger alarm", required: true + input "A_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false + input "A_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false + input "A_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true + if (A_alarmType != "3") { - if (A_alarmType == "1"){ - input "A_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true + if (A_alarmType == "1"){ + input "A_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true } if (A_alarmType == "2"){ - input "A_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true + input "A_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true } - } + } } if (A_alarmType == "1"){ - section ("Alarm sound options"){ - input "A_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] - input "A_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false - } - } + section ("Alarm sound options"){ + input "A_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] + input "A_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false + } + } if (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1")) { - section ("Voice greeting options") { - input "A_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false - href "pageWeatherSettingsA", title: "Weather Reporting Settings", description: getWeatherDesc(A_weatherReport, A_includeSunrise, A_includeSunset, A_includeTemp, A_humidity, A_localTemp), state: greyOut1(A_weatherReport, A_includeSunrise, A_includeSunset, A_includeTemp, A_humidity, A_localTemp) - } - } - if (A_alarmType == "3" || (A_alarmType == "1" && A_secondAlarm =="2") || (A_alarmType == "2" && A_secondAlarmMusic)){ - section ("Music track/internet radio options"){ - input "A_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(A_sonos, 1) - } - } + section ("Voice greeting options") { + input "A_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false + href "pageWeatherSettingsA", title: "Weather Reporting Settings", description: getWeatherDesc(A_weatherReport, A_includeSunrise, A_includeSunset, A_includeTemp, A_humidity, A_localTemp), state: greyOut1(A_weatherReport, A_includeSunrise, A_includeSunset, A_includeTemp, A_humidity, A_localTemp) + } + } + if (A_alarmType == "3" || (A_alarmType == "1" && A_secondAlarm =="2") || (A_alarmType == "2" && A_secondAlarmMusic)){ + section ("Music track/internet radio options"){ + input "A_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(A_sonos, 1) + } + } section("Devices to control in this alarm scenario") { - input "A_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true - href "pageDimmersA", title: "Dimmer Settings", description: dimmerDesc(A_dimmers), state: greyOutOption(A_dimmers), submitOnChange:true + input "A_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true + href "pageDimmersA", title: "Dimmer Settings", description: dimmerDesc(A_dimmers), state: greyOutOption(A_dimmers), submitOnChange:true href "pageThermostatsA", title: "Thermostat Settings", description: thermostatDesc(A_thermostats, A_temperatureH, A_temperatureC), state: greyOutOption(A_thermostats), submitOnChange:true - if ((A_switches || A_dimmers || A_thermostats) && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ - input "A_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" + if ((A_switches || A_dimmers || A_thermostats) && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ + input "A_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" } } - section ("Other actions at alarm time"){ + section ("Other actions at alarm time"){ def phrases = location.helloHome?.getPhrases()*.label - if (phrases) { - phrases.sort() - input "A_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true - if (A_phrase && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ - input "A_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" - } + if (phrases) { + phrases.sort() + input "A_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true + if (A_phrase && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ + input "A_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" + } } input "A_triggerMode", "mode", title: "Alarm triggers the following mode", required: false, submitOnChange:true - if (A_triggerMode && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ - input "A_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" + if (A_triggerMode && (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1"))){ + input "A_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" } } - } + } } page(name: "pageDimmersA", title: "Dimmer Settings") { - section { - input "A_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false - input "A_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false - } + section { + input "A_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false + input "A_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false + } } page(name: "pageThermostatsA", title: "Thermostat Settings") { - section { - input "A_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false - } + section { + input "A_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false + } section { input "A_temperatureH", "number", title: "Heating setpoint", required: false, description: "Temperature when in heat mode" - input "A_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" - } + input "A_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" + } } def pageWeatherSettingsA() { - dynamicPage(name: "pageWeatherSettingsA", title: "Weather Reporting Settings") { - section { - input "A_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" - input "A_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false - input "A_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false - input "A_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" - input "A_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" - input "A_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" - } - } + dynamicPage(name: "pageWeatherSettingsA", title: "Weather Reporting Settings") { + section { + input "A_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" + input "A_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false + input "A_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false + input "A_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" + input "A_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" + input "A_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" + } + } } //Show "pageSetupScenarioB" page def pageSetupScenarioB() { dynamicPage(name: "pageSetupScenarioB") { - section("Alarm settings") { - input "ScenarioNameB", "text", title: "Scenario Name", multiple: false, required: true - input "B_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true + section("Alarm settings") { + input "ScenarioNameB", "text", title: "Scenario Name", multiple: false, required: true + input "B_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true input "B_volume", "number", title: "Alarm volume", description: "0-100%", required: false - input "B_timeStart", "time", title: "Time to trigger alarm", required: true - input "B_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false - input "B_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false - input "B_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true - + input "B_timeStart", "time", title: "Time to trigger alarm", required: true + input "B_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false + input "B_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false + input "B_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true + if (B_alarmType != "3") { - if (B_alarmType == "1"){ - input "B_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true + if (B_alarmType == "1"){ + input "B_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true } if (B_alarmType == "2"){ - input "B_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true + input "B_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true } - } + } } if (B_alarmType == "1"){ - section ("Alarm sound options"){ - input "B_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] - input "B_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false - } - } - if (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1")){ - section ("Voice greeting options") { - input "B_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false + section ("Alarm sound options"){ + input "B_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] + input "B_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false + } + } + if (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1")){ + section ("Voice greeting options") { + input "B_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false href "pageWeatherSettingsB", title: "Weather Reporting Settings", description: getWeatherDesc(B_weatherReport, B_includeSunrise, B_includeSunset, B_includeTemp, B_humidity, B_localTemp), state: greyOut1(B_weatherReport, B_includeSunrise, B_includeSunset, B_includeTemp, B_humidity, B_localTemp) - } - } - if (B_alarmType == "3" || (B_alarmType == "1" && B_secondAlarm =="2") || (B_alarmType == "2" && B_secondAlarmMusic)){ - section ("Music track/internet radio options"){ - input "B_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(B_sonos, 1) - } - } + } + } + if (B_alarmType == "3" || (B_alarmType == "1" && B_secondAlarm =="2") || (B_alarmType == "2" && B_secondAlarmMusic)){ + section ("Music track/internet radio options"){ + input "B_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(B_sonos, 1) + } + } section("Devices to control in this alarm scenario") { - input "B_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true - href "pageDimmersB", title: "Dimmer Settings", description: dimmerDesc(B_dimmers), state: greyOutOption(B_dimmers), submitOnChange:true + input "B_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true + href "pageDimmersB", title: "Dimmer Settings", description: dimmerDesc(B_dimmers), state: greyOutOption(B_dimmers), submitOnChange:true href "pageThermostatsB", title: "Thermostat Settings", description: thermostatDesc(B_thermostats, B_temperatureH, B_temperatureC), state: greyOutOption(B_thermostats), submitOnChange:true - if ((B_switches || B_dimmers || B_thermostats) && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ - input "B_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" + if ((B_switches || B_dimmers || B_thermostats) && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ + input "B_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" } } section ("Other actions at alarm time"){ def phrases = location.helloHome?.getPhrases()*.label - if (phrases) { - phrases.sort() - input "B_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true - if (B_phrase && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ - input "B_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" - } + if (phrases) { + phrases.sort() + input "B_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true + if (B_phrase && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ + input "B_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" + } } input "B_triggerMode", "mode", title: "Alarm triggers the following mode", required: false, submitOnChange:true - if (B_triggerMode && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ - input "B_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" + if (B_triggerMode && (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1"))){ + input "B_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" } } - } + } } page(name: "pageDimmersB", title: "Dimmer Settings") { - section { - input "B_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false - input "B_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false - } + section { + input "B_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false + input "B_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false + } } page(name: "pageThermostatsB", title: "Thermostat Settings") { - section { - input "B_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false - } + section { + input "B_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false + } section { input "B_temperatureH", "number", title: "Heating setpoint", required: false, description: "Temperature when in heat mode" - input "B_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" - } + input "B_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" + } } def pageWeatherSettingsB() { - dynamicPage(name: "pageWeatherSettingsB", title: "Weather Reporting Settings") { - section { - input "B_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" - input "B_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false - input "B_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false - input "B_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" - input "B_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" - input "B_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" - } - } + dynamicPage(name: "pageWeatherSettingsB", title: "Weather Reporting Settings") { + section { + input "B_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" + input "B_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false + input "B_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false + input "B_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" + input "B_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" + input "B_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" + } + } } //Show "pageSetupScenarioC" page def pageSetupScenarioC() { dynamicPage(name: "pageSetupScenarioC") { - section("Alarm settings") { - input "ScenarioNameC", "text", title: "Scenario Name", multiple: false, required: true - input "C_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true + section("Alarm settings") { + input "ScenarioNameC", "text", title: "Scenario Name", multiple: false, required: true + input "C_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true input "C_volume", "number", title: "Alarm volume", description: "0-100%", required: false - input "C_timeStart", "time", title: "Time to trigger alarm", required: true - input "C_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false - input "C_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false - input "C_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true - + input "C_timeStart", "time", title: "Time to trigger alarm", required: true + input "C_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false + input "C_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false + input "C_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true + if (C_alarmType != "3") { - if (C_alarmType == "1"){ - input "C_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true + if (C_alarmType == "1"){ + input "C_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true } if (C_alarmType == "2"){ - input "C_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true + input "C_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true } - } + } } if (C_alarmType == "1"){ - section ("Alarm sound options"){ - input "C_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] - input "C_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false - } - } - + section ("Alarm sound options"){ + input "C_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] + input "C_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false + } + } + if (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1")) { - section ("Voice greeting options") { - input "C_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false - href "pageWeatherSettingsC", title: "Weather Reporting Settings", description: getWeatherDesc(C_weatherReport, C_includeSunrise, C_includeSunset, C_includeTemp, A_humidity, C_localTemp), state: greyOut1(C_weatherReport, C_includeSunrise, C_includeSunset, C_includeTemp, C_humidity, C_localTemp) } - } - - if (C_alarmType == "3" || (C_alarmType == "1" && C_secondAlarm =="2") || (C_alarmType == "2" && C_secondAlarmMusic)){ - section ("Music track/internet radio options"){ - input "C_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(C_sonos, 1) - } - } + section ("Voice greeting options") { + input "C_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false + href "pageWeatherSettingsC", title: "Weather Reporting Settings", description: getWeatherDesc(C_weatherReport, C_includeSunrise, C_includeSunset, C_includeTemp, A_humidity, C_localTemp), state: greyOut1(C_weatherReport, C_includeSunrise, C_includeSunset, C_includeTemp, C_humidity, C_localTemp) } + } + + if (C_alarmType == "3" || (C_alarmType == "1" && C_secondAlarm =="2") || (C_alarmType == "2" && C_secondAlarmMusic)){ + section ("Music track/internet radio options"){ + input "C_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(C_sonos, 1) + } + } section("Devices to control in this alarm scenario") { - input "C_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true - href "pageDimmersC", title: "Dimmer Settings", description: dimmerDesc(C_dimmers), state: greyOutOption(C_dimmers), submitOnChange:true + input "C_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true + href "pageDimmersC", title: "Dimmer Settings", description: dimmerDesc(C_dimmers), state: greyOutOption(C_dimmers), submitOnChange:true href "pageThermostatsC", title: "Thermostat Settings", description: thermostatDesc(C_thermostats, C_temperatureH, C_temperatureC), state: greyOutOption(C_thermostats), submitOnChange:true - if ((C_switches || C_dimmers || C_thermostats) && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ - input "C_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" + if ((C_switches || C_dimmers || C_thermostats) && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ + input "C_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" } } section ("Other actions at alarm time"){ def phrases = location.helloHome?.getPhrases()*.label - if (phrases) { - phrases.sort() - input "C_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true - if (C_phrase && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ - input "C_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" - } + if (phrases) { + phrases.sort() + input "C_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true + if (C_phrase && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ + input "C_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" + } } input "C_triggerMode", "mode", title: "Alarm triggers the following mode", required: false, submitOnChange:true - if (C_triggerMode && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ - input "C_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" + if (C_triggerMode && (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1"))){ + input "C_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" } } - } + } } page(name: "pageDimmersC", title: "Dimmer Settings") { - section { - input "C_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false - input "C_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false - } + section { + input "C_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false + input "C_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false + } } page(name: "pageThermostatsC", title: "Thermostat Settings") { - section { - input "C_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false - } + section { + input "C_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false + } section { input "C_temperatureH", "number", title: "Heating setpoint", required: false, description: "Temperature when in heat mode" - input "C_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" - } + input "C_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" + } } def pageWeatherSettingsC() { - dynamicPage(name: "pageWeatherSettingsC", title: "Weather Reporting Settings") { - section { - input "C_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" - input "C_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false - input "C_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false - input "C_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" - input "C_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" - input "C_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" - } - } + dynamicPage(name: "pageWeatherSettingsC", title: "Weather Reporting Settings") { + section { + input "C_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" + input "C_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false + input "C_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false + input "C_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" + input "C_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" + input "C_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" + } + } } //Show "pageSetupScenarioD" page def pageSetupScenarioD() { dynamicPage(name: "pageSetupScenarioD") { - section("Alarm settings") { - input "ScenarioNameD", "text", title: "Scenario Name", multiple: false, required: true - input "D_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true + section("Alarm settings") { + input "ScenarioNameD", "text", title: "Scenario Name", multiple: false, required: true + input "D_sonos", "capability.musicPlayer", title: "Choose a Sonos speaker", required: true, submitOnChange:true input "D_volume", "number", title: "Alarm volume", description: "0-100%", required: false - input "D_timeStart", "time", title: "Time to trigger alarm", required: true - input "D_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false - input "D_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false - input "D_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true - + input "D_timeStart", "time", title: "Time to trigger alarm", required: true + input "D_day", "enum", options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], title: "Alarm on certain days of the week...", multiple: true, required: false + input "D_mode", "mode", title: "Alarm only during the following modes...", multiple: true, required: false + input "D_alarmType", "enum", title: "Select a primary alarm type...", multiple: false, required: true, options: [[1:"Alarm sound (up to 20 seconds)"],[2:"Voice Greeting"],[3:"Music track/Internet Radio"]], submitOnChange:true + if (D_alarmType != "3") { - if (D_alarmType == "1"){ - input "D_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true + if (D_alarmType == "1"){ + input "D_secondAlarm", "enum", title: "Select a second alarm after the first is completed", multiple: false, required: false, options: [[1:"Voice Greeting"],[2:"Music track/Internet Radio"]], submitOnChange:true } if (D_alarmType == "2"){ - input "D_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true + input "D_secondAlarmMusic", "bool", title: "Play a track after voice greeting", defaultValue: "false", required: false, submitOnChange:true } - } + } } if (D_alarmType == "1"){ - section ("Alarm sound options"){ - input "D_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] - input "D_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false - } - } - + section ("Alarm sound options"){ + input "D_soundAlarm", "enum", title: "Play this sound...", required:false, multiple: false, options: [[1:"Alien-8 seconds"],[2:"Bell-12 seconds"], [3:"Buzzer-20 seconds"], [4:"Fire-20 seconds"], [5:"Rooster-2 seconds"], [6:"Siren-20 seconds"]] + input "D_soundLength", "number", title: "Maximum time to play sound (empty=use sound default)", description: "1-20", required: false + } + } + if (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1")) { - section ("Voice greeting options") { - input "D_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false - href "pageWeatherSettingsD", title: "Weather Reporting Settings", description: getWeatherDesc(D_weatherReport, D_includeSunrise, D_includeSunset, D_includeTemp, D_humidity, D_localTemp), state: greyOut1(D_weatherReport, D_includeSunrise, D_includeSunset, D_includeTemp, D_humidity, D_localTemp) } - } - - if (D_alarmType == "3" || (D_alarmType == "1" && D_secondAlarm =="2") || (D_alarmType == "2" && D_secondAlarmMusic)){ - section ("Music track/internet radio options"){ - input "D_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(D_sonos, 1) - } - } + section ("Voice greeting options") { + input "D_wakeMsg", "text", title: "Wake voice message", defaultValue: "Good morning! It is %time% on %day%, %date%.", required: false + href "pageWeatherSettingsD", title: "Weather Reporting Settings", description: getWeatherDesc(D_weatherReport, D_includeSunrise, D_includeSunset, D_includeTemp, D_humidity, D_localTemp), state: greyOut1(D_weatherReport, D_includeSunrise, D_includeSunset, D_includeTemp, D_humidity, D_localTemp) } + } + + if (D_alarmType == "3" || (D_alarmType == "1" && D_secondAlarm =="2") || (D_alarmType == "2" && D_secondAlarmMusic)){ + section ("Music track/internet radio options"){ + input "D_musicTrack", "enum", title: "Play this track/internet radio station", required:false, multiple: false, options: songOptions(D_sonos, 1) + } + } section("Devices to control in this alarm scenario") { - input "D_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true - href "pageDimmersD", title: "Dimmer Settings", description: dimmerDesc(D_dimmers), state: greyOutOption(D_dimmers), submitOnChange:true + input "D_switches", "capability.switch",title: "Control the following switches...", multiple: true, required: false, submitOnChange:true + href "pageDimmersD", title: "Dimmer Settings", description: dimmerDesc(D_dimmers), state: greyOutOption(D_dimmers), submitOnChange:true href "pageThermostatsD", title: "Thermostat Settings", description: thermostatDesc(D_thermostats, D_temperatureH, D_temperatureC), state: greyOutOption(D_thermostats), submitOnChange:true - if ((D_switches || D_dimmers || D_thermostats) && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ - input "D_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" + if ((D_switches || D_dimmers || D_thermostats) && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ + input "D_confirmSwitches", "bool", title: "Confirm switches/thermostats status in voice message", defaultValue: "false" } } section ("Other actions at alarm time"){ def phrases = location.helloHome?.getPhrases()*.label - if (phrases) { - phrases.sort() - input "D_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true - if (D_phrase && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ - input "D_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" - } + if (phrases) { + phrases.sort() + input "D_phrase", "enum", title: "Alarm triggers the following phrase", required: false, options: phrases, multiple: false, submitOnChange:true + if (D_phrase && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ + input "D_confirmPhrase", "bool", title: "Confirm Hello, Home phrase in voice message", defaultValue: "false" + } } input "D_triggerMode", "mode", title: "Alarm triggers the following mode", required: false, submitOnChange:true - if (D_triggerMode && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ - input "D_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" + if (D_triggerMode && (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1"))){ + input "D_confirmMode", "bool", title: "Confirm mode in voice message", defaultValue: "false" } } - } + } } page(name: "pageDimmersD", title: "Dimmer Settings") { - section { - input "D_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false - input "D_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false - } + section { + input "D_dimmers", "capability.switchLevel", title: "Dim the following...", multiple: true, required: false + input "D_level", "enum", options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]],title: "Set dimmers to this level", multiple: false, required: false + } } page(name: "pageThermostatsD", title: "Thermostat Settings") { - section { - input "D_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false - } + section { + input "D_thermostats", "capability.thermostat", title: "Thermostat to control...", multiple: false, required: false + } section { input "D_temperatureH", "number", title: "Heating setpoint", required: false, description: "Temperature when in heat mode" - input "D_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" - } + input "D_temperatureC", "number", title: "Cooling setpoint", required: false, description: "Temperature when in cool mode" + } } def pageWeatherSettingsD() { - dynamicPage(name: "pageWeatherSettingsD", title: "Weather Reporting Settings") { - section { - input "D_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" - input "D_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false - input "D_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false - input "D_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" - input "D_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" - input "D_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" - } - } + dynamicPage(name: "pageWeatherSettingsD", title: "Weather Reporting Settings") { + section { + input "D_includeTemp", "bool", title: "Speak current temperature (from local forecast)", defaultValue: "false" + input "D_localTemp", "capability.temperatureMeasurement", title: "Speak local temperature (from device)", required: false, multiple: false + input "D_humidity", "capability.relativeHumidityMeasurement", title: "Speak local humidity (from device)", required: false, multiple: false + input "D_weatherReport", "bool", title: "Speak today's weather forecast", defaultValue: "false" + input "D_includeSunrise", "bool", title: "Speak today's sunrise", defaultValue: "false" + input "D_includeSunset", "bool", title: "Speak today's sunset", defaultValue: "false" + } + } } page(name: "pageAbout", title: "About ${textAppName()}") { @@ -493,445 +493,445 @@ def updated() { } def initialize() { - if (A_alarmType =="1"){ - alarmSoundUri(A_soundAlarm, A_soundLength, 1) + if (A_alarmType =="1"){ + alarmSoundUri(A_soundAlarm, A_soundLength, 1) } if (B_alarmType =="1"){ - alarmSoundUri(B_soundAlarm, B_soundLength, 2) + alarmSoundUri(B_soundAlarm, B_soundLength, 2) } if (C_alarmType =="1"){ - alarmSoundUri(C_soundAlarm, C_soundLength, 3) + alarmSoundUri(C_soundAlarm, C_soundLength, 3) } if (D_alarmType =="1"){ - alarmSoundUri(D_soundAlarm, D_soundLength, 4) + alarmSoundUri(D_soundAlarm, D_soundLength, 4) } - + if (alarmSummary && summarySonos) { - subscribe(app, appTouchHandler) + subscribe(app, appTouchHandler) } if (ScenarioNameA && A_timeStart && A_sonos && A_alarmOn && A_alarmType){ - schedule (A_timeStart, alarm_A) + schedule (A_timeStart, alarm_A) if (A_musicTrack){ - saveSelectedSong(A_sonos, A_musicTrack, 1) + saveSelectedSong(A_sonos, A_musicTrack, 1) } - } + } if (ScenarioNameB && B_timeStart && B_sonos &&B_alarmOn && B_alarmType){ - schedule (B_timeStart, alarm_B) + schedule (B_timeStart, alarm_B) if (B_musicTrack){ - saveSelectedSong(B_sonos, B_musicTrack, 2) + saveSelectedSong(B_sonos, B_musicTrack, 2) } - } + } if (ScenarioNameC && C_timeStart && C_sonos && C_alarmOn && C_alarmType){ - schedule (C_timeStart, alarm_C) + schedule (C_timeStart, alarm_C) if (C_musicTrack){ - saveSelectedSong(C_sonos, C_musicTrack, 3) + saveSelectedSong(C_sonos, C_musicTrack, 3) } - } - if (ScenarioNameD && D_timeStart && D_sonos && D_alarmOn && D_alarmType){ - schedule (D_timeStart, alarm_D) + } + if (ScenarioNameD && D_timeStart && D_sonos && D_alarmOn && D_alarmType){ + schedule (D_timeStart, alarm_D) if (D_musicTrack){ - saveSelectedSong(D_sonos, D_musicTrack, 4) + saveSelectedSong(D_sonos, D_musicTrack, 4) } - } + } } //-------------------------------------- def alarm_A() { - if ((!A_mode || A_mode.contains(location.mode)) && getDayOk(A_day)) { + if ((!A_mode || A_mode.contains(location.mode)) && getDayOk(A_day)) { if (A_switches || A_dimmers || A_thermostats) { - def dimLevel = A_level as Integer + def dimLevel = A_level as Integer A_switches?.on() - A_dimmers?.setLevel(dimLevel) + A_dimmers?.setLevel(dimLevel) if (A_thermostats) { - def thermostatState = A_thermostats.currentThermostatMode - if (thermostatState == "auto") { - A_thermostats.setHeatingSetpoint(A_temperatureH) - A_thermostats.setCoolingSetpoint(A_temperatureC) - } - else if (thermostatState == "heat") { - A_thermostats.setHeatingSetpoint(A_temperatureH) - log.info "Set $A_thermostats Heat $A_temperatureH°" - } - else { - A_thermostats.setCoolingSetpoint(A_temperatureC) - log.info "Set $A_thermostats Cool $A_temperatureC°" - } - } + def thermostatState = A_thermostats.currentThermostatMode + if (thermostatState == "auto") { + A_thermostats.setHeatingSetpoint(A_temperatureH) + A_thermostats.setCoolingSetpoint(A_temperatureC) + } + else if (thermostatState == "heat") { + A_thermostats.setHeatingSetpoint(A_temperatureH) + log.info "Set $A_thermostats Heat $A_temperatureH°" + } + else { + A_thermostats.setCoolingSetpoint(A_temperatureC) + log.info "Set $A_thermostats Cool $A_temperatureC°" + } + } } if (A_phrase) { - location.helloHome.execute(A_phrase) + location.helloHome.execute(A_phrase) } - + if (A_triggerMode && location.mode != A_triggerMode) { - if (location.modes?.find{it.name == A_triggerMode}) { - setLocationMode(A_triggerMode) - } + if (location.modes?.find{it.name == A_triggerMode}) { + setLocationMode(A_triggerMode) + } else { - log.debug "Unable to change to undefined mode '${A_triggerMode}'" - } - } - + log.debug "Unable to change to undefined mode '${A_triggerMode}'" + } + } + if (A_volume) { - A_sonos.setLevel(A_volume) - } - + A_sonos.setLevel(A_volume) + } + if (A_alarmType == "2" || (A_alarmType == "1" && A_secondAlarm =="1")) { - state.fullMsgA = "" - if (A_wakeMsg) { - getGreeting(A_wakeMsg, 1) - } - + state.fullMsgA = "" + if (A_wakeMsg) { + getGreeting(A_wakeMsg, 1) + } + if (A_weatherReport || A_humidity || A_includeTemp || A_localTemp) { - getWeatherReport(1, A_weatherReport, A_humidity, A_includeTemp, A_localTemp) - } - - if (A_includeSunrise || A_includeSunset) { - getSunriseSunset(1, A_includeSunrise, A_includeSunset) - } - + getWeatherReport(1, A_weatherReport, A_humidity, A_includeTemp, A_localTemp) + } + + if (A_includeSunrise || A_includeSunset) { + getSunriseSunset(1, A_includeSunrise, A_includeSunset) + } + if ((A_switches || A_dimmers || A_thermostats) && A_confirmSwitches) { - getOnConfimation(A_switches, A_dimmers, A_thermostats, 1) - } - + getOnConfimation(A_switches, A_dimmers, A_thermostats, 1) + } + if (A_phrase && A_confirmPhrase) { - getPhraseConfirmation(1, A_phrase) - } - + getPhraseConfirmation(1, A_phrase) + } + if (A_triggerMode && A_confirmMode){ - getModeConfirmation(A_triggerMode, 1) + getModeConfirmation(A_triggerMode, 1) } - + state.soundA = textToSpeech(state.fullMsgA, true) - } - + } + if (A_alarmType == "1"){ - if (A_secondAlarm == "1" && state.soundAlarmA){ - A_sonos.playSoundAndTrack (state.soundAlarmA.uri, state.soundAlarmA.duration, state.soundA.uri) - } + if (A_secondAlarm == "1" && state.soundAlarmA){ + A_sonos.playSoundAndTrack (state.soundAlarmA.uri, state.soundAlarmA.duration, state.soundA.uri) + } if (A_secondAlarm == "2" && state.selectedSongA && state.soundAlarmA){ - A_sonos.playSoundAndTrack (state.soundAlarmA.uri, state.soundAlarmA.duration, state.selectedSongA) + A_sonos.playSoundAndTrack (state.soundAlarmA.uri, state.soundAlarmA.duration, state.selectedSongA) } if (!A_secondAlarm){ - A_sonos.playTrack(state.soundAlarmA.uri) + A_sonos.playTrack(state.soundAlarmA.uri) } } - + if (A_alarmType == "2") { - if (A_secondAlarmMusic && state.selectedSongA){ - A_sonos.playSoundAndTrack (state.soundA.uri, state.soundA.duration, state.selectedSongA) + if (A_secondAlarmMusic && state.selectedSongA){ + A_sonos.playSoundAndTrack (state.soundA.uri, state.soundA.duration, state.selectedSongA) } else { - A_sonos.playTrack(state.soundA.uri) + A_sonos.playTrack(state.soundA.uri) } } - + if (A_alarmType == "3") { - A_sonos.playTrack(state.selectedSongA) + A_sonos.playTrack(state.selectedSongA) } - } + } } def alarm_B() { - if ((!B_mode || B_mode.contains(location.mode)) && getDayOk(B_day)) { + if ((!B_mode || B_mode.contains(location.mode)) && getDayOk(B_day)) { if (B_switches || B_dimmers || B_thermostats) { - def dimLevel = B_level as Integer + def dimLevel = B_level as Integer B_switches?.on() - B_dimmers?.setLevel(dimLevel) + B_dimmers?.setLevel(dimLevel) if (B_thermostats) { - def thermostatState = B_thermostats.currentThermostatMode - if (thermostatState == "auto") { - B_thermostats.setHeatingSetpoint(B_temperatureH) - B_thermostats.setCoolingSetpoint(B_temperatureC) - } - else if (thermostatState == "heat") { - B_thermostats.setHeatingSetpoint(B_temperatureH) - log.info "Set $B_thermostats Heat $B_temperatureH°" - } - else { - B_thermostats.setCoolingSetpoint(B_temperatureC) - log.info "Set $B_thermostats Cool $B_temperatureC°" - } - } + def thermostatState = B_thermostats.currentThermostatMode + if (thermostatState == "auto") { + B_thermostats.setHeatingSetpoint(B_temperatureH) + B_thermostats.setCoolingSetpoint(B_temperatureC) + } + else if (thermostatState == "heat") { + B_thermostats.setHeatingSetpoint(B_temperatureH) + log.info "Set $B_thermostats Heat $B_temperatureH°" + } + else { + B_thermostats.setCoolingSetpoint(B_temperatureC) + log.info "Set $B_thermostats Cool $B_temperatureC°" + } + } } if (B_phrase) { - location.helloHome.execute(B_phrase) + location.helloHome.execute(B_phrase) } - + if (B_triggerMode && location.mode != B_triggerMode) { - if (location.modes?.find{it.name == B_triggerMode}) { - setLocationMode(B_triggerMode) - } + if (location.modes?.find{it.name == B_triggerMode}) { + setLocationMode(B_triggerMode) + } else { - log.debug "Unable to change to undefined mode '${B_triggerMode}'" - } - } - + log.debug "Unable to change to undefined mode '${B_triggerMode}'" + } + } + if (B_volume) { - B_sonos.setLevel(B_volume) - } - + B_sonos.setLevel(B_volume) + } + if (B_alarmType == "2" || (B_alarmType == "1" && B_secondAlarm =="1")) { - state.fullMsgB = "" - if (B_wakeMsg) { - getGreeting(B_wakeMsg, 2) - } - + state.fullMsgB = "" + if (B_wakeMsg) { + getGreeting(B_wakeMsg, 2) + } + if (B_weatherReport || B_humidity || B_includeTemp || B_localTemp) { - getWeatherReport(2, B_weatherReport, B_humidity, B_includeTemp, B_localTemp) - } - - if (B_includeSunrise || B_includeSunset) { - getSunriseSunset(2, B_includeSunrise, B_includeSunset) - } - + getWeatherReport(2, B_weatherReport, B_humidity, B_includeTemp, B_localTemp) + } + + if (B_includeSunrise || B_includeSunset) { + getSunriseSunset(2, B_includeSunrise, B_includeSunset) + } + if ((B_switches || B_dimmers || B_thermostats) && B_confirmSwitches) { - getOnConfimation(B_switches, B_dimmers, B_thermostats, 2) - } - + getOnConfimation(B_switches, B_dimmers, B_thermostats, 2) + } + if (B_phrase && B_confirmPhrase) { - getPhraseConfirmation(2, B_phrase) - } - + getPhraseConfirmation(2, B_phrase) + } + if (B_triggerMode && B_confirmMode){ - getModeConfirmation(B_triggerMode, 2) + getModeConfirmation(B_triggerMode, 2) } - + state.soundB = textToSpeech(state.fullMsgB, true) - } - + } + if (B_alarmType == "1"){ - if (B_secondAlarm == "1" && state.soundAlarmB) { - B_sonos.playSoundAndTrack (state.soundAlarmB.uri, state.soundAlarmB.duration, state.soundB.uri) - } + if (B_secondAlarm == "1" && state.soundAlarmB) { + B_sonos.playSoundAndTrack (state.soundAlarmB.uri, state.soundAlarmB.duration, state.soundB.uri) + } if (B_secondAlarm == "2" && state.selectedSongB && state.soundAlarmB){ - B_sonos.playSoundAndTrack (state.soundAlarmB.uri, state.soundAlarmB.duration, state.selectedSongB) + B_sonos.playSoundAndTrack (state.soundAlarmB.uri, state.soundAlarmB.duration, state.selectedSongB) } if (!B_secondAlarm){ - B_sonos.playTrack(state.soundAlarmB.uri) + B_sonos.playTrack(state.soundAlarmB.uri) } } - + if (B_alarmType == "2") { - if (B_secondAlarmMusic && state.selectedSongB){ - B_sonos.playSoundAndTrack (state.soundB.uri, state.soundB.duration, state.selectedSongB) + if (B_secondAlarmMusic && state.selectedSongB){ + B_sonos.playSoundAndTrack (state.soundB.uri, state.soundB.duration, state.selectedSongB) } else { - B_sonos.playTrack(state.soundB.uri) + B_sonos.playTrack(state.soundB.uri) } } - + if (B_alarmType == "3") { - B_sonos.playTrack(state.selectedSongB) + B_sonos.playTrack(state.selectedSongB) } - } + } } def alarm_C() { - if ((!C_mode || C_mode.contains(location.mode)) && getDayOk(C_day)) { + if ((!C_mode || C_mode.contains(location.mode)) && getDayOk(C_day)) { if (C_switches || C_dimmers || C_thermostats) { - def dimLevel = C_level as Integer + def dimLevel = C_level as Integer C_switches?.on() - C_dimmers?.setLevel(dimLevel) + C_dimmers?.setLevel(dimLevel) if (C_thermostats) { - def thermostatState = C_thermostats.currentThermostatMode - if (thermostatState == "auto") { - C_thermostats.setHeatingSetpoint(C_temperatureH) - C_thermostats.setCoolingSetpoint(C_temperatureC) - } - else if (thermostatState == "heat") { - C_thermostats.setHeatingSetpoint(C_temperatureH) - log.info "Set $C_thermostats Heat $C_temperatureH°" - } - else { - C_thermostats.setCoolingSetpoint(C_temperatureC) - log.info "Set $C_thermostats Cool $C_temperatureC°" - } - } + def thermostatState = C_thermostats.currentThermostatMode + if (thermostatState == "auto") { + C_thermostats.setHeatingSetpoint(C_temperatureH) + C_thermostats.setCoolingSetpoint(C_temperatureC) + } + else if (thermostatState == "heat") { + C_thermostats.setHeatingSetpoint(C_temperatureH) + log.info "Set $C_thermostats Heat $C_temperatureH°" + } + else { + C_thermostats.setCoolingSetpoint(C_temperatureC) + log.info "Set $C_thermostats Cool $C_temperatureC°" + } + } } if (C_phrase) { - location.helloHome.execute(C_phrase) + location.helloHome.execute(C_phrase) } - + if (C_triggerMode && location.mode != C_triggerMode) { - if (location.modes?.find{it.name == C_triggerMode}) { - setLocationMode(C_triggerMode) - } + if (location.modes?.find{it.name == C_triggerMode}) { + setLocationMode(C_triggerMode) + } else { - log.debug "Unable to change to undefined mode '${C_triggerMode}'" - } - } - + log.debug "Unable to change to undefined mode '${C_triggerMode}'" + } + } + if (C_volume) { - C_sonos.setLevel(C_volume) - } - + C_sonos.setLevel(C_volume) + } + if (C_alarmType == "2" || (C_alarmType == "1" && C_secondAlarm =="1")) { - state.fullMsgC = "" - if (C_wakeMsg) { - getGreeting(C_wakeMsg, 3) - } - + state.fullMsgC = "" + if (C_wakeMsg) { + getGreeting(C_wakeMsg, 3) + } + if (C_weatherReport || C_humidity || C_includeTemp || C_localTemp) { - getWeatherReport(3, C_weatherReport, C_humidity, C_includeTemp, C_localTemp) - } - - if (C_includeSunrise || C_includeSunset) { - getSunriseSunset(3, C_includeSunrise, C_includeSunset) - } - + getWeatherReport(3, C_weatherReport, C_humidity, C_includeTemp, C_localTemp) + } + + if (C_includeSunrise || C_includeSunset) { + getSunriseSunset(3, C_includeSunrise, C_includeSunset) + } + if ((C_switches || C_dimmers || C_thermostats) && C_confirmSwitches) { - getOnConfimation(C_switches, C_dimmers, C_thermostats, 3) - } - + getOnConfimation(C_switches, C_dimmers, C_thermostats, 3) + } + if (C_phrase && C_confirmPhrase) { - getPhraseConfirmation(3, C_phrase) - } - + getPhraseConfirmation(3, C_phrase) + } + if (C_triggerMode && C_confirmMode){ - getModeConfirmation(C_triggerMode, 3) + getModeConfirmation(C_triggerMode, 3) } - + state.soundC = textToSpeech(state.fullMsgC, true) - } - + } + if (C_alarmType == "1"){ - if (C_secondAlarm == "1" && state.soundAlarmC){ - C_sonos.playSoundAndTrack (state.soundAlarmC.uri, state.soundAlarmC.duration, state.soundC.uri) - } + if (C_secondAlarm == "1" && state.soundAlarmC){ + C_sonos.playSoundAndTrack (state.soundAlarmC.uri, state.soundAlarmC.duration, state.soundC.uri) + } if (C_secondAlarm == "2" && state.selectedSongC && state.soundAlarmC){ - C_sonos.playSoundAndTrack (state.soundAlarmC.uri, state.soundAlarmC.duration, state.selectedSongC) + C_sonos.playSoundAndTrack (state.soundAlarmC.uri, state.soundAlarmC.duration, state.selectedSongC) } if (!C_secondAlarm){ - C_sonos.playTrack(state.soundAlarmC.uri) + C_sonos.playTrack(state.soundAlarmC.uri) } } - + if (C_alarmType == "2") { - if (C_secondAlarmMusic && state.selectedSongC){ - C_sonos.playSoundAndTrack (state.soundC.uri, state.soundC.duration, state.selectedSongC) + if (C_secondAlarmMusic && state.selectedSongC){ + C_sonos.playSoundAndTrack (state.soundC.uri, state.soundC.duration, state.selectedSongC) } else { - C_sonos.playTrack(state.soundC.uri) + C_sonos.playTrack(state.soundC.uri) } } - + if (C_alarmType == "3") { - C_sonos.playTrack(state.selectedSongC) + C_sonos.playTrack(state.selectedSongC) } - } + } } def alarm_D() { - if ((!D_mode || D_mode.contains(location.mode)) && getDayOk(D_day)) { + if ((!D_mode || D_mode.contains(location.mode)) && getDayOk(D_day)) { if (D_switches || D_dimmers || D_thermostats) { - def dimLevel = D_level as Integer + def dimLevel = D_level as Integer D_switches?.on() - D_dimmers?.setLevel(dimLevel) + D_dimmers?.setLevel(dimLevel) if (D_thermostats) { - def thermostatState = D_thermostats.currentThermostatMode - if (thermostatState == "auto") { - D_thermostats.setHeatingSetpoint(D_temperatureH) - D_thermostats.setCoolingSetpoint(D_temperatureC) - } - else if (thermostatState == "heat") { - D_thermostats.setHeatingSetpoint(D_temperatureH) - log.info "Set $D_thermostats Heat $D_temperatureH°" - } - else { - D_thermostats.setCoolingSetpoint(D_temperatureC) - log.info "Set $D_thermostats Cool $D_temperatureC°" - } - } + def thermostatState = D_thermostats.currentThermostatMode + if (thermostatState == "auto") { + D_thermostats.setHeatingSetpoint(D_temperatureH) + D_thermostats.setCoolingSetpoint(D_temperatureC) + } + else if (thermostatState == "heat") { + D_thermostats.setHeatingSetpoint(D_temperatureH) + log.info "Set $D_thermostats Heat $D_temperatureH°" + } + else { + D_thermostats.setCoolingSetpoint(D_temperatureC) + log.info "Set $D_thermostats Cool $D_temperatureC°" + } + } } if (D_phrase) { - location.helloHome.execute(D_phrase) + location.helloHome.execute(D_phrase) } - + if (D_triggerMode && location.mode != D_triggerMode) { - if (location.modes?.find{it.name == D_triggerMode}) { - setLocationMode(D_triggerMode) - } + if (location.modes?.find{it.name == D_triggerMode}) { + setLocationMode(D_triggerMode) + } else { - log.debug "Unable to change to undefined mode '${D_triggerMode}'" - } - } - + log.debug "Unable to change to undefined mode '${D_triggerMode}'" + } + } + if (D_volume) { - D_sonos.setLevel(D_volume) - } - + D_sonos.setLevel(D_volume) + } + if (D_alarmType == "2" || (D_alarmType == "1" && D_secondAlarm =="1")) { - state.fullMsgD = "" - if (D_wakeMsg) { - getGreeting(D_wakeMsg, 4) - } - + state.fullMsgD = "" + if (D_wakeMsg) { + getGreeting(D_wakeMsg, 4) + } + if (D_weatherReport || D_humidity || D_includeTemp || D_localTemp) { - getWeatherReport(4, D_weatherReport, D_humidity, D_includeTemp, D_localTemp) - } - - if (D_includeSunrise || D_includeSunset) { - getSunriseSunset(4, D_includeSunrise, D_includeSunset) - } - + getWeatherReport(4, D_weatherReport, D_humidity, D_includeTemp, D_localTemp) + } + + if (D_includeSunrise || D_includeSunset) { + getSunriseSunset(4, D_includeSunrise, D_includeSunset) + } + if ((D_switches || D_dimmers || D_thermostats) && D_confirmSwitches) { - getOnConfimation(D_switches, D_dimmers, D_thermostats, 4) - } - + getOnConfimation(D_switches, D_dimmers, D_thermostats, 4) + } + if (D_phrase && D_confirmPhrase) { - getPhraseConfirmation(4, D_phrase) - } - + getPhraseConfirmation(4, D_phrase) + } + if (D_triggerMode && D_confirmMode){ - getModeConfirmation(D_triggerMode, 4) + getModeConfirmation(D_triggerMode, 4) } - + state.soundD = textToSpeech(state.fullMsgD, true) - } - + } + if (D_alarmType == "1"){ - if (D_secondAlarm == "1" && state.soundAlarmD){ - D_sonos.playSoundAndTrack (state.soundAlarmD.uri, state.soundAlarmD.duration, state.soundD.uri) - } + if (D_secondAlarm == "1" && state.soundAlarmD){ + D_sonos.playSoundAndTrack (state.soundAlarmD.uri, state.soundAlarmD.duration, state.soundD.uri) + } if (D_secondAlarm == "2" && state.selectedSongD && state.soundAlarmD){ - D_sonos.playSoundAndTrack (state.soundAlarmD.uri, state.soundAlarmD.duration, state.selectedSongD) + D_sonos.playSoundAndTrack (state.soundAlarmD.uri, state.soundAlarmD.duration, state.selectedSongD) } if (!D_secondAlarm){ - D_sonos.playTrack(state.soundAlarmD.uri) + D_sonos.playTrack(state.soundAlarmD.uri) } } - + if (D_alarmType == "2") { - if (D_secondAlarmMusic && state.selectedSongD){ - D_sonos.playSoundAndTrack (state.soundD.uri, state.soundD.duration, state.selectedSongD) + if (D_secondAlarmMusic && state.selectedSongD){ + D_sonos.playSoundAndTrack (state.soundD.uri, state.soundD.duration, state.selectedSongD) } else { - D_sonos.playTrack(state.soundD.uri) + D_sonos.playTrack(state.soundD.uri) } } - + if (D_alarmType == "3") { - D_sonos.playTrack(state.selectedSongD) + D_sonos.playTrack(state.selectedSongD) } - } + } } def appTouchHandler(evt){ - if (!summaryMode || summaryMode.contains(location.mode)) { - state.summaryMsg = "The following is a summary of the alarm settings. " - getSummary (A_alarmOn, ScenarioNameA, A_timeStart, 1) - getSummary (B_alarmOn, ScenarioNameB, B_timeStart, 2) - getSummary (C_alarmOn, ScenarioNameC, C_timeStart, 3) - getSummary (D_alarmOn, ScenarioNameD, D_timeStart, 4) - - log.debug "Summary message = ${state.summaryMsg}" - def summarySound = textToSpeech(state.summaryMsg, true) - if (summaryVolume) { - summarySonos.setLevel(summaryVolume) - } - summarySonos.playTrack(summarySound.uri) - } + if (!summaryMode || summaryMode.contains(location.mode)) { + state.summaryMsg = "The following is a summary of the alarm settings. " + getSummary (A_alarmOn, ScenarioNameA, A_timeStart, 1) + getSummary (B_alarmOn, ScenarioNameB, B_timeStart, 2) + getSummary (C_alarmOn, ScenarioNameC, C_timeStart, 3) + getSummary (D_alarmOn, ScenarioNameD, D_timeStart, 4) + + log.debug "Summary message = ${state.summaryMsg}" + def summarySound = textToSpeech(state.summaryMsg, true) + if (summaryVolume) { + summarySonos.setLevel(summaryVolume) + } + summarySonos.playTrack(summarySound.uri) + } } def getSummary (alarmOn, scenarioName, timeStart, num){ @@ -949,161 +949,161 @@ def getSummary (alarmOn, scenarioName, timeStart, num){ //-------------------------------------- def getDesc(timeStart, sonos, day, mode) { - def desc = "Tap to set alarm" - if (timeStart) { - desc = "Alarm set to " + parseDate(timeStart,"", "h:mm a") +" on ${sonos}" - + def desc = "Tap to set alarm" + if (timeStart) { + desc = "Alarm set to " + parseDate(timeStart,"", "h:mm a") +" on ${sonos}" + def dayListSize = day ? day.size() : 7 - + if (day && dayListSize < 7) { - desc = desc + " on" + desc = desc + " on" for (dayName in day) { - desc = desc + " ${dayName}" - dayListSize = dayListSize -1 + desc = desc + " ${dayName}" + dayListSize = dayListSize -1 if (dayListSize) { - desc = "${desc}, " - } - } + desc = "${desc}, " + } + } } else { - desc = desc + " every day" - } - + desc = desc + " every day" + } + if (mode) { - def modeListSize = mode.size() - def modePrefix =" in the following modes: " - if (modeListSize == 1) { - modePrefix = " in the following mode: " - } - desc = desc + "${modePrefix}" - for (modeName in mode) { - desc = desc + "'${modeName}'" - modeListSize = modeListSize -1 - if (modeListSize) { - desc = "${desc}, " - } - else { - desc = "${desc}" - } - } - } - else { - desc = desc + " in all modes" + def modeListSize = mode.size() + def modePrefix =" in the following modes: " + if (modeListSize == 1) { + modePrefix = " in the following mode: " + } + desc = desc + "${modePrefix}" + for (modeName in mode) { + desc = desc + "'${modeName}'" + modeListSize = modeListSize -1 + if (modeListSize) { + desc = "${desc}, " + } + else { + desc = "${desc}" + } + } + } + else { + desc = desc + " in all modes" } } - desc + desc } def greyOut(scenario, sonos, alarmTime, alarmOn, alarmType){ - def result = scenario && sonos && alarmTime && alarmOn && alarmType ? "complete" : "" + def result = scenario && sonos && alarmTime && alarmOn && alarmType ? "complete" : "" } def greyOut1(param1, param2, param3, param4, param5, param6){ - def result = param1 || param2 || param3 || param4 || param5 || param6 ? "complete" : "" + def result = param1 || param2 || param3 || param4 || param5 || param6 ? "complete" : "" } def getWeatherDesc(param1, param2, param3, param4, param5, param6) { - def title = param1 || param2 || param3 || param4 || param5 || param6 ? "Tap to edit weather reporting options" : "Tap to setup weather reporting options" + def title = param1 || param2 || param3 || param4 || param5 || param6 ? "Tap to edit weather reporting options" : "Tap to setup weather reporting options" } def greyOutOption(param){ - def result = param ? "complete" : "" + def result = param ? "complete" : "" } def getTitle(scenario, num) { - def title = scenario ? scenario : "Alarm ${num} not configured" + def title = scenario ? scenario : "Alarm ${num} not configured" } def dimmerDesc(dimmer){ - def desc = dimmer ? "Tap to edit dimmer settings" : "Tap to set dimmer setting" + def desc = dimmer ? "Tap to edit dimmer settings" : "Tap to set dimmer setting" } def thermostatDesc(thermostat, heating, cooling){ - def tempText + def tempText if (heating || cooling){ - if (heating){ - tempText = "${heating} heat" + if (heating){ + tempText = "${heating} heat" } if (cooling){ - tempText = "${cooling} cool" + tempText = "${cooling} cool" } - if (heating && cooling) { - tempText ="${heating} heat / ${cooling} cool" + if (heating && cooling) { + tempText ="${heating} heat / ${cooling} cool" } } else { - tempText="Tap to edit thermostat settings" + tempText="Tap to edit thermostat settings" } - + def desc = thermostat ? "${tempText}" : "Tap to set thermostat settings" - return desc + return desc } private getDayOk(dayList) { - def result = true - if (dayList) { - result = dayList.contains(getDay()) - } - result + def result = true + if (dayList) { + result = dayList.contains(getDay()) + } + result } private getDay(){ - def df = new java.text.SimpleDateFormat("EEEE") - if (location.timeZone) { - df.setTimeZone(location.timeZone) - } - else { - df.setTimeZone(TimeZone.getTimeZone("America/New_York")) - } - def day = df.format(new Date()) + def df = new java.text.SimpleDateFormat("EEEE") + if (location.timeZone) { + df.setTimeZone(location.timeZone) + } + else { + df.setTimeZone(TimeZone.getTimeZone("America/New_York")) + } + def day = df.format(new Date()) } private parseDate(date, epoch, type){ def parseDate = "" if (epoch){ - long longDate = Long.valueOf(epoch).longValue() + long longDate = Long.valueOf(epoch).longValue() parseDate = new Date(longDate).format("yyyy-MM-dd'T'HH:mm:ss.SSSZ", location.timeZone) } else { - parseDate = date + parseDate = date } new Date().parse("yyyy-MM-dd'T'HH:mm:ss.SSSZ", parseDate).format("${type}", timeZone(parseDate)) } private getSunriseSunset(scenario, includeSunrise, includeSunset){ - if (location.timeZone || zipCode) { - def todayDate = new Date() - def s = getSunriseAndSunset(zipcode: zipCode, date: todayDate) - def riseTime = parseDate("", s.sunrise.time, "h:mm a") - def setTime = parseDate ("", s.sunset.time, "h:mm a") - def msg = "" - def currTime = now() + if (location.timeZone || zipCode) { + def todayDate = new Date() + def s = getSunriseAndSunset(zipcode: zipCode, date: todayDate) + def riseTime = parseDate("", s.sunrise.time, "h:mm a") + def setTime = parseDate ("", s.sunset.time, "h:mm a") + def msg = "" + def currTime = now() def verb1 = currTime >= s.sunrise.time ? "rose" : "will rise" def verb2 = currTime >= s.sunset.time ? "set" : "will set" - + if (includeSunrise && includeSunset) { - msg = "The sun ${verb1} this morning at ${riseTime} and ${verb2} at ${setTime}. " - } - else if (includeSunrise && !includeSunset) { - msg = "The sun ${verb1} this morning at ${riseTime}. " - } - else if (!includeSunrise && includeSunset) { - msg = "The sun ${verb2} tonight at ${setTime}. " - } - compileMsg(msg, scenario) - } - else { - msg = "Please set the location of your hub with the SmartThings mobile app, or enter a zip code to receive sunset and sunrise information. " - compileMsg(msg, scenario) - } + msg = "The sun ${verb1} this morning at ${riseTime} and ${verb2} at ${setTime}. " + } + else if (includeSunrise && !includeSunset) { + msg = "The sun ${verb1} this morning at ${riseTime}. " + } + else if (!includeSunrise && includeSunset) { + msg = "The sun ${verb2} tonight at ${setTime}. " + } + compileMsg(msg, scenario) + } + else { + msg = "Please set the location of your hub with the SmartThings mobile app, or enter a zip code to receive sunset and sunrise information. " + compileMsg(msg, scenario) + } } private getGreeting(msg, scenario) { - def day = getDay() + def day = getDay() def time = parseDate("", now(), "h:mm a") def month = parseDate("", now(), "MMMM") def year = parseDate("", now(), "yyyy") def dayNum = parseDate("", now(), "dd") - msg = msg.replace('%day%', day) + msg = msg.replace('%day%', day) msg = msg.replace('%date%', "${month} ${dayNum}, ${year}") msg = msg.replace('%time%', "${time}") msg = "${msg} " @@ -1111,199 +1111,188 @@ private getGreeting(msg, scenario) { } private getWeatherReport(scenario, weatherReport, humidity, includeTemp, localTemp) { - if (location.timeZone || zipCode) { - def isMetric = location.temperatureScale == "C" + if (location.timeZone || zipCode) { + def isMetric = location.temperatureScale == "C" def sb = new StringBuilder() - + if (includeTemp){ - def current = getWeatherFeature("conditions", zipCode) - if (isMetric) { - sb << "The current temperature is ${Math.round(current.current_observation.temp_c)} degrees. " - } - else { - sb << "The current temperature is ${Math.round(current.current_observation.temp_f)} degrees. " - } - } - + def current = = getTwcConditions(zipCode) + sb << "The current temperature is ${Math.round(current.temperature)} degrees. " + } + if (localTemp){ - sb << "The local temperature is ${Math.round(localTemp.currentTemperature)} degrees. " + sb << "The local temperature is ${Math.round(localTemp.currentTemperature)} degrees. " } if (humidity) { - sb << "The local relative humidity is ${humidity.currentValue("humidity")}%. " + sb << "The local relative humidity is ${humidity.currentValue("humidity")}%. " } - + if (weatherReport) { - def weather = getWeatherFeature("forecast", zipCode) - + def weather = getTwcForecast(zipCode) sb << "Today's forecast is " - if (isMetric) { - sb << weather.forecast.txt_forecast.forecastday[0].fcttext_metric - } - else { - sb << weather.forecast.txt_forecast.forecastday[0].fcttext - } - } - - def msg = sb.toString() + sb << weather.daypart[0].narrative[0] + } + + def msg = sb.toString() msg = msg.replaceAll(/([0-9]+)C/,'$1 degrees') msg = msg.replaceAll(/([0-9]+)F/,'$1 degrees') - compileMsg(msg, scenario) - } - else { - msg = "Please set the location of your hub with the SmartThings mobile app, or enter a zip code to receive weather forecasts." - compileMsg(msg, scenario) + compileMsg(msg, scenario) + } + else { + msg = "Please set the location of your hub with the SmartThings mobile app, or enter a zip code to receive weather forecasts." + compileMsg(msg, scenario) } } private getOnConfimation(switches, dimmers, thermostats, scenario) { - def msg = "" + def msg = "" if ((switches || dimmers) && !thermostats) { - msg = "All switches" + msg = "All switches" } if (!switches && !dimmers && thermostats) { - msg = "All Thermostats" + msg = "All Thermostats" } if ((switches || dimmers) && thermostats) { - msg = "All switches and thermostats" - } + msg = "All switches and thermostats" + } msg = "${msg} are now on and set. " compileMsg(msg, scenario) } private getPhraseConfirmation(scenario, phrase) { - def msg="The Smart Things Hello Home phrase, ${phrase}, has been activated. " - compileMsg(msg, scenario) + def msg="The Smart Things Hello Home phrase, ${phrase}, has been activated. " + compileMsg(msg, scenario) } private getModeConfirmation(mode, scenario) { - def msg="The Smart Things mode is now being set to, ${mode}. " - compileMsg(msg, scenario) + def msg="The Smart Things mode is now being set to, ${mode}. " + compileMsg(msg, scenario) } private compileMsg(msg, scenario) { - log.debug "msg = ${msg}" - if (scenario == 1) {state.fullMsgA = state.fullMsgA + "${msg}"} - if (scenario == 2) {state.fullMsgB = state.fullMsgB + "${msg}"} - if (scenario == 3) {state.fullMsgC = state.fullMsgC + "${msg}"} - if (scenario == 4) {state.fullMsgD = state.fullMsgD + "${msg}"} + log.debug "msg = ${msg}" + if (scenario == 1) {state.fullMsgA = state.fullMsgA + "${msg}"} + if (scenario == 2) {state.fullMsgB = state.fullMsgB + "${msg}"} + if (scenario == 3) {state.fullMsgC = state.fullMsgC + "${msg}"} + if (scenario == 4) {state.fullMsgD = state.fullMsgD + "${msg}"} } private alarmSoundUri(selection, length, scenario){ - def soundUri = "" - def soundLength = "" + def soundUri = "" + def soundLength = "" switch(selection) { - case "1": - soundLength = length >0 && length < 8 ? length : 8 + case "1": + soundLength = length >0 && length < 8 ? length : 8 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmAlien.mp3", duration: "${soundLength}"] - break + break case "2": - soundLength = length >0 && length < 12 ? length : 12 + soundLength = length >0 && length < 12 ? length : 12 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmBell.mp3", duration: "${soundLength}"] - break + break case "3": - soundLength = length >0 && length < 20 ? length : 20 + soundLength = length >0 && length < 20 ? length : 20 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmBuzzer.mp3", duration: "${soundLength}"] - break + break case "4": - soundLength = length >0 && length < 20 ? length : 20 + soundLength = length >0 && length < 20 ? length : 20 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmFire.mp3", duration: "${soundLength}"] - break + break case "5": - soundLength = length >0 && length < 2 ? length : 2 + soundLength = length >0 && length < 2 ? length : 2 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmRooster.mp3", duration: "${soundLength}"] - break + break case "6": - soundLength = length >0 && length < 20 ? length : 20 + soundLength = length >0 && length < 20 ? length : 20 soundUri = [uri: "https://raw.githubusercontent.com/MichaelStruck/SmartThings/master/Other-SmartApps/Talking-Alarm-Clock/AlarmSounds/AlarmSiren.mp3", duration: "${soundLength}"] - break + break } - if (scenario == 1) {state.soundAlarmA = soundUri} - if (scenario == 2) {state.soundAlarmB = soundUri} - if (scenario == 3) {state.soundAlarmC = soundUri} - if (scenario == 4) {state.soundAlarmD = soundUri} -} + if (scenario == 1) {state.soundAlarmA = soundUri} + if (scenario == 2) {state.soundAlarmB = soundUri} + if (scenario == 3) {state.soundAlarmC = soundUri} + if (scenario == 4) {state.soundAlarmD = soundUri} +} //Sonos Aquire Track from SmartThings code private songOptions(sonos, scenario) { - if (sonos){ - // Make sure current selection is in the set - def options = new LinkedHashSet() - if (scenario == 1){ - if (state.selectedSongA?.station) { - options << state.selectedSongA.station - } - else if (state.selectedSongA?.description) { - options << state.selectedSongA.description - } - } - if (scenario == 2){ - if (state.selectedSongB?.station) { - options << state.selectedSongB.station - } - else if (state.selectedSongB?.description) { - options << state.selectedSongB.description - } - } - if (scenario == 3){ - if (state.selectedSongC?.station) { - options << state.selectedSongC.station - } - else if (state.selectedSongC?.description) { - options << state.selectedSongC.description - } - } - if (scenario == 4){ - if (state.selectedSongD?.station) { - options << state.selectedSongD.station - } - else if (state.selectedSongD?.description) { - options << state.selectedSongD.description - } - } - // Query for recent tracks - def states = sonos.statesSince("trackData", new Date(0), [max:30]) - def dataMaps = states.collect{it.jsonValue} - options.addAll(dataMaps.collect{it.station}) - - log.trace "${options.size()} songs in list" - options.take(20) as List - } + if (sonos){ + // Make sure current selection is in the set + def options = new LinkedHashSet() + if (scenario == 1){ + if (state.selectedSongA?.station) { + options << state.selectedSongA.station + } + else if (state.selectedSongA?.description) { + options << state.selectedSongA.description + } + } + if (scenario == 2){ + if (state.selectedSongB?.station) { + options << state.selectedSongB.station + } + else if (state.selectedSongB?.description) { + options << state.selectedSongB.description + } + } + if (scenario == 3){ + if (state.selectedSongC?.station) { + options << state.selectedSongC.station + } + else if (state.selectedSongC?.description) { + options << state.selectedSongC.description + } + } + if (scenario == 4){ + if (state.selectedSongD?.station) { + options << state.selectedSongD.station + } + else if (state.selectedSongD?.description) { + options << state.selectedSongD.description + } + } + // Query for recent tracks + def states = sonos.statesSince("trackData", new Date(0), [max:30]) + def dataMaps = states.collect{it.jsonValue} + options.addAll(dataMaps.collect{it.station}) + + log.trace "${options.size()} songs in list" + options.take(20) as List + } } private saveSelectedSong(sonos, song, scenario) { - try { - def thisSong = song - log.info "Looking for $thisSong" - def songs = sonos.statesSince("trackData", new Date(0), [max:30]).collect{it.jsonValue} - log.info "Searching ${songs.size()} records" - - def data = songs.find {s -> s.station == thisSong} - log.info "Found ${data?.station}" - if (data) { - if (scenario == 1) {state.selectedSongA = data} + try { + def thisSong = song + log.info "Looking for $thisSong" + def songs = sonos.statesSince("trackData", new Date(0), [max:30]).collect{it.jsonValue} + log.info "Searching ${songs.size()} records" + + def data = songs.find {s -> s.station == thisSong} + log.info "Found ${data?.station}" + if (data) { + if (scenario == 1) {state.selectedSongA = data} if (scenario == 2) {state.selectedSongB = data} if (scenario == 3) {state.selectedSongC = data} if (scenario == 4) {state.selectedSongD = data} - log.debug "Selected song for Scenario ${scenario} = ${data}" - } - else if (song == state.selectedSongA?.station || song == state.selectedSongB?.station || song == state.selectedSongC?.station || song == state.selectedSongD?.station) { - log.debug "Selected existing entry '$song', which is no longer in the last 20 list" - } - else { - log.warn "Selected song '$song' not found" - } - } - catch (Throwable t) { - log.error t - } + log.debug "Selected song for Scenario ${scenario} = ${data}" + } + else if (song == state.selectedSongA?.station || song == state.selectedSongB?.station || song == state.selectedSongC?.station || song == state.selectedSongD?.station) { + log.debug "Selected existing entry '$song', which is no longer in the last 20 list" + } + else { + log.warn "Selected song '$song' not found" + } + } + catch (Throwable t) { + log.error t + } } //Version/Copyright/Information/Help private def textAppName() { - def text = "Talking Alarm Clock" -} + def text = "Talking Alarm Clock" +} private def textVersion() { def text = "Version 1.4.5 (06/17/2015)" @@ -1315,22 +1304,22 @@ private def textCopyright() { private def textLicense() { def text = - "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"+ - "\n\n"+ - " http://www.apache.org/licenses/LICENSE-2.0"+ - "\n\n"+ - "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." + "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"+ + "\n\n"+ + " http://www.apache.org/licenses/LICENSE-2.0"+ + "\n\n"+ + "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." } private def textHelp() { - def text = - "Within each alarm scenario, choose a Sonos speaker, an alarm time and alarm type along with " + + def text = + "Within each alarm scenario, choose a Sonos speaker, an alarm time and alarm type along with " + "switches, dimmers and thermostat to control when the alarm is triggered. Hello, Home phrases and modes can be triggered at alarm time. "+ "You also have the option of setting up different alarm sounds, tracks and a personalized spoken greeting that can include a weather report. " + "Variables that can be used in the voice greeting include %day%, %time% and %date%.\n\n"+ @@ -1338,4 +1327,3 @@ private def textHelp() { "speak a summary of the alarms enabled or disabled without having to go into the application itself. This " + "functionality is optional and can be configured from the main setup page." } - diff --git a/smartapps/shabbatholidaymode/shabbat-and-holiday-modes.src/shabbat-and-holiday-modes.groovy b/smartapps/shabbatholidaymode/shabbat-and-holiday-modes.src/shabbat-and-holiday-modes.groovy index 35a90ea6f66..6d8bd11ca6d 100644 --- a/smartapps/shabbatholidaymode/shabbat-and-holiday-modes.src/shabbat-and-holiday-modes.groovy +++ b/smartapps/shabbatholidaymode/shabbat-and-holiday-modes.src/shabbat-and-holiday-modes.groovy @@ -19,21 +19,21 @@ definition( ) preferences { - - section("At Candlelighting Change Mode To:") + + section("At Candlelighting Change Mode To:") { - input "startMode", "mode", title: "Mode?" - } - section("At Havdalah Change Mode To:") + input "startMode", "mode", title: "Mode?" + } + section("At Havdalah Change Mode To:") { - input "endMode", "mode", title: "Mode?" - } - section("Havdalah Offset (Usually 50 or 72)") { - input "havdalahOffset", "number", title: "Minutes After Sundown", required:true - } - section("Your ZipCode") { - input "zipcode", "text", title: "ZipCode", required:true - } + input "endMode", "mode", title: "Mode?" + } + section("Havdalah Offset (Usually 50 or 72)") { + input "havdalahOffset", "number", title: "Minutes After Sundown", required:true + } + section("Your ZipCode") { + input "zipcode", "text", title: "ZipCode", required:true + } section( "Notifications" ) { input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false input "phone", "phone", title: "Send a Text Message?", required: false @@ -42,28 +42,28 @@ preferences { } def installed() { - log.debug "Installed with settings: ${settings}" - initialize() + log.debug "Installed with settings: ${settings}" + initialize() } def updated() { - log.debug "Updated with settings: ${settings}" - unsubscribe() - initialize() + log.debug "Updated with settings: ${settings}" + unsubscribe() + initialize() } def initialize() { poll(); - schedule("0 0 8 1/1 * ? *", poll) + schedule("0 0 8 1/1 * ? *", poll) } //Check hebcal for today's candle lighting or havdalah def poll() { - + unschedule("endChag") unschedule("setChag") - Hebcal_WebRequest() + Hebcal_WebRequest() }//END def poll() @@ -79,8 +79,8 @@ def Hebcal_WebRequest(){ def today = new Date().format("yyyy-MM-dd") //def today = "2014-11-14" def zip = settings.zip as String -def locale = getWeatherFeature("geolookup", zip) -def timezone = TimeZone.getTimeZone(locale.location.tz_long) +def locale = getTwcLocation(zipCode).location +def timezone = TimeZone.getTimeZone(locale.ianaTimeZone) def hebcal_date def hebcal_category def hebcal_title @@ -94,39 +94,39 @@ def urlRequest = "http://www.hebcal.com/hebcal/?v=1&cfg=json&nh=off&nx=off&year= log.trace "${urlRequest}" def hebcal = { response -> - hebcal_date = response.data.items.date - hebcal_category = response.data.items.category - hebcal_title = response.data.items.title - - for (int i = 0; i < hebcal_date.size; i++) + hebcal_date = response.data.items.date + hebcal_category = response.data.items.category + hebcal_title = response.data.items.title + + for (int i = 0; i < hebcal_date.size; i++) { - if(hebcal_date[i].split("T")[0]==today) + if(hebcal_date[i].split("T")[0]==today) { - if(hebcal_category[i]=="candles") - { - candlelightingLocalTime = HebCal_GetTime12(hebcal_title[i]) + if(hebcal_category[i]=="candles") + { + candlelightingLocalTime = HebCal_GetTime12(hebcal_title[i]) pushMessage = "Candle Lighting is at ${candlelightingLocalTime}" candlelightingLocalTime = HebCal_GetTime24(hebcal_date[i]) - candlelighting = timeToday(candlelightingLocalTime, timezone) - - sendMessage(pushMessage) - schedule(candlelighting, setChag) + candlelighting = timeToday(candlelightingLocalTime, timezone) + + sendMessage(pushMessage) + schedule(candlelighting, setChag) log.debug pushMessage - }//END if(hebcal_category=="candles") - - else if(hebcal_category[i]=="havdalah") - { - havdalahLocalTime = HebCal_GetTime12(hebcal_title[i]) + }//END if(hebcal_category=="candles") + + else if(hebcal_category[i]=="havdalah") + { + havdalahLocalTime = HebCal_GetTime12(hebcal_title[i]) pushMessage = "Havdalah is at ${havdalahLocalTime}" havdalahLocalTime = HebCal_GetTime24(hebcal_date[i]) - havdalah = timeToday(havdalahLocalTime, timezone) + havdalah = timeToday(havdalahLocalTime, timezone) testmessage = "Scheduling for ${havdalah}" - schedule(havdalah, endChag) + schedule(havdalah, endChag) log.debug pushMessage log.debug testmessage - }//END if(hebcal_category=="havdalah"){ + }//END if(hebcal_category=="havdalah"){ }//END if(hebcal_date[i].split("T")[0]==today) - + }//END for (int i = 0; i < hebcal_date.size; i++) }//END def hebcal = { response -> httpGet(urlRequest, hebcal); @@ -151,49 +151,49 @@ return returnTime -----------------------------------------------*/ def setChag() { - - if (location.mode != startMode) - { - if (location.modes?.find{it.name == startMode}) + + if (location.mode != startMode) + { + if (location.modes?.find{it.name == startMode}) { - setLocationMode(startMode) - //sendMessage("Changed the mode to '${startMode}'") + setLocationMode(startMode) + //sendMessage("Changed the mode to '${startMode}'") def dayofweek = new Date().format("EEE") - if(dayofweek=='Fri'){ - sendMessage("Shabbat Shalom!") - } - else{ - sendMessage("Chag Sameach!") - } - - }//END if (location.modes?.find{it.name == startMode}) - else + if(dayofweek=='Fri'){ + sendMessage("Shabbat Shalom!") + } + else{ + sendMessage("Chag Sameach!") + } + + }//END if (location.modes?.find{it.name == startMode}) + else { - sendMessage("Tried to change to undefined mode '${startMode}'") - }//END else - }//END if (location.mode != newMode) - + sendMessage("Tried to change to undefined mode '${startMode}'") + }//END else + }//END if (location.mode != newMode) + unschedule("setChag") }//END def setChag() def endChag() { - - if (location.mode != endMode) - { - if (location.modes?.find{it.name == endMode}) + + if (location.mode != endMode) + { + if (location.modes?.find{it.name == endMode}) { - setLocationMode(endMode) - sendMessage("Changed the mode to '${endMode}'") - }//END if (location.modes?.find{it.name == endMode}) - else + setLocationMode(endMode) + sendMessage("Changed the mode to '${endMode}'") + }//END if (location.modes?.find{it.name == endMode}) + else { - sendMessage("Tried to change to undefined mode '${endMode}'") - }//END else - }//END if (location.mode != endMode) - - //sendMessage("Shavuah Tov!") + sendMessage("Tried to change to undefined mode '${endMode}'") + }//END else + }//END if (location.mode != endMode) + + //sendMessage("Shavuah Tov!") unschedule("endChag") }//END def setChag()