diff --git a/devicetypes/smartthings/testing/simulated-dimmable-bulb.src/simulated-dimmable-bulb.groovy b/devicetypes/smartthings/testing/simulated-dimmable-bulb.src/simulated-dimmable-bulb.groovy index 571305f9cef..73527e3f21e 100644 --- a/devicetypes/smartthings/testing/simulated-dimmable-bulb.src/simulated-dimmable-bulb.groovy +++ b/devicetypes/smartthings/testing/simulated-dimmable-bulb.src/simulated-dimmable-bulb.groovy @@ -24,6 +24,9 @@ metadata { capability "Switch Level" capability "Refresh" capability "Configuration" + + command "markDeviceOnline" + command "markDeviceOffline" } preferences { @@ -34,8 +37,8 @@ metadata { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#FFFFFF", nextState:"turningOn" - attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"on" - attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#FFFFFF", nextState:"off" + attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#FFFFFF", nextState:"on" + attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#00A0DC", nextState:"off" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action: "setLevel" @@ -45,16 +48,22 @@ metadata { } } - standardTile("refresh", "device.switch", width: 1, height: 1, inactiveLabel: false, decoration: "flat") { + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { state "default", label: "", action:"refresh.refresh", icon:"st.secondary.refresh" } - valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) { + valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label: "Reset", action: "configure" } - main(["switch"]) - details(["switch", "refresh", "reset"]) + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main(["switch"]) + details(["switch", "refresh", "deviceHealthControl", "reset"]) } } @@ -77,7 +86,7 @@ def parse(String description) { def installed() { log.trace "Executing 'installed'" - initialize() + configure() } def updated() { @@ -88,9 +97,6 @@ def updated() { // // command methods // -def ping() { - refresh() -} def refresh() { log.trace "Executing 'refresh'" @@ -100,6 +106,11 @@ def refresh() { def configure() { log.trace "Executing 'configure'" + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() } @@ -130,6 +141,14 @@ def setLevel(value, duration) { setLevel(value) } +def markDeviceOnline() { + setDeviceHealth("online") +} + +def markDeviceOffline() { + setDeviceHealth("offline") +} + private String getSwitch() { def switchState = device.currentState("switch") return switchState ? switchState.getStringValue() : "off" @@ -140,19 +159,25 @@ private Integer getLevel() { return levelState ? levelState.getIntegerValue() : 100 } +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + private initialize() { log.trace "Executing 'initialize'" sendEvent(name: "switch", value: "off") sendEvent(name: "level", value: 100) - - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) } private Map buildSetLevelEvent(value) { Integer intValue = value as Integer - Integer newLevel = Math.max(Math.min(intValue, 99), 0) + Integer newLevel = Math.max(Math.min(intValue, 100), 0) Map eventMap = [name: "level", value: newLevel, unit: "%"] return eventMap } diff --git a/devicetypes/smartthings/testing/simulated-dimmer-switch.src/simulated-dimmer-switch.groovy b/devicetypes/smartthings/testing/simulated-dimmer-switch.src/simulated-dimmer-switch.groovy index 50c09331b20..9c181f538f4 100644 --- a/devicetypes/smartthings/testing/simulated-dimmer-switch.src/simulated-dimmer-switch.groovy +++ b/devicetypes/smartthings/testing/simulated-dimmer-switch.src/simulated-dimmer-switch.groovy @@ -14,7 +14,7 @@ * */ metadata { - definition (name: "Simulated Dimmer Switch", namespace: "smartthings/testing", author: "SmartThings", runLocally: false, mnmn: "SmartThings", vid: "generic-dimmer") { + definition (name: "Simulated Dimmer Switch", namespace: "smartthings/testing", author: "SmartThings", ocfDeviceType: "oic.d.light", runLocally: false, mnmn: "SmartThings", vid: "generic-dimmer") { capability "Health Check" capability "Actuator" capability "Sensor" @@ -27,6 +27,9 @@ metadata { command "onPhysical" command "offPhysical" command "setLevelPhysical" + + command "markDeviceOnline" + command "markDeviceOffline" } preferences { @@ -37,8 +40,8 @@ metadata { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#FFFFFF", nextState:"turningOn", defaultState: true - attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOn" - attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#FFFFFF", nextState:"turningOff" + attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#FFFFFF", nextState:"turningOn" + attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { attributeState "level", action: "setLevel" @@ -66,16 +69,22 @@ metadata { state "physicalLevel", action: "setLevelPhysical" } - standardTile("refresh", "device.switch", width: 1, height: 1, inactiveLabel: false, decoration: "flat") { + standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { state "default", label: "", action:"refresh.refresh", icon:"st.secondary.refresh" } - valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) { + valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label: "Reset", action: "configure" } - main(["switch"]) - details(["switch", "physicalLabel", "physicalOn", "physicalOff", "physicalLevelLabel", "physicalLevelSlider", "refresh", "reset"]) + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main(["switch"]) + details(["switch", "physicalLabel", "physicalOn", "physicalOff", "physicalLevelLabel", "physicalLevelSlider", "deviceHealthControl", "refresh", "reset"]) } } @@ -98,7 +107,7 @@ def parse(String description) { def installed() { log.trace "Executing 'installed'" - initialize() + configure() } def updated() { @@ -116,6 +125,12 @@ def refresh() { def configure() { log.trace "Executing 'configure'" + // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme: "untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() } @@ -146,15 +161,28 @@ def setLevel(value, duration) { setLevel(value) } +def markDeviceOnline() { + setDeviceHealth("online") +} + +def markDeviceOffline() { + setDeviceHealth("offline") +} + +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + private initialize() { log.trace "Executing 'initialize'" sendEvent(name: "switch", value: "off") sendEvent(name: "level", value: 100) - - - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) } private Map buildSetLevelEvent(value) { diff --git a/devicetypes/smartthings/testing/simulated-lock.src/simulated-lock.groovy b/devicetypes/smartthings/testing/simulated-lock.src/simulated-lock.groovy index 6026023cea1..b7842c1c24c 100644 --- a/devicetypes/smartthings/testing/simulated-lock.src/simulated-lock.groovy +++ b/devicetypes/smartthings/testing/simulated-lock.src/simulated-lock.groovy @@ -26,11 +26,16 @@ metadata { capability "Lock" capability "Battery" capability "Refresh" + capability "Configuration" + command "jam" command "setBatteryLevel" command "setJamNextOperation" command "clearJamNextOperation" attribute "doesNextOperationJam", "enum", ["true", "false"] + + command "markDeviceOnline" + command "markDeviceOffline" } // Simulated lock @@ -40,48 +45,69 @@ metadata { attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00A0DC", nextState:"unlocking" attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#FFFFFF", nextState:"locking" attributeState "unknown", label:'jammed', action:"lock.lock", icon:"st.secondary.activity", backgroundColor:"#E86D13" - attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#00A0DC" - attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#FFFFFF" + attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#FFFFFF" + attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#00A0DC" } tileAttribute ("device.battery", key: "SECONDARY_CONTROL") { attributeState "battery", label: 'battery ${currentValue}%', unit: "%" } } - standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat", width: 3, height: 2) { + standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat", width: 3, height: 1) { state "default", label:'lock', action:"lock.lock", icon: "st.locks.lock.locked" } - standardTile("unlock", "device.lock", inactiveLabel: false, decoration: "flat", width: 3, height: 2) { + + standardTile("unlock", "device.lock", inactiveLabel: false, decoration: "flat", width: 3, height: 1) { state "default", label:'unlock', action:"lock.unlock", icon: "st.locks.lock.unlocked" } + valueTile("jamLabel", "device.id", inactiveLabel: false, decoration: "flat", width: 4, height: 1) { - state "default", label:"Tap button to simulate a jam now.\nUse Lock or Unlock to clear jam." + state "default", label:"Tap button to jam the lock now.\nUse main button to clear jam." } + standardTile("jam", "device.lock", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { state "default", label:'', action:"jam", nextState: "unknown", backgroundColor:"#CCCCCC", defaultState: true state "unknown", label:'jammed', backgroundColor:"#E86D13" } + valueTile("jamToggleLabel", "device.doesNextOperationJam", inactiveLabel: false, decoration: "flat", width: 4, height: 1) { - state "default", label: "When button is active, lock will\nsimulate a jam on the next operation.", defaultState: true + state "default", label: "When button is active, lock will\njam on the next operation.", defaultState: true } + standardTile("jamToggle", "device.doesNextOperationJam", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { state "false", label:'', action: "setJamNextOperation", backgroundColor:"#CCCCCC", defaultState: true state "true", label:'', action: "clearJamNextOperation", backgroundColor:"#E86D13" } - valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { - state "battery", label:'battery ${currentValue}%', unit:"%" + + valueTile("batterySliderLabel", "device.battery", inactiveLabel: false, decoration: "flat", width: 4, height: 1) { + state "battery", label:'battery ${currentValue}%\nUse slider to set battery level', unit:"%" } - controlTile("batterySliderControl", "device.battery", "slider", - height: 1, width: 4, range:"(1..100)") { + + controlTile("batterySliderControl", "device.battery", "slider", width: 2, height: 1, range:"(1..100)") { state "battery", action:"setBatteryLevel" } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh", icon: "st.secondary.refresh" + } + + valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "Reset", action: "configure" + } + + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main "toggle" details(["toggle", - "lock", "unlock", + "deviceHealthControl", "refresh", "reset", "jamLabel", "jam", "jamToggleLabel", "jamToggle", - "battery", "batterySliderControl" ]) + "batterySliderLabel", "batterySliderControl"]) } } // parse events into attributes @@ -103,9 +129,7 @@ def parse(String description) { def installed() { log.trace "installed()" - initialize() - setBatteryLevel(94) - unlock() + configure() } def updated() { @@ -114,14 +138,26 @@ def updated() { initialize() } -def initialize() { - log.trace "initialize()" +def markDeviceOnline() { + setDeviceHealth("online") +} - // for HealthCheck - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) +def markDeviceOffline() { + setDeviceHealth("offline") +} + +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} +private initialize() { + log.trace "initialize()" clearJamNextOperation() } @@ -148,8 +184,21 @@ private processPreferences() { } def refresh() { - sendEvent(name: "lock", value: device.currentValue("lock")) - sendEvent(name: "battery", value: device.currentValue("battery")) + log.trace "refresh()" + sendEvent(name: "lock", value: device.currentValue("lock") ?: "locked") + sendEvent(name: "battery", value: device.currentValue("battery") ?: 94) +} + +def configure() { + log.trace "configure()" + // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + initialize() + markDeviceOnline() + setBatteryLevel(94) + unlock() } def lock() { diff --git a/devicetypes/smartthings/testing/simulated-rgb-bulb.src/simulated-rgb-bulb.groovy b/devicetypes/smartthings/testing/simulated-rgb-bulb.src/simulated-rgb-bulb.groovy index aa128e3609d..67a0ecc48fd 100644 --- a/devicetypes/smartthings/testing/simulated-rgb-bulb.src/simulated-rgb-bulb.groovy +++ b/devicetypes/smartthings/testing/simulated-rgb-bulb.src/simulated-rgb-bulb.groovy @@ -36,7 +36,7 @@ import groovy.transform.Field ] metadata { - definition (name: "Simulated RGB Bulb", namespace: "smartthings/testing", author: "SmartThings") { + definition (name: "Simulated RGB Bulb", namespace: "smartthings/testing", author: "SmartThings", ocfDeviceType: "oic.d.light") { capability "HealthCheck" capability "Actuator" capability "Sensor" @@ -52,6 +52,9 @@ metadata { attribute "bulbValue", "string" attribute "colorIndicator", "number" command "simulateBulbState" + + command "markDeviceOnline" + command "markDeviceOffline" } // UI tile definitions @@ -218,8 +221,15 @@ metadata { state "default", label: "Reset", action: "configure" } + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main(["switch"]) - details(["switch", "bulbValue", "colorIndicator", "refresh"]) + details(["switch", "bulbValue", "colorIndicator", "refresh", "deviceHealthControl", "reset"]) } } @@ -247,7 +257,7 @@ def parse(String description) { def installed() { log.trace "Executing 'installed'" - initialize() + configure() } def updated() { @@ -278,6 +288,11 @@ def refresh() { def configure() { log.trace "Executing 'configure'" // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() } @@ -371,17 +386,26 @@ def setColor(Map colorHSMap) { done() } -private initialize() { - log.trace "Executing 'initialize'" +def markDeviceOnline() { + setDeviceHealth("online") +} - // for HealthCheck - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) +def markDeviceOffline() { + setDeviceHealth("offline") +} - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + +private initialize() { + log.trace "Executing 'initialize'" sendEvent(name: "hue", value: BLACK.h) sendEvent(name: "saturation", value: BLACK.s) diff --git a/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy b/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy index b3ed898e93c..1284ae3398e 100644 --- a/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy +++ b/devicetypes/smartthings/testing/simulated-rgbw-bulb.src/simulated-rgbw-bulb.groovy @@ -43,7 +43,7 @@ import groovy.transform.Field ] metadata { - definition (name: "Simulated RGBW Bulb", namespace: "smartthings/testing", author: "SmartThings") { + definition (name: "Simulated RGBW Bulb", namespace: "smartthings/testing", author: "SmartThings", ocfDeviceType: "oic.d.light") { capability "Health Check" capability "Actuator" capability "Sensor" @@ -62,6 +62,9 @@ metadata { attribute "bulbValue", "STRING" attribute "colorIndicator", "NUMBER" command "simulateBulbState" + + command "markDeviceOnline" + command "markDeviceOffline" } // UI tile definitions @@ -258,16 +261,23 @@ metadata { state "bulbValue", label: '${currentValue}' } - standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 1) { + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label: "", action: "refresh", icon: "st.secondary.refresh" } - valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 3, height: 1) { + valueTile("reset", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { state "default", label: "Reset", action: "configure" } + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main(["switch"]) - details(["switch", "colorTempControlLabel", "colorTempSliderControl", "bulbValue", "colorIndicator", "refresh"]) + details(["switch", "colorTempControlLabel", "colorTempSliderControl", "bulbValue", "colorIndicator", "refresh", "deviceHealthControl", "reset"]) } } @@ -295,7 +305,7 @@ def parse(String description) { def installed() { log.trace "Executing 'installed'" - initialize() + configure() } def updated() { @@ -307,11 +317,6 @@ def updated() { // command methods // -def ping() { - log.trace "Executing 'ping'" - refresh() -} - def refresh() { log.trace "Executing 'refresh'" String currentMode = device.currentValue("bulbMode") @@ -325,6 +330,11 @@ def refresh() { def configure() { log.trace "Executing 'configure'" // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() } @@ -427,17 +437,26 @@ def setColor(Map colorHSMap) { done() } -private initialize() { - log.trace "Executing 'initialize'" +def markDeviceOnline() { + setDeviceHealth("online") +} - // for HealthCheck - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) +def markDeviceOffline() { + setDeviceHealth("offline") +} - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + +private initialize() { + log.trace "Executing 'initialize'" sendEvent(name: "colorTemperatureRange", value: COLOR_TEMP_RANGE) sendEvent(name: "colorTemperature", value: COLOR_TEMP_DEFAULT) diff --git a/devicetypes/smartthings/testing/simulated-switch.src/simulated-switch.groovy b/devicetypes/smartthings/testing/simulated-switch.src/simulated-switch.groovy index f09571f6442..6411bc07901 100644 --- a/devicetypes/smartthings/testing/simulated-switch.src/simulated-switch.groovy +++ b/devicetypes/smartthings/testing/simulated-switch.src/simulated-switch.groovy @@ -22,6 +22,9 @@ metadata { command "onPhysical" command "offPhysical" + + command "markDeviceOnline" + command "markDeviceOffline" } tiles { @@ -35,13 +38,21 @@ metadata { standardTile("off", "device.switch", decoration: "flat") { state "default", label: 'Off', action: "offPhysical", backgroundColor: "#ffffff" } + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 1, height: 1, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } main "switch" - details(["switch","on","off"]) + details(["switch","on","off","deviceHealthControl"]) } } def installed() { log.trace "Executing 'installed'" + markDeviceOnline() + off() initialize() } @@ -50,11 +61,26 @@ def updated() { initialize() } +def markDeviceOnline() { + setDeviceHealth("online") +} + +def markDeviceOffline() { + setDeviceHealth("offline") +} + +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + private initialize() { log.trace "Executing 'initialize'" - - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) } diff --git a/devicetypes/smartthings/testing/simulated-thermostat.src/simulated-thermostat.groovy b/devicetypes/smartthings/testing/simulated-thermostat.src/simulated-thermostat.groovy index 9bef27b6e05..6a8df3ccd38 100644 --- a/devicetypes/smartthings/testing/simulated-thermostat.src/simulated-thermostat.groovy +++ b/devicetypes/smartthings/testing/simulated-thermostat.src/simulated-thermostat.groovy @@ -108,19 +108,22 @@ metadata { command "setHumidityPercent", ["number"] command "delayedEvaluate" command "runSimHvacCycle" + + command "markDeviceOnline" + command "markDeviceOffline" } tiles(scale: 2) { multiAttributeTile(name:"thermostatMulti", type:"thermostat", width:6, height:4) { tileAttribute("device.temperature", key: "PRIMARY_CONTROL") { - attributeState("default", label:'${currentValue} °F', unit:"°F") + attributeState("temp", label:'${currentValue}°', unit:"°F", defaultState: true) } tileAttribute("device.temperature", key: "VALUE_CONTROL") { attributeState("VALUE_UP", action: "setpointUp") attributeState("VALUE_DOWN", action: "setpointDown") } tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { - attributeState("default", label: '${currentValue}% Hum', unit: "%", icon: "st.Weather.weather12") + attributeState("humidity", label: '${currentValue}%', unit: "%", defaultState: true) } tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { attributeState("idle", backgroundColor: "#FFFFFF") @@ -135,10 +138,10 @@ metadata { attributeState("emergency heat", label: 'e-heat') } tileAttribute("device.heatingSetpoint", key: "HEATING_SETPOINT") { - attributeState("default", label: '${currentValue}', unit: "°F") + attributeState("default", label: '${currentValue}', unit: "°F", defaultState: true) } tileAttribute("device.coolingSetpoint", key: "COOLING_SETPOINT") { - attributeState("default", label: '${currentValue}', unit: "°F") + attributeState("default", label: '${currentValue}', unit: "°F", defaultState: true) } } @@ -160,7 +163,7 @@ metadata { } valueTile("heatingSetpoint", "device.heatingSetpoint", width: 2, height: 2, decoration: "flat") { - state "heat", label:'Heat\n${currentValue} °F', unit: "°F", backgroundColor:"#E86D13" + state "heat", label:'Heat\n${currentValue}°', unit: "°F", backgroundColor:"#E86D13" } standardTile("heatDown", "device.temperature", width: 1, height: 1, decoration: "flat") { state "default", label: "heat", action: "heatDown", icon: "st.thermostat.thermostat-down" @@ -170,7 +173,7 @@ metadata { } valueTile("coolingSetpoint", "device.coolingSetpoint", width: 2, height: 2, decoration: "flat") { - state "cool", label: 'Cool\n${currentValue} °F', unit: "°F", backgroundColor: "#00A0DC" + state "cool", label: 'Cool\n${currentValue}°', unit: "°F", backgroundColor: "#00A0DC" } standardTile("coolDown", "device.temperature", width: 1, height: 1, decoration: "flat") { state "default", label: "cool", action: "coolDown", icon: "st.thermostat.thermostat-down" @@ -179,8 +182,8 @@ metadata { state "default", label: "cool", action: "coolUp", icon: "st.thermostat.thermostat-up" } - valueTile("roomTemp", "device.temperature", width: 2, height: 2, decoration: "flat") { - state "default", label:'${currentValue} °F', unit: "°F", backgroundColors: [ + valueTile("roomTemp", "device.temperature", width: 2, height: 1, decoration: "flat") { + state "default", label:'${currentValue}°', unit: "°F", backgroundColors: [ // Celsius Color Range [value: 0, color: "#153591"], [value: 7, color: "#1E9CBB"], @@ -218,18 +221,29 @@ metadata { state "default", label: "" } - valueTile("reset", "device.switch", width: 4, height: 1, decoration: "flat") { - state "default", label: "Reset to Defaults", action: "configure" - } - - valueTile("humiditySliderLabel", "device.humidity", width: 4, height: 1, decoration: "flat") { + valueTile("humiditySliderLabel", "device.humidity", width: 3, height: 1, decoration: "flat") { state "default", label: 'Simulated Humidity: ${currentValue}%' } - controlTile("humiditySlider", "device.humidity", "slider", width: 4, height: 1, range: "(0..100)") { + controlTile("humiditySlider", "device.humidity", "slider", width: 1, height: 1, range: "(0..100)") { state "humidity", action: "setHumidityPercent" } + standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { + state "default", label: "", action: "refresh", icon: "st.secondary.refresh" + } + + valueTile("reset", "device.switch", width: 2, height: 2, decoration: "flat") { + state "default", label: "Reset to Defaults", action: "configure" + } + + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main("roomTemp") details(["thermostatMulti", "heatDown", "heatUp", @@ -239,17 +253,17 @@ metadata { "coolingSetpoint", "fanMode", "blank2x1", "blank2x1", + "deviceHealthControl", "refresh", "reset", "blank1x1", "simControlLabel", "blank1x1", - "tempDown", "tempUp", "humiditySliderLabel", - "roomTemp", "humiditySlider", - "reset" + "tempDown", "tempUp", "humiditySliderLabel", "humiditySlider", + "roomTemp" ]) } } def installed() { log.trace "Executing 'installed'" - initialize() + configure() done() } @@ -261,18 +275,37 @@ def updated() { def configure() { log.trace "Executing 'configure'" + // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() done() } +def markDeviceOnline() { + setDeviceHealth("online") +} + +def markDeviceOffline() { + setDeviceHealth("offline") +} + +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + private initialize() { log.trace "Executing 'initialize'" - // for HealthCheck - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) - sendEvent(name: "temperature", value: DEFAULT_TEMPERATURE, unit: "°F") sendEvent(name: "humidity", value: DEFAULT_HUMIDITY, unit: "%") sendEvent(name: "heatingSetpoint", value: DEFAULT_HEATING_SETPOINT, unit: "°F") @@ -292,7 +325,6 @@ private initialize() { unschedule() } - // parse events into attributes def parse(String description) { log.trace "Executing parse $description" diff --git a/devicetypes/smartthings/testing/simulated-white-color-temperature-bulb.src/simulated-white-color-temperature-bulb.groovy b/devicetypes/smartthings/testing/simulated-white-color-temperature-bulb.src/simulated-white-color-temperature-bulb.groovy index dd340106b50..43ea4abe9a6 100644 --- a/devicetypes/smartthings/testing/simulated-white-color-temperature-bulb.src/simulated-white-color-temperature-bulb.groovy +++ b/devicetypes/smartthings/testing/simulated-white-color-temperature-bulb.src/simulated-white-color-temperature-bulb.groovy @@ -35,7 +35,7 @@ import groovy.transform.Field ] metadata { - definition (name: "Simulated White Color Temperature Bulb", namespace: "smartthings/testing", author: "SmartThings") { + definition (name: "Simulated White Color Temperature Bulb", namespace: "smartthings/testing", author: "SmartThings", ocfDeviceType: "oic.d.light") { capability "HealthCheck" capability "Actuator" capability "Sensor" @@ -53,6 +53,9 @@ metadata { attribute "bulbValue", "STRING" attribute "colorIndicator", "NUMBER" command "simulateBulbState" + + command "markDeviceOnline" + command "markDeviceOffline" } // UI tile definitions @@ -61,8 +64,8 @@ metadata { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#FFFFFF", nextState:"turningOn" - attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"on" - attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#FFFFFF", nextState:"off" + attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#FFFFFF", nextState:"on" + attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#00A0DC", nextState:"off" } tileAttribute ("device.level", key: "SLIDER_CONTROL") { @@ -130,8 +133,15 @@ metadata { state "default", label: "Reset", action: "configure" } + standardTile("deviceHealthControl", "device.healthStatus", decoration: "flat", width: 2, height: 2, inactiveLabel: false) { + state "online", label: "ONLINE", backgroundColor: "#00A0DC", action: "markDeviceOffline", icon: "st.Health & Wellness.health9", nextState: "goingOffline", defaultState: true + state "offline", label: "OFFLINE", backgroundColor: "#E86D13", action: "markDeviceOnline", icon: "st.Health & Wellness.health9", nextState: "goingOnline" + state "goingOnline", label: "Going ONLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + state "goingOffline", label: "Going OFFLINE", backgroundColor: "#FFFFFF", icon: "st.Health & Wellness.health9" + } + main(["switch"]) - details(["switch", "colorTempControlLabel", "colorTempControlSlider", "bulbValue", "colorIndicator", "refresh", "reset"]) + details(["switch", "colorTempControlLabel", "colorTempControlSlider", "bulbValue", "colorIndicator", "deviceHealthControl", "refresh", "reset"]) } } @@ -159,7 +169,7 @@ def parse(String description) { def installed() { log.trace "Executing 'installed'" - initialize() + configure() done() } @@ -189,6 +199,12 @@ def refresh() { def configure() { log.trace "Executing 'configure'" + // this would be for a physical device when it gets a handler assigned to it + + // for HealthCheck + sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) + markDeviceOnline() + initialize() done() } @@ -232,21 +248,30 @@ def setColorTemperature(kelvin) { done() } +def markDeviceOnline() { + setDeviceHealth("online") +} + +def markDeviceOffline() { + setDeviceHealth("offline") +} + +private setDeviceHealth(String healthState) { + log.debug("healthStatus: ${device.currentValue('healthStatus')}; DeviceWatch-DeviceStatus: ${device.currentValue('DeviceWatch-DeviceStatus')}") + // ensure healthState is valid + List validHealthStates = ["online", "offline"] + healthState = validHealthStates.contains(healthState) ? healthState : device.currentValue("healthStatus") + // set the healthState + sendEvent(name: "DeviceWatch-DeviceStatus", value: healthState) + sendEvent(name: "healthStatus", value: healthState) +} + /** * initialize all the attributes and state variable */ private initialize() { log.trace "Executing 'initialize'" - // for HealthCheck - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) - - sendEvent(name: "DeviceWatch-DeviceStatus", value: "online") - sendEvent(name: "healthStatus", value: "online") - sendEvent(name: "DeviceWatch-Enroll", value: [protocol: "cloud", scheme:"untracked"].encodeAsJson(), displayed: false) - sendEvent(name: "colorTemperatureRange", value: COLOR_TEMP_RANGE) sendEvent(name: "colorTemperature", value: COLOR_TEMP_DEFAULT)