Compare commits

...

14 Commits

Author SHA1 Message Date
Michael Murray
9a92e3f728 null: control smartthings from smartwatch. 2019-01-30 22:34:47 -08:00
Vinay Rao
3d67448aa5 Merge pull request #3922 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2019-01-29 11:40:41 -08:00
ady624
224747408b Merge pull request #3907 from ady624/keen_temperature_fix
Fix an issue with the scale being presented in the temperature custom…
2019-01-29 13:50:13 -05:00
DCzarneckaS
4bc177f638 [WWST-2275] Fingeprint for Sengled Element Classic A19 100W (5000k) - E11-N14 2019-01-29 15:56:09 +01:00
DCzarneckaS
97970cd0f0 [WWST-2241] Add readAttribute in refresh() for correct device status after pairing (#3905)
* [WWST-2241] Add readAttribute in refresh()

* [WWST-2241] Add readAttribute in refresh() and zigbee.enrollResponse() to configure
2019-01-28 15:24:57 -08:00
Konrad K
4e1a2c4004 WWST-1636 New DTH for Dome Mouser - DMMZ1 (#3880)
* new DTH for Dome Mouser
2019-01-28 14:46:40 -08:00
Mariusz A
94320f74cb ICP-7910 Innr RB 245 name fix (#3898)
Device Join name Typo fix only.
2019-01-28 10:30:50 +01:00
MGoralczykS
3745a305c2 [WWST-1625] Add fingerprint for Sengled Element Classic. (#3908) 2019-01-28 10:14:16 +01:00
Adrian Caramaliu
0b73e5c4de Fix an issue with the scale being presented in the temperature custom message 2019-01-24 14:46:48 -05:00
DCzarneckaS
85352ad7f4 [WWST-2244] Change device name for compatibility with rest Iris devices (#3906)
DeviceJoinName correction only.
2019-01-24 16:13:02 +01:00
Tom Manley
e6d4e3e529 Merge pull request #3887 from FenMei007S/WWST-2225
WWST-2225 [China] Ezex Temp/Humidity Sensor
2019-01-24 06:45:26 -06:00
MGoralczykS
1e2f1feff8 [WWST-2246] New DTH for Iris Plug. Add fingerprint for Iris Smart Plug. (#3904)
* Add fingerprint for Iris Smart Plug.
2019-01-24 13:26:09 +01:00
Fen Mei
2419b977fd WWST-2225:Add DTH for ezex temparture and humidity sensor 2019-01-24 14:26:35 +08:00
rboy1
ab754469be Fix return value to avoid an exception (#3902)
Return  null from poll() and refresh() otherwise when a SA calls the refresh method it results in an error:
`error groovy.lang.MissingMethodException: No signature of method: physicalgraph.device.HubMultiAction.add() is applicable for argument types: (groovy.json.internal.LazyMap)`
2019-01-23 19:22:50 -05:00
8 changed files with 597 additions and 20 deletions

View File

@@ -171,12 +171,10 @@ private Map parseReportAttributeMessage(String description) {
private Map parseCustomMessage(String description) {
Map resultMap = [:]
if (description?.startsWith('temperature: ')) {
// log.debug "${description}"
// def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
// log.debug "split: " + description.split(": ")
def value = Double.parseDouble(description.split(": ")[1])
// log.debug "${value}"
resultMap = makeTemperatureResult(convertTemperature(value))
def tempData = description.split(": ")[1].split(" ")
def scale = (tempData.length > 1) ? tempData[1] : "C"
def value = Double.parseDouble(tempData[0])
resultMap = makeTemperatureResult(convertTemperature(value, scale))
}
return resultMap
}
@@ -282,18 +280,19 @@ private def convertTemperatureHex(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
// log.debug "celsius: ${celsius}"
return convertTemperature(celsius)
return convertTemperature(celsius, "C")
}
private def convertTemperature(celsius) {
// log.debug "convertTemperature()"
if(getTemperatureScale() == "C"){
return celsius
private def convertTemperature(value, scale = "C") {
if(getTemperatureScale() == scale){
return Math.round(value * 100) / 100
} else {
def fahrenheit = Math.round(celsiusToFahrenheit(celsius) * 100) /100
// log.debug "converted to F: ${fahrenheit}"
return fahrenheit
if (scale == "C") {
// Celsius to Fahrenheit
return Math.round(celsiusToFahrenheit(value) * 100) /100
}
// Fahrenheit to Celsius
return Math.round(fahrenheitToCelsius(value) * 100) /100
}
}

View File

@@ -0,0 +1,117 @@
/**
* eZEX Temp & Humidity Sensor (AC Type)
*
* Copyright 2019 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 physicalgraph.zigbee.zcl.DataType
metadata {
definition(name: "eZEX Temp & Humidity Sensor", namespace: "smartthings", author: "SmartThings", mnmn:"SmartThings", vid:"generic-humidity") {
capability "Configuration"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Sensor"
fingerprint profileId: "0104", inClusters: "0000,0003,0402,0405,0500", outClusters: "0019", model: "E282-KR0B0Z1-HA", deviceJoinName: "eZEX Temperature & Humidity Sensor (AC Type)"
}
preferences {
input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
input title: "Humidity Offset", description: "This feature allows you to correct any humidity variations by selecting an offset. Ex: If your sensor consistently reports a humidity that's 6% higher then a similiar calibrated sensor, you'd enter \"-6\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "humidityOffset", "number", title: "Humidity Offset in Percent", description: "Adjust humidity by this percentage", range: "*..*", displayDuringSetup: false
}
tiles(scale: 2) {
multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) {
tileAttribute("device.temperature", key: "PRIMARY_CONTROL") {
attributeState "temperature", label: '${currentValue}°',
backgroundColors: [
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
}
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
state "humidity", label: '${currentValue}% humidity', unit: ""
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
}
main "temperature", "humidity"
details(["temperature", "humidity", "refresh"])
}
}
def parse(String description) {
log.debug "description: $description"
// getEvent will handle temperature and humidity
Map map = zigbee.getEvent(description)
if (!map) {
Map descMap = zigbee.parseDescriptionAsMap(description)
if (descMap?.clusterInt == zigbee.TEMPERATURE_MEASUREMENT_CLUSTER && descMap.commandInt == 0x07) {
if (descMap.data[0] == "00") {
log.debug "TEMP REPORTING CONFIG RESPONSE: $descMap"
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
} else {
log.warn "TEMP REPORTING CONFIG FAILED- error code: ${descMap.data[0]}"
}
}
} else if (map.name == "temperature") {
if (tempOffset) {
map.value = (int) map.value + (int) tempOffset
}
map.descriptionText = temperatureScale == 'C' ? '{{ device.displayName }} was {{ value }}°C' : '{{ device.displayName }} was {{ value }}°F'
map.translatable = true
} else if (map.name == "humidity") {
if (humidityOffset) {
map.value = (int) map.value + (int) humidityOffset
}
}
log.debug "Parse returned $map"
return map ? createEvent(map) : [:]
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def refresh() {
log.debug "refresh temperature, humidity"
return zigbee.readAttribute(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000) +
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000)
}
def configure() {
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
log.debug "Configuring Reporting and Bindings."
// temperature minReportTime 30 seconds, maxReportTime 1 hour. Reporting interval if no activity
return refresh() +
zigbee.configureReporting(zigbee.RELATIVE_HUMIDITY_CLUSTER, 0x0000, DataType.UINT16, 30, 3600, 100) +
zigbee.configureReporting(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000, DataType.UINT16, 30, 3600, 100)
}

View File

@@ -171,9 +171,9 @@ def ping() {
def refresh() {
log.debug "Refreshing Temperature and Battery"
def refreshCmds = zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.readAttribute(zigbee.IAS_ZONE_CLUSTER, zigbee.ATTRIBUTE_IAS_ZONE_STATUS) + zigbee.enrollResponse()
return refreshCmds + zigbee.enrollResponse()
return refreshCmds
}
def configure() {
@@ -182,7 +182,7 @@ def configure() {
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID, offlinePingable: "1"])
log.debug "Configuring Reporting, IAS CIE, and Bindings."
def cmds = refresh() + zigbee.iasZoneConfig(30, 60 * 5) + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 60 * 30)
def cmds = refresh() + zigbee.iasZoneConfig(30, 60 * 5) + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 60 * 30) + zigbee.enrollResponse()
if(getDataValue("manufacturer") == "Ecolink") {
cmds += configureEcolink()
}

View File

@@ -292,6 +292,8 @@ def poll() {
else {
log.warn "No response from TWC API"
}
return null
}
def parseAlertTime(s) {

View File

@@ -56,9 +56,10 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Aurora", model: "FWGU10Bulb50AU", deviceJoinName: "Aurora Smart Dimmable GU10"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05, 1000, FEDC", outClusters: "000A, 0019", manufacturer: "Smarthome", model: "S111-201A", deviceJoinName: "Leedarson Dimmable White Bulb A19"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 265", deviceJoinName: "Innr Smart Bulb White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 245", deviceJoinName: "Innr Smart Candle Warm white"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RB 245", deviceJoinName: "Innr Smart Candle Warm White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 1000", outClusters: "0019", manufacturer: "innr", model: "RS 225", deviceJoinName: "Innr Smart Spot White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N13", deviceJoinName: "Sengled Element Classic"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0702, 0B05", outClusters: "0019", manufacturer: "sengled", model: "E11-N14", deviceJoinName: "Sengled Element Classic"
}
tiles(scale: 2) {

View File

@@ -0,0 +1,28 @@
# Z-Wave Mouse Trap
Local Execution
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Sensor** - detects sensor events
* **Battery** - defines that the device has a battery
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
* **Refresh** - _refresh()_ command for status updates
* **Pest Control** - indicates ability to get mouse trap notifications
## Device Health
Z-Wave Mouse Trap is a Z-Wave sleepy device and checks in every 12 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2 * 12 * 60 * 60 + 2 * 60) sek. = 1442 mins.
* __1442min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.

View File

@@ -0,0 +1,208 @@
/**
* Copyright 2019 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition(name: "Z-Wave Mouse Trap", namespace: "smartthings", author: "SmartThings", mnmn: "SmartThings", vid: "generic-pestcontrol-1", runLocally: false, executeCommandsLocally: false) {
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Health Check"
capability "Pest Control"
//capability "pestControl", enum: idle, trapArmed, trapRearmRequired, pestDetected, pestExterminated
//zw:S type:0701 mfr:021F prod:0003 model:0104 ver:3.49 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,71,30,85,59,84,70 role:06 ff:8C13 ui:8C13
fingerprint mfr: "021F", prod: "0003", model: "0104", deviceJoinName: "Dome Mouser"
}
tiles(scale: 2) {
multiAttributeTile(name: "pestControl", type: "generic", width: 6, height: 4) {
tileAttribute("device.pestControl", key: "PRIMARY_CONTROL") {
attributeState("idle", label: 'IDLE', icon: "st.contact.contact.open", backgroundColor: "#00FF00")
attributeState("trapRearmRequired", label: 'TRAP RE-ARM REQUIRED', icon: "st.contact.contact.open", backgroundColor: "#00A0DC")
attributeState("trapArmed", label: 'TRAP ARMED', icon: "st.contact.contact.open", backgroundColor: "#FF6600")
attributeState("pestDetected", label: 'PEST DETECTED', icon: "st.contact.contact.open", backgroundColor: "#FF6600")
attributeState("pestExterminated", label: 'PEST EXTERMINATED', icon: "st.contact.contact.closed", backgroundColor: "#FF0000")
}
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label: '${currentValue}% battery', unit: ""
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label: '', action: "configuration.configure", icon: "st.secondary.configure"
}
main "pestControl"
details(["pestControl", "battery", "configure"])
}
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
}
def parse(String description) {
def result = []
log.debug "desc: $description"
def cmd = zwave.parse(description)
if (cmd) {
result = zwaveEvent(cmd)
}
log.debug "parsed '$description' to $result"
return result
}
def installed() {
log.debug "installed()"
// Device-Watch simply pings if no device events received for 24h 2min(checkInterval)
sendEvent(name: "checkInterval", value: 24 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
initialize()
}
def updated() {
log.debug "updated()"
// Device-Watch simply pings if no device events received for 24h 2min(checkInterval)
sendEvent(name: "checkInterval", value: 24 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def initialize() {
log.debug "initialize()"
def cmds = []
cmds << zwave.batteryV1.batteryGet().format()
cmds << getConfigurationCommands()
sendHubCommand(cmds)
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
// ignore, to prevent override of NotificationReport
[]
}
def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) {
// ignore, to prevent override of SensorBinaryReport
[]
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
log.debug "Event: ${cmd.event}, Notification type: ${cmd.notificationType}"
def result = []
def value
def description
if (cmd.notificationType == 0x07) {
//notificationType == 0x07 (Home Security)
switch (cmd.event) {
case 0x00:
value = "idle"
description = "Trap cleared"
break
case 0x07:
value = "pestExterminated"
description = "Pest exterminated"
break
default:
log.debug "Not handled event type: ${cmd.event}"
break
}
result = createEvent(name: "pestControl", value: value, descriptionText: description)
} else if (cmd.notificationType == 0x13) {
//notificationType == 0x13 (Pest Control)
switch (cmd.event) {
case 0x00:
value = "idle"
description = "Trap cleared"
break
case 0x02:
value = "trapArmed"
description = "Trap armed"
break
case 0x04:
value = "trapRearmRequired"
description = "Trap re-arm required"
break
case 0x06:
value = "pestDetected"
description = "Pest detected"
break
case 0x08:
value = "pestExterminated"
description = "Pest exterminated"
break
default:
log.debug "Not handled event type: ${cmd.event}"
break
}
result = createEvent(name: "pestControl", value: value, descriptionText: description)
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
log.debug "WakeUpNotification ${cmd}"
def event = createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
def cmds = []
if (device.currentValue("pestControl") == null) { // In case our initial request didn't make it
cmds << getConfigurationCommands()
}
if (!state.lastbat || now() - state.lastbat > (12 * 60 * 60 + 6 * 60) * 1000 /*milliseconds*/) {
cmds << zwave.batteryV1.batteryGet().format()
} else {
// If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
}
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [name: "battery", unit: "%"]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
log.debug "Battery report: $cmd"
map.value = cmd.batteryLevel
}
state.lastbat = now()
[createEvent(map), response(zwave.wakeUpV1.wakeUpNoMoreInformation())]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: "$device.displayName: $cmd", displayed: true)
}
def configure() {
log.debug "config"
response(getConfigurationCommands())
}
def getConfigurationCommands() {
log.debug "getConfigurationCommands"
def cmds = []
cmds << zwave.notificationV3.notificationGet(notificationType: 0x13).format()
// The wake-up interval is set in seconds, and is 43,200 seconds (12 hours) by default.
cmds << zwave.wakeUpV2.wakeUpIntervalSet(seconds: 12 * 3600, nodeid: zwaveHubNodeId).format()
// BASIC_SET Level, default: 255
cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [255]).format()
// Set Firing Mode, default: 2 (Burst fire)
cmds << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, configurationValue: [2]).format()
// This parameter defines how long the Mouser will fire continuously before it starts to burst-fire, default: 360 seconds
cmds << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, configurationValue: [360]).format()
// Enable/Disable LED Alarm, default: 1 (enabled)
cmds << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, configurationValue: [1]).format()
// LED Alarm Duration, default: 0 hours
cmds << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, configurationValue: [0]).format()
cmds
}

View File

@@ -0,0 +1,222 @@
/*
* Shanes Webservice Test
* Copyright 2017 Shane
*/
//Apollo Spock, we have lift off... wait what?
definition(
name: "Gear Watch",
namespace: "shaneshuford",
author: "Shane",
description: "Gear Watch",
category: "",
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(oauthPage: "pageOne") {
page(name: "pageOne", title: "Gear Devices:", nextPage: "selectActions", install: false, uninstall: true) {
section("Choose devices to control with watch") {
input "switches", "capability.switch", title: "Which Switches?", required: false, multiple: true
input "locks", "capability.lock", title: "Which Locks?", required: false, multiple: true
//input "lights", "capability.light", title: "Which Lights?", required: false, multiple: true
//input "levels", "capability.switchLevel", title: "Which level switches?", required: false, multiple: true
//input "motion", "capability.motionSensor", title: "Which Motion Sensors?", required: false, multiple: true
}
}
page(name: "selectActions")
}
def selectActions() {
dynamicPage(name: "selectActions", title: "Gear Actions/Routines", install: true, uninstall: true) {
// get the available actions
def actions = location.helloHome?.getPhrases()*.label
if (actions) {
// sort them alphabetically
actions.sort()
section("Choose routines to execute with watch:") {
log.trace actions
input "action", "enum", title: "Select an routines to execute", options: actions, required: false, multiple: true
}
}
}
}
def installed() {}
def updated() {}
mappings {
//Switches
path("/switches") {
action: [
GET: "listSwitches"
]
}
path("/switches/:id") {
action: [
GET: "showSwitch"
]
}
path("/switches/:id/:command") {
action: [
GET: "updateSwitch"
]
}
path("/switches/:id/:command/:value") {
action: [
GET: "setSwitchLevel"
]
}
//Locks
path("/locks") {
action: [
GET: "listLocks"
]
}
path("/locks/:id") {
action: [
GET: "showLock"
]
}
path("/locks/:id/:command") {
action: [
GET: "updateLock"
]
}
//Routines
path("/routines/:name") {
action: [
GET: "executeRoutine"
]
}
path("/routines") {
action: [
GET: "listRoutines"
]
}
path("/version") {
action: [
GET: "smartAppVersion"
]
}
}
//version
def smartAppVersion(){
[version: "1.0.1"]
}
//switches
def listSwitches() {
switches.collect{device(it,"switch")}
}
def showSwitch() {
show(switches, "switch")
}
def updateSwitch() {
update(switches)
}
def setSwitchLevel(){
setlevel(switches)
}
//Locks
def listLocks() {
locks.collect{device(it,"lock")}
}
def showLock() {
show(locks, "lock")
}
def updateLock() {
update(locks)
}
//Routines
def listRoutines() {
def actions = location.helloHome?.getPhrases()*.label
return actions
}
def executeRoutine(){
def name = params.name
location.helloHome?.execute(name)
def resp = []
resp << [ok: "executed"]
return resp
}
//in the future...
def deviceHandler(evt) {}
private void setlevel(devices){
def command = params.command
if(command)
{
def device = devices.find { it.id == params.id }
if(!device) {
httpError(404, "Device not found")
} else {
if(command == "level")
{
device.setLevel(params.value as int)
}
}
}
}
private update(devices) {
def command = params.command
if (command){
def device = devices.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
if(command == "toggle"){
if(device.currentValue('switch') == "on"){
device.off();
[status: "off"]}
else{
device.on();
[status: "on"]}
}else{
device."$command"()
if(command == "on" || command == "off")
{
[status: command]
}
else if(command == "lock" || command == "unlock")
{
[status: command + "ed"]
}
}
}
}
}
private show(devices, type) {
def device = devices.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def attributeName = type == "motionSensor" ? "motion" : type
def s = device.currentState(attributeName)
[id: device.id, label: device.displayName, level: it.currentValue("level"), value: s?.value, unitTime: s?.date?.time, type: type]
}
}
private device(it, type) {
def attributeName = type == "motionSensor" ? "motion" : type
def s = it.currentState(attributeName)
it ? [id: it.id, label: it.label, level: it.currentValue("level"), value: s?.value, type: type] : null
}