Compare commits

...

25 Commits

Author SHA1 Message Date
home.ai
2640a9ac87 MSA-1900: Please push this as soon as possible to all environments and all 3 apps. 2017-04-18 15:48:47 -07:00
Vinay Rao
5b39a9f840 Merge pull request #1916 from SmartThingsCommunity/staging
Rolling down staging to master
2017-04-18 13:42:58 -07:00
Vinay Rao
7f61feaebc Merge pull request #1909 from larsfinander/DVCSMP-2572_OpenT2T_Update_4_14_submission_staging
DVCSMP-2572 OpenT2T: Update to 4/14 submission
2017-04-18 11:23:07 -07:00
Lars Finander
7a467df659 DVCSMP-2572 OpenT2T: Update to 4/14 submission 2017-04-18 12:01:56 -06:00
Vinay Rao
538eb057ce Merge pull request #1913 from SmartThingsCommunity/production
Rolling down production to staging
2017-04-17 12:59:57 -07:00
Vinay Rao
2ff9486790 Merge pull request #1912 from varzac/sengled-level-fix
[ICP-691] Set level on sengled bulbs configure
2017-04-17 12:59:20 -07:00
Zach Varberg
5429986e81 Set level on sengled bulbs configure
This works around the sengled bulbs not following the ZCL spec and using
the value 0xFF as a valid level (the spec says it should be invalid).
It does this by manually setting the level of the bulb to
0xFE (SmartThings 100%) when it is configured, or if it previously had a
level set, manually setting it to that value.  This avoids the issue of
the bulb reporting 0xFF and having the library ignore it because it is
an invalid value.

This resolves: https://smartthings.atlassian.net/browse/ICP-691
2017-04-17 12:36:13 -05:00
Vinay Rao
6514087a1a Merge pull request #1905 from workingmonk/log/hue_logs
CELL-139 Hue logging to detect hue pairing
2017-04-13 16:31:45 -07:00
Vinay Rao
0f2b8c18d2 CELL-139 Hue logging to detect hue pairing 2017-04-13 16:06:49 -07:00
Vinay Rao
ce0363fa43 Merge pull request #1889 from SmartThingsCommunity/MSA-1883-3
MSA-1883: EZMultipli 3:1 MultiSensor wall powered
2017-04-13 15:56:30 -07:00
Vinay Rao
fd620977bb Merge pull request #1902 from workingmonk/bug/arrival_battery
DVCSMP-2568 Arrival-sensor-ha Read battery level on join
2017-04-12 12:20:41 -07:00
Tom Manley
a308bff574 arrival-sensor-ha: Read battery level on join
In configure we were setting up the battery level to be reported every
20 seconds but we weren't reading the attribute so it would take 20
seconds before the battery level was reported. Now we read it during
configure so it is updated right away after join.

https://smartthings.atlassian.net/browse/DVCSMP-2568
2017-04-12 12:19:36 -07:00
Vinay Rao
068cfaeaad Merge pull request #1901 from workingmonk/bug/zwave_enerwave
[ICP-598] Adding Enerwave Door/Window Sensor
2017-04-11 21:53:14 -07:00
jackchi
fb55349db0 [ICP-598] Adding Enerwave Door/Window Sensor 2017-04-11 21:49:51 -07:00
Vinay Rao
476d3caa38 Merge pull request #1900 from tpmanley/feature/arrival-sensor-reporting
DVCSMP-2568 arrival-sensor-ha: Read battery level on join
2017-04-11 21:39:19 -07:00
Tom Manley
9b621c9a7b arrival-sensor-ha: Read battery level on join
In configure we were setting up the battery level to be reported every
20 seconds but we weren't reading the attribute so it would take 20
seconds before the battery level was reported. Now we read it during
configure so it is updated right away after join.

https://smartthings.atlassian.net/browse/DVCSMP-2568
2017-04-11 23:35:49 -05:00
Vinay Rao
619b3499c8 Merge pull request #1899 from workingmonk/bug/zwave_fingerprint
[ICP-598] Adding Z-Wave device manufacturer
2017-04-11 20:14:11 -07:00
jackchi
3ec8be708a [ICP-598] Adding Z-Wave device manufacturer 2017-04-11 17:39:17 -07:00
Vinay Rao
34b2210134 Merge pull request #1898 from jackchi/zwave-manufacturer-update
[ICP-598] Adding Enerwave Door/Window Sensor
2017-04-11 17:06:13 -07:00
jackchi
8abb82ecae [ICP-598] Adding Enerwave Door/Window Sensor 2017-04-11 17:00:48 -07:00
Vinay Rao
55da70cd7c Merge pull request #1897 from jackchi/zwave-manufacturer-update
[ICP-598] Adding Z-Wave device manufacturer
2017-04-11 16:46:00 -07:00
jackchi
80a5a41f7e [ICP-598] Adding Z-Wave device manufacturer 2017-04-11 16:21:28 -07:00
Vinay Rao
b4276c05e0 Merge pull request #1896 from SmartThingsCommunity/master
Rolling up master to staging
2017-04-11 14:07:20 -07:00
Vinay Rao
264e822c9f Merge pull request #1894 from SmartThingsCommunity/staging
Rolling up staging to production
2017-04-11 13:40:00 -07:00
Eric Ryherd
c65c9cc185 MSA-1883: Features:
Motion Sensor
-  Passive Infrared Sensor (PIR)
-  12’ range - 90 coverage
-  Programmable timeout
-  Control four associated devices
Temperature Sensor
-  -10 - 80C range
-  0.1C resolution
Light Level Sensor
-  Relative light level 0-100%
Color Indicator Night Light
-  Eight colors
Wall Powered
-  110VAC 60Hz
-  No wires - just plug it in
-  Never needs batteries
Wireless Z-Wave ® RF Technology
-  Fifth generation chipset
-  Z-Wave range extender
-  100,000 bits/sec data rate
-  300’ RF range
-  Over-the-air firmware update
-  Push button to join network
-  Z-Wave Plus certified
Designed and assembled in USA
2017-04-11 05:25:16 -07:00
11 changed files with 2917 additions and 111 deletions

View File

@@ -0,0 +1,426 @@
// Express Controls EZMultiPli Multi-sensor
// Motion Sensor - Temperature - Light level - 8 Color Indicator LED - Z-Wave Range Extender - Wall Powered
// driver for SmartThings
// The EZMultiPli is also known as the HSM200 from HomeSeer.com
//
// 2017-04-10 - DrZwave (with help from Don Kirker) - changed fingerprint to the new format, lowered the OnTime
// and other parameters to be "more in line with ST user expectations", get the luminance in LUX so it reports in lux all the time.
// 2016-10-06 - erocm1231 - Added "updated" method to run when configuration options are changed. Depending on model of unit, luminance is being
// reported as a relative percentace or as a lux value. Added the option to configure this in the handler.
// 2016-01-28 - erocm1231 - Changed the configuration method to use scaledConfiguration so that it properly formatted negative numbers.
// Also, added configurationGet and a configurationReport method so that config values can be verified.
// 2015-12-04 - erocm1231 - added range value to preferences as suggested by @Dela-Rick.
// 2015-11-26 - erocm1231 - Fixed null condition error when adding as a new device.
// 2015-11-24 - erocm1231 - Added refresh command. Made a few changes to how the handler maps colors to the LEDs. Fixed
// the device not having its on/off status updated when colors are changed.
// 2015-11-23 - erocm1231 - Changed the look to match SmartThings v2 devices.
// 2015-11-21 - erocm1231 - Made code much more efficient. Also made it compatible when setColor is passed a hex value.
// Mapping of special colors: Soft White - Default - Yellow, White - Concentrate - White,
// Daylight - Energize - Teal, Warm White - Relax - Yellow
// 2015-11-19 - erocm1231 - Fixed a couple incorrect colors, changed setColor to be more compatible with other apps
// 2015-11-18 - erocm1231 - Added to setColor for compatibility with Smart Lighting
// v0.1.0 - DrZWave - chose better icons, Got color LED to work - first fully functional version
// v0.0.9 - jrs - got the temp and luminance to work. Motion works. Debugging the color wheel.
// v0.0.8 - DrZWave 2/25/2015 - change the color control to be tiles since there are only 8 colors.
// v0.0.7 - jrs - 02/23/2015 - Jim Sulin
metadata {
definition (name: "EZmultiPli", namespace: "DrZWave", author: "Eric Ryherd", oauth: true) {
capability "Actuator"
capability "Sensor"
capability "Motion Sensor"
capability "Temperature Measurement"
capability "Illuminance Measurement"
capability "Switch"
capability "Color Control"
capability "Configuration"
capability "Refresh"
fingerprint mfr: "001E", prod: "0004", model: "0001" // new format for Fingerprint which is unique for every certified Z-Wave product
} // end definition
simulator {
// messages the device returns in response to commands it receives
status "motion" : "command: 7105000000FF07, payload: 07"
status "no motion" : "command: 7105000000FF07, payload: 00"
for (int i = 0; i <= 100; i += 20) {
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
}
for (int i = 0; i <= 100; i += 20) {
status "luminance ${i} %": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 3).incomingMessage()
}
} //end simulator
tiles (scale: 2){
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#79b821"
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setColor"
}
tileAttribute ("statusText", key: "SECONDARY_CONTROL") {
attributeState "statusText", label:'${currentValue}'
}
}
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
backgroundColors:[
[value: 0, color: "#1010ff"], // blue=cold
[value: 65, color: "#a0a0f0"],
[value: 70, color: "#e0e050"],
[value: 75, color: "#f0d030"], // yellow
[value: 80, color: "#fbf020"],
[value: 85, color: "#fbdc01"],
[value: 90, color: "#fb3a01"],
[value: 95, color: "#fb0801"] // red=hot
]
}
// icons to use would be st.Weather.weather2 or st.alarm.temperature.normal - see http://scripts.3dgo.net/smartthings/icons/ for a list of icons
valueTile("illuminance", "device.illuminance", width: 2, height: 2, inactiveLabel: false) {
// jrs 4/7/2015 - Null on display
//state "luminosity", label:'${currentValue} ${unit}'
state "luminosity", label:'${currentValue}', unit:'${currentValue}', icon:"",
backgroundColors:[
[value: 25, color: "#404040"],
[value: 50, color: "#808080"],
[value: 75, color: "#a0a0a0"],
[value: 90, color: "#e0e0e0"],
//lux measurement values
[value: 150, color: "#404040"],
[value: 300, color: "#808080"],
[value: 600, color: "#a0a0a0"],
[value: 900, color: "#e0e0e0"]
]
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.configure", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main (["temperature","motion", "switch"])
details(["switch", "motion", "temperature", "illuminance", "refresh", "configure"])
} // end tiles
preferences {
input "OnTime", "number", title: "No Motion Interval", description: "N minutes lights stay on after no motion detected [0, 1-127]", range: "0..127", defaultValue: 2, displayDuringSetup: true, required: false
input "OnLevel", "number", title: "Dimmer Onlevel", description: "Dimmer OnLevel for associated node 2 lights [-1, 0, 1-99]", range: "-1..99", defaultValue: -1, displayDuringSetup: true, required: false
input "LiteMin", "number", title: "Luminance Report Frequency", description: "Luminance report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
input "TempMin", "number", title: "Temperature Report Frequency", description: "Temperature report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
input "TempAdj", "number", title: "Temperature Calibration", description: "Adjust temperature up/down N tenths of a degree F [(-127)-(+128)]", range: "-127..128", defaultValue: 0, displayDuringSetup: true, required: false
input("lum", "enum", title:"Illuminance Measurement", description: "Percent or Lux", defaultValue: 2 ,required: false, displayDuringSetup: true, options:
[1:"Percent",
2:"Lux"])
}
} // end metadata
// Parse incoming device messages from device to generate events
def parse(String description){
//log.debug "==> New Zwave Event: ${description}"
def result = []
def cmd = zwave.parse(description, [0x31: 5]) // 0x31=SensorMultilevel which we force to be version 5
if (cmd) {
def cmdData = zwaveEvent(cmd)
if (cmdData != [:])
result << createEvent(cmdData)
}
def statusTextmsg = ""
if (device.currentState('temperature') != null && device.currentState('illuminance') != null) {
statusTextmsg = "${device.currentState('temperature').value} ° - ${device.currentState('illuminance').value} ${(lum == "" || lum == null || lum == 1) ? "%" : "LUX"}"
sendEvent("name":"statusText", "value":statusTextmsg, displayed:false)
}
if (result != [null] && result != []) log.debug "Parse returned ${result}"
return result
}
// Event Generation
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
def map = [:]
switch (cmd.sensorType) {
case 0x01: // SENSOR_TYPE_TEMPERATURE_VERSION_1
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
log.debug "Temperature report"
break;
case 0x03 : // SENSOR_TYPE_LUMINANCE_VERSION_1
map.value = cmd.scaledSensorValue.toInteger().toString()
if(lum == "" || lum == null || lum == 1) map.unit = "%"
else map.unit = "lux"
map.name = "illuminance"
log.debug "Luminance report"
break;
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'"
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType==0x07) { // NOTIFICATION_TYPE_BURGLAR
if (cmd.event==0x07 || cmd.event==0x08) {
map.name = "motion"
map.value = "active"
map.descriptionText = "$device.displayName motion detected"
log.debug "motion recognized"
} else if (cmd.event==0) {
map.name = "motion"
map.value = "inactive"
map.descriptionText = "$device.displayName no motion detected"
log.debug "No motion recognized"
}
}
if (map.name != "motion") {
log.debug "unmatched parameters for cmd: ${cmd.toString()}}"
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
if (cmd.value == 0 && device.latestState("color").value != "#ffffff") {
sendEvent(name: "color", value: "#ffffff", displayed: true)
}
[name: "switch", value: cmd.value ? "on" : "off", type: "digital"]
}
def updated()
{
log.debug "updated() is being called"
def cmds = configure()
if (cmds != []) response(cmds)
}
def on() {
log.debug "Turning Light 'on'"
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def off() {
log.debug "Turning Light 'off'"
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def setColor(value) {
log.debug "setColor() : ${value}"
def myred
def mygreen
def myblue
def hexValue
def cmds = []
if ( value.level == 1 && value.saturation > 20) {
def rgb = huesatToRGB(value.hue as Integer, 100)
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else if ( value.level > 1 ) {
def rgb = huesatToRGB(value.hue as Integer, value.saturation as Integer)
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else if (value.hex) {
def rgb = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) }
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else {
myred=value.red >=128 ? 255 : 0 // the EZMultiPli has just on/off for each of the 3 channels RGB so convert the 0-255 value into 0 or 255.
mygreen=value.green >=128 ? 255 : 0
myblue=value.blue>=128 ? 255 : 0
}
//log.debug "Red: ${myred} Green: ${mygreen} Blue: ${myblue}"
//cmds << zwave.colorControlV1.stateSet(stateDataLength: 3, VariantGroup1: [0x02, myred], VariantGroup2:[ 0x03, mygreen], VariantGroup3:[0x04,myblue]).format() // ST support for this command as of 2015/02/23 does not support the color IDs so this command cannot be used.
// So instead we'll use these commands to hack around the lack of support of the above command
cmds << zwave.basicV1.basicSet(value: 0x00).format() // As of 2015/02/23 ST is not supporting stateSet properly but found this hack that works.
if (myred!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x02, startState: myred, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x02).format()
}
if (mygreen!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x03, startState: mygreen, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x03).format()
}
if (myblue!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x04, startState: myblue, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x04).format()
}
cmds << zwave.basicV1.basicGet().format()
hexValue = rgbToHex([r:myred, g:mygreen, b:myblue])
if(hexValue) sendEvent(name: "color", value: hexValue, displayed: true)
delayBetween(cmds, 100)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}
// ensure we are passing acceptable param values for LiteMin & TempMin configs
def checkLiteTempInput(value) {
if (value == null) {
value=60
}
def liteTempVal = value.toInteger()
switch (liteTempVal) {
case { it < 0 }:
return 60 // bad value, set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return liteTempVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnTime config
def checkOnTimeInput(value) {
if (value == null) {
value=10
}
def onTimeVal = value.toInteger()
switch (onTimeVal) {
case { it < 0 }:
return 10 // bad value set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return onTimeVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnLevel config
def checkOnLevelInput(value) {
if (value == null) {
value=99
}
def onLevelVal = value.toInteger()
switch (onLevelVal) {
case { it < -1 }:
return -1 // bad value set to default
break
case { it > 99 }:
return 99 // bad value, greater then MAX, set to MAX
break
default:
return onLevelVal // acceptable value
}
}
// ensure we are passing an acceptable param value for TempAdj configs
def checkTempAdjInput(value) {
if (value == null) {
value=0
}
def tempAdjVal = value.toInteger()
switch (tempAdjVal) {
case { it < -127 }:
return 0 // bad value, set to default
break
case { it > 128 }:
return 128 // bad value, greater then MAX, set to MAX
break
default:
return tempAdjVal // acceptable value
}
}
def refresh() {
def cmd = []
cmd << zwave.switchColorV3.switchColorGet().format()
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format()
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:1).format()
cmd << zwave.basicV1.basicGet().format()
delayBetween(cmd, 1000)
}
def configure() {
log.debug "OnTime=${settings.OnTime} OnLevel=${settings.OnLevel} TempAdj=${settings.TempAdj}"
def cmd = delayBetween([
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, scaledConfigurationValue: checkOnTimeInput(settings.OnTime)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: checkOnLevelInput(settings.OnLevel)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.LiteMin)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.TempMin)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: checkTempAdjInput(settings.TempAdj)).format(),
zwave.configurationV1.configurationGet(parameterNumber: 1).format(),
zwave.configurationV1.configurationGet(parameterNumber: 2).format(),
zwave.configurationV1.configurationGet(parameterNumber: 3).format(),
zwave.configurationV1.configurationGet(parameterNumber: 4).format(),
zwave.configurationV1.configurationGet(parameterNumber: 5).format()
], 100)
//log.debug cmd
cmd + refresh()
}
def huesatToRGB(float hue, float sat) {
while(hue >= 100) hue -= 100
int h = (int)(hue / 100 * 6)
float f = hue / 100 * 6 - h
int p = Math.round(255 * (1 - (sat / 100)))
int q = Math.round(255 * (1 - (sat / 100) * f))
int t = Math.round(255 * (1 - (sat / 100) * (1 - f)))
switch (h) {
case 0: return [255, t, p]
case 1: return [q, 255, p]
case 2: return [p, 255, t]
case 3: return [p, q, 255]
case 4: return [t, p, 255]
case 5: return [255, p, q]
}
}
def rgbToHex(rgb) {
def r = hex(rgb.r)
def g = hex(rgb.g)
def b = hex(rgb.b)
def hexColor = "#${r}${g}${b}"
hexColor
}
private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = "0" + s
}
s
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright 2016 SmartThings
* Copyright 2017 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:
@@ -59,7 +59,7 @@ def updated() {
}
def configure() {
def cmds = zigbee.batteryConfig(20, 20, 0x01)
def cmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.batteryConfig(20, 20, 0x01)
log.debug "configure -- cmds: ${cmds}"
return cmds
}
@@ -166,4 +166,4 @@ def checkPresenceCallback() {
if (timeSinceLastCheckin >= theCheckInterval) {
handlePresenceEvent(false)
}
}
}

View File

@@ -23,9 +23,9 @@ metadata {
capability "Health Check"
capability "Light"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer "
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer "
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer "
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer"
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer"
fingerprint mfr:"0063", prod:"4944", model:"3034", deviceJoinName: "GE In-Wall Smart Fan Control"
}

View File

@@ -114,9 +114,17 @@ def refresh() {
def configure() {
log.debug "Configuring Reporting and Bindings."
def cmds = []
if (device.getDataValue("manufacturer") == "sengled") {
def startLevel = 0xFE
if ((device.currentState("level")?.value != null)) {
startLevel = Math.round(Integer.parseInt(device.currentState("level").value) * 0xFE / 100)
}
// Level Control Cluster, command Move to Level, level start level, transition time 0
cmds << zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, 0x00, sprintf("%02X0000", startLevel))
}
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
refresh()
cmds + refresh()
}

View File

@@ -30,6 +30,9 @@ metadata {
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
fingerprint mfr:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
fingerprint mfr:"0086", prod:"0102", model:"0070", deviceJoinName: "Aeon Labs Door/Window Sensor 6"
fingerprint mfr:"011A", prod:"0601", model:"0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor"
}
// simulator metadata

View File

@@ -22,9 +22,9 @@ metadata {
capability "Health Check"
capability "Light"
fingerprint mfr:"0063", prod:"4952", deviceJoinName: "Z-Wave Wall Switch"
fingerprint mfr:"0063", prod:"5257", deviceJoinName: "Z-Wave Wall Switch"
fingerprint mfr:"0063", prod:"5052", deviceJoinName: "Z-Wave Plug-In Switch"
fingerprint mfr:"0063", prod:"4952", deviceJoinName: "GE Wall Switch"
fingerprint mfr:"0063", prod:"5257", deviceJoinName: "GE Wall Switch"
fingerprint mfr:"0063", prod:"5052", deviceJoinName: "GE Plug-In Switch"
fingerprint mfr:"0113", prod:"5257", deviceJoinName: "Z-Wave Wall Switch"
}

View File

@@ -0,0 +1,711 @@
definition(
name: "app.home.ai",
namespace: "app.home.ai",
author: "Eric Greer",
description: "SmartThings SmartApp for app.home.ai.",
category: "Fun & Social",
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"
)
// These are preferences displayed in the smart phone app
preferences {
// we need a settings section to enable subscriptions
section("Pick which devices home.ai will help you automate:"){
input "motion", "capability.motionSensor", title: "Choose motion sensors", required: false, multiple: true
input "contact", "capability.contactSensor", title: "Choose contact sensors", required: false, multiple: true
input "lightswitch", "capability.switch", title: "Choose normal power switches", required: false, multiple: true
input "lightswitchlevel", "capability.switchLevel", title: "Choose dimmer power switches", required: false, multiple: true
input "presence", "capability.presenceSensor", title: "Choose presence sensors", required: false, multiple: true
// removed in prod until dual-signal devices are supported
//input "tempSensor", "capability.temperatureMeasurement", title: "Choose temperature sensors", required: false, multiple: true
//input "humidity", "capability.relativeHumidityMeasurement", title: "Choose humidity sensors", required: false, multiple: true
input "waterSensor", "capability.waterSensor", title: "Choose water sensors", required: false, multiple: true
input "lock", "capability.lock", title: "Pick Door Locks", required: false, multiple: true
input "garagedoor", "capability.garageDoorControl", title: "Pick garage doors", required: false, multiple: true
input "touchsensor", "capability.touchSensor", title: "Pick touch sensors", required: false, multiple: true
input "speechparser", "capability.speechRecognition", title: "Pick speech recognizers", required: false, multiple: true
input "soundsensor", "capability.soundSensor", title: "Pick sound sensors", required: false, multiple: true
input "smokedetector", "capability.smokeDetector", title: "Pick smoke detectors", required: false, multiple: true
input "sleepsensor", "capability.sleepSensor", title: "Pick sleep sensors", required: false, multiple: true
input "carbonsensor", "capability.carbonMonoxideDetector", title: "Pick carbon monoxide detectors", required: false, multiple: true
input "button", "capability.button", title: "Pick buttons", required: false, multiple: true
input "beacon", "capability.beacon", title: "Pick beacons", required: false, multiple: true
input "alarm", "capability.alarm", title: "Pick alarms", required: false, multiple: true
input "thermostat", "capability.thermostat", title: "Pick thermostats", required: false, multiple: true
input "voltage", "capability.voltageMeasurement", title: "Pick voltage sensors", required: false, multiple: true
input "windowshade", "capability.windowShade", title: "Pick window shades", required: false, multiple: true
input "powermeter", "capability.powerMeter", title: "Pick power meters", required: false, multiple: true
}
}
// vlaues for security system are 'away', 'stay', or 'off'
// off security
def offSecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "off",
displayed: false,
isStateChange: true)
}
// stay security
def staySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "stay",
displayed: false,
isStateChange: true)
}
// away security
def awaySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "away",
displayed: false,
isStateChange: true)
}
// sets window shade open temperature
def setWindowShadeOpen() {
def deviceID = params.deviceID
log.debug("setWindowShadeOpen command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets window shade close temperature
def setWindowShadeClosed() {
def deviceID = params.deviceID
log.debug("setWindowShadeClosed command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat heating temperature
def setThermostatHeatTemp() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setHeatingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat cooling temperature
def setThermostatCoolTemp() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setCoolingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat off
def setThermostatOff() {
def deviceID = params.deviceID
log.debug("setThermostatOff command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to heat
def setThermostatHeat() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.heat()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to cool
def setThermostatCool() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.cool()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat mode
def setThermostatMode() {
def deviceID = params.deviceID
log.debug("setThermostatMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat fan mode
def setThermostatFanMode() {
def deviceID = params.deviceID
log.debug("setThermostatFanMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatFanMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm strobe
def strobeAlarm() {
def deviceID = params.deviceID
log.debug("Alarm strobe command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.strobe()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm siren
def sirenAlarm() {
def deviceID = params.deviceID
log.debug("Alarm siren command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.siren()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// disables an alarm siren
def silenceAlarm() {
def deviceID = params.deviceID
log.debug("Alarm silence command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// opens a garage door
def openGarage() {
def deviceID = params.deviceID
log.debug("Open Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// closes a garage door
def closeGarage() {
def deviceID = params.deviceID
log.debug("Close Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// lock locks a door lock
def lockDoor() {
def deviceID = params.deviceID
log.debug("Lock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.lock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// unlock unlocks a door lock
def unlockDoor() {
def deviceID = params.deviceID
log.debug("Unlock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.unlock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// turns on a wall switch as instructed from the homeai webservice
def switchOn() {
def deviceID = params.deviceID
log.debug("Switch on command recieved ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.on()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// turns off a wall switch as instructed from the homeai webservice
def switchOff() {
def deviceID = params.deviceID
log.debug("Switch off desired for ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// fetch the id of this smartthings hub
def hubId() {
log.debug("hub id requested.")
def response = [hubId: location.hubs.id[0]]
}
// This handles requests for device inventories
def inventory() {
def response = []
lightswitch.each {
response << [name: it.displayName, value: it.currentValue("switch"), deviceId: it.id, type: "lightSwitch"]
}
contact.each {
response << [name: it.displayName, value: it.currentValue("contact"), deviceId: it.id, type: "contact"]
}
motion.each {
response << [name: it.displayName, value: it.currentValue("motion"), deviceId: it.id, type: "motion"]
}
presence.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "presence"]
}
// removed until dual device functions are supported on the backend
//tempSensor.each {
// response << [name: it.displayName, value: it.currentValue("temperature"), deviceId: it.id, type: "tempSensor"]
//}
//humidity.each {
// response << [name: it.displayName, value: it.currentValue("humidity"), deviceId: it.id, type: "humiditySensor"]
//}
waterSensor.each {
response << [name: it.displayName, value: it.currentValue("water"), deviceId: it.id, type: "waterSensor"]
}
lock.each {
response << [name: it.displayName, value: it.currentValue("lock"), deviceId: it.id, type: "lock"]
}
garagedoor.each {
response << [name: it.displayName, value: it.currentValue("door"), deviceId: it.id, type: "garagedoor"]
}
touchsensor.each {
response << [name: it.displayName, value: it.currentValue("touch"), deviceId: it.id, type: "touchsensor"]
}
speechparser.each {
response << [name: it.displayName, value: it.currentValue("phraseSpoken"), deviceId: it.id, type: "speechparser"]
}
soundsensor.each {
response << [name: it.displayName, value: it.currentValue("sound"), deviceId: it.id, type: "sound"]
}
smokedetector.each {
response << [name: it.displayName, value: it.currentValue("smoke"), deviceId: it.id, type: "smoke"]
}
sleepsensor.each {
response << [name: it.displayName, value: it.currentValue("sleeping"), deviceId: it.id, type: "sleepsensor"]
}
carbonsensor.each {
response << [name: it.displayName, value: it.currentValue("carbonMonoxide"), deviceId: it.id, type: "carbonsensor"]
}
button.each {
response << [name: it.displayName, value: it.currentValue("button"), deviceId: it.id, type: "button"]
}
beacon.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "beacon"]
}
alarm.each {
response << [name: it.displayName, value: it.currentValue("alarm"), deviceId: it.id, type: "alarm"]
}
thermostat.each {
response << [name: it.displayName, value: it.currentValue("thermostatMode"), deviceId: it.id, type: "thermostat"]
}
voltage.each {
response << [name: it.displayName, value: it.currentValue("voltage"), deviceId: it.id, type: "voltage"]
}
windowshade.each {
response << [name: it.displayName, value: it.currentValue("windowShade"), deviceId: it.id, type: "windowshade"]
}
powermeter.each {
response << [name: it.displayName, value: it.currentValue("power"), deviceId: it.id, type: "powermeter"]
}
lightswitchlevel.each {
response << [name: it.displayName, value: it.currentValue("level"), deviceId: it.id, type: "lightswitchlevel"]
}
log.debug("Inventory request processed. Response: " + response)
return response
}
// After the user hits the 'install' button in the mobile app
def installed() {
initialize()
}
// After app settings are changed. All subscriptions are wiped before this is invoked by smartthings.
def updated() {
unsubscribe()
initialize()
}
// This appears to be what the tutorials meant to use in the examples
def initialize() {
// SHM subscription
// evt.value will be "off", "stay", or "away"
subscribe(location, "alarmSystemStatus", eventForwarder)
// motion sensor subscription
subscribe(motion, "motion", eventForwarder)
// Contact sensor subscription
subscribe(contact, "contact", eventForwarder)
// power plug subscription
subscribe(lightswitch, "switch", eventForwarder)
// presence sensor subscription
subscribe(presence, "presence", eventForwarder)
// temperature sensor subscription
subscribe(tempSensor, "temperature", eventForwarder)
// water sensor subscription
subscribe(waterSensor, "water", eventForwarder)
// humidity sensor subscription
subscribe(humidity, "humidity", eventForwarder)
// lock subscription
subscribe(lock, "lock", eventForwarder)
// garage door subscription
subscribe(garagedoor, "garagedoor", eventForwarder)
// touch sensor subscription
subscribe(touchsensor, "touchsensor", eventForwarder)
// speech parser subscription
subscribe(speechparser, "phraseSpoken", eventForwarder)
// sound sensor subscription
subscribe(soundsensor, "sound", eventForwarder)
// smoke detector subscription
subscribe(smokedetector, "smoke", eventForwarder)
// sleep sensor subscription
subscribe(sleepsensor, "sleeping", eventForwarder)
// carbon monoxide sensor subscription
subscribe(carbonsensor, "carbonMonoxide", eventForwarder)
// button subscription
subscribe(button, "button", eventForwarder)
// beacon subscription
subscribe(beacon, "presence", eventForwarder)
// alarm subscription
subscribe(alarm, "alarm", eventForwarder)
// thermostat subscriptions
subscribe(thermostat, "temperature", eventForwarder)
subscribe(thermostat, "heatingSetpoint", eventForwarder)
subscribe(thermostat, "coolingSetpoint", eventForwarder)
subscribe(thermostat, "thermostatSetpoint", eventForwarder)
subscribe(thermostat, "thermostatMode", eventForwarder)
subscribe(thermostat, "thermostatFanMode", eventForwarder)
subscribe(thermostat, "thermostatOperatingState", eventForwarder)
// voltage subscription
subscribe(voltage, "voltage", eventForwarder)
// window shade subscription
subscribe(windowshade, "windowShade", eventForwarder)
// shm events
subscribe(location, "alarmSystemStatus", shmEventForwarder)
// power meter subscription
subscribe(powermeter, "power", eventForwarder)
// level switch (dimmer switch)
subscribe(lightswitchlevel, "level", eventForwarder)
}
def shmEventForwarder(evt) {
// evt.value will be "off", "stay", or "away"
log.debug("FORWARDING SHM CHANGE" + evt.value + " " + evt.hub.id)
def deviceState = evt.value
def deviceId = "smarthomemonitor"
def hubId = hubId()
def params = [
uri: "https://app.home.ai",
path: "/smartThingsPostback/shmStateChange/${hubId}/${deviceId}/${deviceState}"
]
log.info(params)
httpGet(params)
}
// This is used to forward events to the home.ai webservice
def eventForwarder(evt) {
def hubId = location.hubs.id[0]
log.debug(params.uri + " " + params.path)
log.debug("FORWARDING EVENT" + evt.deviceId + " " + evt.value + " " + hubId)
def deviceId = evt.deviceId
def deviceState = evt.value
def params = [
uri: "https://app.home.ai",
path: "/smartThingsPostback/stateChange/${hubId}/${deviceId}/${deviceState}"
]
log.info(params)
httpGet(params)
}
// Mappings that serve web requests against our smart app
mappings {
path("/inventory") {
action: [
GET: "inventory"
]
}
path("/hubId") {
action: [
GET: "hubId"
]
}
path("/switchOn/:deviceID") {
action: [
GET: "switchOn"
]
}
path("/switchOff/:deviceID") {
action: [
GET: "switchOff"
]
}
path("/lock/:deviceID") {
action: [
GET: "lockDoor"
]
}
path("/unlock/:deviceID") {
action: [
GET: "unlockDoor"
]
}
path("/opengarage/:deviceID") {
action: [
GET: "openGarage"
]
}
path("/closegarage/:deviceID") {
action: [
GET: "closeGarage"
]
}
path("/strobeAlarm/:deviceID") {
action: [
GET: "strobeAlarm"
]
}
path("/sirenAlarm/:deviceID") {
action: [
GET: "sirenAlarm"
]
}
path("/silenceAlarm/:deviceID") {
action: [
GET: "silenceAlarm"
]
}
path("/setThermostatHeatTemp/:deviceID/:temp") {
action: [
GET: "setThermostatHeatTemp"
]
}
path("/setThermostatCoolTemp/:deviceID/:temp") {
action: [
GET: "setThermostatCoolTemp"
]
}
path("/setThermostatHeat/:deviceID") {
action: [
GET: "setThermostatHeat"
]
}
path("/setThermostatCool/:deviceID") {
action: [
GET: "setThermostatCool"
]
}
path("/setThermostatMode/:deviceID/:mode") {
action: [
GET: "setThermostatMode"
]
}
path("/setThermostatFanMode/:deviceID/:mode") {
action: [
GET: "setThermostatFanMode"
]
}
path("/closeWindowShade/:deviceID") {
action: [
GET: "setWindowShadeClosed"
]
}
path("/openWindowShade/:deviceID") {
action: [
GET: "setWindowShadeOpen"
]
}
path("/awaySecurity") {
action: [
GET: "awaySecurity"
]
}
path("/staySecurity") {
action: [
GET: "staySecurity"
]
}
path("/offSecurity") {
action: [
GET: "offSecurity"
]
}
}

View File

@@ -0,0 +1,829 @@
definition(
name: "demo.home.ai",
namespace: "demo.home.ai",
author: "Eric Greer",
description: "SmartThings demo SmartApp for home.ai.",
category: "Fun & Social",
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"
)
// These are preferences displayed in the smart phone app
preferences {
// we need a settings section to enable subscriptions
section("Pick which devices home.ai will help you automate:"){
input "motion", "capability.motionSensor", title: "Choose motion sensors", required: false, multiple: true
input "contact", "capability.contactSensor", title: "Choose contact sensors", required: false, multiple: true
input "lightswitch", "capability.switch", title: "Choose normal power switches", required: false, multiple: true
input "lightswitchlevel", "capability.switchLevel", title: "Choose dimmer power switches", required: false, multiple: true
input "presence", "capability.presenceSensor", title: "Choose presence sensors", required: false, multiple: true
input "tempSensor", "capability.temperatureMeasurement", title: "Choose temperature sensors", required: false, multiple: true
input "humidity", "capability.relativeHumidityMeasurement", title: "Choose humidity sensors", required: false, multiple: true
input "waterSensor", "capability.waterSensor", title: "Choose water sensors", required: false, multiple: true
input "lock", "capability.lock", title: "Pick Door Locks", required: false, multiple: true
input "garagedoor", "capability.garageDoorControl", title: "Pick garage doors", required: false, multiple: true
input "touchsensor", "capability.touchSensor", title: "Pick touch sensors", required: false, multiple: true
input "speechparser", "capability.speechRecognition", title: "Pick speech recognizers", required: false, multiple: true
input "soundsensor", "capability.soundSensor", title: "Pick sound sensors", required: false, multiple: true
input "smokedetector", "capability.smokeDetector", title: "Pick smoke detectors", required: false, multiple: true
input "sleepsensor", "capability.sleepSensor", title: "Pick sleep sensors", required: false, multiple: true
input "carbonsensor", "capability.carbonMonoxideDetector", title: "Pick carbon monoxide detectors", required: false, multiple: true
input "button", "capability.button", title: "Pick buttons", required: false, multiple: true
input "beacon", "capability.beacon", title: "Pick beacons", required: false, multiple: true
input "alarm", "capability.alarm", title: "Pick alarms", required: false, multiple: true
input "thermostat", "capability.thermostat", title: "Pick thermostats", required: false, multiple: true
input "voltage", "capability.voltageMeasurement", title: "Pick voltage sensors", required: false, multiple: true
input "windowshade", "capability.windowShade", title: "Pick window shades", required: false, multiple: true
input "powermeter", "capability.powerMeter", title: "Pick power meters", required: false, multiple: true
}
}
// vlaues for security system are 'away', 'stay', or 'off'
// off security
def offSecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "off",
displayed: false,
isStateChange: true)
}
// stay security
def staySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "stay",
displayed: false,
isStateChange: true)
}
// away security
def awaySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "away",
displayed: false,
isStateChange: true)
}
// sets window shade open temperature
def setWindowShadeOpen() {
def deviceID = params.deviceID
log.debug("setWindowShadeOpen command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets window shade close temperature
def setWindowShadeClosed() {
def deviceID = params.deviceID
log.debug("setWindowShadeClosed command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat heating temperature
def setThermostatHeatTemp() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setHeatingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat cooling temperature
def setThermostatCoolTemp() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setCoolingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat off
def setThermostatOff() {
def deviceID = params.deviceID
log.debug("setThermostatOff command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to heat
def setThermostatHeat() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.heat()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to cool
def setThermostatCool() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.cool()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat mode
def setThermostatMode() {
def deviceID = params.deviceID
log.debug("setThermostatMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat fan mode
def setThermostatFanMode() {
def deviceID = params.deviceID
log.debug("setThermostatFanMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatFanMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm strobe
def strobeAlarm() {
def deviceID = params.deviceID
log.debug("Alarm strobe command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.strobe()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm siren
def sirenAlarm() {
def deviceID = params.deviceID
log.debug("Alarm siren command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.siren()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// disables an alarm siren
def silenceAlarm() {
def deviceID = params.deviceID
log.debug("Alarm silence command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// opens a garage door
def openGarage() {
def deviceID = params.deviceID
log.debug("Open Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// closes a garage door
def closeGarage() {
def deviceID = params.deviceID
log.debug("Close Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// lock locks a door lock
def lockDoor() {
def deviceID = params.deviceID
log.debug("Lock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.lock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// unlock unlocks a door lock
def unlockDoor() {
def deviceID = params.deviceID
log.debug("Unlock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.unlock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// turns on a wall switch as instructed from the homeai webservice
def switchOn() {
def deviceID = params.deviceID
log.debug("Switch on command recieved ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.on()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// turns off a wall switch as instructed from the homeai webservice
def switchOff() {
def deviceID = params.deviceID
log.debug("Switch off desired for ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// sets a level switch to off
def setLevelSwitch0() {
def deviceID = params.deviceID
log.debug("Level switch off desired for ${deviceID}")
lightswitchlevel.each {
if (it.id == deviceID) {
log.debug("Operating level switch device because it is the one specified: ${deviceID}");
it.setLevel(0)
} else {
log.debug("Skipping level switch device because it is not the one specified: ${deviceID}");
}
}
}
// sets a level switch to 25%
def setLevelSwitch25() {
def deviceID = params.deviceID
log.debug("Level switch 25 desired for ${deviceID}")
lightswitchlevel.each {
if (it.id == deviceID) {
log.debug("Operating level switch device because it is the one specified: ${deviceID}");
it.setLevel(25)
} else {
log.debug("Skipping level switch device because it is not the one specified: ${deviceID}");
}
}
}
// sets a level switch to 50%
def setLevelSwitch50() {
def deviceID = params.deviceID
log.debug("Level switch 50 desired for ${deviceID}")
lightswitchlevel.each {
if (it.id == deviceID) {
log.debug("Operating level switch device because it is the one specified: ${deviceID}");
it.setLevel(50)
} else {
log.debug("Skipping level switch device because it is not the one specified: ${deviceID}");
}
}
}
// sets a level switch to 75%
def setLevelSwitch75() {
def deviceID = params.deviceID
log.debug("Level switch 75 desired for ${deviceID}")
lightswitchlevel.each {
if (it.id == deviceID) {
log.debug("Operating level switch device because it is the one specified: ${deviceID}");
it.setLevel(75)
} else {
log.debug("Skipping level switch device because it is not the one specified: ${deviceID}");
}
}
}
// sets a level switch to 100%
def setLevelSwitch100() {
def deviceID = params.deviceID
log.debug("Level switch 100 desired for ${deviceID}")
lightswitchlevel.each {
if (it.id == deviceID) {
log.debug("Operating level switch device because it is the one specified: ${deviceID}");
it.setLevel(100)
} else {
log.debug("Skipping level switch device because it is not the one specified: ${deviceID}");
}
}
}
// fetch the id of this smartthings hub
def hubId() {
log.debug("hub id requested.")
def response = [hubId: location.hubs.id[0]]
}
// This handles requests for device inventories
def inventory() {
def response = []
lightswitch.each {
response << [name: it.displayName, value: it.currentValue("switch"), deviceId: it.id, type: "lightSwitch"]
}
contact.each {
response << [name: it.displayName, value: it.currentValue("contact"), deviceId: it.id, type: "contact"]
}
motion.each {
response << [name: it.displayName, value: it.currentValue("motion"), deviceId: it.id, type: "motion"]
}
presence.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "presence"]
}
tempSensor.each {
response << [name: it.displayName, value: it.currentValue("temperature"), deviceId: it.id, type: "tempSensor"]
}
waterSensor.each {
response << [name: it.displayName, value: it.currentValue("water"), deviceId: it.id, type: "waterSensor"]
}
humidity.each {
response << [name: it.displayName, value: it.currentValue("humidity"), deviceId: it.id, type: "humiditySensor"]
}
lock.each {
response << [name: it.displayName, value: it.currentValue("lock"), deviceId: it.id, type: "lock"]
}
garagedoor.each {
response << [name: it.displayName, value: it.currentValue("door"), deviceId: it.id, type: "garagedoor"]
}
touchsensor.each {
response << [name: it.displayName, value: it.currentValue("touch"), deviceId: it.id, type: "touchsensor"]
}
speechparser.each {
response << [name: it.displayName, value: it.currentValue("phraseSpoken"), deviceId: it.id, type: "speechparser"]
}
soundsensor.each {
response << [name: it.displayName, value: it.currentValue("sound"), deviceId: it.id, type: "sound"]
}
smokedetector.each {
response << [name: it.displayName, value: it.currentValue("smoke"), deviceId: it.id, type: "smoke"]
}
sleepsensor.each {
response << [name: it.displayName, value: it.currentValue("sleeping"), deviceId: it.id, type: "sleepsensor"]
}
carbonsensor.each {
response << [name: it.displayName, value: it.currentValue("carbonMonoxide"), deviceId: it.id, type: "carbonsensor"]
}
button.each {
response << [name: it.displayName, value: it.currentValue("button"), deviceId: it.id, type: "button"]
}
beacon.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "beacon"]
}
alarm.each {
response << [name: it.displayName, value: it.currentValue("alarm"), deviceId: it.id, type: "alarm"]
}
thermostat.each {
response << [name: it.displayName, value: it.currentValue("thermostatMode"), deviceId: it.id, type: "thermostat"]
}
voltage.each {
response << [name: it.displayName, value: it.currentValue("voltage"), deviceId: it.id, type: "voltage"]
}
windowshade.each {
response << [name: it.displayName, value: it.currentValue("windowShade"), deviceId: it.id, type: "windowshade"]
}
powermeter.each {
response << [name: it.displayName, value: it.currentValue("power"), deviceId: it.id, type: "powermeter"]
}
lightswitchlevel.each {
response << [name: it.displayName, value: it.currentValue("level"), deviceId: it.id, type: "lightswitchlevel"]
}
log.debug("Inventory request processed. Response: " + response)
return response
}
// After the user hits the 'install' button in the mobile app
def installed() {
initialize()
}
// After app settings are changed. All subscriptions are wiped before this is invoked by smartthings.
def updated() {
unsubscribe()
initialize()
}
// This appears to be what the tutorials meant to use in the examples
def initialize() {
// motion sensor subscription
subscribe(motion, "motion", eventForwarder)
// Contact sensor subscription
subscribe(contact, "contact", eventForwarder)
// power plug subscription
subscribe(lightswitch, "switch", eventForwarder)
// presence sensor subscription
subscribe(presence, "presence", eventForwarder)
// temperature sensor subscription
subscribe(tempSensor, "temperature", eventForwarder)
// water sensor subscription
subscribe(waterSensor, "water", eventForwarder)
// humidity sensor subscription
subscribe(humidity, "humidity", eventForwarder)
// lock subscription
subscribe(lock, "lock", eventForwarder)
// garage door subscription
subscribe(garagedoor, "garagedoor", eventForwarder)
// touch sensor subscription
subscribe(touchsensor, "touchsensor", eventForwarder)
// speech parser subscription
subscribe(speechparser, "phraseSpoken", eventForwarder)
// sound sensor subscription
subscribe(soundsensor, "sound", eventForwarder)
// smoke detector subscription
subscribe(smokedetector, "smoke", eventForwarder)
// sleep sensor subscription
subscribe(sleepsensor, "sleeping", eventForwarder)
// carbon monoxide sensor subscription
subscribe(carbonsensor, "carbonMonoxide", eventForwarder)
// button subscription
subscribe(button, "button", eventForwarder)
// beacon subscription
subscribe(beacon, "presence", eventForwarder)
// alarm subscription
subscribe(alarm, "alarm", eventForwarder)
// thermostat subscriptions
subscribe(thermostat, "temperature", eventForwarder)
subscribe(thermostat, "heatingSetpoint", eventForwarder)
subscribe(thermostat, "coolingSetpoint", eventForwarder)
subscribe(thermostat, "thermostatSetpoint", eventForwarder)
subscribe(thermostat, "thermostatMode", eventForwarder)
subscribe(thermostat, "thermostatFanMode", eventForwarder)
subscribe(thermostat, "thermostatOperatingState", eventForwarder)
// voltage subscription
subscribe(voltage, "voltage", eventForwarder)
// window shade subscription
subscribe(windowshade, "windowShade", eventForwarder)
// shm events
subscribe(location, "alarmSystemStatus", shmEventForwarder)
// power meter subscription
subscribe(powermeter, "power", eventForwarder)
// level switch (dimmer switch)
subscribe(lightswitchlevel, "level", eventForwarder)
}
// This is used to forward events to the home.ai webservice
def eventForwarder(evt) {
log.debug(params.uri + " " + params.path)
log.debug("FORWARDING EVENT" + evt.deviceId + " " + evt.value + " " + evt.hub.id)
def deviceId = evt.deviceId
def deviceState = evt.value
def hubId = evt.hub.id
def params = [
uri: "https://demo.home.ai",
path: "/smartThingsPostback/stateChange/${hubId}/${deviceId}/${deviceState}"
]
log.info(params)
httpGet(params)
}
// Mappings that serve web requests against our smart app
mappings {
path("/inventory") {
action: [
GET: "inventory"
]
}
path("/hubId") {
action: [
GET: "hubId"
]
}
path("/switchOn/:deviceID") {
action: [
GET: "switchOn"
]
}
path("/switchOff/:deviceID") {
action: [
GET: "switchOff"
]
}
path("/lock/:deviceID") {
action: [
GET: "lockDoor"
]
}
path("/unlock/:deviceID") {
action: [
GET: "unlockDoor"
]
}
path("/opengarage/:deviceID") {
action: [
GET: "openGarage"
]
}
path("/closegarage/:deviceID") {
action: [
GET: "closeGarage"
]
}
path("/strobeAlarm/:deviceID") {
action: [
GET: "strobeAlarm"
]
}
path("/sirenAlarm/:deviceID") {
action: [
GET: "sirenAlarm"
]
}
path("/silenceAlarm/:deviceID") {
action: [
GET: "silenceAlarm"
]
}
path("/setThermostatHeatTemp/:deviceID/:temp") {
action: [
GET: "setThermostatHeatTemp"
]
}
path("/setThermostatCoolTemp/:deviceID/:temp") {
action: [
GET: "setThermostatCoolTemp"
]
}
path("/setThermostatHeat/:deviceID") {
action: [
GET: "setThermostatHeat"
]
}
path("/setThermostatCool/:deviceID") {
action: [
GET: "setThermostatCool"
]
}
path("/setThermostatMode/:deviceID/:mode") {
action: [
GET: "setThermostatMode"
]
}
path("/setThermostatFanMode/:deviceID/:mode") {
action: [
GET: "setThermostatFanMode"
]
}
path("/closeWindowShade/:deviceID") {
action: [
GET: "setWindowShadeClosed"
]
}
path("/openWindowShade/:deviceID") {
action: [
GET: "setWindowShadeOpen"
]
}
// level switch setting endpoints
path("/levelSwitch0/:deviceID") {
action: [
GET: "setLevelSwitch0"
]
}
path("/levelSwitch25/:deviceID") {
action: [
GET: "setLevelSwitch25"
]
}
path("/levelSwitch50/:deviceID") {
action: [
GET: "setLevelSwitch50"
]
}
path("/levelSwitch75/:deviceID") {
action: [
GET: "setLevelSwitch75"
]
}
path("/levelSwitch100/:deviceID") {
action: [
GET: "setLevelSwitch100"
]
}
// Smart home monitor controls
path("/awaySecurity") {
action: [
GET: "awaySecurity"
]
}
path("/staySecurity") {
action: [
GET: "staySecurity"
]
}
path("/offSecurity") {
action: [
GET: "offSecurity"
]
}
}

View File

@@ -52,15 +52,15 @@ definition(
//Device Inputs
preferences {
section("Allow OpenT2T to control these things...") {
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 "locks", "capability.lock", title: "Which Locks?", 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 "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 "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false, hideWhenEmpty: true
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false, hideWhenEmpty: true
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false, hideWhenEmpty: true
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false, hideWhenEmpty: true
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false, hideWhenEmpty: true
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false, hideWhenEmpty: true
input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false, hideWhenEmpty: true
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false, hideWhenEmpty: true
}
}
@@ -80,16 +80,6 @@ def getInputs() {
//API external Endpoints
mappings {
path("/subscriptionURL/:url") {
action: [
PUT: "updateEndpointURL"
]
}
path("/connectionId/:connId") {
action: [
PUT: "updateConnectionId"
]
}
path("/devices") {
action: [
GET: "getDevices"
@@ -105,33 +95,52 @@ mappings {
PUT: "updateDevice"
]
}
path("/subscription/:id") {
path("/deviceSubscription") {
action: [
POST: "registerDeviceChange",
DELETE: "unregisterDeviceChange"
]
}
path("/locationSubscription") {
action: [
POST: "registerDeviceGraph",
DELETE: "unregisterDeviceGraph"
]
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
log.debug "Installing with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
log.debug "Updating with settings: ${settings}"
if(state.deviceSubscriptionMap == null){
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
}
if( state.locationSubscriptionMap == null){
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
}
unsubscribe()
registerSubscriptions()
registerAllDeviceSubscriptions()
}
def initialize() {
state.connectionId = ""
state.endpointURL = "https://ifs.windows-int.com/v1/cb/81C7E77B-EABC-488A-B2BF-FEC42F0DABD2/notify"
registerSubscriptions()
log.debug "Initializing with settings: ${settings}"
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
registerAllDeviceSubscriptions()
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
}
/*** Subscription Functions ***/
//Subscribe events for all devices
def registerSubscriptions() {
def registerAllDeviceSubscriptions() {
registerChangeHandler(inputs)
}
@@ -140,101 +149,195 @@ def registerChangeHandler(myList) {
myList.each { myDevice ->
def theAtts = myDevice.supportedAttributes
theAtts.each {att ->
subscribe(myDevice, att.name, eventHandler)
log.info "Registering ${myDevice.displayName}.${att.name}"
subscribe(myDevice, att.name, deviceEventHandler)
log.info "Registering for ${myDevice.displayName}.${att.name}"
}
}
}
//Endpoints function: Subscribe to events from a specific device
def registerDeviceChange() {
def myDevice = findDevice(params.id)
def subscriptionEndpt = params.subscriptionURL
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if( myDevice == null ){
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
def theAtts = myDevice.supportedAttributes
try {
theAtts.each {att ->
subscribe(myDevice, att.name, eventHandler)
log.info "Registering ${myDevice.displayName}.${att.name}"
subscribe(myDevice, att.name, deviceEventHandler)
}
log.info "Subscribing for ${myDevice.displayName}"
if(subscriptionEndpt != null){
if(state.deviceSubscriptionMap[deviceId] == null){
state.deviceSubscriptionMap.put(deviceId, [subscriptionEndpt])
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
} else if (!state.deviceSubscriptionMap[deviceId].contains(subscriptionEndpt)){
state.deviceSubscriptionMap[deviceId] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
}
return ["succeed"]
} catch (e) {
httpError(500, "something went wrong: $e")
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
return ["succeed"]
}
//Endpoints function: Unsubscribe to events from a specific device
def unregisterDeviceChange() {
def myDevice = findDevice(params.id)
def subscriptionEndpt = params.subscriptionURL
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if( myDevice == null ){
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
try {
unsubscribe(myDevice)
log.info "Unregistering ${myDevice.displayName}"
return ["succeed"]
if(subscriptionEndpt != null && subscriptionEndpt != "undefined"){
if (state.deviceSubscriptionMap[deviceId]?.contains(subscriptionEndpt)){
if(state.deviceSubscriptionMap[deviceId].size() == 1){
state.deviceSubscriptionMap.remove(deviceId)
} else {
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
}
log.info "Removed subscription URL: ${subscriptionEndpt} for ${myDevice.displayName}"
}
} else {
state.deviceSubscriptionMap.remove(deviceId)
log.info "Unsubscriping for ${myDevice.displayName}"
}
} catch (e) {
httpError(500, "something went wrong: $e")
}
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
}
//Endpoints function: Subscribe to device additiona/removal updated in a location
def registerDeviceGraph() {
def subscriptionEndpt = params.subscriptionURL
if (subscriptionEndpt != null && subscriptionEndpt != "undefined"){
subscribe(location, "DeviceCreated", locationEventHandler, [filterEvents: false])
subscribe(location, "DeviceUpdated", locationEventHandler, [filterEvents: false])
subscribe(location, "DeviceDeleted", locationEventHandler, [filterEvents: false])
if(state.locationSubscriptionMap[location.id] == null){
state.locationSubscriptionMap.put(location.id, [subscriptionEndpt])
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
} else if (!state.locationSubscriptionMap[location.id].contains(subscriptionEndpt)){
state.locationSubscriptionMap[location.id] << subscriptionEndpt
log.info "Added subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
return ["succeed"]
} else {
httpError(400, "missing input parameter: subscriptionURL")
}
}
//Endpoints function: Unsubscribe to events from a specific device
def unregisterDeviceGraph() {
def subscriptionEndpt = params.subscriptionURL
try {
if(subscriptionEndpt != null && subscriptionEndpt != "undefined"){
if (state.locationSubscriptionMap[location.id]?.contains(subscriptionEndpt)){
if(state.locationSubscriptionMap[location.id].size() == 1){
state.locationSubscriptionMap.remove(location.id)
} else {
state.locationSubscriptionMap[location.id].remove(subscriptionEndpt)
}
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
}else{
httpError(400, "missing input parameter: subscriptionURL")
}
} catch (e) {
httpError(500, "something went wrong: $e")
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
}
//When events are triggered, send HTTP post to web socket servers
def eventHandler(evt) {
def evt_device_id = evt.deviceId
def evt_device_value = evt.value
def evt_name = evt.name
def deviceEventHandler(evt) {
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 = [ body: [deviceName: evt_device.displayName, deviceId: evt_device.id, locationId: location.id] ]
if(evt.data != null){
def evtData = parseJson(evt.data)
log.info "Received event for ${evt_device.displayName}, data: ${evtData}, description: ${evt.descriptionText}"
}
def params = [
uri: "${state.endpointURL}/${state.connectionId}",
body: [ deviceInfo ]
]
try {
//send event to all subscriptions urls
log.debug "Current subscription urls for ${evt_device.displayName} is ${state.deviceSubscriptionMap[evt_device.id]}"
state.deviceSubscriptionMap[evt_device.id].each {
params.uri = "${it}"
log.trace "POST URI: ${params.uri}"
log.trace "Payload: ${params.body}"
httpPostJson(params) { resp ->
resp.headers.each {
log.debug "${it.name} : ${it.value}"
try{
httpPostJson(params) { resp ->
log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
}
log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
} catch (e) {
log.error "something went wrong: $e"
}
} catch (e) {
log.debug "something went wrong: $e"
}
}
//Endpoints function: update subcription endpoint url [state.endpoint]
void updateEndpointURL() {
state.endpointURL = params.url
log.info "Updated EndpointURL to ${state.endpointURL}"
def locationEventHandler(evt) {
log.info "Received event for location ${location.name}/${location.id}, Event: ${evt.name}, description: ${evt.descriptionText}, apiServerUrl: ${apiServerUrl("")}"
switch(evt.name){
case "DeviceCreated":
case "DeviceDeleted":
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device)
log.info "DeviceName: ${evt_device.displayName}, DeviceID: ${evt_device.id}, deviceType: ${evt_deviceType}"
def params = [ body: [ eventType:evt.name, deviceId: evt_device.id, locationId: location.id ] ]
state.locationSubscriptionMap[location.id].each {
params.uri = "${it}"
log.trace "POST URI: ${params.uri}"
log.trace "Payload: ${params.body}"
try{
httpPostJson(params) { resp ->
log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
}
} catch (e) {
log.error "something went wrong: $e"
}
}
case "DeviceUpdated":
default:
break
}
}
//Endpoints function: update global variable [state.connectionId]
void updateConnectionId() {
def connId = params.connId
state.connectionId = connId
log.info "Updated ConnectionID to ${state.connectionId}"
}
/*** Device Query/Update Functions ***/
//Endpoints function: return all device data in json format
def getDevices() {
def deviceData = []
inputs?.each {
def deviceType = getDeviceType(it)
if(deviceType == "thermostat")
{
deviceData << [name: it.displayName, id: it.id, status:it.getStatus(), 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)]
if(deviceType == "thermostat") {
deviceData << [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType), locationMode: getLocationModeInfo()]
} else {
deviceData << [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType)]
}
}
@@ -247,14 +350,12 @@ def getDevice() {
def it = findDevice(params.id)
def deviceType = getDeviceType(it)
def device
if(deviceType == "thermostat")
{
device = [name: it.displayName, id: it.id, status:it.getStatus(), 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)]
if(deviceType == "thermostat") {
device = [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it,deviceType), locationMode: getLocationModeInfo()]
} else {
device = [name: it.displayName, id: it.id, status:it.status, deviceType:deviceType, manufacturer:it.manufacturerName, model:it.modelName, attributes: deviceAttributeList(it, deviceType)]
}
log.debug "getDevice, return: ${device}"
return device
}
@@ -350,9 +451,6 @@ private getDeviceType(device) {
}
}
break
case "contact sensor":
deviceType = "contactSensor"
return deviceType
case "garageDoorControl":
deviceType = "garageDoor"
return deviceType
@@ -362,17 +460,15 @@ private getDeviceType(device) {
case "video camera":
deviceType = "camera"
return deviceType
case "motion sensor":
deviceType = "motionSensor"
return deviceType
case "presence sensor":
deviceType = "presenceSensor"
return deviceType
case "thermostat":
deviceType = "thermostat"
return deviceType
case "acceleration sensor":
case "contact sensor":
case "motion sensor":
case "presence sensor":
case "water sensor":
deviceType = "waterSensor"
deviceType = "genericSensor"
return deviceType
default:
break
@@ -387,14 +483,33 @@ private findDevice(deviceId) {
}
//Return a list of device attributes
private deviceAttributeList(device) {
device.supportedAttributes.collectEntries { attribute->
private deviceAttributeList(device, deviceType) {
def attributeList = [:]
def allAttributes = device.supportedAttributes
allAttributes.each { attribute ->
try {
[ (attribute.name): device.currentValue(attribute.name) ]
def currentState = device.currentState(attribute.name)
if(currentState != null ){
switch(attribute.name){
case 'temperature':
attributeList.putAll([ (attribute.name): currentState.value, 'temperatureScale':location.temperatureScale ])
break;
default:
attributeList.putAll([(attribute.name): currentState.value ])
break;
}
if( deviceType == "genericSensor" ){
def key = attribute.name + "_lastUpdated"
attributeList.putAll([ (key): currentState.isoDate ])
}
} else {
attributeList.putAll([ (attribute.name): null ]);
}
} catch(e) {
[ (attribute.name): null ]
attributeList.putAll([ (attribute.name): null ]);
}
}
return attributeList
}
//Map device command and value.

View File

@@ -73,7 +73,7 @@ def bridgeDiscovery(params = [:]) {
}
ssdpSubscribe()
log.trace "bridgeRefreshCount: $bridgeRefreshCount"
//bridge discovery request every 15 //25 seconds
if ((bridgeRefreshCount % 5) == 0) {
discoverBridges()
@@ -207,6 +207,7 @@ def bulbDiscovery() {
}
private discoverBridges() {
log.trace "Sending Hue Discovery message to the hub"
sendHubCommand(new physicalgraph.device.HubAction("lan discovery urn:schemas-upnp-org:device:basic:1", physicalgraph.device.Protocol.LAN))
}

View File

@@ -0,0 +1,713 @@
definition(
name: "stage.app.home.ai",
namespace: "stage.app.home.ai",
author: "Eric Greer",
description: "SmartThings SmartApp for stage.app.home.ai.",
category: "Fun & Social",
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"
)
// These are preferences displayed in the smart phone app
preferences {
// we need a settings section to enable subscriptions
section("Pick which devices home.ai will help you automate:"){
input "motion", "capability.motionSensor", title: "Choose motion sensors", required: false, multiple: true
input "contact", "capability.contactSensor", title: "Choose contact sensors", required: false, multiple: true
input "lightswitch", "capability.switch", title: "Choose normal power switches", required: false, multiple: true
input "lightswitchlevel", "capability.switchLevel", title: "Choose dimmer power switches", required: false, multiple: true
input "presence", "capability.presenceSensor", title: "Choose presence sensors", required: false, multiple: true
input "tempSensor", "capability.temperatureMeasurement", title: "Choose temperature sensors", required: false, multiple: true
input "humidity", "capability.relativeHumidityMeasurement", title: "Choose humidity sensors", required: false, multiple: true
input "waterSensor", "capability.waterSensor", title: "Choose water sensors", required: false, multiple: true
input "lock", "capability.lock", title: "Pick Door Locks", required: false, multiple: true
input "garagedoor", "capability.garageDoorControl", title: "Pick garage doors", required: false, multiple: true
input "touchsensor", "capability.touchSensor", title: "Pick touch sensors", required: false, multiple: true
input "speechparser", "capability.speechRecognition", title: "Pick speech recognizers", required: false, multiple: true
input "soundsensor", "capability.soundSensor", title: "Pick sound sensors", required: false, multiple: true
input "smokedetector", "capability.smokeDetector", title: "Pick smoke detectors", required: false, multiple: true
input "sleepsensor", "capability.sleepSensor", title: "Pick sleep sensors", required: false, multiple: true
input "carbonsensor", "capability.carbonMonoxideDetector", title: "Pick carbon monoxide detectors", required: false, multiple: true
input "button", "capability.button", title: "Pick buttons", required: false, multiple: true
input "beacon", "capability.beacon", title: "Pick beacons", required: false, multiple: true
input "alarm", "capability.alarm", title: "Pick alarms", required: false, multiple: true
input "thermostat", "capability.thermostat", title: "Pick thermostats", required: false, multiple: true
input "voltage", "capability.voltageMeasurement", title: "Pick voltage sensors", required: false, multiple: true
input "windowshade", "capability.windowShade", title: "Pick window shades", required: false, multiple: true
input "powermeter", "capability.powerMeter", title: "Pick power meters", required: false, multiple: true
}
}
// vlaues for security system are 'away', 'stay', or 'off'
// off security
def offSecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "off",
displayed: false,
isStateChange: true
)
}
// stay security
def staySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "stay",
displayed: false,
isStateChange: true
)
}
// away security
def awaySecurity() {
sendLocationEvent(
name: "alarmSystemStatus",
value: "away",
displayed: false,
isStateChange: true
)
}
// sets window shade open temperature
def setWindowShadeOpen() {
def deviceID = params.deviceID
log.debug("setWindowShadeOpen command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets window shade close temperature
def setWindowShadeClosed() {
def deviceID = params.deviceID
log.debug("setWindowShadeClosed command recieved ${deviceID}")
windowshade.each {
if (it.id == deviceID) {
log.debug("Operating window shade because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting window shade because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat heating temperature
def setThermostatHeatTemp() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setHeatingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat cooling temperature
def setThermostatCoolTemp() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setCoolingSetpoint(params.temp)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat off
def setThermostatOff() {
def deviceID = params.deviceID
log.debug("setThermostatOff command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to heat
def setThermostatHeat() {
def deviceID = params.deviceID
log.debug("setThermostatHeat command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.heat()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat to cool
def setThermostatCool() {
def deviceID = params.deviceID
log.debug("setThermostatCool command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.cool()
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat mode
def setThermostatMode() {
def deviceID = params.deviceID
log.debug("setThermostatMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sets thermostat fan mode
def setThermostatFanMode() {
def deviceID = params.deviceID
log.debug("setThermostatFanMode command recieved ${deviceID}")
thermostat.each {
if (it.id == deviceID) {
log.debug("Operating thermostat because it is the one specified: ${deviceID}");
it.setThermostatFanMode(params.mode)
} else {
log.debug("NOT operting thermostat because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm strobe
def strobeAlarm() {
def deviceID = params.deviceID
log.debug("Alarm strobe command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.strobe()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// sends an alarm siren
def sirenAlarm() {
def deviceID = params.deviceID
log.debug("Alarm siren command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.siren()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// disables an alarm siren
def silenceAlarm() {
def deviceID = params.deviceID
log.debug("Alarm silence command recieved ${deviceID}")
alarm.each {
if (it.id == deviceID) {
log.debug("Operating alarm because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("NOT operting alarm because it is not the one specified: ${deviceID}");
}
}
}
// opens a garage door
def openGarage() {
def deviceID = params.deviceID
log.debug("Open Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.open()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// closes a garage door
def closeGarage() {
def deviceID = params.deviceID
log.debug("Close Garage command recieved ${deviceID}")
garagedoor.each {
if (it.id == deviceID) {
log.debug("Operating garage door because it is the one specified: ${deviceID}");
it.close()
} else {
log.debug("NOT operting garage door device because it is not the one specified: ${deviceID}");
}
}
}
// lock locks a door lock
def lockDoor() {
def deviceID = params.deviceID
log.debug("Lock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.lock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// unlock unlocks a door lock
def unlockDoor() {
def deviceID = params.deviceID
log.debug("Unlock command recieved ${deviceID}")
lock.each {
if (it.id == deviceID) {
log.debug("Operating lock device because it is the one specified: ${deviceID}");
it.unlock()
} else {
log.debug("NOT operting lock device because it is not the one specified: ${deviceID}");
}
}
}
// turns on a wall switch as instructed from the homeai webservice
def switchOn() {
def deviceID = params.deviceID
log.debug("Switch on command recieved ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.on()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// turns off a wall switch as instructed from the homeai webservice
def switchOff() {
def deviceID = params.deviceID
log.debug("Switch off desired for ${deviceID}")
lightswitch.each {
if (it.id == deviceID) {
log.debug("Operating switch device because it is the one specified: ${deviceID}");
it.off()
} else {
log.debug("Skipping switch device because it is not the one specified: ${deviceID}");
}
}
}
// fetch the id of this smartthings hub
def hubId() {
log.debug("hub id requested.")
def response = [hubId: location.hubs.id[0]]
}
// This handles requests for device inventories
def inventory() {
def response = []
lightswitch.each {
response << [name: it.displayName, value: it.currentValue("switch"), deviceId: it.id, type: "lightSwitch"]
}
contact.each {
response << [name: it.displayName, value: it.currentValue("contact"), deviceId: it.id, type: "contact"]
}
motion.each {
response << [name: it.displayName, value: it.currentValue("motion"), deviceId: it.id, type: "motion"]
}
presence.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "presence"]
}
// removed until dual device functions are supported on the backend
//tempSensor.each {
// response << [name: it.displayName, value: it.currentValue("temperature"), deviceId: it.id, type: "tempSensor"]
//}
//humidity.each {
// response << [name: it.displayName, value: it.currentValue("humidity"), deviceId: it.id, type: "humiditySensor"]
//}
waterSensor.each {
response << [name: it.displayName, value: it.currentValue("water"), deviceId: it.id, type: "waterSensor"]
}
lock.each {
response << [name: it.displayName, value: it.currentValue("lock"), deviceId: it.id, type: "lock"]
}
garagedoor.each {
response << [name: it.displayName, value: it.currentValue("door"), deviceId: it.id, type: "garagedoor"]
}
touchsensor.each {
response << [name: it.displayName, value: it.currentValue("touch"), deviceId: it.id, type: "touchsensor"]
}
speechparser.each {
response << [name: it.displayName, value: it.currentValue("phraseSpoken"), deviceId: it.id, type: "speechparser"]
}
soundsensor.each {
response << [name: it.displayName, value: it.currentValue("sound"), deviceId: it.id, type: "sound"]
}
smokedetector.each {
response << [name: it.displayName, value: it.currentValue("smoke"), deviceId: it.id, type: "smoke"]
}
sleepsensor.each {
response << [name: it.displayName, value: it.currentValue("sleeping"), deviceId: it.id, type: "sleepsensor"]
}
carbonsensor.each {
response << [name: it.displayName, value: it.currentValue("carbonMonoxide"), deviceId: it.id, type: "carbonsensor"]
}
button.each {
response << [name: it.displayName, value: it.currentValue("button"), deviceId: it.id, type: "button"]
}
beacon.each {
response << [name: it.displayName, value: it.currentValue("presence"), deviceId: it.id, type: "beacon"]
}
alarm.each {
response << [name: it.displayName, value: it.currentValue("alarm"), deviceId: it.id, type: "alarm"]
}
thermostat.each {
response << [name: it.displayName, value: it.currentValue("thermostatMode"), deviceId: it.id, type: "thermostat"]
}
voltage.each {
response << [name: it.displayName, value: it.currentValue("voltage"), deviceId: it.id, type: "voltage"]
}
windowshade.each {
response << [name: it.displayName, value: it.currentValue("windowShade"), deviceId: it.id, type: "windowshade"]
}
powermeter.each {
response << [name: it.displayName, value: it.currentValue("power"), deviceId: it.id, type: "powermeter"]
}
lightswitchlevel.each {
response << [name: it.displayName, value: it.currentValue("level"), deviceId: it.id, type: "lightswitchlevel"]
}
log.debug("Inventory request processed. Response: " + response)
return response
}
// After the user hits the 'install' button in the mobile app
def installed() {
initialize()
}
// After app settings are changed. All subscriptions are wiped before this is invoked by smartthings.
def updated() {
unsubscribe()
initialize()
}
// This appears to be what the tutorials meant to use in the examples
def initialize() {
// SHM subscription
// evt.value will be "off", "stay", or "away"
subscribe(location, "alarmSystemStatus", eventForwarder)
// motion sensor subscription
subscribe(motion, "motion", eventForwarder)
// Contact sensor subscription
subscribe(contact, "contact", eventForwarder)
// power plug subscription
subscribe(lightswitch, "switch", eventForwarder)
// presence sensor subscription
subscribe(presence, "presence", eventForwarder)
// temperature sensor subscription
subscribe(tempSensor, "temperature", eventForwarder)
// water sensor subscription
subscribe(waterSensor, "water", eventForwarder)
// humidity sensor subscription
subscribe(humidity, "humidity", eventForwarder)
// lock subscription
subscribe(lock, "lock", eventForwarder)
// garage door subscription
subscribe(garagedoor, "garagedoor", eventForwarder)
// touch sensor subscription
subscribe(touchsensor, "touchsensor", eventForwarder)
// speech parser subscription
subscribe(speechparser, "phraseSpoken", eventForwarder)
// sound sensor subscription
subscribe(soundsensor, "sound", eventForwarder)
// smoke detector subscription
subscribe(smokedetector, "smoke", eventForwarder)
// sleep sensor subscription
subscribe(sleepsensor, "sleeping", eventForwarder)
// carbon monoxide sensor subscription
subscribe(carbonsensor, "carbonMonoxide", eventForwarder)
// button subscription
subscribe(button, "button", eventForwarder)
// beacon subscription
subscribe(beacon, "presence", eventForwarder)
// alarm subscription
subscribe(alarm, "alarm", eventForwarder)
// thermostat subscriptions
subscribe(thermostat, "temperature", eventForwarder)
subscribe(thermostat, "heatingSetpoint", eventForwarder)
subscribe(thermostat, "coolingSetpoint", eventForwarder)
subscribe(thermostat, "thermostatSetpoint", eventForwarder)
subscribe(thermostat, "thermostatMode", eventForwarder)
subscribe(thermostat, "thermostatFanMode", eventForwarder)
subscribe(thermostat, "thermostatOperatingState", eventForwarder)
// voltage subscription
subscribe(voltage, "voltage", eventForwarder)
// window shade subscription
subscribe(windowshade, "windowShade", eventForwarder)
// shm events
subscribe(location, "alarmSystemStatus", shmEventForwarder)
// power meter subscription
subscribe(powermeter, "power", eventForwarder)
// level switch (dimmer switch)
subscribe(lightswitchlevel, "level", eventForwarder)
}
def shmEventForwarder(evt) {
// evt.value will be "off", "stay", or "away"
log.debug("FORWARDING SHM CHANGE" + evt.value + " " + evt.hub.id)
def deviceState = evt.value
def deviceId = "smarthomemonitor"
def hubId = hubId()
def params = [
uri: "https://stage.app.home.ai",
path: "/smartThingsPostback/shmStateChange/${hubId}/${deviceId}/${deviceState}"
]
log.info(params)
httpGet(params)
}
// This is used to forward events to the home.ai webservice
def eventForwarder(evt) {
def hubId = location.hubs.id[0]
log.debug(params.uri + " " + params.path)
log.debug("FORWARDING EVENT" + evt.deviceId + " " + evt.value + " " + hubId)
def deviceId = evt.deviceId
def deviceState = evt.value
def params = [
uri: "https://stage.app.home.ai",
path: "/smartThingsPostback/stateChange/${hubId}/${deviceId}/${deviceState}"
]
log.info(params)
httpGet(params)
}
// Mappings that serve web requests against our smart app
mappings {
path("/inventory") {
action: [
GET: "inventory"
]
}
path("/hubId") {
action: [
GET: "hubId"
]
}
path("/switchOn/:deviceID") {
action: [
GET: "switchOn"
]
}
path("/switchOff/:deviceID") {
action: [
GET: "switchOff"
]
}
path("/lock/:deviceID") {
action: [
GET: "lockDoor"
]
}
path("/unlock/:deviceID") {
action: [
GET: "unlockDoor"
]
}
path("/opengarage/:deviceID") {
action: [
GET: "openGarage"
]
}
path("/closegarage/:deviceID") {
action: [
GET: "closeGarage"
]
}
path("/strobeAlarm/:deviceID") {
action: [
GET: "strobeAlarm"
]
}
path("/sirenAlarm/:deviceID") {
action: [
GET: "sirenAlarm"
]
}
path("/silenceAlarm/:deviceID") {
action: [
GET: "silenceAlarm"
]
}
path("/setThermostatHeatTemp/:deviceID/:temp") {
action: [
GET: "setThermostatHeatTemp"
]
}
path("/setThermostatCoolTemp/:deviceID/:temp") {
action: [
GET: "setThermostatCoolTemp"
]
}
path("/setThermostatHeat/:deviceID") {
action: [
GET: "setThermostatHeat"
]
}
path("/setThermostatCool/:deviceID") {
action: [
GET: "setThermostatCool"
]
}
path("/setThermostatMode/:deviceID/:mode") {
action: [
GET: "setThermostatMode"
]
}
path("/setThermostatFanMode/:deviceID/:mode") {
action: [
GET: "setThermostatFanMode"
]
}
path("/closeWindowShade/:deviceID") {
action: [
GET: "setWindowShadeClosed"
]
}
path("/openWindowShade/:deviceID") {
action: [
GET: "setWindowShadeOpen"
]
}
path("/awaySecurity") {
action: [
GET: "awaySecurity"
]
}
path("/staySecurity") {
action: [
GET: "staySecurity"
]
}
path("/offSecurity") {
action: [
GET: "offSecurity"
]
}
}