Compare commits

..

1 Commits

3 changed files with 250 additions and 49 deletions

View File

@@ -18,7 +18,6 @@ metadata {
command "raiseHeatingSetpoint"
command "lowerCoolSetpoint"
command "raiseCoolSetpoint"
command "poll"
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
@@ -102,8 +101,9 @@ metadata {
def installed() {
// Configure device
def cmds = [new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()),
new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())]
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)
runIn(3, "initialize", [overwrite: true]) // Allow configure command to be sent and acknowledged before proceeding
}
@@ -123,7 +123,7 @@ def initialize() {
// 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])
// Poll device for additional data that will be updated by refresh tile
pollDevice()
poll()
}
def parse(String description)
@@ -150,6 +150,7 @@ def parse(String description)
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiInstanceCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x31: 3])
log.debug ("multiinstancev1.MultiInstanceCmdEncap: command from instance ${cmd.instance}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
}
@@ -340,7 +341,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSuppo
if(cmd.auxiliaryemergencyHeat) { supportedModes << "emergency heat" }
state.supportedModes = supportedModes
sendEvent(name: "supportedThermostatModes", value: supportedModes, displayed: false)
sendEvent(name: "supportedThermostatModes", value: supportedModes, isStateChange: true, displayed: false)
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
@@ -350,7 +351,7 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanMod
if(cmd.circulation) { supportedFanModes << "circulate" }
state.supportedFanModes = supportedFanModes
sendEvent(name: "supportedThermostatFanModes", value: supportedFanModes, displayed: false)
sendEvent(name: "supportedThermostatFanModes", value: supportedFanModes, isStateChange: true, displayed: false)
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
@@ -376,6 +377,7 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "ManufacturerSpecificReport ${cmd}: value:${cmd}"
if (cmd.manufacturerName) {
updateDataValue("manufacturer", cmd.manufacturerName)
}
@@ -387,11 +389,6 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
}
}
def poll() {
// Call refresh which will cap the polling to once every 2 minutes
refresh()
}
def refresh() {
// Only allow refresh every 2 minutes to prevent flooding the Zwave network
def timeNow = now()
@@ -400,11 +397,11 @@ def refresh() {
// 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, "pollDevice", [overwrite: true])
runIn(2, "poll", [overwrite: true])
}
}
def pollDevice() {
def poll() {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())
@@ -617,7 +614,7 @@ def updateThermostatSetpoint(setpoint, value) {
* */
def ping() {
log.debug "ping() called"
// Just get Operating State as it is not reported when it changes and there's no need to flood more commands
// 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()))
}
@@ -627,7 +624,7 @@ def switchMode() {
if (supportedModes) {
def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] }
def nextMode = next(currentMode)
runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.warn "supportedModes not defined"
getSupportedModes()
@@ -638,7 +635,7 @@ def switchToMode(nextMode) {
def supportedModes = state.supportedModes
if (supportedModes) {
if (supportedModes.contains(nextMode)) {
runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}")
}
@@ -660,7 +657,7 @@ def switchFanMode() {
if (supportedFanModes) {
def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] }
def nextMode = next(currentMode)
runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.warn "supportedFanModes not defined"
getSupportedFanModes()
@@ -671,7 +668,7 @@ def switchToFanMode(nextMode) {
def supportedFanModes = state.supportedFanModes
if (supportedFanModes) {
if (supportedFanModes.contains(nextMode)) {
runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.debug("FanMode $nextMode is not supported by ${device.displayName}")
}
@@ -682,7 +679,8 @@ def switchToFanMode(nextMode) {
}
def getSupportedFanModes() {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())]
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())
sendHubCommand(cmds)
}
@@ -698,9 +696,10 @@ def setThermostatMode(String value) {
switchToMode(value)
}
def setGetThermostatMode(data) {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()),
new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())]
def setThermostatMode(data) {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())
sendHubCommand(cmds)
}
@@ -714,9 +713,10 @@ def setThermostatFanMode(String value) {
switchToFanMode(value)
}
def setGetThermostatFanMode(data) {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()),
new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())]
def setThermostatFanMode(data) {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())
sendHubCommand(cmds)
}

View File

@@ -28,7 +28,6 @@ metadata {
command "raiseHeatingSetpoint"
command "lowerCoolSetpoint"
command "raiseCoolSetpoint"
command "poll"
fingerprint deviceId: "0x08"
fingerprint inClusters: "0x43,0x40,0x44,0x31"
@@ -92,7 +91,7 @@ metadata {
standardTile("raiseCoolSetpoint", "device.heatingSetpoint", width:2, height:1, inactiveLabel: false, decoration: "flat") {
state "heatingSetpoint", action:"raiseCoolSetpoint", icon:"st.thermostat.thermostat-right"
}
standardTile("thermostatOperatingState", "device.thermostatOperatingState", width: 2, height:1, decoration: "flat") {
valueTile("thermostatOperatingState", "device.thermostatOperatingState", width: 2, height:1, decoration: "flat") {
state "thermostatOperatingState", label:'${currentValue}', backgroundColor:"#ffffff"
}
standardTile("refresh", "device.thermostatMode", width:2, height:1, inactiveLabel: false, decoration: "flat") {
@@ -106,8 +105,9 @@ metadata {
def installed() {
// Configure device
def cmds = [new physicalgraph.device.HubAction(zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()),
new physicalgraph.device.HubAction(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())]
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)
runIn(3, "initialize", [overwrite: true]) // Allow configure command to be sent and acknowledged before proceeding
}
@@ -129,7 +129,7 @@ def initialize() {
if (getDataValue("manufacturer") != "Honeywell") {
runEvery5Minutes("poll") // This is not necessary for Honeywell Z-wave, but could be for other Z-wave thermostats
}
pollDevice()
poll()
}
def parse(String description)
@@ -319,22 +319,17 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
}
// Command Implementations
def poll() {
// Call refresh which will cap the polling to once every 2 minutes
refresh()
}
def refresh() {
// Only allow refresh every 2 minutes to prevent flooding the Zwave network
def timeNow = now()
if (!state.refreshTriggeredAt || (2 * 60 * 1000 < (timeNow - state.refreshTriggeredAt))) {
state.refreshTriggeredAt = timeNow
// use runIn with overwrite to prevent multiple DTH instances run before state.refreshTriggeredAt has been saved
runIn(2, "pollDevice", [overwrite: true])
runIn(2, "poll", [overwrite: true])
}
}
def pollDevice() {
def poll() {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSupportedGet().format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())
@@ -510,7 +505,7 @@ def switchMode() {
if (supportedModes) {
def next = { supportedModes[supportedModes.indexOf(it) + 1] ?: supportedModes[0] }
def nextMode = next(currentMode)
runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.warn "supportedModes not defined"
getSupportedModes()
@@ -521,7 +516,7 @@ def switchToMode(nextMode) {
def supportedModes = state.supportedModes
if (supportedModes) {
if (supportedModes.contains(nextMode)) {
runIn(2, "setGetThermostatMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.debug("ThermostatMode $nextMode is not supported by ${device.displayName}")
}
@@ -543,7 +538,7 @@ def switchFanMode() {
if (supportedFanModes) {
def next = { supportedFanModes[supportedFanModes.indexOf(it) + 1] ?: supportedFanModes[0] }
def nextMode = next(currentMode)
runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.warn "supportedFanModes not defined"
getSupportedFanModes()
@@ -554,7 +549,7 @@ def switchToFanMode(nextMode) {
def supportedFanModes = state.supportedFanModes
if (supportedFanModes) {
if (supportedFanModes.contains(nextMode)) {
runIn(2, "setGetThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
runIn(2, "setThermostatFanMode", [data: [nextMode: nextMode], overwrite: true])
} else {
log.debug("FanMode $nextMode is not supported by ${device.displayName}")
}
@@ -565,7 +560,8 @@ def switchToFanMode(nextMode) {
}
def getSupportedFanModes() {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())]
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format())
sendHubCommand(cmds)
}
@@ -581,9 +577,10 @@ def setThermostatMode(String value) {
switchToMode(value)
}
def setGetThermostatMode(data) {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format()),
new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())]
def setThermostatMode(data) {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[data.nextMode]).format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatModeV2.thermostatModeGet().format())
sendHubCommand(cmds)
}
@@ -597,9 +594,10 @@ def setThermostatFanMode(String value) {
switchToFanMode(value)
}
def setGetThermostatFanMode(data) {
def cmds = [new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format()),
new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())]
def setThermostatFanMode(data) {
def cmds = []
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[data.nextMode]).format())
cmds << new physicalgraph.device.HubAction(zwave.thermostatFanModeV3.thermostatFanModeGet().format())
sendHubCommand(cmds)
}
@@ -665,7 +663,7 @@ def getTempInDeviceScale(temp, scale) {
if (temp && scale) {
def deviceScale = (state.scale == 1) ? "F" : "C"
return (deviceScale == scale) ? temp :
(deviceScale == "F" ? celsiusToFahrenheit(temp).toDouble().round(0).toInteger() : roundC(fahrenheitToCelsius(temp)))
(deviceScale == "F" ? celsiusToFahrenheit(temp) : roundC(fahrenheitToCelsius(temp)))
}
return 0
}

View File

@@ -0,0 +1,203 @@
import grails.converters.JSON
/**
* JSON API Access App
*/
definition(
name: "Quantum",
namespace: "Quantum",
author: "Qblinks",
description: "Quantum is an iPaaS (integration platform as a service) designed for your Smart Home products. With Quantum, you can easily integrate your product with different 3rd party smart home products around the world through a single API call. Smart home features of Qblinks Inc. products are powered by Quantum.",
category: "Convenience",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
oauth: true
)
preferences {
section("Allow these things to be exposed via JSON...") {
input "switches", "capability.colorControl", title: "Switches", multiple: true, required: false, hideWhenEmpty: true
input "outlets", "capability.outlet", title: "Outlets", multiple: true, required: false, hideWhenEmpty: true
}
}
mappings {
path("/switchDiscovery") {
action: [
GET: "listSwitches"
]
}
path("/outletDiscovery") {
action: [
GET: "listOutlets"
]
}
path("/switchAction/:id/:command/:value") {
action: [
PUT: "actionSwitches"
]
}
path("/outletAction/:id/:command") {
action: [
PUT: "actionOutlets"
]
}
path("/switchStat/:id") {
action: [
GET: "statSwitches"
]
}
path("/outletStat/:id") {
action: [
GET: "statOutlets"
]
}
}
def listSwitches() {
[ switches: switches.collect{device(it, "switch")} ]
}
def listOutlets() {
[ outlets: outlets.collect{device(it, "outlet")} ]
}
void actionSwitches() {
def device = switches.find { it.id == params.id }
def command = params.command
switch(command) {
case "on":
if (!device) {
httpError(404, "Device not found")
} else {
device.on()
//def newValue = [level: body.level as Integer ?: 100]
//device.setColor(newValue)
}
break
case "off":
if (!device) {
httpError(404, "Device not found")
} else {
device.off()
}
break
case "bri":
if (!device) {
httpError(404, "Device not found")
} else {
def newValue = [level: params.value as Integer ?: 0]
device.setColor(newValue)
}
break
case "sat":
if (!device) {
httpError(404, "Device not found")
} else {
def newValue = [saturation: params.value as Integer ?: 0]
device.setColor(newValue)
}
break
case "hue":
if (!device) {
httpError(404, "Device not found")
} else {
def newValue = [hue: params.value as Integer ?: 0]
device.setColor(newValue)
}
break
case "allOn":
switches.on()
break
case "allOff":
switches.off()
break
default:
httpError(404, "$command is not a valid command for all outlets specified")
}
}
def statSwitches() {
show(switches, "switch")
}
void actionOutlets() {
def device = outlets.find { it.id == params.id }
def command = params.command
switch(command) {
case "on":
if (!device) {
httpError(404, "Device not found")
} else {
device.on()
result:true
}
break
case "off":
if (!device) {
httpError(404, "Device not found")
} else {
device.off()
result:true
}
break
case "onoff":
if (!device) {
httpError(404, "Device not found")
} else {
device.on()
device.off()
result:true
}
break
case "allOn":
outlets.on()
break
case "allOff":
outlets.off()
break
default:
httpError(404, "$command is not a valid command for all outlets specified")
}
}
def statOutlets() {
show(outlets, "outlet")
}
private show(devices, type) {
def device = devices.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
}
else {
def device_state = [ label: device.name, type: type, id: device.id, network: device.getDeviceNetworkId() ]
for (attribute in device.supportedAttributes) {
device_state."${attribute}" = device.currentValue("${attribute}")
}
device_state ? device_state : null
}
}
private device(it, type) {
def device_state = [ label: it.name, type: type, id: it.id, network: it.getDeviceNetworkId()]
for (attribute in it.supportedAttributes) {
device_state."${attribute}" = it.currentValue("${attribute}")
}
device_state ? device_state : null
}
def installed() {
}
def updated() {
}