Compare commits

...

30 Commits

Author SHA1 Message Date
Vinay Rao
79c254cfac Merge pull request #1774 from SmartThingsCommunity/staging
Rolling up staging to production
2017-03-14 11:40:39 -07:00
Vinay Rao
72248b0004 Merge pull request #1773 from SmartThingsCommunity/production
Rolling down production to staging
2017-03-14 11:38:11 -07:00
Vinay Rao
d8b35b23ea Merge pull request #1770 from dkirker/DVCSMP-2472
DVCSMP-2472: Add Eaton Halo downlight
2017-03-14 02:28:47 -07:00
Donald Kirker
9a53e12427 DVCSMP-2472: Add Eaton Halo downlight 2017-03-14 02:20:58 -07:00
Vinay Rao
3c4d86bb31 Merge pull request #1761 from mckeed/ICP-399-prod
Update Fibaro Flood Sensor configuration ICP-399 ICP-398
2017-03-08 16:43:23 -08:00
Duncan McKee
1f69ab6634 Update Fibaro Flood Sensor configuration
ICP-399 ICP-398
2017-03-08 19:17:46 -05:00
Vinay Rao
b0ac006781 Merge pull request #1758 from mckeed/ICP-399-staging
Update Fibaro Flood Sensor configuration ICP-399 ICP-398
2017-03-07 17:53:27 -08:00
Duncan McKee
ef1ebc8347 Update Fibaro Flood Sensor configuration
ICP-399 ICP-398
2017-03-07 20:45:49 -05:00
Vinay Rao
aa1f2f21e8 Merge pull request #1756 from SmartThingsCommunity/master
Rolling up master to staging
2017-03-07 13:55:39 -08:00
Vinay Rao
cb6377886d Merge pull request #1755 from SmartThingsCommunity/staging
Rolling down staging to master
2017-03-07 13:54:54 -08:00
Vinay Rao
7a605373d6 Merge pull request #1754 from SmartThingsCommunity/staging
Rolling up staging to production
2017-03-07 13:27:33 -08:00
Vinay Rao
90fb9251a6 Merge pull request #1753 from SmartThingsCommunity/production
Rolling down production to staging
2017-03-07 13:27:02 -08:00
Vinay Rao
195e0babb2 Merge pull request #1752 from larsfinander/DVCSMP-2497_OpenT2T_Update_3_5_submission_staging
DVCSMP-2497 OpenT2T: Update to 3/5 submission
2017-03-06 20:52:51 -08:00
Lars Finander
065715f296 DVCSMP-2497 OpenT2T: Update to 3/5 submission 2017-03-06 21:43:42 -07:00
tslagle13
a544e2f019 Merge pull request #1712 from SmartThingsCommunity/MSA-1803-1
MSA-1803: Gideon Smart home smartapp
2017-03-06 12:07:11 -08:00
Vinay Rao
10acb76b34 Merge pull request #1747 from workingmonk/feature/zwave_chf_prod
[CHF-532] [CHF-533] Health Check Z-Wave Sleepy Fibaro Sensors
2017-03-05 13:29:49 -08:00
Jack Chi
4fc046f57f [CHF-532] [CHF-533] Health Check Z-Wave Sleepy Fibaro Sensors (#1741) 2017-03-05 13:26:30 -08:00
Vinay Rao
ff2e70b011 Merge pull request #1744 from workingmonk/feature/na04_deploy_tag
TECHOPS-1788 update deploy script
2017-03-03 16:37:42 -08:00
Vinay Rao
79e2789f68 TECHOPS-1788 update deploy script 2017-03-03 16:32:32 -08:00
Vinay Rao
a777c298ca Merge pull request #1743 from dbradmit/shabbat-zipcode-fix
Update shabbat-and-holiday-modes.groovy
2017-03-03 04:04:00 -08:00
Jack Chi
94a87e5c7f [CHF-532] [CHF-533] Health Check Z-Wave Sleepy Fibaro Sensors (#1741) 2017-03-02 17:53:17 -08:00
Vinay Rao
22be8ef2e8 Merge pull request #1739 from larsfinander/DVCSMP-2487_OpenT2T_Update_to_3_2_submission_staging
DVCSMP-2487 OpenT2T: Update to 3/2 submission
2017-03-02 11:26:42 -08:00
Lars Finander
2f20a339c3 DVCSMP-2487 OpenT2T: Update to 3/2 submission 2017-03-02 12:16:03 -07:00
Vinay Rao
ab79ceb857 Merge pull request #1728 from SmartThingsCommunity/staging
Rolling up staging to production
2017-02-28 14:01:19 -08:00
Nicola Russo
a583a25ef3 MSA-1803: A simple web service smartapp that allows the users to control their devices through Gideon Smart home app. 2017-02-23 15:31:44 -08:00
Vinay Rao
2151e2dd3e Merge pull request #1706 from SmartThingsCommunity/staging
Rolling up staging to production for deploy
2017-02-22 13:44:57 -08:00
Vinay Rao
bfd2b6c0fa Merge pull request #1674 from SmartThingsCommunity/staging
Rolling up staging to production
2017-02-14 12:09:12 -08:00
Vinay Rao
fc312286a2 Merge pull request #1653 from SmartThingsCommunity/staging
Rolling up staging to production for deploy
2017-02-07 14:21:49 -08:00
Vinay Rao
0846b6f34c Merge pull request #1629 from SmartThingsCommunity/staging
Rolling up staging to production
2017-01-31 13:25:26 -08:00
dbradmit
a15ca97988 Update shabbat-and-holiday-modes.groovy 2017-01-24 19:16:10 -07:00
9 changed files with 1353 additions and 351 deletions

View File

@@ -9,7 +9,7 @@ apply plugin: 'smartthings-slack'
buildscript { buildscript {
dependencies { dependencies {
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.8" classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.11"
} }
repositories { repositories {
mavenLocal() mavenLocal()

View File

@@ -21,28 +21,30 @@ metadata {
capability "Tamper Alert" capability "Tamper Alert"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Water Sensor" capability "Water Sensor"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
fingerprint mfr:"010F", prod:"0B01", model:"2002"
fingerprint mfr:"010F", prod:"0B01", model:"1002"
} }
simulator { simulator {
} }
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.water", key:"PRIMARY_CONTROL") { tileAttribute("device.water", key:"PRIMARY_CONTROL") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc") attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13") attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc") attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc") attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
} }
} }
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) { valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',
backgroundColors:[ backgroundColors:[
[value: 31, color: "#153591"], [value: 31, color: "#153591"],
@@ -54,22 +56,22 @@ metadata {
[value: 96, color: "#bc2323"] [value: 96, color: "#bc2323"]
] ]
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""
} }
main "FGFS" main "FGFS"
details(["FGFS","battery", "temperature"]) details(["FGFS","battery", "temperature"])
} }
} }
// parse events into attributes // parse events into attributes
def parse(String description) { def parse(String description) {
log.debug "Parsing '${description}'" log.debug "Parsing '${description}'"
def result = [] def result = []
if (description.startsWith("Err 106")) { if (description.startsWith("Err 106")) {
if (state.sec) { if (state.sec) {
result = createEvent(descriptionText:description, displayed:false) result = createEvent(descriptionText:description, displayed:false)
} else { } else {
@@ -84,13 +86,13 @@ def parse(String description) {
} else if (description == "updated") { } else if (description == "updated") {
return null return null
} else { } else {
def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1]) def cmd = zwave.parse(description, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) { if (cmd) {
log.debug "Parsed '${cmd}'" log.debug "Parsed '${cmd}'"
zwaveEvent(cmd) zwaveEvent(cmd)
} }
} }
} }
//security //security
@@ -107,7 +109,7 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
//crc16 //crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{ {
def versions = [0x31: 5, 0x72: 2, 0x80: 1] def versions = [0x31: 5, 0x72: 2, 0x80: 1]
def version = versions[cmd.commandClass as Integer] def version = versions[cmd.commandClass as Integer]
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass) def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data) def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
@@ -121,105 +123,124 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{ {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false) def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = [] def cmds = []
cmds << encap(zwave.batteryV1.batteryGet()) // cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 500" // cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)) cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 1200" [event, response(cmds)]
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
} }
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}" log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}" log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}" log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}" log.debug "productTypeId: ${cmd.productTypeId}"
} }
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}" log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}" log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}" log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}" log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) { //serial number in binary format
String serialNumber = "h'" String serialNumber = "h'"
cmd.deviceIdData.each{ data -> cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}" serialNumber += "${String.format("%02X", data)}"
} }
updateDataValue("serialNumber", serialNumber) updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}" log.debug "${device.displayName} - serial number: ${serialNumber}"
} }
def response_cmds = []
if (!device.currentState("temperature")) {
response_cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
}
if (!getDataValue("version") && !zwaveInfo.ver) {
log.debug "Requesting Version Report"
response_cmds << "delay 500"
response_cmds << encap(zwave.versionV1.versionGet())
}
response_cmds << "delay 1000"
response_cmds << encap(zwave.wakeUpV2.wakeUpNoMoreInformation())
[[:], response(response_cmds)]
} }
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}") updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}" log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}" log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}" log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}" log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}" log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
} }
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def result = []
def map = [:] def map = [:]
map.name = "battery" map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString() map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%" map.unit = "%"
map.displayed = true
createEvent(map) result << createEvent(map)
if (!getDataValue("serialNumber")) {
result << response(encap(zwave.manufacturerSpecificV2.deviceSpecificGet()))
} else {
result << response(encap(zwave.wakeUpV2.wakeUpNoMoreInformation()))
}
result
} }
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:] def map = [:]
if (cmd.notificationType == 5) { if (cmd.notificationType == 5) {
switch (cmd.event) { switch (cmd.event) {
case 2: case 2:
map.name = "water" map.name = "water"
map.value = "wet" map.value = "wet"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
break
case 0:
map.name = "water"
map.value = "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break break
case 3: case 0:
map.name = "tamper" map.name = "water"
map.value = "active" map.value = "dry"
map.descriptionText = "${device.displayName}: tamper alarm activated" map.descriptionText = "${device.displayName} is ${map.value}"
break break
} }
} } else if (cmd.notificationType == 7) {
switch (cmd.event) {
createEvent(map) case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:] def map = [:]
if (cmd.sensorType == 1) { if (cmd.sensorType == 1) {
// temperature // temperature
def cmdScale = cmd.scale == 1 ? "F" : "C" def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision) map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale() map.unit = getTemperatureScale()
map.name = "temperature" map.name = "temperature"
map.displayed = true map.displayed = true
} }
createEvent(map) createEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
@@ -228,19 +249,18 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() { def configure() {
log.debug "Executing 'configure'" log.debug "Executing 'configure'"
// Device wakes up every 4 hours, this interval of 8h 2m allows us to miss one wakeup notification before marking offline
def cmds = [] sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGFS' default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500) // default initial state
sendEvent(name: "water", value: "dry")
def cmds = []
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds << zwave.batteryV1.batteryGet() // other queries sent as response to BatteryReport
encapSequence(cmds, 200)
} }
private secure(physicalgraph.zwave.Command cmd) { private secure(physicalgraph.zwave.Command cmd) {
@@ -249,7 +269,7 @@ private secure(physicalgraph.zwave.Command cmd) {
private crc16(physicalgraph.zwave.Command cmd) { private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() //zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000" "5601${cmd.format()}0000"
} }
private encapSequence(commands, delay=200) { private encapSequence(commands, delay=200) {
@@ -257,13 +277,10 @@ private encapSequence(commands, delay=200) {
} }
private encap(physicalgraph.zwave.Command cmd) { private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C] if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) {
// Secure inclusion failed
//todo: check if secure inclusion was successful crc16(cmd)
//if not do not send security-encapsulated command } else {
if (secureClasses.find{ it == cmd.commandClassId }) { secure(cmd)
secure(cmd) }
} else { }
crc16(cmd)
}
}

View File

@@ -22,6 +22,7 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Tamper Alert" capability "Tamper Alert"
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: "" fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
} }
@@ -240,7 +241,9 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() { def configure() {
log.debug "Executing 'configure'" log.debug "Executing 'configure'"
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds: 7200, nodeid: zwaveHubNodeId)//FGMS' default wake up interval cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds: 7200, nodeid: zwaveHubNodeId)//FGMS' default wake up interval

View File

@@ -1,12 +1,12 @@
/** /**
* Device Type Definition File * Device Type Definition File
* *
* Device Type: Fibaro Flood Sensor * Device Type: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy * File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10 * Initial Release: 2014-12-10
* @author: Todd Wackford * @author: Todd Wackford
* Email: todd@wackford.net * Email: todd@wackford.net
* @version: 1.0 * @version: 1.0
* *
* Copyright 2014 SmartThings * Copyright 2014 SmartThings
* *
@@ -26,8 +26,8 @@
* not displayed to the user. We do this so we can receive events and display on device * not displayed to the user. We do this so we can receive events and display on device
* activity. If the user wants to display the tamper tile, adjust the tile display lines * activity. If the user wants to display the tamper tile, adjust the tile display lines
* with the following: * with the following:
* main(["water", "temperature", "tamper"]) * main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"]) * details(["water", "temperature", "battery", "tamper"])
* *
* @param none * @param none
* *
@@ -39,13 +39,17 @@ metadata {
capability "Temperature Measurement" capability "Temperature Measurement"
capability "Configuration" capability "Configuration"
capability "Battery" capability "Battery"
capability "Health Check"
command "resetParams2StDefaults"
command "listCurrentParams" command "resetParams2StDefaults"
command "updateZwaveParam" command "listCurrentParams"
command "test" command "updateZwaveParam"
command "test"
fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84" fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84"
fingerprint mfr:"010F", prod:"0000", model:"2002"
fingerprint mfr:"010F", prod:"0000", model:"1002"
fingerprint mfr:"010F", prod:"0B00", model:"1001"
} }
simulator { simulator {
@@ -86,9 +90,9 @@ metadata {
[value: 96, color: "#bc2323"] [value: 96, color: "#bc2323"]
] ]
} }
standardTile("tamper", "device.tamper") { standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff") state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0") state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""
@@ -106,26 +110,17 @@ metadata {
def parse(String description) def parse(String description)
{ {
def result = [] def result = []
if (description == "updated") { def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
if (!state.MSR) {
result << response(zwave.wakeUpV1.wakeUpIntervalSet(seconds: 60*60, nodeid:zwaveHubNodeId)) if (cmd) {
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
} }
} else {
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3]) if ( result[0] != null ) {
if (cmd) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
}
}
result << response(zwave.batteryV1.batteryGet().format())
if ( result[0] != null ) {
log.debug "Parse returned ${result}" log.debug "Parse returned ${result}"
result result
} }
} }
@@ -142,10 +137,9 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)] def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
if (!isConfigured()) { if (!isConfigured()) {
// we're still in the process of configuring a newly joined device // we're still in the process of configuring a newly joined device
result += lateConfigure(true) result << lateConfigure(true)
} else { } else {
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
log.debug "We're done with WakeUp!"
} }
result result
} }
@@ -153,7 +147,7 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{ {
def map = [:] def map = [:]
switch (cmd.sensorType) { switch (cmd.sensorType) {
case 1: case 1:
// temperature // temperature
@@ -184,7 +178,7 @@ def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cm
def map = [:] def map = [:]
map.value = cmd.sensorValue ? "active" : "inactive" map.value = cmd.sensorValue ? "active" : "inactive"
map.name = "acceleration" map.name = "acceleration"
if (map.value == "active") { if (map.value == "active") {
map.descriptionText = "$device.displayName detected vibration" map.descriptionText = "$device.displayName detected vibration"
} }
@@ -199,49 +193,49 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport
} }
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
log.debug "BasicSet with CMD = ${cmd}" log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) { if (!isConfigured()) {
def result = [] def result = []
def map = [:] def map = [:]
map.name = "water" map.name = "water"
map.value = cmd.value ? "wet" : "dry" map.value = cmd.value ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured. // If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true) result += lateConfigure(true)
result << createEvent(map) result << createEvent(map)
result result
} }
} }
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
{ {
def map = [:] def map = [:]
if (cmd.sensorType == 0x05) { if (cmd.sensorType == 0x05) {
map.name = "water" map.name = "water"
map.value = cmd.sensorState ? "wet" : "dry" map.value = cmd.sensorState ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}" map.descriptionText = "${device.displayName} is ${map.value}"
log.debug "CMD = SensorAlarmReport: ${cmd}" log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured() setConfigured()
} else if ( cmd.sensorType == 0) { } else if ( cmd.sensorType == 0) {
map.name = "tamper" map.name = "tamper"
map.isStateChange = true map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure" map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with" map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) { } else if ( cmd.sensorType == 1) {
map.name = "tamper" map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure" map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with" map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation runIn(30, "resetTamper") //device does not send alarm cancelation
} else { } else {
map.descriptionText = "${device.displayName}: ${cmd}" map.descriptionText = "${device.displayName}: ${cmd}"
} }
@@ -250,10 +244,10 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
def resetTamper() { def resetTamper() {
def map = [:] def map = [:]
map.name = "tamper" map.name = "tamper"
map.value = "secure" map.value = "secure"
map.descriptionText = "$device.displayName is secure" map.descriptionText = "$device.displayName is secure"
sendEvent(map) sendEvent(map)
} }
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
@@ -267,10 +261,10 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
log.debug "msr: $msr" log.debug "msr: $msr"
device.updateDataValue(["MSR", msr]) device.updateDataValue(["MSR", msr])
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true) result += lateConfigure(true)
} }
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false) result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
result result
@@ -282,17 +276,17 @@ def setConfigured() {
def isConfigured() { def isConfigured() {
Boolean configured = device.getDataValue(["configured"]) as Boolean Boolean configured = device.getDataValue(["configured"]) as Boolean
return configured return configured
} }
def lateConfigure(setConf = False) { def lateConfigure(setConf = False) {
def res = response(configure()) def res = response(configure())
if (setConf) if (setConf)
setConfigured() setConfigured()
return res return res
} }
/** /**
@@ -304,26 +298,34 @@ def lateConfigure(setConf = False) {
*/ */
def configure() { def configure() {
log.debug "Configuring Device..." log.debug "Configuring Device..."
def cmds = [] // Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
// send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// temp hysteresis set to .5 degrees celcius // default initial state
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format() sendEvent(name: "water", value: "dry")
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
def cmds = []
// send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// reporting frequency of temps and battery set to one hour // reporting frequency of temps and battery set to one hour
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format() // cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() // temp hysteresis set to .5 degrees celcius
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.batteryV1.batteryGet().format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
delayBetween(cmds, 100) delayBetween(cmds, 100)
} }
@@ -349,18 +351,18 @@ def test() {
* @return none * @return none
*/ */
def updateZwaveParam(params) { def updateZwaveParam(params) {
if ( params ) { if ( params ) {
def pNumber = params.paramNumber def pNumber = params.paramNumber
def pSize = params.size def pSize = params.size
def pValue = [params.value] def pValue = [params.value]
log.debug "Make sure device is awake and in recieve mode (triple-click?)" log.debug "Make sure device is awake and in recieve mode (triple-click?)"
log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'" log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format() cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000) delayBetween(cmds, 1000)
} }
} }
/** /**
@@ -377,26 +379,26 @@ def updateZwaveParam(params) {
def resetParams2StDefaults() { def resetParams2StDefaults() {
log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults" log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format() cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200) delayBetween(cmds, 1200)
} }
/** /**
@@ -413,25 +415,25 @@ def resetParams2StDefaults() {
def listCurrentParams() { def listCurrentParams() {
log.debug "Listing of current parameter settings of ${device.displayName}" log.debug "Listing of current parameter settings of ${device.displayName}"
def cmds = [] def cmds = []
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format() cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
delayBetween(cmds, 1200) delayBetween(cmds, 1200)
} }

View File

@@ -46,6 +46,7 @@
capability "Illuminance Measurement" capability "Illuminance Measurement"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
command "resetParams2StDefaults" command "resetParams2StDefaults"
command "listCurrentParams" command "listCurrentParams"
@@ -125,6 +126,9 @@
*/ */
def configure() { def configure() {
log.debug "Configuring Device For SmartThings Use" log.debug "Configuring Device For SmartThings Use"
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = [] def cmds = []
// send associate to group 3 to get sensor data reported only to hub // send associate to group 3 to get sensor data reported only to hub

View File

@@ -0,0 +1,169 @@
/**
* Copyright 2016 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.
*
*/
import groovy.transform.Field
@Field Boolean hasConfiguredHealthCheck = false
metadata {
definition (name: "ZLL White Color Temperature Bulb 5000K", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Color Temperature"
capability "Configuration"
capability "Polling"
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
attribute "colorName", "string"
command "setGenericName"
fingerprint profileId: "C05E", deviceId: "0220", inClusters: "0000, 0004, 0003, 0006, 0008, 0005, 0300", outClusters: "0019", manufacturer: "Eaton", model: "Halo_LT01", deviceJoinName: "Halo RL56 Wireless"
}
// UI tile definitions
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("colorName", key: "SECONDARY_CONTROL") {
attributeState "colorName", label:'${currentValue}'
}
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..5000)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K'
}
main(["switch"])
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
if (event.name == "colorTemperature") {
event.unit = "K"
}
sendEvent(event)
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
}
def off() {
zigbee.off() + ["delay 1500"] + zigbee.onOffRefresh()
}
def on() {
zigbee.on() + ["delay 1500"] + zigbee.onOffRefresh()
}
def setLevel(value) {
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh()
}
def refresh() {
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
// Do NOT config if the device is the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, and maybe other weird things with the others
if (!((device.getDataValue("manufacturer") == "Eaton") && (device.getDataValue("model") == "Halo_LT01"))) {
cmds = cmds + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
}
cmds
}
def poll() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
}
def configureHealthCheck() {
Integer hcIntervalMinutes = 12
if (!hasConfiguredHealthCheck) {
log.debug "Configuring Health Check, Reporting"
unschedule("healthPoll")
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
hasConfiguredHealthCheck = true
}
}
def configure() {
log.debug "configure()"
configureHealthCheck()
// Implementation note: for the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, so be sure this is before the call to onOffRefresh
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def updated() {
log.debug "updated()"
configureHealthCheck()
}
def setColorTemperature(value) {
setGenericName(value)
zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
}
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
def setGenericName(value){
if (value != null) {
def genericName = ""
if (value < 3300) {
genericName = "Soft White"
} else if (value < 4150) {
genericName = "Moonlight"
} else if (value <= 5000) {
genericName = "Cool White"
} else {
genericName = "Daylight"
}
sendEvent(name: "colorName", value: genericName, displayed: false)
}
}

View File

@@ -0,0 +1,794 @@
/**
* Gideon
*
* Copyright 2016 Nicola Russo
*
* 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(
name: "Gideon Smart Home",
namespace: "gideon.api",
author: "Braindrain Solutions ltd",
description: "Gideon Smart Home SmartApp allows you to connect and control all of your SmartThings devices through the Gideon app, making your SmartThings devices even smarter.",
category: "Family",
iconUrl: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX2Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX3Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
oauth: [displayName: "Gideon Smart Home API app", displayLink: "gideon.ai"])
preferences {
section("Control these contact sensors...") {
input "contact", "capability.contactSensor", multiple:true, required:false
}
section("Control these switch levels...") {
input "switchlevels", "capability.switchLevel", multiple:true, required:false
}
/* section("Control these thermostats...") {
input "thermostats", "capability.thermostat", multiple:true, required:false
}*/
section("Control the color for these devices...") {
input "colors", "capability.colorControl", multiple:true, required:false
}
section("Control the color temperature for these devices...") {
input "kelvin", "capability.colorTemperature", multiple:true, required:false
}
section("Control these switches...") {
input "switches", "capability.switch", multiple:true, required:false
}
section("Control these smoke alarms...") {
input "smoke_alarms", "capability.smokeDetector", multiple:true, required:false
}
section("Control these window shades...") {
input "shades", "capability.windowShade", multiple:true, required:false
}
section("Control these garage doors...") {
input "garage", "capability.garageDoorControl", multiple:true, required:false
}
section("Control these water sensors...") {
input "water_sensors", "capability.waterSensor", multiple:true, required:false
}
section("Control these motion sensors...") {
input "motions", "capability.motionSensor", multiple:true, required:false
}
section("Control these presence sensors...") {
input "presence_sensors", "capability.presenceSensor", multiple:true, required:false
}
section("Control these outlets...") {
input "outlets", "capability.outlet", multiple:true, required:false
}
section("Control these power meters...") {
input "meters", "capability.powerMeter", multiple:true, required:false
}
section("Control these locks...") {
input "locks", "capability.lock", multiple:true, required:false
}
section("Control these temperature sensors...") {
input "temperature_sensors", "capability.temperatureMeasurement", multiple:true, required:false
}
section("Control these batteries...") {
input "batteries", "capability.battery", multiple:true, required:false
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
}
private device(it, type) {
it ? [id: it.id, label: it.label, type: type] : null
}
//API Mapping
mappings {
path("/getalldevices") {
action: [
GET: "getAllDevices"
]
}
/*
path("/thermostat/setcool/:id/:temp") {
action: [
GET: "setCoolTemp"
]
}
path("/thermostat/setheat/:id/:temp") {
action: [
GET: "setHeatTemp"
]
}
path("/thermostat/setfanmode/:id/:mode") {
action: [
GET: "setFanMode"
]
}
path("/thermostat/setmode/:id/:mode") {
action: [
GET: "setThermostatMode"
]
}
path("/thermostat/:id") {
action: [
GET: "getThermostatStatus"
]
}
*/
path("/light/dim/:id/:dim") {
action: [
GET: "setLevelStatus"
]
}
path("/light/kelvin/:id/:kelvin") {
action: [
GET: "setKelvin"
]
}
path("/colorlight/:id/:hue/:sat") {
action: [
GET: "setColor"
]
}
path("/light/status/:id") {
action: [
GET: "getLightStatus"
]
}
path("/light/on/:id") {
action: [
GET: "turnOnLight"
]
}
path("/light/off/:id") {
action: [
GET: "turnOffLight"
]
}
path("/doorlocks/lock/:id") {
action: [
GET: "lockDoorLock"
]
}
path("/doorlocks/unlock/:id") {
action: [
GET: "unlockDoorLock"
]
}
path("/doorlocks/:id") {
action: [
GET: "getDoorLockStatus"
]
}
path("/contacts/:id") {
action: [
GET: "getContactStatus"
]
}
path("/smoke/:id") {
action: [
GET: "getSmokeStatus"
]
}
path("/shades/open/:id") {
action: [
GET: "openShade"
]
}
path("/shades/preset/:id") {
action: [
GET: "presetShade"
]
}
path("/shades/close/:id") {
action: [
GET: "closeShade"
]
}
path("/shades/:id") {
action: [
GET: "getShadeStatus"
]
}
path("/garage/open/:id") {
action: [
GET: "openGarage"
]
}
path("/garage/close/:id") {
action: [
GET: "closeGarage"
]
}
path("/garage/:id") {
action: [
GET: "getGarageStatus"
]
}
path("/watersensors/:id") {
action: [
GET: "getWaterSensorStatus"
]
}
path("/tempsensors/:id") {
action: [
GET: "getTempSensorsStatus"
]
}
path("/meters/:id") {
action: [
GET: "getMeterStatus"
]
}
path("/batteries/:id") {
action: [
GET: "getBatteryStatus"
]
}
path("/presences/:id") {
action: [
GET: "getPresenceStatus"
]
}
path("/motions/:id") {
action: [
GET: "getMotionStatus"
]
}
path("/outlets/:id") {
action: [
GET: "getOutletStatus"
]
}
path("/outlets/turnon/:id") {
action: [
GET: "turnOnOutlet"
]
}
path("/outlets/turnoff/:id") {
action: [
GET: "turnOffOutlet"
]
}
path("/switches/turnon/:id") {
action: [
GET: "turnOnSwitch"
]
}
path("/switches/turnoff/:id") {
action: [
GET: "turnOffSwitch"
]
}
path("/switches/:id") {
action: [
GET: "getSwitchStatus"
]
}
}
//API Methods
def getAllDevices() {
def locks_list = locks.collect{device(it,"Lock")}
/*def thermo_list = thermostats.collect{device(it,"Thermostat")}*/
def colors_list = colors.collect{device(it,"Color")}
def kelvin_list = kelvin.collect{device(it,"Kelvin")}
def contact_list = contact.collect{device(it,"Contact Sensor")}
def smokes_list = smoke_alarms.collect{device(it,"Smoke Alarm")}
def shades_list = shades.collect{device(it,"Window Shade")}
def garage_list = garage.collect{device(it,"Garage Door")}
def water_sensors_list = water_sensors.collect{device(it,"Water Sensor")}
def presences_list = presence_sensors.collect{device(it,"Presence")}
def motions_list = motions.collect{device(it,"Motion")}
def outlets_list = outlets.collect{device(it,"Outlet")}
def switches_list = switches.collect{device(it,"Switch")}
def switchlevels_list = switchlevels.collect{device(it,"Switch Level")}
def temp_list = temperature_sensors.collect{device(it,"Temperature")}
def meters_list = meters.collect{device(it,"Power Meters")}
def battery_list = batteries.collect{device(it,"Batteries")}
return outlets_list + kelvin_list + colors_list + switchlevels_list + smokes_list + contact_list + water_sensors_list + shades_list + garage_list + locks_list + presences_list + motions_list + switches_list + temp_list + meters_list + battery_list
}
//thermostat
/*
def setCoolTemp() {
def device = thermostats.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
if(device.hasCommand("setCoolingSetpoint")) {
device.setCoolingSetpoint(params.temp.toInteger());
return [result_action: "200"]
}
else {
httpError(510, "Not supported!")
}
}
}
def setHeatTemp() {
def device = thermostats.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
if(device.hasCommand("setHeatingSetpoint")) {
device.setHeatingSetpoint(params.temp.toInteger());
return [result_action: "200"]
}
else {
httpError(510, "Not supported!")
}
}
}
def setFanMode() {
def device = thermostats.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
if(device.hasCommand("setThermostatFanMode")) {
device.setThermostatFanMode(params.mode);
return [result_action: "200"]
}
else {
httpError(510, "Not supported!")
}
}
}
def setThermostatMode() {
def device = thermostats.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
if(device.hasCommand("setThermostatMode")) {
device.setThermostatMode(params.mode);
return [result_action: "200"]
}
else {
httpError(510, "Not supported!")
}
}
}
def getThermostatStatus() {
def device = thermostats.find{ it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [ThermostatOperatingState: device.currentValue('thermostatOperatingState'), ThermostatSetpoint: device.currentValue('thermostatSetpoint'),
ThermostatFanMode: device.currentValue('thermostatFanMode'), ThermostatMode: device.currentValue('thermostatMode')]
}
}
*/
//light
def turnOnLight() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
def turnOffLight() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
def getLightStatus() {
def device = switches.find{ it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Status: device.currentValue('switch'), Dim: getLevelStatus(params.id), Color: getColorStatus(params.id), Kelvin: getKelvinStatus(params.id)]
}
}
//color control
def setColor() {
def device = colors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def map = [hue:params.hue.toInteger(), saturation:params.sat.toInteger()]
device.setColor(map);
return [Device_id: params.id, result_action: "200"]
}
}
def getColorStatus(id) {
def device = colors.find { it.id == id }
if (!device) {
return [Color: "none"]
} else {
return [hue: device.currentValue('hue'), saturation: device.currentValue('saturation')]
}
}
//kelvin control
def setKelvin() {
def device = kelvin.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.setColorTemperature(params.kelvin.toInteger());
return [Device_id: params.id, result_action: "200"]
}
}
def getKelvinStatus(id) {
def device = kelvin.find { it.id == id }
if (!device) {
return [kelvin: "none"]
} else {
return [kelvin: device.currentValue('colorTemperature')]
}
}
//switch level
def getLevelStatus() {
def device = switchlevels.find { it.id == params.id }
if (!device) {
[Level: "No dimmer"]
} else {
return [Level: device.currentValue('level')]
}
}
def getLevelStatus(id) {
def device = switchlevels.find { it.id == id }
if (!device) {
[Level: "No dimmer"]
} else {
return [Level: device.currentValue('level')]
}
}
def setLevelStatus() {
def device = switchlevels.find { it.id == params.id }
def level = params.dim
if (!device) {
httpError(404, "Device not found")
} else {
device.setLevel(level.toInteger())
return [result_action: "200", Level: device.currentValue('level')]
}
}
//contact sensors
def getContactStatus() {
def device = contact.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def args = getTempSensorsStatus(device.id)
return [Device_state: device.currentValue('contact')] + args
}
}
//smoke detectors
def getSmokeStatus() {
def device = smoke_alarms.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('smoke')] + bat
}
}
//garage
def getGarageStatus() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('door')]
}
}
def openGarage() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.open();
return [Device_id: params.id, result_action: "200"]
}
}
def closeGarage() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.close();
return [Device_id: params.id, result_action: "200"]
}
}
//shades
def getShadeStatus() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('windowShade')]
}
}
def openShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.open();
return [Device_id: params.id, result_action: "200"]
}
}
def presetShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.presetPosition();
return [Device_id: params.id, result_action: "200"]
}
}
def closeShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.close();
return [Device_id: params.id, result_action: "200"]
}
}
//water sensor
def getWaterSensorStatus() {
def device = water_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('water')] + bat
}
}
//batteries
def getBatteryStatus() {
def device = batteries.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.latestValue("battery")]
}
}
def getBatteryStatus(id) {
def device = batteries.find { it.id == id }
if (!device) {
return []
} else {
return [battery_state: device.latestValue("battery")]
}
}
//LOCKS
def getDoorLockStatus() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('lock')] + bat
}
}
def lockDoorLock() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.lock();
return [Device_id: params.id, result_action: "200"]
}
}
def unlockDoorLock() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.unlock();
return [Device_id: params.id, result_action: "200"]
}
}
//PRESENCE
def getPresenceStatus() {
def device = presence_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('presence')] + bat
}
}
//MOTION
def getMotionStatus() {
def device = motions.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def args = getTempSensorsStatus(device.id)
return [Device_state: device.currentValue('motion')] + args
}
}
//OUTLET
def getOutletStatus() {
def device = outlets.find { it.id == params.id }
if (!device) {
device = switches.find { it.id == params.id }
if(!device) {
httpError(404, "Device not found")
}
}
def watt = getMeterStatus(device.id)
return [Device_state: device.currentValue('switch')] + watt
}
def getMeterStatus() {
def device = meters.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_id: device.id, Device_type: device.type, Current_watt: device.currentValue("power")]
}
}
def getMeterStatus(id) {
def device = meters.find { it.id == id }
if (!device) {
return []
} else {
return [Current_watt: device.currentValue("power")]
}
}
def turnOnOutlet() {
def device = outlets.find { it.id == params.id }
if (!device) {
device = switches.find { it.id == params.id }
if(!device) {
httpError(404, "Device not found")
}
}
device.on();
return [Device_id: params.id, result_action: "200"]
}
def turnOffOutlet() {
def device = outlets.find { it.id == params.id }
if (!device) {
device = switches.find { it.id == params.id }
if(!device) {
httpError(404, "Device not found")
}
}
device.off();
return [Device_id: params.id, result_action: "200"]
}
//SWITCH
def getSwitchStatus() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('switch'), Dim: getLevelStatus(params.id)]
}
}
def turnOnSwitch() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
def turnOffSwitch() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
//TEMPERATURE
def getTempSensorsStatus() {
def device = temperature_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
def scale = [Scale: location.temperatureScale]
return [Device_state: device.currentValue('temperature')] + scale + bat
}
}
def getTempSensorsStatus(id) {
def device = temperature_sensors.find { it.id == id }
if (!device) {
return []
} else {
def bat = getBatteryStatus(device.id)
return [temperature: device.currentValue('temperature')] + bat
}
}

View File

@@ -39,7 +39,7 @@ definition(
* garageDoors | door | open, close | unknown, closed, open, closing, opening * garageDoors | door | open, close | unknown, closed, open, closing, opening
* cameras | image | take | <String> * cameras | image | take | <String>
* thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint, * thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint,
* | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode, * | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode,
* | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState * | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState
* | | emergencyHeat, | * | | emergencyHeat, |
* | | setThermostatMode, | * | | setThermostatMode, |
@@ -55,7 +55,7 @@ preferences {
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false
@@ -66,54 +66,48 @@ preferences {
def getInputs() { def getInputs() {
def inputList = [] def inputList = []
inputList += contactSensors ?: [] inputList += contactSensors?: []
inputList += garageDoors ?: [] inputList += garageDoors?: []
inputList += locks ?: [] inputList += locks?: []
inputList += cameras ?: [] inputList += cameras?: []
inputList += motionSensors ?: [] inputList += motionSensors?: []
inputList += presenceSensors ?: [] inputList += presenceSensors?: []
inputList += switches ?: [] inputList += switches?: []
inputList += thermostats ?: [] inputList += thermostats?: []
inputList += waterSensors ?: [] inputList += waterSensors?: []
return inputList return inputList
} }
//API external Endpoints //API external Endpoints
mappings { mappings {
path("/subscriptionURL/:url") { path("/subscriptionURL/:url") {
action: action: [
[
PUT: "updateEndpointURL" PUT: "updateEndpointURL"
] ]
} }
path("/connectionId/:connId") { path("/connectionId/:connId") {
action: action: [
[
PUT: "updateConnectionId" PUT: "updateConnectionId"
] ]
} }
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("/subscription/:id") { path("/subscription/:id") {
action: action: [
[ POST: "registerDeviceChange",
POST : "registerDeviceChange",
DELETE: "unregisterDeviceChange" DELETE: "unregisterDeviceChange"
] ]
} }
@@ -145,7 +139,7 @@ def registerSubscriptions() {
def registerChangeHandler(myList) { def registerChangeHandler(myList) {
myList.each { myDevice -> myList.each { myDevice ->
def theAtts = myDevice.supportedAttributes def theAtts = myDevice.supportedAttributes
theAtts.each { att -> theAtts.each {att ->
subscribe(myDevice, att.name, eventHandler) subscribe(myDevice, att.name, eventHandler)
log.info "Registering ${myDevice.displayName}.${att.name}" log.info "Registering ${myDevice.displayName}.${att.name}"
} }
@@ -157,7 +151,7 @@ def registerDeviceChange() {
def myDevice = findDevice(params.id) def myDevice = findDevice(params.id)
def theAtts = myDevice.supportedAttributes def theAtts = myDevice.supportedAttributes
try { try {
theAtts.each { att -> theAtts.each {att ->
subscribe(myDevice, att.name, eventHandler) subscribe(myDevice, att.name, eventHandler)
log.info "Registering ${myDevice.displayName}.${att.name}" log.info "Registering ${myDevice.displayName}.${att.name}"
} }
@@ -186,16 +180,20 @@ def eventHandler(evt) {
def evt_name = evt.name def evt_name = evt.name
def evt_device = evt.device def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device); def evt_deviceType = getDeviceType(evt_device);
def deviceInfo
if(evt_deviceType == "thermostat")
{
deviceInfo = [name: evt_device.displayName, id: evt_device.id, status:evt_device.getStatus(), deviceType:evt_deviceType, manufacturer:evt_device.getManufacturerName(), model:evt_device.getModelName(), attributes: deviceAttributeList(evt_device), locationMode: getLocationModeInfo()]
}
else
{
deviceInfo = [name: evt_device.displayName, id: evt_device.id, status:evt_device.getStatus(), deviceType:evt_deviceType, manufacturer:evt_device.getManufacturerName(), model:evt_device.getModelName(), attributes: deviceAttributeList(evt_device)]
}
def params = [ def params = [
uri : "${state.endpointURL}/${state.connectionId}", uri: "${state.endpointURL}/${state.connectionId}",
body: [ body: [ deviceInfo ]
name : evt_device.displayName,
id : evt_device.id,
deviceType : evt_deviceType,
manufacturer: evt_device.getManufacturerName(),
model : evt_device.getModelName(),
attributes : deviceAttributeList(evt_device)
]
] ]
try { try {
log.trace "POST URI: ${params.uri}" log.trace "POST URI: ${params.uri}"
@@ -230,10 +228,13 @@ def getDevices() {
def deviceData = [] def deviceData = []
inputs?.each { inputs?.each {
def deviceType = getDeviceType(it) def deviceType = getDeviceType(it)
if (deviceType == "thermostat") { if(deviceType == "thermostat")
deviceData << [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()] {
} else { deviceData << [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
deviceData << [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it)] }
else
{
deviceData << [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it)]
} }
} }
@@ -246,10 +247,13 @@ def getDevice() {
def it = findDevice(params.id) def it = findDevice(params.id)
def deviceType = getDeviceType(it) def deviceType = getDeviceType(it)
def device def device
if (deviceType == "thermostat") { if(deviceType == "thermostat")
device = [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()] {
} else { device = [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
device = [name: it.displayName, id: it.id, deviceType: deviceType, manufacturer: it.getManufacturerName(), model: it.getModelName(), attributes: deviceAttributeList(it)] }
else
{
device = [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it)]
} }
log.debug "getDevice, return: ${device}" log.debug "getDevice, return: ${device}"
return device return device
@@ -261,18 +265,18 @@ void updateDevice() {
request.JSON.each { request.JSON.each {
def command = it.key def command = it.key
def value = it.value def value = it.value
if (command) { if (command){
def commandList = mapDeviceCommands(command, value) def commandList = mapDeviceCommands(command, value)
command = commandList[0] command = commandList[0]
value = commandList[1] value = commandList[1]
if (command == "setAwayMode") { if (command == "setAwayMode") {
log.info "Setting away mode to ${value}" log.info "Setting away mode to ${value}"
if (location.modes?.find { it.name == value }) { if (location.modes?.find {it.name == value}) {
location.setMode(value) location.setMode(value)
} }
} else if (command == "thermostatSetpoint") { }else if (command == "thermostatSetpoint"){
switch (device.currentThermostatMode) { switch(device.currentThermostatMode){
case "cool": case "cool":
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device.setCoolingSetpoint(value) device.setCoolingSetpoint(value)
@@ -286,7 +290,7 @@ void updateDevice() {
httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.") httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.")
break break
} }
} else if (!device) { }else if (!device) {
log.error "updateDevice, Device not found" log.error "updateDevice, Device not found"
httpError(404, "Device not found") httpError(404, "Device not found")
} else if (!device.hasCommand(command)) { } else if (!device.hasCommand(command)) {
@@ -296,11 +300,11 @@ void updateDevice() {
if (command == "setColor") { if (command == "setColor") {
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(hex: value) device."$command"(hex: value)
} else if (value.isNumber()) { } else if(value.isNumber()) {
def intValue = value as Integer def intValue = value as Integer
log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]" log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]"
device."$command"(intValue) device."$command"(intValue)
} else if (value) { } else if (value){
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(value) device."$command"(value)
} else { } else {
@@ -322,19 +326,28 @@ private getLocationModeInfo() {
//Map each device to a type given it's capabilities //Map each device to a type given it's capabilities
private getDeviceType(device) { private getDeviceType(device) {
def deviceType def deviceType
def caps = device.capabilities def capabilities = device.capabilities
log.debug "capabilities: [${device}, ${caps}]" log.debug "capabilities: [${device}, ${capabilities}]"
log.debug "supported commands: [${device}, ${device.supportedCommands}]" log.debug "supported commands: [${device}, ${device.supportedCommands}]"
caps.each {
switch (it.name.toLowerCase()) { //Loop through the device capability list to determine the device type.
capabilities.each {capability ->
switch(capability.name.toLowerCase())
{
case "switch": case "switch":
deviceType = "switch" deviceType = "switch"
if (caps.any { it.name.toLowerCase() == "power meter" }) {
return deviceType //If the device also contains "Switch Level" capability, identify it as a "light" device.
} if (capabilities.any{it.name.toLowerCase() == "switch level"}){
if (caps.any { it.name.toLowerCase() == "switch level" }) {
deviceType = "light" //If the device also contains "Power Meter" capability, identify it as a "dimmerSwitch" device.
return deviceType if (capabilities.any{it.name.toLowerCase() == "power meter"}){
deviceType = "dimmerSwitch"
return deviceType
} else {
deviceType = "light"
return deviceType
}
} }
break break
case "contact sensor": case "contact sensor":
@@ -375,16 +388,16 @@ private findDevice(deviceId) {
//Return a list of device attributes //Return a list of device attributes
private deviceAttributeList(device) { private deviceAttributeList(device) {
device.supportedAttributes.collectEntries { attribute -> device.supportedAttributes.collectEntries { attribute->
try { try {
[(attribute.name): device.currentValue(attribute.name)] [ (attribute.name): device.currentValue(attribute.name) ]
} catch (e) { } catch(e) {
[(attribute.name): null] [ (attribute.name): null ]
} }
} }
} }
//Map device command and value. //Map device command and value.
//input command and value are from UWP, //input command and value are from UWP,
//returns resultCommand and resultValue that corresponds with function and value in SmartApps //returns resultCommand and resultValue that corresponds with function and value in SmartApps
private mapDeviceCommands(command, value) { private mapDeviceCommands(command, value) {
@@ -414,7 +427,7 @@ private mapDeviceCommands(command, value) {
resultCommand = "setSaturation" resultCommand = "setSaturation"
resultValue = value resultValue = value
break break
case "ct": case "colorTemperature":
resultCommand = "setColorTemperature" resultCommand = "setColorTemperature"
resultValue = value resultValue = value
break break
@@ -451,7 +464,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 = ""
} }
@@ -460,6 +474,5 @@ private mapDeviceCommands(command, value) {
break break
} }
return [resultCommand, resultValue] return [resultCommand,resultValue]
} }

View File

@@ -30,7 +30,7 @@ preferences {
input "havdalahOffset", "number", title: "Minutes After Sundown", required:true input "havdalahOffset", "number", title: "Minutes After Sundown", required:true
} }
section("Your ZipCode") { section("Your ZipCode") {
input "zipcode", "number", title: "ZipCode", required:true input "zipcode", "text", title: "ZipCode", required:true
} }
section( "Notifications" ) { section( "Notifications" ) {
input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false
@@ -205,4 +205,4 @@ if ( sendPushMessage != "No" ) {
log.debug( "sending text message" ) log.debug( "sending text message" )
sendSms( phone, msg ) sendSms( phone, msg )
} }
}//END def sendMessage(msg) }//END def sendMessage(msg)