mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
Merge pull request #2192 from SmartThingsCommunity/staging
Rolling up staging to production
This commit is contained in:
@@ -73,7 +73,7 @@ metadata {
|
|||||||
[value: 64, color: "#44B621"],
|
[value: 64, color: "#44B621"],
|
||||||
[value: 80, color: "#3D79D9"],
|
[value: 80, color: "#3D79D9"],
|
||||||
[value: 96, color: "#0A50C2"]
|
[value: 96, color: "#0A50C2"]
|
||||||
]
|
], icon:"st.Weather.weather12"
|
||||||
}
|
}
|
||||||
|
|
||||||
valueTile("maxHum", "device.maxHum", canChangeIcon: false, canChangeBackground: false) {
|
valueTile("maxHum", "device.maxHum", canChangeIcon: false, canChangeBackground: false) {
|
||||||
|
|||||||
@@ -27,13 +27,9 @@ Works with:
|
|||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
Aeon Labs MultiSensor (Gen 5) is polled by the hub.
|
Aeon Labs MultiSensor (Gen 5) is polled by the hub.
|
||||||
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
Aeon MultiSensor Gen5 reports in once every hour.
|
||||||
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
|
||||||
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
|
||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
|
||||||
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
|
||||||
|
|
||||||
* __32min__ checkInterval
|
* __122min__ checkInterval
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -100,12 +100,12 @@ metadata {
|
|||||||
|
|
||||||
def installed(){
|
def installed(){
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated(){
|
def updated(){
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description)
|
def parse(String description)
|
||||||
|
|||||||
@@ -28,13 +28,9 @@ Works with:
|
|||||||
## Device Health
|
## Device Health
|
||||||
|
|
||||||
Aeon Labs MultiSensor is polled by the hub.
|
Aeon Labs MultiSensor is polled by the hub.
|
||||||
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
|
Aeon MultiSensor reports in once every hour.
|
||||||
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
|
|
||||||
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
|
|
||||||
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
|
|
||||||
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
|
|
||||||
|
|
||||||
* __32min__ checkInterval
|
* __122min__ checkInterval
|
||||||
|
|
||||||
## Battery Specification
|
## Battery Specification
|
||||||
|
|
||||||
|
|||||||
@@ -96,12 +96,12 @@ metadata {
|
|||||||
|
|
||||||
def installed(){
|
def installed(){
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated(){
|
def updated(){
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse incoming device messages to generate events
|
// Parse incoming device messages to generate events
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ metadata {
|
|||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
capability "Thermostat"
|
capability "Thermostat"
|
||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Configuration"
|
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
capability "Sensor"
|
capability "Sensor"
|
||||||
capability "Health Check"
|
capability "Health Check"
|
||||||
@@ -15,161 +14,173 @@ metadata {
|
|||||||
|
|
||||||
command "switchMode"
|
command "switchMode"
|
||||||
command "switchFanMode"
|
command "switchFanMode"
|
||||||
command "quickSetCool"
|
command "lowerHeatingSetpoint"
|
||||||
command "quickSetHeat"
|
command "raiseHeatingSetpoint"
|
||||||
|
command "lowerCoolSetpoint"
|
||||||
|
command "raiseCoolSetpoint"
|
||||||
|
|
||||||
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
|
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
|
||||||
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
|
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulator metadata
|
|
||||||
simulator {
|
|
||||||
status "off" : "command: 4003, payload: 00"
|
|
||||||
status "heat" : "command: 4003, payload: 01"
|
|
||||||
status "cool" : "command: 4003, payload: 02"
|
|
||||||
status "auto" : "command: 4003, payload: 03"
|
|
||||||
status "emergencyHeat" : "command: 4003, payload: 04"
|
|
||||||
|
|
||||||
status "fanAuto" : "command: 4403, payload: 00"
|
|
||||||
status "fanOn" : "command: 4403, payload: 01"
|
|
||||||
status "fanCirculate" : "command: 4403, payload: 06"
|
|
||||||
|
|
||||||
status "heat 60" : "command: 4303, payload: 01 09 3C"
|
|
||||||
status "heat 72" : "command: 4303, payload: 01 09 48"
|
|
||||||
|
|
||||||
status "cool 76" : "command: 4303, payload: 02 09 4C"
|
|
||||||
status "cool 80" : "command: 4303, payload: 02 09 50"
|
|
||||||
|
|
||||||
status "temp 58" : "command: 3105, payload: 01 2A 02 44"
|
|
||||||
status "temp 62" : "command: 3105, payload: 01 2A 02 6C"
|
|
||||||
status "temp 78" : "command: 3105, payload: 01 2A 03 0C"
|
|
||||||
status "temp 86" : "command: 3105, payload: 01 2A 03 34"
|
|
||||||
|
|
||||||
status "idle" : "command: 4203, payload: 00"
|
|
||||||
status "heating" : "command: 4203, payload: 01"
|
|
||||||
status "cooling" : "command: 4203, payload: 02"
|
|
||||||
|
|
||||||
// reply messages
|
|
||||||
reply "2502": "command: 2503, payload: FF"
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
valueTile("temperature", "device.temperature", width: 2, height: 2) {
|
multiAttributeTile(name:"temperature", type:"generic", width:3, height:2, canChangeIcon: true) {
|
||||||
state("temperature", label:'${currentValue}°',
|
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState("temperature", label:'${currentValue}°', icon: "st.alarm.temperature.normal",
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
[value: 32, color: "#153591"],
|
// 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: 44, color: "#1e9cbb"],
|
||||||
[value: 59, color: "#90d2a7"],
|
[value: 59, color: "#90d2a7"],
|
||||||
[value: 74, color: "#44b621"],
|
[value: 74, color: "#44b621"],
|
||||||
[value: 84, color: "#f1d801"],
|
[value: 84, color: "#f1d801"],
|
||||||
[value: 92, color: "#d04e00"],
|
[value: 95, color: "#d04e00"],
|
||||||
[value: 98, color: "#bc2323"]
|
[value: 96, color: "#bc2323"]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
tileAttribute("device.batteryIcon", key: "SECONDARY_CONTROL") {
|
||||||
state "off", label:'${name}', action:"switchMode", nextState:"to_heat"
|
attributeState "ok_battery", label:'${currentValue}%', icon:"st.arlo.sensor_battery_4"
|
||||||
state "heat", label:'${name}', action:"switchMode", nextState:"to_cool"
|
attributeState "low_battery", label:'Low Battery', icon:"st.arlo.sensor_battery_0"
|
||||||
state "cool", label:'${name}', action:"switchMode", nextState:"..."
|
|
||||||
state "auto", label:'${name}', action:"switchMode", nextState:"..."
|
|
||||||
state "emergency heat", label:'${name}', action:"switchMode", nextState:"..."
|
|
||||||
state "to_heat", label: "heat", action:"switchMode", nextState:"to_cool"
|
|
||||||
state "to_cool", label: "cool", action:"switchMode", nextState:"..."
|
|
||||||
state "...", label: "...", action:"off", nextState:"off"
|
|
||||||
}
|
}
|
||||||
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "fanAuto", label:'${name}', action:"switchFanMode"
|
|
||||||
state "fanOn", label:'${name}', action:"switchFanMode"
|
|
||||||
state "fanCirculate", label:'${name}', action:"switchFanMode"
|
|
||||||
}
|
}
|
||||||
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
standardTile("mode", "device.thermostatMode", width:2, height:2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#e86d13"
|
state "off", action:"switchMode", nextState:"to_heat", icon: "st.thermostat.heating-cooling-off"
|
||||||
|
state "heat", action:"switchMode", nextState:"to_cool", icon: "st.thermostat.heat"
|
||||||
|
state "cool", action:"switchMode", nextState:"...", icon: "st.thermostat.cool"
|
||||||
|
state "auto", action:"switchMode", nextState:"...", icon: "st.thermostat.auto"
|
||||||
|
state "emergency heat", action:"switchMode", nextState:"...", icon: "st.thermostat.emergency-heat"
|
||||||
|
state "to_heat", action:"switchMode", nextState:"to_cool", icon: "st.secondary.secondary"
|
||||||
|
state "to_cool", action:"switchMode", nextState:"...", icon: "st.secondary.secondary"
|
||||||
|
state "...", label: "...", action:"off", nextState:"off", icon: "st.secondary.secondary"
|
||||||
}
|
}
|
||||||
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
|
standardTile("fanMode", "device.thermostatFanMode", width:2, height:2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
|
state "auto", action:"switchFanMode", icon: "st.thermostat.fan-auto"
|
||||||
|
state "on", action:"switchFanMode", icon: "st.thermostat.fan-on"
|
||||||
|
state "circulate", action:"switchFanMode", icon: "st.thermostat.fan-circulate"
|
||||||
}
|
}
|
||||||
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
|
valueTile("humidity", "device.humidity", width:2, height:2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#00a0dc"
|
state "humidity", label:'${currentValue}%', icon:"st.Weather.weather12"
|
||||||
}
|
}
|
||||||
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
|
standardTile("lowerHeatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"
|
state "heatingSetpoint", action:"lowerHeatingSetpoint", icon:"st.thermostat.thermostat-left"
|
||||||
}
|
}
|
||||||
valueTile("humidity", "device.humidity", inactiveLabel: false, decoration: "flat") {
|
valueTile("heatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
state "heatingSetpoint", label:'${currentValue}° heat', backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
standardTile("raiseHeatingSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "heatingSetpoint", action:"raiseHeatingSetpoint", icon:"st.thermostat.thermostat-right"
|
||||||
}
|
}
|
||||||
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
|
standardTile("lowerCoolSetpoint", "device.coolingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "coolingSetpoint", action:"lowerCoolSetpoint", icon:"st.thermostat.thermostat-left"
|
||||||
|
}
|
||||||
|
valueTile("coolingSetpoint", "device.coolingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "coolingSetpoint", label:'${currentValue}° cool', backgroundColor:"#ffffff"
|
||||||
|
}
|
||||||
|
standardTile("raiseCoolSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
|
||||||
|
state "heatingSetpoint", action:"raiseCoolSetpoint", icon:"st.thermostat.thermostat-right"
|
||||||
|
}
|
||||||
|
|
||||||
|
standardTile("refresh", "device.thermostatMode", width:2, height:2, inactiveLabel: false, decoration: "flat") {
|
||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
main "temperature"
|
main "temperature"
|
||||||
details(["temperature", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "refresh", "humidity", "battery"])
|
details(["temperature", "mode", "fanMode", "humidity", "lowerHeatingSetpoint", "heatingSetpoint", "raiseHeatingSetpoint", "lowerCoolSetpoint", "coolingSetpoint", "raiseCoolSetpoint", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// If not set update ManufacturerSpecific data
|
||||||
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
if (!getDataValue("manufacturer")) {
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()))
|
||||||
|
}
|
||||||
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
def installed() {
|
def installed() {
|
||||||
|
// Configure device
|
||||||
|
def cmds = []
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format())
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())
|
||||||
|
sendHubCommand(cmds)
|
||||||
|
initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize() {
|
||||||
// Device-Watch simply pings if no device events received for 32min(checkInterval)
|
// 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])
|
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
// Poll device for additional data that will be updated by refresh tile
|
||||||
|
refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
def parse(String description)
|
def parse(String description)
|
||||||
{
|
{
|
||||||
def result = []
|
def result = null
|
||||||
if (description == "updated") {
|
if (description == "updated") {
|
||||||
} else {
|
} else {
|
||||||
def zwcmd = zwave.parse(description, [0x42:2, 0x43:2, 0x31: 2, 0x60: 3])
|
def zwcmd = zwave.parse(description, [0x42:2, 0x43:2, 0x31: 2, 0x60: 3])
|
||||||
if (zwcmd) {
|
if (zwcmd) {
|
||||||
result += zwaveEvent(zwcmd)
|
result = zwaveEvent(zwcmd)
|
||||||
|
// Check battery level at least once every 2 days
|
||||||
|
if (!state.lastbatt || now() - state.lastbatt > 48*60*60*1000) {
|
||||||
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.batteryV1.batteryGet().format()))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug "$device.displayName couldn't parse $description"
|
log.debug "$device.displayName couldn't parse $description"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return null
|
return []
|
||||||
}
|
}
|
||||||
if (result.size() == 1 && (!state.lastbatt || now() - state.lastbatt > 48*60*60*1000)) {
|
return [result]
|
||||||
result << response(zwave.batteryV1.batteryGet().format())
|
|
||||||
}
|
|
||||||
log.debug "$device.displayName parsed '$description' to $result"
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiInstanceCmdEncap cmd) {
|
||||||
def result = null
|
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 3])
|
||||||
def encapsulatedCommand = cmd.encapsulatedCommand([0x42:2, 0x43:2, 0x31: 2])
|
log.debug ("multiinstancev1.MultiInstanceCmdEncap: command from instance ${cmd.instance}: ${encapsulatedCommand}")
|
||||||
log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
|
|
||||||
if (encapsulatedCommand) {
|
if (encapsulatedCommand) {
|
||||||
result = zwaveEvent(encapsulatedCommand)
|
zwaveEvent(encapsulatedCommand)
|
||||||
if (cmd.sourceEndPoint == 1) { // indicates a response to refresh() vs an unrequested update
|
|
||||||
def event = ([] + result)[0] // in case zwaveEvent returns a list
|
|
||||||
def resp = nextRefreshQuery(event?.name)
|
|
||||||
if (resp) {
|
|
||||||
log.debug("sending next refresh query: $resp")
|
|
||||||
result = [] + result + response(["delay 200", resp])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
|
||||||
{
|
{
|
||||||
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
def sendCmd = []
|
||||||
def temp = convertTemperatureIfNeeded(cmd.scaledValue, cmdScale, cmd.precision)
|
|
||||||
def unit = getTemperatureScale()
|
def unit = getTemperatureScale()
|
||||||
def map1 = [ value: temp, unit: unit, displayed: false ]
|
def cmdScale = cmd.scale == 1 ? "F" : "C"
|
||||||
|
def setpoint = getTempInLocalScale(cmd.scaledValue, cmdScale)
|
||||||
switch (cmd.setpointType) {
|
switch (cmd.setpointType) {
|
||||||
case 1:
|
case 1:
|
||||||
map1.name = "heatingSetpoint"
|
//map1.name = "heatingSetpoint"
|
||||||
|
sendEvent(name: "heatingSetpoint", value: setpoint, unit: unit, displayed: false)
|
||||||
|
updateThermostatSetpoint("heatingSetpoint", setpoint)
|
||||||
|
// Enforce coolingSetpoint limits, as device doesn't
|
||||||
|
if (setpoint > getTempInLocalScale("coolingSetpoint")) {
|
||||||
|
sendCmd << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointSet(
|
||||||
|
setpointType: 2, scale: cmd.scale, precision: cmd.precision, scaledValue: cmd.scaledValue).format())
|
||||||
|
sendCmd << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format())
|
||||||
|
sendHubCommand(sendCmd)
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
map1.name = "coolingSetpoint"
|
//map1.name = "coolingSetpoint"
|
||||||
|
sendEvent(name: "coolingSetpoint", value: setpoint, unit: unit, displayed: false)
|
||||||
|
updateThermostatSetpoint("coolingSetpoint", setpoint)
|
||||||
|
// Enforce heatingSetpoint limits, as device doesn't
|
||||||
|
if (setpoint < getTempInLocalScale("heatingSetpoint")) {
|
||||||
|
sendCmd << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointSet(
|
||||||
|
setpointType: 1, scale: cmd.scale, precision: cmd.precision, scaledValue: cmd.scaledValue).format())
|
||||||
|
sendCmd << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format())
|
||||||
|
sendHubCommand(sendCmd)
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.debug "unknown setpointType $cmd.setpointType"
|
log.debug "unknown setpointType $cmd.setpointType"
|
||||||
@@ -180,33 +191,55 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpo
|
|||||||
state.size = cmd.size
|
state.size = cmd.size
|
||||||
state.scale = cmd.scale
|
state.scale = cmd.scale
|
||||||
state.precision = cmd.precision
|
state.precision = cmd.precision
|
||||||
|
|
||||||
def mode = device.latestValue("thermostatMode")
|
|
||||||
if (mode && map1.name.startsWith(mode) || (mode == "emergency heat" && map1.name == "heatingSetpoint")) {
|
|
||||||
def map2 = [ name: "thermostatSetpoint", value: temp, unit: unit ]
|
|
||||||
[ createEvent(map1), createEvent(map2) ]
|
|
||||||
} else {
|
|
||||||
createEvent(map1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
|
// thermostatSetpoint is not displayed by any tile as it can't be predictable calculated due to
|
||||||
{
|
// the device's quirkiness but it is defined by the capability so it must be set, set it to the most likely value
|
||||||
|
def updateThermostatSetpoint(setpoint, value) {
|
||||||
|
def scale = getTemperatureScale()
|
||||||
|
def heatingSetpoint = (setpoint == "heatingSetpoint") ? value : getTempInLocalScale("heatingSetpoint")
|
||||||
|
def coolingSetpoint = (setpoint == "coolingSetpoint") ? value : getTempInLocalScale("coolingSetpoint")
|
||||||
|
def mode = device.currentValue("thermostatMode")
|
||||||
|
def thermostatSetpoint = heatingSetpoint // corresponds to (mode == "heat" || mode == "emergency heat")
|
||||||
|
if (mode == "cool") {
|
||||||
|
thermostatSetpoint = coolingSetpoint
|
||||||
|
}
|
||||||
|
// Just set to average of heating + cooling for mode off and auto
|
||||||
|
if (mode == "off" || mode == "auto") {
|
||||||
|
thermostatSetpoint = getTempInLocalScale((heatingSetpoint + coolingSetpoint)/2, scale)
|
||||||
|
}
|
||||||
|
sendEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: scale)
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
if (cmd.sensorType == 1) {
|
if (cmd.sensorType == 1) {
|
||||||
map.name = "temperature"
|
map.name = "temperature"
|
||||||
map.unit = getTemperatureScale()
|
map.unit = getTemperatureScale()
|
||||||
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmd.scale == 1 ? "F" : "C", cmd.precision)
|
map.value = getTempInLocalScale(cmd.scaledSensorValue, (cmd.scale == 1 ? "F" : "C"))
|
||||||
} else if (cmd.sensorType == 5) {
|
} else if (cmd.sensorType == 5) {
|
||||||
map.name = "humidity"
|
map.name = "humidity"
|
||||||
map.unit = "%"
|
map.unit = "%"
|
||||||
map.value = cmd.scaledSensorValue
|
map.value = cmd.scaledSensorValue
|
||||||
}
|
}
|
||||||
createEvent(map)
|
sendEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd)
|
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv3.SensorMultilevelReport cmd) {
|
||||||
{
|
def map = [:]
|
||||||
|
if (cmd.sensorType == 1) {
|
||||||
|
map.name = "temperature"
|
||||||
|
map.unit = getTemperatureScale()
|
||||||
|
map.value = getTempInLocalScale(cmd.scaledSensorValue, (cmd.scale == 1 ? "F" : "C"))
|
||||||
|
} else if (cmd.sensorType == 5) {
|
||||||
|
map.value = cmd.scaledSensorValue
|
||||||
|
map.unit = "%"
|
||||||
|
map.name = "humidity"
|
||||||
|
}
|
||||||
|
sendEvent(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport cmd) {
|
||||||
def map = [name: "thermostatOperatingState" ]
|
def map = [name: "thermostatOperatingState" ]
|
||||||
switch (cmd.operatingState) {
|
switch (cmd.operatingState) {
|
||||||
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
|
case physicalgraph.zwave.commands.thermostatoperatingstatev2.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
|
||||||
@@ -231,12 +264,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev2.Thermosta
|
|||||||
map.value = "vent economizer"
|
map.value = "vent economizer"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
def result = createEvent(map)
|
sendEvent(map)
|
||||||
if (result.isStateChange && device.latestValue("thermostatMode") == "auto" && (result.value == "heating" || result.value == "cooling")) {
|
|
||||||
def thermostatSetpoint = device.latestValue("${result.value}Setpoint")
|
|
||||||
result = [result, createEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: getTemperatureScale())]
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanStateReport cmd) {
|
||||||
@@ -252,203 +280,256 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanstatev1.ThermostatFanSt
|
|||||||
map.value = "running high"
|
map.value = "running high"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
createEvent(map)
|
sendEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
|
||||||
def map = [name: "thermostatMode"]
|
def map = [name: "thermostatMode", data:[supportedThermostatModes: state.supportedModes]]
|
||||||
def thermostatSetpoint = null
|
|
||||||
switch (cmd.mode) {
|
switch (cmd.mode) {
|
||||||
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
|
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
|
||||||
map.value = "off"
|
map.value = "off"
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
|
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
|
||||||
map.value = "heat"
|
map.value = "heat"
|
||||||
thermostatSetpoint = device.latestValue("heatingSetpoint")
|
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
|
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
|
||||||
map.value = "emergency heat"
|
map.value = "emergency heat"
|
||||||
thermostatSetpoint = device.latestValue("heatingSetpoint")
|
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
|
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
|
||||||
map.value = "cool"
|
map.value = "cool"
|
||||||
thermostatSetpoint = device.latestValue("coolingSetpoint")
|
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
|
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
|
||||||
map.value = "auto"
|
map.value = "auto"
|
||||||
def temp = device.latestValue("temperature")
|
|
||||||
def heatingSetpoint = device.latestValue("heatingSetpoint")
|
|
||||||
def coolingSetpoint = device.latestValue("coolingSetpoint")
|
|
||||||
if (temp && heatingSetpoint && coolingSetpoint) {
|
|
||||||
if (temp < (heatingSetpoint + coolingSetpoint) / 2.0) {
|
|
||||||
thermostatSetpoint = heatingSetpoint
|
|
||||||
} else {
|
|
||||||
thermostatSetpoint = coolingSetpoint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
state.lastTriedMode = map.value
|
state.lastTriedMode = map.value
|
||||||
if (thermostatSetpoint) {
|
sendEvent(map)
|
||||||
[ createEvent(map), createEvent(name: "thermostatSetpoint", value: thermostatSetpoint, unit: getTemperatureScale()) ]
|
updateThermostatSetpoint(null, null)
|
||||||
} else {
|
|
||||||
createEvent(map)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
|
||||||
def map = [name: "thermostatFanMode", displayed: false]
|
def map = [name: "thermostatFanMode", data:[supportedThermostatFanModes: state.supportedFanModes]]
|
||||||
switch (cmd.fanMode) {
|
switch (cmd.fanMode) {
|
||||||
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
|
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
|
||||||
map.value = "fanAuto"
|
map.value = "auto"
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
|
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
|
||||||
map.value = "fanOn"
|
map.value = "on"
|
||||||
break
|
break
|
||||||
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
|
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
|
||||||
map.value = "fanCirculate"
|
map.value = "circulate"
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
state.lastTriedFanMode = map.value
|
state.lastTriedFanMode = map.value
|
||||||
createEvent(map)
|
sendEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
|
||||||
def supportedModes = ""
|
def supportedModes = []
|
||||||
if(cmd.off) { supportedModes += "off " }
|
if(cmd.heat) { supportedModes << "heat" }
|
||||||
if(cmd.heat) { supportedModes += "heat " }
|
if(cmd.cool) { supportedModes << "cool" }
|
||||||
if(cmd.auxiliaryemergencyHeat) { supportedModes += "emergency heat " }
|
// Make sure off is before auto, this ensures the right setpoint is used based on current temperature when auto is set
|
||||||
if(cmd.cool) { supportedModes += "cool " }
|
if(cmd.off) { supportedModes << "off" }
|
||||||
if(cmd.auto) { supportedModes += "auto " }
|
if(cmd.auto) { supportedModes << "auto" }
|
||||||
|
if(cmd.auxiliaryemergencyHeat) { supportedModes << "emergency heat" }
|
||||||
|
|
||||||
state.supportedModes = supportedModes
|
state.supportedModes = supportedModes
|
||||||
[ createEvent(name:"supportedModes", value: supportedModes, displayed: false),
|
sendEvent(name: "supportedThermostatModes", value: supportedModes, isStateChange: true, displayed: false)
|
||||||
response(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet()) ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
|
||||||
def supportedFanModes = ""
|
def supportedFanModes = []
|
||||||
if(cmd.auto) { supportedFanModes += "fanAuto " }
|
if(cmd.auto) { supportedFanModes << "auto" }
|
||||||
if(cmd.low) { supportedFanModes += "fanOn " }
|
if(cmd.low) { supportedFanModes << "on" }
|
||||||
if(cmd.circulation) { supportedFanModes += "fanCirculate " }
|
if(cmd.circulation) { supportedFanModes << "circulate" }
|
||||||
|
|
||||||
state.supportedFanModes = supportedFanModes
|
state.supportedFanModes = supportedFanModes
|
||||||
[ createEvent(name:"supportedFanModes", value: supportedModes, displayed: false),
|
sendEvent(name: "supportedThermostatFanModes", value: supportedFanModes, isStateChange: true, displayed: false)
|
||||||
response(refresh()) ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||||
log.debug "Zwave event received: $cmd"
|
log.debug "Zwave BasicReport: $cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
|
||||||
def map = [ name: "battery", unit: "%" ]
|
def batteryState = cmd.batteryLevel
|
||||||
if (cmd.batteryLevel == 0xFF) {
|
def map = [name: "battery", unit: "%", value: cmd.batteryLevel]
|
||||||
|
if ((cmd.batteryLevel == 0xFF) || (cmd.batteryLevel == 0x00)) { // Special value for low battery alert
|
||||||
map.value = 1
|
map.value = 1
|
||||||
map.descriptionText = "${device.displayName} battery is low"
|
map.descriptionText = "${device.displayName} battery is low"
|
||||||
map.isStateChange = true
|
map.isStateChange = true
|
||||||
} else {
|
batteryState = "low_battery"
|
||||||
map.value = cmd.batteryLevel
|
|
||||||
}
|
}
|
||||||
state.lastbatt = now()
|
state.lastbatt = now()
|
||||||
createEvent(map)
|
sendEvent(name: "batteryIcon", value: batteryState, displayed: false)
|
||||||
|
sendEvent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
def zwaveEvent(physicalgraph.zwave.Command cmd) {
|
||||||
log.warn "Unexpected zwave command $cmd"
|
log.warn "Unexpected zwave command $cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
|
||||||
|
log.debug "ManufacturerSpecificReport ${cmd}: value:${cmd}"
|
||||||
|
if (cmd.manufacturerName) {
|
||||||
|
updateDataValue("manufacturer", cmd.manufacturerName)
|
||||||
|
}
|
||||||
|
if (cmd.productTypeId) {
|
||||||
|
updateDataValue("productTypeId", cmd.productTypeId.toString())
|
||||||
|
}
|
||||||
|
if (cmd.productId) {
|
||||||
|
updateDataValue("productId", cmd.productId.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
// Use encapsulation to differentiate refresh cmds from what the thermostat sends proactively on change
|
// Only allow refresh every 2 minutes to prevent flooding the Zwave network
|
||||||
def cmd = zwave.sensorMultilevelV2.sensorMultilevelGet()
|
def timeNow = now()
|
||||||
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:1).encapsulate(cmd).format()
|
if (!state.refreshTriggeredAt || (2 * 60 * 1000 < (timeNow - state.refreshTriggeredAt))) {
|
||||||
|
state.refreshTriggeredAt = timeNow
|
||||||
|
// refresh will request battery, prevent multiple request by setting lastbatt now
|
||||||
|
state.lastbatt = timeNow
|
||||||
|
// use runIn with overwrite to prevent multiple DTH instances run before state.refreshTriggeredAt has been saved
|
||||||
|
runIn(2, "poll", [overwrite: true])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def nextRefreshQuery(name) {
|
def poll() {
|
||||||
def cmd = null
|
def cmds = []
|
||||||
switch (name) {
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format())
|
||||||
case "temperature":
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())
|
||||||
cmd = zwave.thermostatModeV2.thermostatModeGet()
|
cmds << new physicalgraph.device.HubAction(zwave.multiChannelV3.multiInstanceCmdEncap(instance: 1).encapsulate(zwave.sensorMultilevelV3.sensorMultilevelGet()).format()) // temperature
|
||||||
break
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())
|
||||||
case "thermostatMode":
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())
|
||||||
cmd = zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1)
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format())
|
||||||
break
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()) // HeatingSetpoint
|
||||||
case "heatingSetpoint":
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()) // CoolingSetpoint
|
||||||
cmd = zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2)
|
cmds << new physicalgraph.device.HubAction(zwave.batteryV1.batteryGet().format())
|
||||||
break
|
cmds << new physicalgraph.device.HubAction(zwave.multiChannelV3.multiInstanceCmdEncap(instance: 2).encapsulate(zwave.sensorMultilevelV3.sensorMultilevelGet()).format()) // humidity
|
||||||
case "coolingSetpoint":
|
def time = getTimeAndDay()
|
||||||
cmd = zwave.thermostatFanModeV3.thermostatFanModeGet()
|
log.debug "time: $time"
|
||||||
break
|
if (time) {
|
||||||
case "thermostatFanMode":
|
cmds << new physicalgraph.device.HubAction(zwave.clockV1.clockSet(time).format())
|
||||||
cmd = zwave.thermostatOperatingStateV2.thermostatOperatingStateGet()
|
|
||||||
break
|
|
||||||
case "thermostatOperatingState":
|
|
||||||
// get humidity, multilevel sensor get to endpoint 2
|
|
||||||
cmd = zwave.sensorMultilevelV2.sensorMultilevelGet()
|
|
||||||
return zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:2).encapsulate(cmd).format()
|
|
||||||
default: return null
|
|
||||||
}
|
}
|
||||||
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:1).encapsulate(cmd).format()
|
// Add 3 seconds delay between each command to avoid flooding the Z-Wave network choking the hub
|
||||||
|
sendHubCommand(cmds, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
def quickSetHeat(degrees) {
|
def raiseHeatingSetpoint() {
|
||||||
setHeatingSetpoint(degrees, 1000)
|
alterSetpoint(null, true, "heatingSetpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHeatingSetpoint(degrees, delay = 30000) {
|
def lowerHeatingSetpoint() {
|
||||||
setHeatingSetpoint(degrees.toDouble(), delay)
|
alterSetpoint(null, false, "heatingSetpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHeatingSetpoint(Double degrees, Integer delay = 30000) {
|
def raiseCoolSetpoint() {
|
||||||
log.trace "setHeatingSetpoint($degrees, $delay)"
|
alterSetpoint(null, true, "coolingSetpoint")
|
||||||
def deviceScale = state.scale ?: 1
|
}
|
||||||
def deviceScaleString = deviceScale == 2 ? "C" : "F"
|
|
||||||
|
def lowerCoolSetpoint() {
|
||||||
|
alterSetpoint(null, false, "coolingSetpoint")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjusts nextHeatingSetpoint either .5° C/1° F) if raise true/false
|
||||||
|
def alterSetpoint(degrees, raise, setpoint) {
|
||||||
def locationScale = getTemperatureScale()
|
def locationScale = getTemperatureScale()
|
||||||
def p = (state.precision == null) ? 1 : state.precision
|
def heatingSetpoint = getTempInLocalScale("heatingSetpoint")
|
||||||
|
def coolingSetpoint = getTempInLocalScale("coolingSetpoint")
|
||||||
def convertedDegrees
|
def targetvalue = (setpoint == "heatingSetpoint") ? heatingSetpoint : coolingSetpoint
|
||||||
if (locationScale == "C" && deviceScaleString == "F") {
|
def delta = (locationScale == "F") ? 1 : 0.5
|
||||||
convertedDegrees = celsiusToFahrenheit(degrees)
|
if (raise != null) {
|
||||||
} else if (locationScale == "F" && deviceScaleString == "C") {
|
targetvalue += raise ? delta : - delta
|
||||||
convertedDegrees = fahrenheitToCelsius(degrees)
|
} else if (degrees) {
|
||||||
|
targetvalue = degrees
|
||||||
} else {
|
} else {
|
||||||
convertedDegrees = degrees
|
log.warn "alterSetpoint called with neither up/down/degree information"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
def data = enforceSetpointLimits(setpoint, [targetvalue: targetvalue, heatingSetpoint: heatingSetpoint, coolingSetpoint: coolingSetpoint])
|
||||||
|
// update UI without waiting for the device to respond, this to give user a smoother UI experience
|
||||||
|
// also, as runIn's have to overwrite and user can change heating/cooling setpoint separately separate runIn's have to be used
|
||||||
|
if (data.targetHeatingSetpoint) {
|
||||||
|
sendEvent("name": "heatingSetpoint", "value": data.targetHeatingSetpoint, unit: locationScale, eventType: "ENTITY_UPDATE")//, displayed: false)
|
||||||
|
runIn(4, "updateHeatingSetpoint", [data: data, overwrite: true])
|
||||||
|
}
|
||||||
|
if (data.targetCoolingSetpoint) {
|
||||||
|
sendEvent("name": "coolingSetpoint", "value": data.targetCoolingSetpoint, unit: locationScale, eventType: "ENTITY_UPDATE")//, displayed: false)
|
||||||
|
runIn(4, "updateCoolingSetpoint", [data: data, overwrite: true])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delayBetween([
|
def updateHeatingSetpoint(data) {
|
||||||
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
|
updateSetpoints(data)
|
||||||
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
|
|
||||||
], delay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def quickSetCool(degrees) {
|
def updateCoolingSetpoint(data) {
|
||||||
setCoolingSetpoint(degrees, 1000)
|
updateSetpoints(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
def setCoolingSetpoint(degrees, delay = 30000) {
|
def enforceSetpointLimits(setpoint, data) {
|
||||||
setCoolingSetpoint(degrees.toDouble(), delay)
|
// Enforce max/min for setpoints
|
||||||
|
def maxSetpoint = getTempInLocalScale(95, "F")
|
||||||
|
def minSetpoint = getTempInLocalScale(35, "F")
|
||||||
|
def targetvalue = data.targetvalue
|
||||||
|
def heatingSetpoint = null
|
||||||
|
def coolingSetpoint = null
|
||||||
|
|
||||||
|
if (targetvalue > maxSetpoint) {
|
||||||
|
targetvalue = maxSetpoint
|
||||||
|
} else if (targetvalue < minSetpoint) {
|
||||||
|
targetvalue = minSetpoint
|
||||||
|
}
|
||||||
|
// Enforce limits, for now make sure heating <= cooling, and cooling >= heating
|
||||||
|
if (setpoint == "heatingSetpoint") {
|
||||||
|
heatingSetpoint = targetvalue
|
||||||
|
coolingSetpoint = (heatingSetpoint > data.coolingSetpoint) ? heatingSetpoint : null
|
||||||
|
}
|
||||||
|
if (setpoint == "coolingSetpoint") {
|
||||||
|
coolingSetpoint = targetvalue
|
||||||
|
heatingSetpoint = (coolingSetpoint < data.heatingSetpoint) ? coolingSetpoint : null
|
||||||
|
}
|
||||||
|
return [targetHeatingSetpoint: heatingSetpoint, targetCoolingSetpoint: coolingSetpoint]
|
||||||
}
|
}
|
||||||
|
|
||||||
def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
|
def setHeatingSetpoint(degrees) {
|
||||||
log.trace "setCoolingSetpoint($degrees, $delay)"
|
if (degrees) {
|
||||||
def deviceScale = state.scale ?: 1
|
def data = enforceSetpointLimits("heatingSetpoint",
|
||||||
def deviceScaleString = deviceScale == 2 ? "C" : "F"
|
[targetvalue: degrees.toDouble(), heatingSetpoint: getTempInLocalScale("heatingSetpoint"), coolingSetpoint: getTempInLocalScale("coolingSetpoint")])
|
||||||
|
updateSetpoints(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def setCoolingSetpoint(degrees) {
|
||||||
|
if (degrees) {
|
||||||
|
def data = enforceSetpointLimits("coolingSetpoint",
|
||||||
|
[targetvalue: degrees.toDouble(), heatingSetpoint: getTempInLocalScale("heatingSetpoint"), coolingSetpoint: getTempInLocalScale("coolingSetpoint")])
|
||||||
|
updateSetpoints(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def updateSetpoints(data) {
|
||||||
|
def cmds = []
|
||||||
|
if (data.targetHeatingSetpoint) {
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointSet(
|
||||||
|
setpointType: 1, scale: state.scale, precision: state.precision, scaledValue: convertToDeviceScale(data.targetHeatingSetpoint)).format())
|
||||||
|
}
|
||||||
|
if (data.targetCoolingSetpoint) {
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointSet(
|
||||||
|
setpointType: 2, scale: state.scale, precision: state.precision, scaledValue: convertToDeviceScale(data.targetCoolingSetpoint)).format())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always request both setpoints in case thermostat changed both
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format())
|
||||||
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format())
|
||||||
|
sendHubCommand(cmds)
|
||||||
|
}
|
||||||
|
|
||||||
|
def convertToDeviceScale(setpoint) {
|
||||||
def locationScale = getTemperatureScale()
|
def locationScale = getTemperatureScale()
|
||||||
def p = (state.precision == null) ? 1 : state.precision
|
def deviceScale = (state.scale == 1) ? "F" : "C"
|
||||||
|
return (deviceScale == locationScale) ? setpoint :
|
||||||
def convertedDegrees
|
(deviceScale == "F" ? celsiusToFahrenheit(setpoint.toBigDecimal()) : roundC(fahrenheitToCelsius(setpoint.toBigDecimal())))
|
||||||
if (locationScale == "C" && deviceScaleString == "F") {
|
|
||||||
convertedDegrees = celsiusToFahrenheit(degrees)
|
|
||||||
} else if (locationScale == "F" && deviceScaleString == "C") {
|
|
||||||
convertedDegrees = fahrenheitToCelsius(degrees)
|
|
||||||
} else {
|
|
||||||
convertedDegrees = degrees
|
|
||||||
}
|
|
||||||
|
|
||||||
delayBetween([
|
|
||||||
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: deviceScale, precision: p, scaledValue: convertedDegrees).format(),
|
|
||||||
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()
|
|
||||||
], delay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -456,78 +537,56 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
|
|||||||
* */
|
* */
|
||||||
def ping() {
|
def ping() {
|
||||||
log.debug "ping() called"
|
log.debug "ping() called"
|
||||||
refresh()
|
// Just get Operating State as it is not reported when it chnages and there's no need to flood more commands
|
||||||
}
|
sendHubCommand(new physicalgraph.device.HubAction(zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format()))
|
||||||
|
|
||||||
def configure() {
|
|
||||||
delayBetween([
|
|
||||||
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
|
|
||||||
], 2300)
|
|
||||||
}
|
|
||||||
|
|
||||||
def modes() {
|
|
||||||
["off", "heat", "cool", "auto", "emergency heat"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def switchMode() {
|
def switchMode() {
|
||||||
def currentMode = device.currentState("thermostatMode")?.value
|
def currentMode = device.currentValue("thermostatMode")
|
||||||
def lastTriedMode = state.lastTriedMode ?: currentMode ?: "off"
|
def lastTriedMode = state.lastTriedMode ?: currentMode ?: "off"
|
||||||
def supportedModes = getDataByName("supportedModes")
|
def supportedModes = state.supportedModes
|
||||||
def modeOrder = modes()
|
if (supportedModes) {
|
||||||
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
|
def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] }
|
||||||
def nextMode = next(lastTriedMode)
|
def nextMode = next(lastTriedMode)
|
||||||
if (supportedModes?.contains(currentMode)) {
|
setThermostatMode(nextMode)
|
||||||
while (!supportedModes.contains(nextMode) && nextMode != "off") {
|
|
||||||
nextMode = next(nextMode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.lastTriedMode = nextMode
|
state.lastTriedMode = nextMode
|
||||||
delayBetween([
|
} else {
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[nextMode]).format(),
|
log.warn "supportedModes not defined"
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
}
|
||||||
], 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def switchToMode(nextMode) {
|
def switchToMode(nextMode) {
|
||||||
def supportedModes = getDataByName("supportedModes")
|
def supportedModes = state.supportedModes
|
||||||
if(supportedModes && !supportedModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
|
if (supportedModes && supportedModes.contains(nextMode)) {
|
||||||
if (nextMode in modes()) {
|
setThermostatMode(nextMode)
|
||||||
state.lastTriedMode = nextMode
|
state.lastTriedMode = nextMode
|
||||||
"$nextMode"()
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("no mode method '$nextMode'")
|
log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def switchFanMode() {
|
def switchFanMode() {
|
||||||
def currentMode = device.currentState("thermostatFanMode")?.value
|
def currentMode = device.currentState("thermostatFanMode")?.value
|
||||||
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
|
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
|
||||||
def supportedModes = getDataByName("supportedFanModes") ?: "fanAuto fanOn"
|
def supportedFanModes = state.supportedFanModes
|
||||||
def modeOrder = ["fanAuto", "fanCirculate", "fanOn"]
|
if (supportedFanModes) {
|
||||||
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
|
def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] }
|
||||||
def nextMode = next(lastTriedMode)
|
def nextMode = next(lastTriedMode)
|
||||||
while (!supportedModes?.contains(nextMode) && nextMode != "fanAuto") {
|
setThermostatFanMode(nextMode)
|
||||||
nextMode = next(nextMode)
|
state.lastTriedFanMode = nextMode
|
||||||
|
} else {
|
||||||
|
log.warn "supportedFanModes not defined"
|
||||||
}
|
}
|
||||||
switchToFanMode(nextMode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def switchToFanMode(nextMode) {
|
def switchToFanMode(nextMode) {
|
||||||
def supportedFanModes = getDataByName("supportedFanModes")
|
def supportedFanModes = state.supportedFanModes
|
||||||
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
|
if (supportedFanModes && supportedFanModes.contains(nextMode)) {
|
||||||
|
setThermostatFanMode(nextMode)
|
||||||
def returnCommand
|
state.lastTriedFanMode = nextMode
|
||||||
if (nextMode == "fanAuto") {
|
|
||||||
returnCommand = fanAuto()
|
|
||||||
} else if (nextMode == "fanOn") {
|
|
||||||
returnCommand = fanOn()
|
|
||||||
} else if (nextMode == "fanCirculate") {
|
|
||||||
returnCommand = fanCirculate()
|
|
||||||
} else {
|
} else {
|
||||||
log.debug("no fan mode '$nextMode'")
|
log.debug("FanMode $nextMode is not supported by ${device.displayName}")
|
||||||
}
|
}
|
||||||
if(returnCommand) state.lastTriedFanMode = nextMode
|
|
||||||
returnCommand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def getDataByName(String name) {
|
def getDataByName(String name) {
|
||||||
@@ -543,10 +602,10 @@ def getModeMap() { [
|
|||||||
]}
|
]}
|
||||||
|
|
||||||
def setThermostatMode(String value) {
|
def setThermostatMode(String value) {
|
||||||
delayBetween([
|
def cmds = []
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[value]).format(),
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[value]).format())
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())
|
||||||
], standardDelay)
|
sendHubCommand(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getFanModeMap() { [
|
def getFanModeMap() { [
|
||||||
@@ -556,69 +615,70 @@ def getFanModeMap() { [
|
|||||||
]}
|
]}
|
||||||
|
|
||||||
def setThermostatFanMode(String value) {
|
def setThermostatFanMode(String value) {
|
||||||
delayBetween([
|
def cmds = []
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[value]).format(),
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[value]).format())
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
|
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())
|
||||||
], standardDelay)
|
sendHubCommand(cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
delayBetween([
|
switchToMode("off")
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: 0).format(),
|
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def heat() {
|
def heat() {
|
||||||
delayBetween([
|
switchToMode("heat")
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: 1).format(),
|
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def emergencyHeat() {
|
def emergencyHeat() {
|
||||||
delayBetween([
|
switchToMode("emergency heat")
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: 4).format(),
|
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def cool() {
|
def cool() {
|
||||||
delayBetween([
|
switchToMode("cool")
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: 2).format(),
|
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def auto() {
|
def auto() {
|
||||||
delayBetween([
|
switchToMode("auto")
|
||||||
zwave.thermostatModeV2.thermostatModeSet(mode: 3).format(),
|
|
||||||
zwave.thermostatModeV2.thermostatModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanOn() {
|
def fanOn() {
|
||||||
delayBetween([
|
switchToFanMode("on")
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 1).format(),
|
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanAuto() {
|
def fanAuto() {
|
||||||
delayBetween([
|
switchToFanMode("auto")
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 0).format(),
|
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fanCirculate() {
|
def fanCirculate() {
|
||||||
delayBetween([
|
switchToFanMode("circulate")
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 6).format(),
|
|
||||||
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
|
|
||||||
], standardDelay)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStandardDelay() {
|
private getTimeAndDay() {
|
||||||
1000
|
def timeNow = now()
|
||||||
|
// Need to check that location have timeZone as SC may have created the location without setting it
|
||||||
|
// Don't update clock more than once a day
|
||||||
|
if (location.timeZone && (!state.timeClockSet || (24 * 60 * 60 * 1000 < (timeNow - state.timeClockSet)))) {
|
||||||
|
def currentDate = Calendar.getInstance(location.timeZone)
|
||||||
|
state.timeClockSet = timeNow
|
||||||
|
return [hour: currentDate.get(Calendar.HOUR_OF_DAY), minute: currentDate.get(Calendar.MINUTE), weekday: currentDate.get(Calendar.DAY_OF_WEEK)]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get stored temperature from currentState in current local scale
|
||||||
|
def getTempInLocalScale(state) {
|
||||||
|
def temp = device.currentState(state)
|
||||||
|
if (temp && temp.value && temp.unit) {
|
||||||
|
return getTempInLocalScale(temp.value.toBigDecimal(), temp.unit)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// get/convert temperature to current local scale
|
||||||
|
def getTempInLocalScale(temp, scale) {
|
||||||
|
def scaledTemp = convertTemperatureIfNeeded(temp.toBigDecimal(), scale).toDouble()
|
||||||
|
return (getTemperatureScale() == "F" ? scaledTemp.round(0).toInteger() : roundC(scaledTemp))
|
||||||
|
}
|
||||||
|
|
||||||
|
def roundC (tempC) {
|
||||||
|
return (Math.round(tempC.toDouble() * 2))/2
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
.st-ignore
|
||||||
|
README.md
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# Z-wave Basic Smoke Alarm
|
||||||
|
|
||||||
|
Cloud Execution
|
||||||
|
|
||||||
|
Works with:
|
||||||
|
|
||||||
|
* [First Alert Smoke Detector (ZSMOKE)](https://www.smartthings.com/products/first-alert-smoke-detector)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
* [Capabilities](#capabilities)
|
||||||
|
* [Health](#device-health)
|
||||||
|
* [Battery](#battery-specification)
|
||||||
|
* [Troubleshooting](#troubleshooting)
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
* **Smoke Detector** - measure smoke and optionally carbon monoxide levels
|
||||||
|
* **Sensor** - detects sensor events
|
||||||
|
* **Battery** - defines device uses a battery
|
||||||
|
* **Health Check** - indicates ability to get device health notifications
|
||||||
|
|
||||||
|
## Device Health
|
||||||
|
|
||||||
|
First Alert Smoke Detector (ZSMOKE) is a Z-wave sleepy device and checks in every 1 hour.
|
||||||
|
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*60 + 2)mins = 122 mins.
|
||||||
|
|
||||||
|
* __122min__ checkInterval
|
||||||
|
|
||||||
|
## Battery Specification
|
||||||
|
|
||||||
|
Two AA 1.5V batteries are required.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
|
||||||
|
Pairing needs to be tried again by placing the device closer to the hub.
|
||||||
|
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
|
||||||
|
* [First Alert Smoke Detector (ZSMOKE) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207150556-First-Alert-Smoke-Detector-ZSMOKE-)
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
||||||
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
metadata {
|
||||||
|
definition (name: "Z-Wave Basic Smoke Alarm", namespace: "smartthings", author: "SmartThings") {
|
||||||
|
capability "Smoke Detector"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Battery"
|
||||||
|
capability "Health Check"
|
||||||
|
|
||||||
|
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
||||||
|
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
|
||||||
|
}
|
||||||
|
|
||||||
|
simulator {
|
||||||
|
status "smoke": "command: 7105, payload: 01 FF"
|
||||||
|
status "clear": "command: 7105, payload: 01 00"
|
||||||
|
status "test": "command: 7105, payload: 0C FF"
|
||||||
|
status "battery 100%": "command: 8003, payload: 64"
|
||||||
|
status "battery 5%": "command: 8003, payload: 05"
|
||||||
|
}
|
||||||
|
|
||||||
|
tiles (scale: 2){
|
||||||
|
multiAttributeTile(name:"smoke", type: "lighting", width: 6, height: 4){
|
||||||
|
tileAttribute ("device.smoke", key: "PRIMARY_CONTROL") {
|
||||||
|
attributeState("clear", label:"clear", icon:"st.alarm.smoke.clear", backgroundColor:"#ffffff")
|
||||||
|
attributeState("detected", label:"SMOKE", icon:"st.alarm.smoke.smoke", backgroundColor:"#e86d13")
|
||||||
|
attributeState("tested", label:"TEST", icon:"st.alarm.smoke.test", backgroundColor:"#e86d13")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
|
}
|
||||||
|
|
||||||
|
main "smoke"
|
||||||
|
details(["smoke", "battery"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def installed() {
|
||||||
|
// Device checks in every hour, this interval allows us to miss one check-in notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
|
def cmds = []
|
||||||
|
createSmokeEvents("smokeClear", cmds)
|
||||||
|
cmds.each { cmd -> sendEvent(cmd) }
|
||||||
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
// Device checks in every hour, this interval allows us to miss one check-in notification before marking offline
|
||||||
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
}
|
||||||
|
|
||||||
|
def parse(String description) {
|
||||||
|
def results = []
|
||||||
|
if (description.startsWith("Err")) {
|
||||||
|
results << createEvent(descriptionText:description, displayed:true)
|
||||||
|
} else {
|
||||||
|
def cmd = zwave.parse(description, [ 0x80: 1, 0x84: 1, 0x71: 2, 0x72: 1 ])
|
||||||
|
if (cmd) {
|
||||||
|
zwaveEvent(cmd, results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug "'$description' parsed to ${results.inspect()}"
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
def createSmokeEvents(name, results) {
|
||||||
|
def text = null
|
||||||
|
switch (name) {
|
||||||
|
case "smoke":
|
||||||
|
text = "$device.displayName smoke was detected!"
|
||||||
|
// these are displayed:false because the composite event is the one we want to see in the app
|
||||||
|
results << createEvent(name: "smoke", value: "detected", descriptionText: text)
|
||||||
|
break
|
||||||
|
case "tested":
|
||||||
|
text = "$device.displayName was tested"
|
||||||
|
results << createEvent(name: "smoke", value: "tested", descriptionText: text)
|
||||||
|
break
|
||||||
|
case "smokeClear":
|
||||||
|
text = "$device.displayName smoke is clear"
|
||||||
|
results << createEvent(name: "smoke", value: "clear", descriptionText: text)
|
||||||
|
name = "clear"
|
||||||
|
break
|
||||||
|
case "testClear":
|
||||||
|
text = "$device.displayName test cleared"
|
||||||
|
results << createEvent(name: "smoke", value: "clear", descriptionText: text)
|
||||||
|
name = "clear"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd, results) {
|
||||||
|
if (cmd.zwaveAlarmType == physicalgraph.zwave.commands.alarmv2.AlarmReport.ZWAVE_ALARM_TYPE_SMOKE) {
|
||||||
|
if (cmd.zwaveAlarmEvent == 3) {
|
||||||
|
createSmokeEvents("tested", results)
|
||||||
|
} else {
|
||||||
|
createSmokeEvents((cmd.zwaveAlarmEvent == 1 || cmd.zwaveAlarmEvent == 2) ? "smoke" : "smokeClear", results)
|
||||||
|
}
|
||||||
|
} else switch(cmd.alarmType) {
|
||||||
|
case 1:
|
||||||
|
createSmokeEvents(cmd.alarmLevel ? "smoke" : "smokeClear", results)
|
||||||
|
break
|
||||||
|
case 12: // test button pressed
|
||||||
|
createSmokeEvents(cmd.alarmLevel ? "tested" : "testClear", results)
|
||||||
|
break
|
||||||
|
case 13: // sent every hour -- not sure what this means, just a wake up notification?
|
||||||
|
if (cmd.alarmLevel == 255) {
|
||||||
|
results << createEvent(descriptionText: "$device.displayName checked in", isStateChange: false)
|
||||||
|
} else {
|
||||||
|
results << createEvent(descriptionText: "$device.displayName code 13 is $cmd.alarmLevel", isStateChange:true, displayed:false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear smoke in case they pulled batteries and we missed the clear msg
|
||||||
|
if(device.currentValue("smoke") != "clear") {
|
||||||
|
createSmokeEvents("smokeClear", results)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check battery if we don't have a recent battery event
|
||||||
|
if (!state.lastbatt || (now() - state.lastbatt) >= 48*60*60*1000) {
|
||||||
|
results << response(zwave.batteryV1.batteryGet())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
results << createEvent(displayed: true, descriptionText: "Alarm $cmd.alarmType ${cmd.alarmLevel == 255 ? 'activated' : cmd.alarmLevel ?: 'deactivated'}".toString())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SensorBinary and SensorAlarm aren't tested, but included to preemptively support future smoke alarms
|
||||||
|
//
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd, results) {
|
||||||
|
if (cmd.sensorType == physicalgraph.zwave.commandclasses.SensorBinaryV2.SENSOR_TYPE_SMOKE) {
|
||||||
|
createSmokeEvents(cmd.sensorValue ? "smoke" : "smokeClear", results)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd, results) {
|
||||||
|
if (cmd.sensorType == 1) {
|
||||||
|
createSmokeEvents(cmd.sensorState ? "smoke" : "smokeClear", results)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd, results) {
|
||||||
|
results << createEvent(descriptionText: "$device.displayName woke up", isStateChange: false)
|
||||||
|
if (!state.lastbatt || (now() - state.lastbatt) >= 56*60*60*1000) {
|
||||||
|
results << response(zwave.batteryV1.batteryGet(), "delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation())
|
||||||
|
} else {
|
||||||
|
results << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd, results) {
|
||||||
|
def map = [ name: "battery", unit: "%", isStateChange: true ]
|
||||||
|
state.lastbatt = now()
|
||||||
|
if (cmd.batteryLevel == 0xFF) {
|
||||||
|
map.value = 1
|
||||||
|
map.descriptionText = "$device.displayName battery is low!"
|
||||||
|
} else {
|
||||||
|
map.value = cmd.batteryLevel
|
||||||
|
}
|
||||||
|
results << createEvent(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.Command cmd, results) {
|
||||||
|
def event = [ displayed: false ]
|
||||||
|
event.linkText = device.label ?: device.name
|
||||||
|
event.descriptionText = "$event.linkText: $cmd"
|
||||||
|
results << createEvent(event)
|
||||||
|
}
|
||||||
@@ -21,8 +21,6 @@ metadata {
|
|||||||
|
|
||||||
attribute "alarmState", "string"
|
attribute "alarmState", "string"
|
||||||
|
|
||||||
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
|
|
||||||
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
|
|
||||||
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +55,10 @@ metadata {
|
|||||||
def installed() {
|
def installed() {
|
||||||
// Device checks in every hour, this interval allows us to miss one check-in notification before marking offline
|
// Device checks in every hour, this interval allows us to miss one check-in notification before marking offline
|
||||||
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
|
||||||
|
|
||||||
|
def cmds = []
|
||||||
|
createSmokeOrCOEvents("allClear", cmds) // allClear to set inital states for smoke and CO
|
||||||
|
cmds.each { cmd -> sendEvent(cmd) }
|
||||||
}
|
}
|
||||||
|
|
||||||
def updated() {
|
def updated() {
|
||||||
@@ -105,6 +107,12 @@ def createSmokeOrCOEvents(name, results) {
|
|||||||
results << createEvent(name: "carbonMonoxide", value: "clear", descriptionText: text, displayed: false)
|
results << createEvent(name: "carbonMonoxide", value: "clear", descriptionText: text, displayed: false)
|
||||||
name = "clear"
|
name = "clear"
|
||||||
break
|
break
|
||||||
|
case "allClear":
|
||||||
|
text = "$device.displayName all clear"
|
||||||
|
results << createEvent(name: "smoke", value: "clear", descriptionText: text, displayed: false)
|
||||||
|
results << createEvent(name: "carbonMonoxide", value: "clear", displayed: false)
|
||||||
|
name = "clear"
|
||||||
|
break
|
||||||
case "testClear":
|
case "testClear":
|
||||||
text = "$device.displayName test cleared"
|
text = "$device.displayName test cleared"
|
||||||
results << createEvent(name: "smoke", value: "clear", descriptionText: text, displayed: false)
|
results << createEvent(name: "smoke", value: "clear", descriptionText: text, displayed: false)
|
||||||
|
|||||||
@@ -2,26 +2,11 @@ import javax.crypto.Mac;
|
|||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenT2T SmartApp Test
|
|
||||||
*
|
|
||||||
* Copyright 2016 OpenT2T
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
|
|
||||||
* in compliance with the License. You may obtain a copy of the License at:
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
|
|
||||||
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing permissions and limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
definition(
|
definition(
|
||||||
name: "OpenT2T SmartApp Test",
|
name: "OpenT2T SmartApp Test",
|
||||||
namespace: "opent2t",
|
namespace: "opent2t",
|
||||||
author: "OpenT2T",
|
author: "Microsoft",
|
||||||
description: "Test app to test end to end SmartThings scenarios via OpenT2T",
|
description: "SmartApp for end to end SmartThings scenarios via OpenT2T",
|
||||||
category: "SmartThings Labs",
|
category: "SmartThings Labs",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
|
||||||
@@ -55,16 +40,16 @@ definition(
|
|||||||
|
|
||||||
//Device Inputs
|
//Device Inputs
|
||||||
preferences {
|
preferences {
|
||||||
section("Allow OpenT2T to control these things...") {
|
section("Allow Microsoft to control these things...") {
|
||||||
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false, hideWhenEmpty: true
|
// input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false, hideWhenEmpty: true
|
// input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false, hideWhenEmpty: true
|
// input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true
|
// input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false, hideWhenEmpty: true
|
// input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false, hideWhenEmpty: true
|
// input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false, hideWhenEmpty: true
|
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false, hideWhenEmpty: true
|
input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false, hideWhenEmpty: true
|
// input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false, hideWhenEmpty: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,36 +67,32 @@ def getInputs() {
|
|||||||
return inputList
|
return inputList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//API external Endpoints
|
//API external Endpoints
|
||||||
mappings {
|
mappings {
|
||||||
path("/devices") {
|
path("/devices") {
|
||||||
action:
|
action: [
|
||||||
[
|
|
||||||
GET: "getDevices"
|
GET: "getDevices"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/devices/:id") {
|
path("/devices/:id") {
|
||||||
action:
|
action: [
|
||||||
[
|
|
||||||
GET: "getDevice"
|
GET: "getDevice"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/update/:id") {
|
path("/update/:id") {
|
||||||
action:
|
action: [
|
||||||
[
|
|
||||||
PUT: "updateDevice"
|
PUT: "updateDevice"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/deviceSubscription") {
|
path("/deviceSubscription") {
|
||||||
action:
|
action: [
|
||||||
[
|
|
||||||
POST : "registerDeviceChange",
|
POST : "registerDeviceChange",
|
||||||
DELETE: "unregisterDeviceChange"
|
DELETE: "unregisterDeviceChange"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
path("/locationSubscription") {
|
path("/locationSubscription") {
|
||||||
action:
|
action: [
|
||||||
[
|
|
||||||
POST : "registerDeviceGraph",
|
POST : "registerDeviceGraph",
|
||||||
DELETE: "unregisterDeviceGraph"
|
DELETE: "unregisterDeviceGraph"
|
||||||
]
|
]
|
||||||
@@ -311,17 +292,17 @@ def deviceEventHandler(evt) {
|
|||||||
def evtDeviceType = getDeviceType(evtDevice)
|
def evtDeviceType = getDeviceType(evtDevice)
|
||||||
def deviceData = [];
|
def deviceData = [];
|
||||||
|
|
||||||
if (evt.data != null) {
|
|
||||||
def evtData = parseJson(evt.data)
|
|
||||||
log.info "Received event for ${evtDevice.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evtDeviceType == "thermostat") {
|
if (evtDeviceType == "thermostat") {
|
||||||
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationMode: getLocationModeInfo(), locationId: location.id]
|
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationMode: getLocationModeInfo(), locationId: location.id]
|
||||||
} else {
|
} else {
|
||||||
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationId: location.id]
|
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationId: location.id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(evt.data != null){
|
||||||
|
def evtData = parseJson(evt.data)
|
||||||
|
log.info "Received event for ${evtDevice.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
|
||||||
|
}
|
||||||
|
|
||||||
def params = [body: deviceData]
|
def params = [body: deviceData]
|
||||||
|
|
||||||
//send event to all subscriptions urls
|
//send event to all subscriptions urls
|
||||||
@@ -330,10 +311,10 @@ def deviceEventHandler(evt) {
|
|||||||
params.uri = "${it}"
|
params.uri = "${it}"
|
||||||
if (state.verificationKeyMap[it] != null) {
|
if (state.verificationKeyMap[it] != null) {
|
||||||
def key = state.verificationKeyMap[it]
|
def key = state.verificationKeyMap[it]
|
||||||
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
|
params.headers = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
|
||||||
}
|
}
|
||||||
log.trace "POST URI: ${params.uri}"
|
log.trace "POST URI: ${params.uri}"
|
||||||
log.trace "Header: ${params.header}"
|
log.trace "Headers: ${params.headers}"
|
||||||
log.trace "Payload: ${params.body}"
|
log.trace "Payload: ${params.body}"
|
||||||
try {
|
try {
|
||||||
httpPostJson(params) { resp ->
|
httpPostJson(params) { resp ->
|
||||||
@@ -363,10 +344,10 @@ def locationEventHandler(evt) {
|
|||||||
params.uri = "${it}"
|
params.uri = "${it}"
|
||||||
if (state.verificationKeyMap[it] != null) {
|
if (state.verificationKeyMap[it] != null) {
|
||||||
def key = state.verificationKeyMap[it]
|
def key = state.verificationKeyMap[it]
|
||||||
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
|
params.headers = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
|
||||||
}
|
}
|
||||||
log.trace "POST URI: ${params.uri}"
|
log.trace "POST URI: ${params.uri}"
|
||||||
log.trace "Header: ${params.header}"
|
log.trace "Headers: ${params.headers}"
|
||||||
log.trace "Payload: ${params.body}"
|
log.trace "Payload: ${params.body}"
|
||||||
try {
|
try {
|
||||||
httpPostJson(params) { resp ->
|
httpPostJson(params) { resp ->
|
||||||
@@ -385,6 +366,7 @@ def locationEventHandler(evt) {
|
|||||||
|
|
||||||
private ComputHMACValue(key, data) {
|
private ComputHMACValue(key, data) {
|
||||||
try {
|
try {
|
||||||
|
log.debug "data hased: ${data}"
|
||||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1")
|
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1")
|
||||||
Mac mac = Mac.getInstance("HmacSHA1")
|
Mac mac = Mac.getInstance("HmacSHA1")
|
||||||
mac.init(secretKeySpec)
|
mac.init(secretKeySpec)
|
||||||
@@ -507,7 +489,8 @@ private getDeviceType(device) {
|
|||||||
|
|
||||||
//Loop through the device capability list to determine the device type.
|
//Loop through the device capability list to determine the device type.
|
||||||
capabilities.each { capability ->
|
capabilities.each { capability ->
|
||||||
switch (capability.name.toLowerCase()) {
|
switch(capability.name.toLowerCase())
|
||||||
|
{
|
||||||
case "switch":
|
case "switch":
|
||||||
deviceType = "switch"
|
deviceType = "switch"
|
||||||
|
|
||||||
@@ -652,7 +635,8 @@ private mapDeviceCommands(command, value) {
|
|||||||
if (value == 1 || value == "1" || value == "lock") {
|
if (value == 1 || value == "1" || value == "lock") {
|
||||||
resultCommand = "lock"
|
resultCommand = "lock"
|
||||||
resultValue = ""
|
resultValue = ""
|
||||||
} else if (value == 0 || value == "0" || value == "unlock") {
|
}
|
||||||
|
else if (value == 0 || value == "0" || value == "unlock") {
|
||||||
resultCommand = "unlock"
|
resultCommand = "unlock"
|
||||||
resultValue = ""
|
resultValue = ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user