Compare commits

..

1 Commits

Author SHA1 Message Date
Justin Waymire
ae3a01a7f7 MSA-1899: Trane XL624 Thermostat with humidity display, up/down buttons instead of slider. 2017-04-17 17:02:01 -07:00
88 changed files with 1087 additions and 2485 deletions

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,44 +0,0 @@
# Express Controls EZMultiPli
Works with:
* [Express Controls EZMultiPli](https://www.smartthings.com/works-with-smartthings/)
## Table of contents
* [Release Notes](#release-notes)
* [Capabilities](#capabilities)
* [Troubleshooting](#troubleshooting)
## Release Notes
* **2017-04-19** - _dkirker_ - Update default config values in config value range check functions, use lux if lum option is null, fix NullPointerException on initial pairing when color data has not been set (and set the default color data!)
* **2017-04-10** - _DrZwave_ (with help from Donald 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
## Capabilities
* **Actuator** - represents that a Device has commands
* **Sensor** - detects sensor events
* **Motion Sensor** - can detect motion
* **Temperature Measurement** - defines device measures current temperature
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
* **Switch** - can detect state (possible values: on/off)
* **Color Control** - represents that the color attributes of a device can be controlled (hue, saturation, color value
* **Configuration** - configure() command called when device is installed or device preferences updated
* **Refresh** - refresh() command for status updates
## Troubleshooting

View File

@@ -1,405 +0,0 @@
// 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
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:"#00A0DC", 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:"#00A0DC"
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:"#00A0DC"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
}
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: "#153591"], // blue=cold
[value: 65, color: "#44b621"], // green
[value: 70, color: "#44b621"], // green
[value: 75, color: "#f1d801"], // yellow
[value: 80, color: "#f1d801"], // yellow
[value: 85, color: "#f1d801"], // yellow
[value: 90, color: "#d04e00"], // red
[value: 95, color: "#bc2323"] // 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 == 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 == 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) {
// The EZMultiPli sets the color back to #ffffff on "off" or at init, so update the ST device to reflect this.
if (device.latestState("color") == null || (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=6
}
def liteTempVal = value.toInteger()
switch (liteTempVal) {
case { it < 0 }:
return 6 // 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=2
}
def onTimeVal = value.toInteger()
switch (onTimeVal) {
case { it < 0 }:
return 2 // 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,268 +0,0 @@
/**
*
* Inovelli 2-Channel Smart Plug
*
* github: Eric Maycock (erocm123)
* Date: 2017-04-27
* Copyright Eric Maycock
*
* Includes all configuration parameters and ease of advanced configuration.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition(name: "Inovelli 2-Channel Smart Plug", namespace: "erocm123", author: "Eric Maycock") {
capability "Actuator"
capability "Sensor"
capability "Switch"
capability "Polling"
capability "Refresh"
capability "Health Check"
fingerprint manufacturer: "015D", prod: "0221", model: "251C", deviceJoinName: "Show Home 2-Channel Smart Plug"
fingerprint manufacturer: "0312", prod: "B221", model: "251C", deviceJoinName: "Inovelli 2-Channel Smart Plug"
}
simulator {}
preferences {}
tiles {
multiAttributeTile(name: "switch", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState: "turningOff"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh"
}
main(["switch"])
details(["switch",
childDeviceTiles("all"), "refresh"
])
}
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description)
if (cmd) {
result += zwaveEvent(cmd)
logging("Parsed ${cmd} to ${result.inspect()}", 1)
} else {
logging("Non-parsed event: ${description}", 2)
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, ep = null) {
logging("BasicReport ${cmd} - ep ${ep}", 2)
if (ep) {
def event
childDevices.each {
childDevice ->
if (childDevice.deviceNetworkId == "$device.deviceNetworkId-ep$ep") {
childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
}
}
if (cmd.value) {
event = [createEvent([name: "switch", value: "on"])]
} else {
def allOff = true
childDevices.each {
n ->
if (n.currentState("switch").value != "off") allOff = false
}
if (allOff) {
event = [createEvent([name: "switch", value: "off"])]
} else {
event = [createEvent([name: "switch", value: "on"])]
}
}
return event
}
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
logging("BasicSet ${cmd}", 2)
def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
def cmds = []
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
return [result, response(commands(cmds))] // returns the result of reponse()
}
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd, ep = null) {
logging("SwitchBinaryReport ${cmd} - ep ${ep}", 2)
if (ep) {
def event
def childDevice = childDevices.find {
it.deviceNetworkId == "$device.deviceNetworkId-ep$ep"
}
if (childDevice) childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
if (cmd.value) {
event = [createEvent([name: "switch", value: "on"])]
} else {
def allOff = true
childDevices.each {
n->
if (n.currentState("switch").value != "off") allOff = false
}
if (allOff) {
event = [createEvent([name: "switch", value: "off"])]
} else {
event = [createEvent([name: "switch", value: "on"])]
}
}
return event
} else {
def result = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
def cmds = []
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 1)
cmds << encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
return [result, response(commands(cmds))] // returns the result of reponse()
}
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
logging("MultiChannelCmdEncap ${cmd}", 2)
def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x25: 1, 0x20: 1])
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
}
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
logging("ManufacturerSpecificReport ${cmd}", 2)
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
logging("msr: $msr", 2)
updateDataValue("MSR", msr)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// This will capture any commands not handled by other instances of zwaveEvent
// and is recommended for development so you can see every command the device sends
logging("Unhandled Event: ${cmd}", 2)
}
def on() {
logging("on()", 1)
commands([
zwave.switchAllV1.switchAllOn(),
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
])
}
def off() {
logging("off()", 1)
commands([
zwave.switchAllV1.switchAllOff(),
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2)
])
}
void childOn(String dni) {
logging("childOn($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0xFF), channelNumber(dni))))
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
void childOff(String dni) {
logging("childOff($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.basicV1.basicSet(value: 0x00), channelNumber(dni))))
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
void childRefresh(String dni) {
logging("childRefresh($dni)", 1)
def cmds = []
cmds << new physicalgraph.device.HubAction(command(encap(zwave.switchBinaryV1.switchBinaryGet(), channelNumber(dni))))
sendHubCommand(cmds, 1000)
}
def poll() {
logging("poll()", 1)
commands([
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
])
}
def refresh() {
logging("refresh()", 1)
commands([
encap(zwave.switchBinaryV1.switchBinaryGet(), 1),
encap(zwave.switchBinaryV1.switchBinaryGet(), 2),
])
}
def ping() {
logging("ping()", 1)
refresh()
}
def installed() {
logging("installed()", 1)
command(zwave.manufacturerSpecificV1.manufacturerSpecificGet())
createChildDevices()
}
def updated() {
logging("updated()", 1)
if (!childDevices) {
createChildDevices()
} else if (device.label != state.oldLabel) {
childDevices.each {
if (it.label == "${state.oldLabel} (CH${channelNumber(it.deviceNetworkId)})") {
def newLabel = "${device.displayName} (CH${channelNumber(it.deviceNetworkId)})"
it.setLabel(newLabel)
}
}
state.oldLabel = device.label
}
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "needUpdate", value: device.currentValue("needUpdate"), displayed: false, isStateChange: true)
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
logging("${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd2Integer(cmd.configurationValue)}'", 2)
}
private encap(cmd, endpoint) {
if (endpoint) {
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint: endpoint).encapsulate(cmd)
} else {
cmd
}
}
private command(physicalgraph.zwave.Command cmd) {
if (state.sec) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}
private commands(commands, delay = 1000) {
delayBetween(commands.collect {
command(it)
}, delay)
}
private channelNumber(String dni) {
dni.split("-ep")[-1] as Integer
}
private void createChildDevices() {
state.oldLabel = device.label
for (i in 1..2) {
addChildDevice("Switch Child Device", "${device.deviceNetworkId}-ep${i}", null, [completedSetup: true, label: "${device.displayName} (CH${i})",
isComponent: true, componentName: "ep$i", componentLabel: "Channel $i"
])
}
}
private def logging(message, level) {
if (logLevel != "0") {
switch (logLevel) {
case "1":
if (level > 1) log.debug "$message"
break
case "99":
log.debug "$message"
break
}
}
}

View File

@@ -1,49 +0,0 @@
/**
* Switch Child Device
*
* Copyright 2017 Eric Maycock
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Switch Child Device", namespace: "erocm123", author: "Eric Maycock") {
capability "Switch"
capability "Actuator"
capability "Sensor"
capability "Refresh"
}
tiles {
multiAttributeTile(name:"switch", type: "lighting", width: 3, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"turningOn"
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
}
}
void on() {
parent.childOn(device.deviceNetworkId)
}
void off() {
parent.childOff(device.deviceNetworkId)
}
void refresh() {
parent.childRefresh(device.deviceNetworkId)
}

View File

@@ -39,8 +39,8 @@ metadata {
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC") attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC") attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
} }
} }

View File

@@ -37,8 +37,8 @@ metadata {
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC") attributeState("active", label:'tamper active', backgroundColor:"#53a7c0")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC") attributeState("inactive", label:'tamper inactive', backgroundColor:"#ffffff")
} }
} }

View File

@@ -34,8 +34,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") { tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc") attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC") attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {

View File

@@ -95,12 +95,12 @@ metadata {
multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL") multiAttributeTile(name:"doorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
{ {
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent" attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", nextState:"Sent"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC" , nextState:"Sent" attributeState "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC" attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff", nextState:"Sent" attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#79b821", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff" attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent" attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent" attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent" attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e" attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
} }
@@ -135,13 +135,13 @@ metadata {
} }
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){ standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#00A0DC", nextState:"Sent" state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#79b821", nextState:"Sent"
state "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent" state "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e" state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
} }
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){ standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC", nextState:"Sent" state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821", nextState:"Sent"
state "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent" state "off", label: 'Auto', action:"autoOpenOn", icon: "st.doors.garage.garage-opening", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e" state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
} }
@@ -189,13 +189,13 @@ metadata {
standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) { standardTile("aux1", "device.Aux1", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent" state "off", label:'Aux 1', action:"Aux1On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent" state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e" state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
} }
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) { standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent" state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent" state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e" state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,33 +0,0 @@
# Osotech Plant Link
Cloud Execution
Works with:
* [OSO Technologies PlantLink Soil Moisture Sensor](https://www.smartthings.com/works-with-smartthings/oso-technologies/oso-technologies-plantlink-soil-moisture-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Plant Link sensor is a ZigBee sleepy device and checks in every 15 minutes.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [OSO Technologies PlantLink Soil Moisture Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206868986-PlantLink-Soil-Moisture-Sensor)

View File

@@ -24,7 +24,6 @@ import groovy.json.JsonBuilder
metadata { metadata {
definition (name: "PlantLink", namespace: "OsoTech", author: "Oso Technologies") { definition (name: "PlantLink", namespace: "OsoTech", author: "Oso Technologies") {
capability "Sensor" capability "Sensor"
capability "Health Check"
command "setStatusIcon" command "setStatusIcon"
command "setPlantFuelLevel" command "setPlantFuelLevel"
@@ -71,16 +70,6 @@ metadata {
} }
} }
def updated() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def installed() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def setStatusIcon(value){ def setStatusIcon(value){
def status = '' def status = ''
switch (value) { switch (value) {
@@ -172,4 +161,4 @@ def parseDescriptionAsMap(description) {
map += [] map += []
} }
} }
} }

View File

@@ -21,7 +21,6 @@ metadata {
capability "Battery" capability "Battery"
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85" fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeon Panic Button"
} }
simulator { simulator {
@@ -131,12 +130,5 @@ def updated() {
} }
def initialize() { def initialize() {
def zwMap = getZwaveInfo() sendEvent(name: "numberOfButtons", value: 4)
def buttons = 4 // Default for Key Fob
// Only one button for Aeon Panic Button
if (zwMap && zwMap.mfr == "0086" && zwMap.prod == "0001" && zwMap.model == "0026") {
buttons = 1
}
sendEvent(name: "numberOfButtons", value: buttons)
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,43 +0,0 @@
# Aeon Multisensor 6
Cloud Execution
Works with:
* [Aeon Labs MultiSensor 6](https://www.smartthings.com/products/aeon-labs-multisensor-6)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Motion Sensor** - can detect motion
* **Temperature Measurement** - defines device measures current temperature
* **Relative Humidity Measurement** - allow reading the relative humidity from devices that support it
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
* **Ultraviolet Index** - gives the ability to get the ultraviolet index from devices that report it
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Labs MultiSensor 6 is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Aeon Labs MultiSensor 6 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226)

View File

@@ -22,7 +22,6 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
attribute "tamper", "enum", ["detected", "clear"] attribute "tamper", "enum", ["detected", "clear"]
attribute "batteryStatus", "string" attribute "batteryStatus", "string"
@@ -30,7 +29,6 @@ metadata {
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A" fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A" fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
fingerprint mfr:"0086", prod:"0102", model:"0064", deviceJoinName: "Aeon Labs MultiSensor 6"
} }
simulator { simulator {
@@ -105,7 +103,7 @@ metadata {
} }
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) { valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "illuminance", label:'${currentValue} lux', unit:"" state "illuminance", label:'${currentValue} ${unit}', unit:"lux"
} }
valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) { valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) {
@@ -129,14 +127,7 @@ metadata {
} }
} }
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() { def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
log.debug "Updated with settings: ${settings}" log.debug "Updated with settings: ${settings}"
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}" log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
@@ -335,13 +326,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false) createEvent(descriptionText: cmd.toString(), isStateChange: false)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() { def configure() {
// This sensor joins as a secure device if you double-click the button to include it // This sensor joins as a secure device if you double-click the button to include it
log.debug "${device.displayName} is configuring its settings" log.debug "${device.displayName} is configuring its settings"
@@ -426,4 +410,4 @@ private command(physicalgraph.zwave.Command cmd) {
private commands(commands, delay=200) { private commands(commands, delay=200) {
log.info "sending commands: ${commands}" log.info "sending commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay) delayBetween(commands.collect{ command(it) }, delay)
} }

View File

@@ -22,6 +22,8 @@ metadata {
capability "Battery" capability "Battery"
capability "Health Check" capability "Health Check"
command "configureAfterSecure"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A" fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)" fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
} }
@@ -84,17 +86,17 @@ metadata {
state "humidity", label:'${currentValue}% humidity', unit:"" state "humidity", label:'${currentValue}% humidity', unit:""
} }
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) { valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} lux', unit:"" state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""
} }
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { standardTile("configureAfterSecure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label:'', action:"configure", icon:"st.secondary.configure" state "configure", label:'', action:"configureAfterSecure", icon:"st.secondary.configure"
} }
main(["motion", "temperature", "humidity", "illuminance"]) main(["motion", "temperature", "humidity", "illuminance"])
details(["motion", "temperature", "humidity", "illuminance", "battery", "configure"]) details(["motion", "temperature", "humidity", "illuminance", "battery", "configureAfterSecure"])
} }
} }
@@ -129,8 +131,8 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
if (!isConfigured()) { if (!isConfigured()) {
// we're still in the process of configuring a newly joined device // we're still in the process of configuring a newly joined device
log.debug("not sending wakeUpNoMoreInformation yet: late configure") log.debug("not sending wakeUpNoMoreInformation yet")
result += response(configure()) result += response(configureAfterSecure())
} else { } else {
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation()) result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
} }
@@ -148,6 +150,11 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
} }
} }
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
// log.debug "Received SecurityCommandsSupportedReport"
response(configureAfterSecure())
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ] def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) { if (cmd.batteryLevel == 0xFF) {
@@ -219,6 +226,36 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false) createEvent(descriptionText: cmd.toString(), isStateChange: false)
} }
def configureAfterSecure() {
// log.debug "configureAfterSecure()"
def request = [
// send temperature, humidity, and illuminance every 8 minutes
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32),
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60),
// send battery every 20 hours
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1),
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60),
// send no-motion report 60 seconds after motion stops
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60),
// send binary sensor report instead of basic set for motion
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2),
// disable notification-style motion events
zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0),
zwave.batteryV1.batteryGet(),
zwave.sensorBinaryV2.sensorBinaryGet(sensorType:0x0C)
]
setConfigured()
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
}
/** /**
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
@@ -228,36 +265,7 @@ def ping() {
def configure() { def configure() {
// log.debug "configure()" // log.debug "configure()"
def request = [] //["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())
// send temperature, humidity, and illuminance every 8 minutes
request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32)
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60)
// send battery every 20 hours
request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1)
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60)
// send no-motion report 60 seconds after motion stops
request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60)
// send binary sensor report instead of basic set for motion
request << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2)
// Turn on the Multisensor Gen5 PIR sensor
request << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: 1)
// disable notification-style motion events
request << zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0)
request << zwave.batteryV1.batteryGet()
request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity
setConfigured()
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
} }
private setConfigured() { private setConfigured() {
@@ -274,4 +282,5 @@ private secure(physicalgraph.zwave.Command cmd) {
private secureSequence(commands, delay=200) { private secureSequence(commands, delay=200) {
delayBetween(commands.collect{ secure(it) }, delay) delayBetween(commands.collect{ secure(it) }, delay)
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,48 +0,0 @@
# Aeon Multisensor
Cloud Execution
Works with:
* [Aeotec MultiSensor (DSB05-ZWUS)](https://www.smartthings.com/products/aeotec-multisensor-5)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Motion Sensor** - can detect motion
* **Temperature Measurement** - defines device measures current temperature
* **Relative Humidity Measurement** - allow reading the relative humidity from devices that support it
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Labs MultiSensor is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Battery Specification
Four AAA batteries are required.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Aeon MultiSensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/206157226-How-to-connect-Aeon-Labs-MultiSensors)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Illuminance Measurement" capability "Illuminance Measurement"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86" fingerprint deviceId: "0x2001", inClusters: "0x30,0x31,0x80,0x84,0x70,0x85,0x72,0x86"
} }
@@ -80,7 +79,7 @@ metadata {
state "humidity", label:'${currentValue}% humidity', unit:"" state "humidity", label:'${currentValue}% humidity', unit:""
} }
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) { valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} lux', unit:"" state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""
@@ -94,16 +93,6 @@ metadata {
} }
} }
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) def parse(String description)
{ {
@@ -190,13 +179,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
[:] [:]
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() { def configure() {
delayBetween([ delayBetween([
// send binary sensor report instead of basic set for motion // send binary sensor report instead of basic set for motion
@@ -211,4 +193,4 @@ def configure() {
// set data reporting period to 5 minutes // set data reporting period to 5 minutes
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300).format() zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300).format()
]) ])
} }

View File

@@ -16,7 +16,7 @@
* Date: 2014-07-15 * Date: 2014-07-15
*/ */
metadata { metadata {
definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") { definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Alarm" capability "Alarm"
capability "Switch" capability "Switch"
@@ -61,8 +61,6 @@ metadata {
def installed() { def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval) // Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(secure(zwave.basicV1.basicGet()))
} }
def updated() { def updated() {
@@ -165,4 +163,4 @@ private secure(physicalgraph.zwave.Command cmd) {
* */ * */
def ping() { def ping() {
secure(zwave.basicV1.basicGet()) secure(zwave.basicV1.basicGet())
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,50 +0,0 @@
# Arrival Sensor HA (2016+ Model)
Cloud Execution
Works with:
* [Samsung SmartThings Arrival Sensor](https://support.smartthings.com/hc/en-us/articles/212417083-Samsung-SmartThings-Arrival-Sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Tone** - beep command to allow an audible tone
* **Actuator** - device has commands
* **Presence Sensor** - device tells presence with enum - {present, not present}
* **Sensor** - device has attributes
* **Battery** - defines device uses a battery
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
## Device Health
Arrival Sensor ZigBee is an untracked device. Sends broadcast of battery level every 20 seconds.
Disconnects when Hub goes OFFLINE.
## Battery
Uses 1 CR2032 Battery
* [Changing the Battery](https://support.smartthings.com/hc/en-us/articles/200907400-How-to-change-the-battery-in-the-SmartSense-Presence-Sensor-and-Samsung-SmartThings-Arrival-Sensor)
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the arrival sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
* [Samsung SmartThings Arrival Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205382134-Samsung-SmartThings-Arrival-Sensor-2015-model-)
If the arrival sensor doesn't update its status, here are a few things you can try to debug.
* [Troubleshooting: Samsung SmartThings Arrival Sensor won't update its status](https://support.smartthings.com/hc/en-us/articles/200846514-Troubleshooting-Samsung-SmartThings-Arrival-Sensor-won-t-update-its-status)

View File

@@ -1,7 +1,5 @@
import groovy.json.JsonOutput
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -21,7 +19,6 @@ metadata {
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Configuration" capability "Configuration"
capability "Health Check"
fingerprint inClusters: "0000,0001,0003,000F,0020", outClusters: "0003,0019", fingerprint inClusters: "0000,0001,0003,000F,0020", outClusters: "0003,0019",
manufacturer: "SmartThings", model: "tagv4", deviceJoinName: "Arrival Sensor" manufacturer: "SmartThings", model: "tagv4", deviceJoinName: "Arrival Sensor"
@@ -61,13 +58,8 @@ def updated() {
startTimer() startTimer()
} }
def installed() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
}
def configure() { def configure() {
def cmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.batteryConfig(20, 20, 0x01) def cmds = zigbee.batteryConfig(20, 20, 0x01)
log.debug "configure -- cmds: ${cmds}" log.debug "configure -- cmds: ${cmds}"
return cmds return cmds
} }
@@ -174,4 +166,4 @@ def checkPresenceCallback() {
if (timeSinceLastCheckin >= theCheckInterval) { if (timeSinceLastCheckin >= theCheckInterval) {
handlePresenceEvent(false) handlePresenceEvent(false)
} }
} }

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,49 +0,0 @@
# Arrival Sensor (2015 Model)
Cloud Execution
Works with:
* [Arrival Sensor](https://www.smartthings.com/products/samsung-smartthings-arrival-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Tone** - beep command to allow an audible tone
* **Actuator** - device has commands
* **Signal Strength** - device can read the strength of signal- lqi: Link Quality Indication, rssi: Received Signal Strength Indication
* **Presence Sensor** - device tells presence with enum - {present, not present}
* **Sensor** - device has attributes
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Arrival Sensor ZigBee is an untracked device. Disconnects when Hub goes OFFLINE.
## Battery
Uses 1 CR2032 Battery
* [Changing the Battery](https://support.smartthings.com/hc/en-us/articles/200907400-How-to-change-the-battery-in-the-SmartSense-Presence-Sensor-and-Samsung-SmartThings-Arrival-Sensor)
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the arrival sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
* [Samsung SmartThings Arrival Sensor Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205382134-Samsung-SmartThings-Arrival-Sensor-2015-model-)
If the arrival sensor doesn't update its status, here are a few things you can try to debug.
* [Troubleshooting: Samsung SmartThings Arrival Sensor won't update its status](https://support.smartthings.com/hc/en-us/articles/200846514-Troubleshooting-Samsung-SmartThings-Arrival-Sensor-won-t-update-its-status)

View File

@@ -1,5 +1,3 @@
import groovy.json.JsonOutput
/** /**
* Copyright 2015 SmartThings * Copyright 2015 SmartThings
* *
@@ -21,7 +19,6 @@ metadata {
capability "Presence Sensor" capability "Presence Sensor"
capability "Sensor" capability "Sensor"
capability "Battery" capability "Battery"
capability "Health Check"
fingerprint profileId: "FC01", deviceId: "019A" fingerprint profileId: "FC01", deviceId: "019A"
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003" fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003"
@@ -114,11 +111,6 @@ def beep() {
] ]
} }
def installed() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
}
def parse(String description) { def parse(String description) {
def results def results
if (isBatteryMessage(description)) { if (isBatteryMessage(description)) {

View File

@@ -9,7 +9,6 @@ metadata {
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Health Check"
attribute "thermostatFanState", "string" attribute "thermostatFanState", "string"
@@ -19,7 +18,6 @@ metadata {
command "quickSetHeat" command "quickSetHeat"
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60" fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
} }
// simulator metadata // simulator metadata
@@ -108,16 +106,6 @@ metadata {
} }
} }
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description) def parse(String description)
{ {
def result = [] def result = []
@@ -451,14 +439,6 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
], delay) ], delay)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
refresh()
}
def configure() { def configure() {
delayBetween([ delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(), zwave.thermostatModeV2.thermostatModeSupportedGet().format(),

View File

@@ -12,7 +12,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") { definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
capability "Switch Level" capability "Switch Level"
capability "Actuator" capability "Actuator"
capability "Indicator" capability "Indicator"
@@ -23,9 +23,9 @@ metadata {
capability "Health Check" capability "Health Check"
capability "Light" capability "Light"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall 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:"4944", deviceJoinName: "GE In-Wall Smart Dimmer "
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In 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" fingerprint mfr:"0063", prod:"4944", model:"3034", deviceJoinName: "GE In-Wall Smart Fan Control"
} }

View File

@@ -1,163 +0,0 @@
/**
* 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
* Everspring ST815 Illuminance Sensor
*
* Author: SmartThings
* Date: 2017-3-4
*/
metadata {
definition (name: "Everspring Illuminance Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Illuminance Measurement"
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0060", prod:"0007", model:"0001"
}
simulator {
for( int i = 0; i <= 100; i += 20 ) {
status "illuminace ${i} lux": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 3, scale: 1).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
batteryLevel: i).incomingMessage()
}
status "wakeup": "command: 8407, payload: "
}
tiles(scale: 2) {
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 32, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 98, color: "#bc2323"]
]
}
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main( ["temperature", "humidity"] )
details( ["temperature", "humidity", "battery"] )
}
}
def updated() {
state.configured = false
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
if (cmd) {
result = zwaveEvent(cmd)
}
if (result instanceof List) {
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
} else {
log.debug "Parsed '$description' to ${result}"
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def result = [
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
]
if (state.configured) {
result << response(zwave.batteryV1.batteryGet())
} else {
result << response(configure())
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
def map = [:]
switch( cmd.sensorType ) {
case 3:
// luminance
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
map.name = "illuminance"
break;
}
return createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
def response_cmds = []
if (!currentTemperature) {
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
response_cmds << "delay 1000"
}
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
return [createEvent(map), response(response_cmds)]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug "Unhandled: ${cmd.toString()}"
return [:]
}
def configure() {
state.configured = true
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
delayBetween([
// Auto report time interval in minutes
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: 20).format(),
// Auto report lux change threshold
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 30).format(),
// Get battery report triggers WakeUpNMI
zwave.batteryV1.batteryGet().format()
])
}

View File

@@ -1,188 +0,0 @@
/**
* 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
* Everspring ST814 Temperature/Humidity Sensor
*
* Author: SmartThings
* Date: 2017-3-4
*/
metadata {
definition (name: "Everspring ST814", namespace: "smartthings", author: "SmartThings") {
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0060", prod:"0006", model:"0001"
}
simulator {
for( int i = 0; i <= 100; i += 20 ) {
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "humidity ${i}%": new physicalgraph.zwave.Zwave().sensorMultilevelV2.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 5).incomingMessage()
}
for( int i = 0; i <= 100; i += 20 ) {
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(
batteryLevel: i).incomingMessage()
}
status "wakeup": "command: 8407, payload: "
}
tiles(scale: 2) {
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 32, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 98, color: "#bc2323"]
]
}
valueTile("humidity", "device.humidity", inactiveLabel: false, width: 2, height: 2) {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main( ["temperature", "humidity"] )
details( ["temperature", "humidity", "battery"] )
}
}
def updated() {
state.configured = false
}
def parse(String description) {
def result = []
def cmd = zwave.parse(description, [0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
if (cmd) {
result = zwaveEvent(cmd)
}
if (result instanceof List) {
log.debug "Parsed '$description' to ${result.collect { it.respondsTo("toHubAction") ? it.toHubAction() : it }}"
} else {
log.debug "Parsed '$description' to ${result}"
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def result = [
createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)
]
if (state.configured) {
result << response(zwave.batteryV1.batteryGet())
} else {
result << response(configure())
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.alarmv1.AlarmReport cmd) {
if (cmd.alarmType == 1 && cmd.alarmType == 0xFF) {
return createEvent(descriptionText: "${device.displayName} battery is low", isStateChange: true)
} else if (cmd.alarmType == 2 && cmd.alarmLevel == 1) {
return createEvent(descriptionText: "${device.displayName} powered up", isStateChange: false)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd) {
def map = [:]
switch( cmd.sensorType ) {
case 1:
/* temperature */
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
break
case 5:
/* humidity */
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "%"
map.name = "humidity"
break
}
return createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
def response_cmds = []
if (!currentTemperature) {
response_cmds << zwave.sensorMultilevelV2.sensorMultilevelGet().format()
response_cmds << "delay 1000"
}
response_cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
return [createEvent(map), response(response_cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def result = null
def encapsulatedCommand = cmd.encapsulatedCommand([0x20: 1, 0x31: 2, 0x70: 1, 0x71: 1, 0x80: 1, 0x84: 2, 0x85: 2])
log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
result = zwaveEvent(encapsulatedCommand)
}
result
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug "Unhandled: ${cmd.toString()}"
return [:]
}
def configure() {
state.configured = true
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
delayBetween([
// Auto report time interval in minutes
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 20).format(),
// Auto report temperature change threshold
zwave.configurationV1.configurationSet(parameterNumber: 7, size: 1, scaledConfigurationValue: 2).format(),
// Auto report humidity change threshold
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 5).format(),
// Get battery report triggers WakeUpNMI
zwave.batteryV1.batteryGet().format()
])
}

View File

@@ -68,8 +68,8 @@
tiles { tiles {
standardTile("contact", "device.contact", width: 2, height: 2) { standardTile("contact", "device.contact", width: 2, height: 2) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13" state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC" state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false) { valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°', state "temperature", label:'${currentValue}°',
@@ -86,7 +86,7 @@
} }
standardTile("tamper", "device.alarm") { standardTile("tamper", "device.alarm") {
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff") state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc") state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
} }
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") { valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:"" state "battery", label:'${currentValue}% battery', unit:""

View File

@@ -107,8 +107,8 @@
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
} }
standardTile("acceleration", "device.acceleration") { standardTile("acceleration", "device.acceleration") {
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc") state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc") state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
} }

View File

@@ -12,13 +12,13 @@
* *
*/ */
metadata { metadata {
definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") { definition (name: "Fortrezz Water Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Health Check" capability "Health Check"
capability "Valve" capability "Valve"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70" fingerprint deviceId: "0x1000", inClusters: "0x25,0x72,0x86,0x71,0x22,0x70"
fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve" fingerprint mfr:"0084", prod:"0213", model:"0215", deviceJoinName: "FortrezZ Water Valve"
} }
@@ -34,22 +34,19 @@ metadata {
} }
// tile definitions // tile definitions
tiles(scale: 2) { tiles {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){ standardTile("contact", "device.contact", width: 2, height: 2, canChangeIcon: true) {
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") { state "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" state "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" state "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC" state "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
attributeState "closing", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
}
} }
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
} }
main "valve" main "contact"
details(["valve","refresh"]) details(["contact","refresh"])
} }
} }
@@ -65,23 +62,22 @@ def updated(){
def parse(String description) { def parse(String description) {
log.trace description log.trace description
def result = null
def cmd = zwave.parse(description) def cmd = zwave.parse(description)
if (cmd) { if (cmd) {
return zwaveEvent(cmd) result = createEvent(zwaveEvent(cmd))
} }
log.debug "Could not parse message" log.debug "Parse returned ${result?.descriptionText}"
return null return result
} }
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def value = cmd.value ? "closed" : "open" def value = cmd.value ? "closed" : "open"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
} }
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in [:] // Handles all Z-Wave commands we aren't interested in
} }
def open() { def open() {
@@ -102,9 +98,3 @@ def ping() {
def refresh() { def refresh() {
zwave.switchBinaryV1.switchBinaryGet().format() zwave.switchBinaryV1.switchBinaryGet().format()
} }
def createEventWithDebug(eventMap) {
def event = createEvent(eventMap)
log.debug "Event created with ${event?.descriptionText}"
return event
}

View File

@@ -62,8 +62,8 @@ metadata {
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
} }
standardTile("contact", "device.contact", inactiveLabel: false) { standardTile("contact", "device.contact", inactiveLabel: false) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13" state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC" state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
} }
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") { standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"

View File

@@ -21,7 +21,7 @@ Works with:
## Device Health ## Device Health
Plant Link sensor is a ZigBee sleepy device and checks in every 15 minutes. Plant Link sensor is a Z-wave sleepy device and checks in every 15 minutes.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins. Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
* __32min__ checkInterval * __32min__ checkInterval

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,39 +0,0 @@
# Smartalert Siren
Cloud Execution
Works with:
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/products/fortrezz-siren-strobe-alarm)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Switch** - can detect state (possible values: on/off)
* **Sensor** - detects sensor events
* **Alarm** - allows for interacting with devices that serve as alarms
* **Health Check** - indicates ability to get device health notifications
## Device Health
FortrezZ Siren Strobe Alarm is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [FortrezZ Siren Strobe Alarm Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202294760-FortrezZ-Siren-Strobe-Alarm)

View File

@@ -16,17 +16,15 @@
* Date: 2013-03-05 * Date: 2013-03-05
*/ */
metadata { metadata {
definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") { definition (name: "SmartAlert Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.smokedetector") {
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
capability "Sensor" capability "Sensor"
capability "Alarm" capability "Alarm"
capability "Health Check"
command "test" command "test"
fingerprint deviceId: "0x1100", inClusters: "0x26,0x71" fingerprint deviceId: "0x1100", inClusters: "0x26,0x71"
fingerprint mfr:"0084", prod:"0313", model:"010B", deviceJoinName: "FortrezZ Siren Strobe Alarm"
} }
simulator { simulator {
@@ -70,16 +68,6 @@ metadata {
} }
} }
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def on() { def on() {
[ [
zwave.basicV1.basicSet(value: 0xFF).format(), zwave.basicV1.basicSet(value: 0xFF).format(),
@@ -161,10 +149,3 @@ def createEvents(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "UNEXPECTED COMMAND: $cmd" log.warn "UNEXPECTED COMMAND: $cmd"
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.basicV1.basicGet())
}

View File

@@ -44,9 +44,9 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute ("device.level", key: "SLIDER_CONTROL") { tileAttribute ("device.level", key: "SLIDER_CONTROL") {

View File

@@ -29,7 +29,6 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019" fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019"
} }

View File

@@ -56,8 +56,8 @@ metadata {
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC") state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
} }
standardTile("contact", "device.contact") { standardTile("contact", "device.contact") {
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13") state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC") state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
} }
standardTile("acceleration", "device.acceleration", decoration: "flat") { standardTile("acceleration", "device.acceleration", decoration: "flat") {
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC") state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")

View File

@@ -61,8 +61,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) { multiAttributeTile(name: "motion", type: "generic", width: 6, height: 4) {
tileAttribute("device.motion", key: "PRIMARY_CONTROL") { tileAttribute("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC" attributeState "active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#53a7c0"
attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#cccccc" attributeState "inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#ffffff"
} }
} }
valueTile("temperature", "device.temperature", width: 2, height: 2) { valueTile("temperature", "device.temperature", width: 2, height: 2) {

View File

@@ -33,6 +33,7 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S", deviceJoinName: "Multipurpose Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3323-G", deviceJoinName: "Centralite Micro Door Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor" fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500,FC02", outClusters: "0019", manufacturer: "SmartThings", model: "multiv4", deviceJoinName: "Multipurpose Sensor"
attribute "status", "string" attribute "status", "string"
@@ -87,8 +88,8 @@ metadata {
state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc") state("closed", label: 'Closed', icon: "st.contact.contact.closed", backgroundColor: "#00a0dc")
} }
standardTile("acceleration", "device.acceleration", width: 2, height: 2) { standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#00a0dc") state("active", label: 'Active', icon: "st.motion.acceleration.active", backgroundColor: "#53a7c0")
state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#cccccc") state("inactive", label: 'Inactive', icon: "st.motion.acceleration.inactive", backgroundColor: "#ffffff")
} }
valueTile("temperature", "device.temperature", width: 2, height: 2) { valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label: '${currentValue}°', state("temperature", label: '${currentValue}°',
@@ -178,7 +179,7 @@ private List<Map> handleAcceleration(descMap) {
result += parseAxis(descMap.additionalAttrs) result += parseAxis(descMap.additionalAttrs)
} }
} else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) { } else if (descMap.clusterInt == 0xFC02 && descMap.attrInt == 0x0012) {
def addAttrs = descMap.additionalAttrs ?: [] def addAttrs = descMap.additionalAttrs
addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value] addAttrs << ["attrInt": descMap.attrInt, "value": descMap.value]
result += parseAxis(addAttrs) result += parseAxis(addAttrs)
} }
@@ -191,10 +192,6 @@ private List<Map> parseAxis(List<Map> attrData) {
def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value) def y = hexToSignedInt(attrData.find { it.attrInt == 0x0013 }?.value)
def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value) def z = hexToSignedInt(attrData.find { it.attrInt == 0x0014 }?.value)
if ([x, y ,z].any { it == null }) {
return []
}
def xyzResults = [:] def xyzResults = [:]
if (device.getDataValue("manufacturer") == "SmartThings") { if (device.getDataValue("manufacturer") == "SmartThings") {
// This mapping matches the current behavior of the Device Handler for the Centralite sensors // This mapping matches the current behavior of the Device Handler for the Centralite sensors
@@ -375,10 +372,6 @@ def updated() {
} }
private hexToSignedInt(hexVal) { private hexToSignedInt(hexVal) {
if (!hexVal) {
return null
}
def unsignedVal = hexToInt(hexVal) def unsignedVal = hexToInt(hexVal)
unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal unsignedVal > 32767 ? unsignedVal - 65536 : unsignedVal
} }

View File

@@ -31,7 +31,6 @@ metadata {
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300-S"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300" fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3300"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor" fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3320-L", deviceJoinName: "Iris Contact Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3323-G", deviceJoinName: "Centralite Micro Door Sensor"
} }
simulator { simulator {

View File

@@ -22,16 +22,16 @@ metadata {
tiles { tiles {
standardTile("contact", "device.contact", width: 2, height: 2) { standardTile("contact", "device.contact", width: 2, height: 2) {
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open") state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close") state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
} }
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") { standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC") state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13") state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
} }
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") { standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC") state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13") state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
} }
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") { standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open") state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")

View File

@@ -25,8 +25,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
standardTile("contact", "device.contact", width: 4, height: 4) { standardTile("contact", "device.contact", width: 4, height: 4) {
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC") state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13") state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
} }
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor") childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor") childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")

View File

@@ -27,7 +27,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") { tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
} }
@@ -35,7 +35,7 @@ metadata {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") { tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute("device.level", key: "SECONDARY_CONTROL") { tileAttribute("device.level", key: "SECONDARY_CONTROL") {
@@ -59,7 +59,7 @@ metadata {
tileAttribute("device.switch", key: "SECONDARY_CONTROL") { tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute("device.level", key: "VALUE_CONTROL") { tileAttribute("device.level", key: "VALUE_CONTROL") {

View File

@@ -40,11 +40,11 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){ multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc" attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
} }
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") { tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: '' attributeState "currentIP", label: ''

View File

@@ -46,8 +46,8 @@
} }
standardTile("motion", "device.motion", width: 2, height: 2) { standardTile("motion", "device.motion", width: 2, height: 2) {
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC") state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC") state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000") state("offline", label:'${name}', icon:"st.motion.motion.inactive", backgroundColor:"#ff0000")
} }

View File

@@ -38,11 +38,11 @@
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){ multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc" attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
} }
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") { tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
attributeState "currentIP", label: '' attributeState "currentIP", label: ''
@@ -50,11 +50,11 @@
} }
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff" state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn" state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff" state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn" state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc" state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ff0000"
} }
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") { standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {

View File

@@ -70,27 +70,19 @@ def parse(String description) {
else { else {
sendEvent(event) sendEvent(event)
} }
} else { }
def descMap = zigbee.parseDescriptionAsMap(description) else {
if (descMap && descMap.clusterInt == 0x0006 && descMap.commandInt == 0x07) { def cluster = zigbee.parse(description)
if (descMap.data[0] == "00") { if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
if (cluster.data[0] == 0x00){
log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster log.debug "ON/OFF REPORTING CONFIG RESPONSE: " + cluster
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
} else { }
else {
log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}" log.warn "ON/OFF REPORTING CONFIG FAILED- error code:${cluster.data[0]}"
} }
} else if (device.getDataValue("manufacturer") == "sengled" && descMap && descMap.clusterInt == 0x0008 && descMap.attrInt == 0x0000) { }
// This is being done because the sengled element touch incorrectly uses the value 0xFF for the max level. else {
// Per the ZCL spec for the UINT8 data type 0xFF is an invalid value, and 0xFE should be the max. Here we
// manually handle the invalid attribute value since it will be ignored by getEvent as an invalid value.
// We also set the level of the bulb to 0xFE so future level reports will be 0xFE until it is changed by
// something else.
if (descMap.value.toUpperCase() == "FF") {
descMap.value = "FE"
}
sendHubCommand(zigbee.command(zigbee.LEVEL_CONTROL_CLUSTER, 0x00, "FE0000").collect { new physicalgraph.device.HubAction(it) }, 0)
sendEvent(zigbee.getEventFromAttrData(descMap.clusterInt, descMap.attrInt, descMap.encoding, descMap.value))
} else {
log.warn "DID NOT PARSE MESSAGE for description : $description" log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description) log.debug zigbee.parseDescriptionAsMap(description)
} }
@@ -122,17 +114,9 @@ def refresh() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." 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) // 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 // 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]) sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
cmds + refresh() refresh()
} }

View File

@@ -25,7 +25,6 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart A19 Soft White" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart A19 Soft White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Smart 10-Year A19"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"

View File

@@ -34,7 +34,7 @@ import physicalgraph.zigbee.zcl.DataType
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
} }
tiles(scale: 2) { tiles(scale: 2) {

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -64,7 +64,6 @@ private getATTRIBUTE_HUE() { 0x0000 }
private getATTRIBUTE_SATURATION() { 0x0001 } private getATTRIBUTE_SATURATION() { 0x0001 }
private getHUE_COMMAND() { 0x00 } private getHUE_COMMAND() { 0x00 }
private getSATURATION_COMMAND() { 0x03 } private getSATURATION_COMMAND() { 0x03 }
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 } private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
@@ -85,11 +84,11 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) { if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed") sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
} }
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false) sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
} }
} }
@@ -124,12 +123,7 @@ def ping() {
} }
def refresh() { def refresh() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
zigbee.levelRefresh() +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
zigbee.onOffConfig(0, 300) +
zigbee.levelConfig()
} }
def configure() { def configure() {
@@ -139,38 +133,26 @@ def configure() {
sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 3 * 10 * 60 + 1 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
refresh() zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01) + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setLevel(value) { def setLevel(value) {
zigbee.setLevel(value) zigbee.setLevel(value)
} }
private getScaledHue(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
private getScaledSaturation(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
def setColor(value){ def setColor(value){
log.trace "setColor($value)" log.trace "setColor($value)"
zigbee.on() + zigbee.on() + setHue(value.hue) + "delay 500" + setSaturation(value.saturation)
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setHue(value) { def setHue(value) {
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") + def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
} }
def setSaturation(value) { def setSaturation(value) {
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + "delay 1000" + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def installed() { def installed() {
@@ -179,4 +161,4 @@ def installed() {
sendEvent(name: "level", value: 100) sendEvent(name: "level", value: 100)
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -46,9 +46,9 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute ("device.level", key: "SLIDER_CONTROL") { tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -78,7 +78,6 @@ private getATTRIBUTE_HUE() { 0x0000 }
private getATTRIBUTE_SATURATION() { 0x0001 } private getATTRIBUTE_SATURATION() { 0x0001 }
private getHUE_COMMAND() { 0x00 } private getHUE_COMMAND() { 0x00 }
private getSATURATION_COMMAND() { 0x03 } private getSATURATION_COMMAND() { 0x03 }
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 } private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 } private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
@@ -103,12 +102,12 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) { if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
state.hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
runIn(5, updateColor, [overwrite: true]) sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
} }
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
state.saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
runIn(5, updateColor, [overwrite: true]) sendEvent(name: "saturation", value: saturationValue, descriptionText: "Color has changed", displayed: false)
} }
} }
else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) { else if (cluster && cluster.clusterId == 0x0006 && cluster.command == 0x07) {
@@ -127,11 +126,6 @@ def parse(String description) {
} }
} }
def updateColor() {
sendEvent(name: "hue", value: state.hueValue, descriptionText: "Color has changed")
sendEvent(name: "saturation", value: state.saturationValue, descriptionText: "Color has changed", displayed: false)
}
def on() { def on() {
zigbee.on() zigbee.on()
} }
@@ -147,13 +141,7 @@ def ping() {
} }
def refresh() { def refresh() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
zigbee.levelRefresh() +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
zigbee.onOffConfig(0, 300) +
zigbee.levelConfig()
} }
def configure() { def configure() {
@@ -168,12 +156,7 @@ def configure() {
def setColorTemperature(value) { def setColorTemperature(value) {
setGenericName(value) setGenericName(value)
value = value as Integer zigbee.setColorTemperature(value)
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, 0x0A, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
} }
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature //Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
@@ -197,31 +180,19 @@ def setLevel(value) {
zigbee.setLevel(value) zigbee.setLevel(value)
} }
private getScaledHue(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
private getScaledSaturation(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
def setColor(value){ def setColor(value){
log.trace "setColor($value)" log.trace "setColor($value)"
zigbee.on() + zigbee.on() + setHue(value.hue) + "delay 300" + setSaturation(value.saturation)
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
} }
def setHue(value) { def setHue(value) {
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") + def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
} }
def setSaturation(value) { def setSaturation(value) {
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + "delay 1000" + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def installed() { def installed() {
@@ -230,4 +201,4 @@ def installed() {
sendEvent(name: "level", value: 100) sendEvent(name: "level", value: 100)
} }
} }
} }

View File

@@ -27,6 +27,7 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "0003, 000A, 0019", manufacturer: "Jasco Products", model: "45853", deviceJoinName: "GE ZigBee Plug-In Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch" fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0702, 0B05", outClusters: "000A, 0019", manufacturer: "Jasco Products", model: "45856", deviceJoinName: "GE ZigBee In-Wall Switch"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
} }
tiles(scale: 2) { tiles(scale: 2) {

View File

@@ -41,9 +41,9 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" 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 "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
} }

View File

@@ -39,7 +39,7 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") { tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
@@ -83,9 +83,6 @@ def parse(String description) {
} }
} }
sendEvent(event) sendEvent(event)
//handle valve attribute
event.name = "valve"
sendEvent(event)
} }
else { else {
def descMap = zigbee.parseDescriptionAsMap(description) def descMap = zigbee.parseDescriptionAsMap(description)

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2015 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -45,9 +45,9 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" 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 "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute ("device.level", key: "SLIDER_CONTROL") { tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -71,11 +71,6 @@ metadata {
} }
} }
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
@@ -128,11 +123,7 @@ def ping() {
} }
def refresh() { def refresh() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
zigbee.levelRefresh() +
zigbee.colorTemperatureRefresh() +
zigbee.onOffConfig(0, 300) +
zigbee.levelConfig()
} }
def configure() { def configure() {
@@ -147,12 +138,7 @@ def configure() {
def setColorTemperature(value) { def setColorTemperature(value) {
setGenericName(value) setGenericName(value)
value = value as Integer zigbee.setColorTemperature(value)
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
} }
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature //Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature

View File

@@ -49,9 +49,9 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") { tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" 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 "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff" attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn" attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
} }
tileAttribute ("device.level", key: "SLIDER_CONTROL") { tileAttribute ("device.level", key: "SLIDER_CONTROL") {

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -55,7 +55,6 @@ private getATTRIBUTE_HUE() { 0x0000 }
private getATTRIBUTE_SATURATION() { 0x0001 } private getATTRIBUTE_SATURATION() { 0x0001 }
private getHUE_COMMAND() { 0x00 } private getHUE_COMMAND() { 0x00 }
private getSATURATION_COMMAND() { 0x03 } private getSATURATION_COMMAND() { 0x03 }
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 } private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
@@ -73,11 +72,11 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) { if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360)
sendEvent(name: "hue", value: hueValue, displayed:false) sendEvent(name: "hue", value: hueValue, displayed:false)
} }
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "saturation", value: saturationValue, displayed:false) sendEvent(name: "saturation", value: saturationValue, displayed:false)
} }
} }
@@ -109,46 +108,28 @@ def configure() {
} }
def configureAttributes() { def configureAttributes() {
zigbee.onOffConfig() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
zigbee.levelConfig()
} }
def refreshAttributes() { def refreshAttributes() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
zigbee.levelRefresh() +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setLevel(value) { def setLevel(value) {
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
} }
private getScaledHue(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
private getScaledSaturation(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
def setColor(value){ def setColor(value){
log.trace "setColor($value)" log.trace "setColor($value)"
zigbee.on() + zigbee.on() + setHue(value.hue) + ["delay 300"] + setSaturation(value.saturation) + ["delay 2000"] + refreshAttributes()
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setHue(value) { def setHue(value) {
//payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") + zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
} }
def setSaturation(value) { def setSaturation(value) {
//payload-> sat value, transition time def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) //payload-> sat value, transition time
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -70,7 +70,6 @@ private getATTRIBUTE_HUE() { 0x0000 }
private getATTRIBUTE_SATURATION() { 0x0001 } private getATTRIBUTE_SATURATION() { 0x0001 }
private getHUE_COMMAND() { 0x00 } private getHUE_COMMAND() { 0x00 }
private getSATURATION_COMMAND() { 0x03 } private getSATURATION_COMMAND() { 0x03 }
private getMOVE_TO_HUE_AND_SATURATION_COMMAND() { 0x06 }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 } private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 } private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
@@ -89,11 +88,11 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) { if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360)
sendEvent(name: "hue", value: hueValue, displayed:false) sendEvent(name: "hue", value: hueValue, displayed:false)
} }
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 0xfe * 100) def saturationValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "saturation", value: saturationValue, displayed:false) sendEvent(name: "saturation", value: saturationValue, displayed:false)
} }
} }
@@ -125,16 +124,11 @@ def configure() {
} }
def configureAttributes() { def configureAttributes() {
zigbee.onOffConfig() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, DataType.UINT8, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, DataType.UINT8, 1, 3600, 0x01)
zigbee.levelConfig()
} }
def refreshAttributes() { def refreshAttributes() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
zigbee.levelRefresh() +
zigbee.colorTemperatureRefresh() +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setColorTemperature(value) { def setColorTemperature(value) {
@@ -145,32 +139,17 @@ def setLevel(value) {
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
} }
private getScaledHue(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
private getScaledSaturation(value) {
zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
}
def setColor(value){ def setColor(value){
log.trace "setColor($value)" log.trace "setColor($value)"
zigbee.on() + zigbee.on() + setHue(value.hue) + ["delay 300"] + setSaturation(value.saturation) + ["delay 2000"] + refreshAttributes()
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_HUE_AND_SATURATION_COMMAND,
getScaledHue(value.hue), getScaledSaturation(value.saturation), "0000") +
zigbee.onOffRefresh() +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setHue(value) { def setHue(value) {
//payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) def scaledHueValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, getScaledHue(value), "00", "0000") + zigbee.command(COLOR_CONTROL_CLUSTER, HUE_COMMAND, scaledHueValue, "00", "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) //payload-> hue value, direction (00-> shortest distance), transition time (1/10th second) (0500 in U16 reads 5)
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE)
} }
def setSaturation(value) { def setSaturation(value) {
//payload-> sat value, transition time def scaledSatValue = zigbee.convertToHexString(Math.round(value * 0xfe / 100.0), 2)
zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, getScaledSaturation(value), "0000") + zigbee.command(COLOR_CONTROL_CLUSTER, SATURATION_COMMAND, scaledSatValue, "0500") + ["delay 1500"] + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) //payload-> sat value, transition time
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -66,11 +66,6 @@ metadata {
} }
} }
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
@@ -100,14 +95,14 @@ def setLevel(value) {
} }
def refresh() { def refresh() {
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
// Do NOT config if the device is the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, and maybe other weird things with the others // Do NOT config if the device is the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, and maybe other weird things with the others
if (!((device.getDataValue("manufacturer") == "Eaton") && (device.getDataValue("model") == "Halo_LT01"))) { if (!((device.getDataValue("manufacturer") == "Eaton") && (device.getDataValue("model") == "Halo_LT01"))) {
cmds += zigbee.onOffConfig() + zigbee.levelConfig() cmds = cmds + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
} }
cmds cmds
} }
def poll() { def poll() {
@@ -143,7 +138,7 @@ def configure() {
log.debug "configure()" log.debug "configure()"
configureHealthCheck() configureHealthCheck()
// Implementation note: for the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, so be sure this is before the call to onOffRefresh // Implementation note: for the Eaton Halo_LT01, it responds with "switch:off" to onOffConfig, so be sure this is before the call to onOffRefresh
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
} }
def updated() { def updated() {
@@ -153,12 +148,7 @@ def updated() {
def setColorTemperature(value) { def setColorTemperature(value) {
setGenericName(value) setGenericName(value)
value = value as Integer zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
} }
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature //Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature

View File

@@ -1,5 +1,5 @@
/** /**
* Copyright 2017 SmartThings * Copyright 2016 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
@@ -68,11 +68,6 @@ metadata {
} }
} }
// Globals
private getMOVE_TO_COLOR_TEMPERATURE_COMMAND() { 0x0A }
private getCOLOR_CONTROL_CLUSTER() { 0x0300 }
private getATTRIBUTE_COLOR_TEMPERATURE() { 0x0007 }
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
@@ -99,11 +94,7 @@ def setLevel(value) {
} }
def refresh() { def refresh() {
zigbee.onOffRefresh() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
zigbee.levelRefresh() +
zigbee.colorTemperatureRefresh() +
zigbee.onOffConfig() +
zigbee.levelConfig()
} }
def poll() { def poll() {
@@ -138,7 +129,8 @@ def configureHealthCheck() {
def configure() { def configure() {
log.debug "configure()" log.debug "configure()"
configureHealthCheck() configureHealthCheck()
refresh() zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
} }
def updated() { def updated() {
@@ -148,12 +140,7 @@ def updated() {
def setColorTemperature(value) { def setColorTemperature(value) {
setGenericName(value) setGenericName(value)
value = value as Integer zigbee.setColorTemperature(value) + ["delay 1500"] + zigbee.colorTemperatureRefresh()
def tempInMired = (1000000 / value) as Integer
def finalHex = zigbee.swapEndianHex(zigbee.convertToHexString(tempInMired, 4))
zigbee.command(COLOR_CONTROL_CLUSTER, MOVE_TO_COLOR_TEMPERATURE_COMMAND, "$finalHex 0000") +
zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE)
} }
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature //Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature

View File

@@ -75,10 +75,6 @@ def parse(String description) {
return result return result
} }
def uninstalled() {
sendEvent(name: "epEvent", value: "delete all", isStateChange: true, displayed: false, descriptionText: "Delete endpoint devices")
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) { def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
[ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true), [ createEvent(descriptionText: "${device.displayName} woke up", isStateChange:true),
response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ] response(["delay 2000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]) ]

View File

@@ -30,15 +30,6 @@ metadata {
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82" 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 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:"0086", prod:"0002", model:"001D", deviceJoinName: "Aeon Labs Door/Window Sensor (Gen 5)"
fingerprint mfr:"0086", prod:"0102", model:"0070", deviceJoinName: "Aeon Labs Door/Window Sensor 6"
fingerprint mfr:"0086", prod:"0102", model:"0059", deviceJoinName: "Aeon Labs Recessed Door Sensor"
fingerprint mfr:"014A", prod:"0001", model:"0002", deviceJoinName: "Ecolink Door/Window Sensor"
fingerprint mfr:"014A", prod:"0001", model:"0003", deviceJoinName: "Ecolink Tilt Sensor"
fingerprint mfr:"011A", prod:"0601", model:"0903", deviceJoinName: "Enerwave Magnetic Door/Window Sensor"
fingerprint mfr:"014F", prod:"2001", model:"0102", deviceJoinName: "Nortek GoControl Door/Window Sensor"
fingerprint mfr:"0063", prod:"4953", model:"3031", deviceJoinName: "Jasco Hinge Pin Door Sensor"
fingerprint mfr:"019A", prod:"0003", model:"0003", deviceJoinName: "Sensative Strips"
} }
// simulator metadata // simulator metadata
@@ -113,9 +104,9 @@ def updated() {
def configure() { def configure() {
commands([ commands([
zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW), zwave.manufacturerSpecificV2.manufacturerSpecificGet(),
zwave.manufacturerSpecificV2.manufacturerSpecificGet() zwave.batteryV1.batteryGet()
], 1000) ], 6000)
} }
def sensorValueEvent(value) { def sensorValueEvent(value) {
@@ -190,17 +181,11 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet()) cmds << command(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
cmds << "delay 1200" cmds << "delay 1200"
} }
if (device.currentValue("contact") == null) { // Incase our initial request didn't make it
cmds << command(zwave.sensorBinaryV2.sensorBinaryGet(sensorType: zwave.sensorBinaryV2.SENSOR_TYPE_DOOR_WINDOW))
}
if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) { if (!state.lastbat || now() - state.lastbat > 53*60*60*1000) {
cmds << command(zwave.batteryV1.batteryGet()) cmds << command(zwave.batteryV1.batteryGet())
} else { // If we check the battery state we will send NoMoreInfo in the handler for BatteryReport so that we definitely get the report } else {
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format() cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
} }
[event, response(cmds)] [event, response(cmds)]
} }

View File

@@ -1,4 +1,4 @@
# Z-Wave Lock # Z-Wave Switch
Cloud Execution Cloud Execution
@@ -6,6 +6,7 @@ Works with:
* [Yale Key Free Touchscreen Deadbolt (YRD240)](https://www.smartthings.com/works-with-smartthings/yale/yale-key-free-touchscreen-deadbolt-yrd240) * [Yale Key Free Touchscreen Deadbolt (YRD240)](https://www.smartthings.com/works-with-smartthings/yale/yale-key-free-touchscreen-deadbolt-yrd240)
## Table of contents ## Table of contents
* [Capabilities](#capabilities) * [Capabilities](#capabilities)
@@ -40,3 +41,5 @@ If the device doesn't pair when trying from the SmartThings mobile app, it is po
Pairing needs to be tried again by placing the device closer to the hub. Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link: Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [General Z-Wave/ZigBee Yale Lock Troubleshooting](https://support.smartthings.com/hc/en-us/articles/205138400-How-to-connect-Yale-locks) * [General Z-Wave/ZigBee Yale Lock Troubleshooting](https://support.smartthings.com/hc/en-us/articles/205138400-How-to-connect-Yale-locks)

View File

@@ -26,24 +26,7 @@ metadata {
fingerprint deviceId: "0x4003", inClusters: "0x98" fingerprint deviceId: "0x4003", inClusters: "0x98"
fingerprint deviceId: "0x4004", inClusters: "0x98" fingerprint deviceId: "0x4004", inClusters: "0x98"
fingerprint mfr:"0090", prod:"0001", model:"0236", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock" fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Key Free Touchscreen Deadbolt"
fingerprint mfr:"0090", prod:"0003", model:"0238", deviceJoinName: "KwikSet SmartCode 910 Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0001", model:"0001", deviceJoinName: "KwikSet SmartCode 910 Contemporary Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"0339", deviceJoinName: "KwikSet SmartCode 912 Lever Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"4006", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock" //backlit version
fingerprint mfr:"0090", prod:"0003", model:"0440", deviceJoinName: "KwikSet SmartCode 914 Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0001", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
fingerprint mfr:"0090", prod:"0003", model:"0642", deviceJoinName: "KwikSet SmartCode 916 Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"6341", model:"0544", deviceJoinName: "Schlage Camelot Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"6341", model:"5044", deviceJoinName: "Schlage Century Touchscreen Deadbolt Door Lock"
fingerprint mfr:"003B", prod:"634B", model:"504C", deviceJoinName: "Schlage Connected Keypad Lever Door Lock"
fingerprint mfr:"0129", prod:"0002", model:"0800", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD120
fingerprint mfr:"0129", prod:"0002", model:"0000", deviceJoinName: "Yale Touchscreen Deadbolt Door Lock" // YRD220, YRD240
fingerprint mfr:"0129", prod:"0002", model:"FFFF", deviceJoinName: "Yale Touchscreen Lever Door Lock" // YRD220
fingerprint mfr:"0129", prod:"0004", model:"0800", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD110
fingerprint mfr:"0129", prod:"0004", model:"0000", deviceJoinName: "Yale Push Button Deadbolt Door Lock" // YRD210
fingerprint mfr:"0129", prod:"0001", model:"0000", deviceJoinName: "Yale Push Button Lever Door Lock" // YRD210
fingerprint mfr:"0129", prod:"8002", model:"0600", deviceJoinName: "Yale Assure Lock with Bluetooth"
} }
simulator { simulator {
@@ -86,13 +69,13 @@ import physicalgraph.zwave.commands.doorlockv1.*
import physicalgraph.zwave.commands.usercodev1.* import physicalgraph.zwave.commands.usercodev1.*
def installed() { def installed() {
// Device-Watch pings if no device events received for 1 hour (checkInterval) // Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
} }
def updated() { def updated() {
// Device-Watch pings if no device events received for 1 hour (checkInterval) // Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 1 * 60 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID]) sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
try { try {
if (!state.init) { if (!state.init) {
state.init = true state.init = true
@@ -152,10 +135,6 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupported
def zwaveEvent(DoorLockOperationReport cmd) { def zwaveEvent(DoorLockOperationReport cmd) {
def result = [] def result = []
unschedule("followupStateCheck")
unschedule("stateCheck")
def map = [ name: "lock" ] def map = [ name: "lock" ]
if (cmd.doorLockMode == 0xFF) { if (cmd.doorLockMode == 0xFF) {
map.value = "locked" map.value = "locked"
@@ -369,7 +348,7 @@ def zwaveEvent(UserCodeReport cmd) {
code = state["set$name"] ?: decrypt(state[name]) ?: "****" code = state["set$name"] ?: decrypt(state[name]) ?: "****"
state.remove("set$name".toString()) state.remove("set$name".toString())
} else { } else {
map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ], isStateChange: true ] map = [ name: "codeReport", value: cmd.userIdentifier, data: [ code: code ] ]
map.descriptionText = "$device.displayName code $cmd.userIdentifier is set" map.descriptionText = "$device.displayName code $cmd.userIdentifier is set"
map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode) map.displayed = (cmd.userIdentifier != state.requestCode && cmd.userIdentifier != state.pollCode)
map.isStateChange = true map.isStateChange = true
@@ -460,12 +439,11 @@ def zwaveEvent(physicalgraph.zwave.commands.timev1.TimeGet cmd) {
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
// The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1 // The old Schlage locks use group 1 for basic control - we don't want that, so unsubscribe from group 1
def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ] def result = [ createEvent(name: "lock", value: cmd.value ? "unlocked" : "locked") ]
def cmds = [ result << response(zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId))
zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format(), if (state.assoc != zwaveHubNodeId) {
"delay 1200", result << response(zwave.associationV1.associationGet(groupingIdentifier:2))
zwave.associationV1.associationGet(groupingIdentifier:2).format() }
] result
[result, response(cmds)]
} }
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
@@ -535,18 +513,11 @@ def unlockwtimeout() {
lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT) lockAndCheck(DoorLockOperationSet.DOOR_LOCK_MODE_DOOR_UNSECURED_WITH_TIMEOUT)
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() { def ping() {
runIn(30, followupStateCheck) refresh()
secure(zwave.doorLockV1.doorLockOperationGet())
}
def followupStateCheck() {
runEvery1Hour(stateCheck)
stateCheck()
}
def stateCheck() {
sendHubCommand(new physicalgraph.device.HubAction(secure(zwave.doorLockV1.doorLockOperationGet())))
} }
def refresh() { def refresh() {

View File

@@ -16,7 +16,7 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Metering Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") { definition (name: "Z-Wave Metering Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
capability "Switch" capability "Switch"
capability "Polling" capability "Polling"
capability "Power Meter" capability "Power Meter"

View File

@@ -29,7 +29,7 @@ metadata {
fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814 fingerprint mfr: "0060", prod: "0001", model: "0002", deviceJoinName: "Everspring Motion Sensor" // Everspring SP814
fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02 fingerprint mfr: "0060", prod: "0001", model: "0003", deviceJoinName: "Everspring Motion Sensor" // Everspring HSP02
fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC fingerprint mfr: "011A", prod: "0601", model: "0901", deviceJoinName: "Enerwave Motion Sensor" // Enerwave ZWN-BPC
fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Portable Smart Motion Sensor" fingerprint mfr: "0063", prod: "4953", model: "3133", deviceJoinName: "GE Smart Motion Sensor"
} }
simulator { simulator {

View File

@@ -37,8 +37,8 @@ metadata {
tiles { tiles {
standardTile("motion", "device.motion", width: 3, height: 2) { standardTile("motion", "device.motion", width: 3, height: 2) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC" state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#CCCCCC" state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
} }
valueTile("temperature", "device.temperature", inactiveLabel: false) { valueTile("temperature", "device.temperature", inactiveLabel: false) {

View File

@@ -16,7 +16,7 @@
* Date: 2014-07-15 * Date: 2014-07-15
*/ */
metadata { metadata {
definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") { definition (name: "Z-Wave Siren", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Alarm" capability "Alarm"
capability "Battery" capability "Battery"

View File

@@ -22,7 +22,6 @@ metadata {
attribute "alarmState", "string" attribute "alarmState", "string"
fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86" fingerprint deviceId: "0xA100", inClusters: "0x20,0x80,0x70,0x85,0x71,0x72,0x86"
fingerprint mfr:"0138", prod:"0001", model:"0001", deviceJoinName: "First Alert Smoke Detector"
fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)" fingerprint mfr:"0138", prod:"0001", model:"0002", deviceJoinName: "First Alert Smoke Detector and Carbon Monoxide Alarm (ZCOMBO)"
} }

View File

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

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,38 +0,0 @@
# Z-Wave Water Valve
Cloud Execution
Works with:
* [Leak Intelligence Leak Gopher Water Shutoff Valve](https://www.smartthings.com/works-with-smartthings/other/leak-intelligence-leak-gopher-water-shutoff-valve)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Valve** - allows for the control of a valve device
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leak Intelligence Leak Gopher Water Shutoff Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/209631423-Leak-Gopher-Z-Wave-Valve-Control)

View File

@@ -12,16 +12,14 @@
* *
*/ */
metadata { metadata {
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.watervalve") { definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator" capability "Actuator"
capability "Health Check"
capability "Valve" capability "Valve"
capability "Polling" capability "Polling"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
fingerprint deviceId: "0x1006", inClusters: "0x25" fingerprint deviceId: "0x1006", inClusters: "0x25"
fingerprint mfr:"0173", prod:"0003", model:"0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve"
} }
// simulator metadata // simulator metadata
@@ -37,7 +35,7 @@ metadata {
// tile definitions // tile definitions
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){ multiAttributeTile(name:"valve", type: "generic", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.valve", key: "PRIMARY_CONTROL") { tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing" attributeState "open", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC", nextState:"closing"
attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening" attributeState "closed", label: '${name}', action: "valve.open", icon: "st.valves.water.closed", backgroundColor: "#ffffff", nextState:"opening"
attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC" attributeState "opening", label: '${name}', action: "valve.close", icon: "st.valves.water.open", backgroundColor: "#00A0DC"
@@ -45,7 +43,7 @@ metadata {
} }
} }
standardTile("refresh", "device.valve", width: 2, height: 2, inactiveLabel: false, decoration: "flat") { standardTile("refresh", "device.contact", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
} }
@@ -55,32 +53,24 @@ metadata {
} }
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() { def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(refresh()) response(refresh())
} }
def parse(String description) { def parse(String description) {
log.trace "parse description : $description" log.trace "parse description : $description"
def result = null
def cmd = zwave.parse(description, [0x20: 1]) def cmd = zwave.parse(description, [0x20: 1])
if (cmd) { if (cmd) {
return zwaveEvent(cmd) result = createEvent(zwaveEvent(cmd))
} }
log.debug "Could not parse message" log.debug "Parse returned ${result?.descriptionText}"
return null return result
} }
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown" def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
} }
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) { //TODO should show MSR when device is discovered
@@ -90,22 +80,20 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "productTypeId: ${cmd.productTypeId}" log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId) def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr) updateDataValue("MSR", msr)
return createEventWithDebug([descriptionText: "$device.displayName MSR: $msr", isStateChange: false]) [descriptionText: "$device.displayName MSR: $msr", isStateChange: false]
} }
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) { def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
return createEventWithDebug([descriptionText: cmd.toString(), isStateChange: true, displayed: true]) [descriptionText: cmd.toString(), isStateChange: true, displayed: true]
} }
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) { def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown" def value = cmd.value == 0xFF ? "open" : cmd.value == 0x00 ? "closed" : "unknown"
[name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]
return [createEventWithDebug([name: "contact", value: value, descriptionText: "$device.displayName valve is $value"]),
createEventWithDebug([name: "valve", value: value, descriptionText: "$device.displayName valve is $value"])]
} }
def zwaveEvent(physicalgraph.zwave.Command cmd) { def zwaveEvent(physicalgraph.zwave.Command cmd) {
return createEvent([:]) // Handles all Z-Wave commands we aren't interested in [:] // Handles all Z-Wave commands we aren't interested in
} }
def open() { def open() {
@@ -126,13 +114,6 @@ def poll() {
zwave.switchBinaryV1.switchBinaryGet().format() zwave.switchBinaryV1.switchBinaryGet().format()
} }
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() { def refresh() {
log.debug "refresh() is called" log.debug "refresh() is called"
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()] def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]
@@ -141,9 +122,3 @@ def refresh() {
} }
delayBetween(commands,100) delayBetween(commands,100)
} }
def createEventWithDebug(eventMap) {
def event = createEvent(eventMap)
log.debug "Event created with ${event?.descriptionText}"
return event
}

View File

@@ -0,0 +1,568 @@
/* TraneXL624.device.groovy
*
* Variation of the stock SmartThings "Zwave-Thermostat" & Better-Thermostat by todd@wackford.net
*
*
*
* Original Modified Code:
* twack@wackware.net
* 20140209
*
* Modified to add Humidity & Clock Set
* Justin Waymire
* justin@waymirenet.com
* 04-01-15
*
*/
metadata {
// Automatically generated. Make future change here.
definition (name: "Trane XL624 Thermostat", author: "justin@waymirenet.com") {
capability "Relative Humidity Measurement"
capability "Temperature Measurement"
capability "Refresh"
capability "Thermostat"
capability "Configuration"
capability "Polling"
command "heatLevelUp"
command "heatLevelDown"
command "coolLevelUp"
command "coolLevelDown"
command "switchMode"
command "switchFanMode"
}
// simulator metadata
simulator {
status "off" : "command: 4003, payload: 00"
status "heat" : "command: 4003, payload: 01"
status "cool" : "command: 4003, payload: 02"
status "auto" : "command: 4003, payload: 03"
status "emergencyHeat" : "command: 4003, payload: 04"
status "fanAuto" : "command: 4403, payload: 00"
status "fanOn" : "command: 4403, payload: 01"
status "fanCirculate" : "command: 4403, payload: 06"
status "heat 60" : "command: 4303, payload: 01 01 3C"
status "heat 68" : "command: 4303, payload: 01 01 44"
status "heat 72" : "command: 4303, payload: 01 01 48"
status "cool 72" : "command: 4303, payload: 02 01 48"
status "cool 76" : "command: 4303, payload: 02 01 4C"
status "cool 80" : "command: 4303, payload: 02 01 50"
status "temp 58" : "command: 3105, payload: 01 22 02 44"
status "temp 62" : "command: 3105, payload: 01 22 02 6C"
status "temp 70" : "command: 3105, payload: 01 22 02 BC"
status "temp 74" : "command: 3105, payload: 01 22 02 E4"
status "temp 78" : "command: 3105, payload: 01 22 03 0C"
status "temp 82" : "command: 3105, payload: 01 22 03 34"
status "idle" : "command: 4203, payload: 00"
status "heating" : "command: 4203, payload: 01"
status "cooling" : "command: 4203, payload: 02"
status "fan only" : "command: 4203, payload: 03"
status "pending heat" : "command: 4203, payload: 04"
status "pending cool" : "command: 4203, payload: 05"
status "vent economizer": "command: 4203, payload: 06"
// reply messages
reply "2502": "command: 2503, payload: FF"
}
tiles {
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', unit:'F',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
)
}
valueTile("humidity", "device.humidity", inactiveLabel: false, decoration: "flat") {
state "humidity", label:'Humidity ${currentValue}%', backgroundColor:"#ffffff"
}
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "off", label:'', action:"switchMode", icon:"st.thermostat.heating-cooling-off"
state "heat", label:'', action:"switchMode", icon:"st.thermostat.heat"
state "emergencyHeat", label:'', action:"switchMode", icon:"st.thermostat.emergency-heat"
state "cool", label:'', action:"switchMode", icon:"st.thermostat.cool"
state "auto", label:'', action:"switchMode", icon:"st.thermostat.auto"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
state "fanAuto", label:'', action:"switchFanMode", icon:"st.thermostat.fan-auto"
state "fanOn", label:'', action:"switchFanMode", icon:"st.thermostat.fan-on"
state "fanCirculate", label:' ', action:"switchFanMode", icon:"st.thermostat.fan-circulate"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue}° heat', unit:"F", backgroundColor:"#ffffff"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue}° cool', unit:"F", backgroundColor:"#ffffff"
}
standardTile("refresh", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "default", action:"polling.poll", icon:"st.secondary.refresh"
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state "configure", label:' ', action:"configuration.configure", icon:"st.secondary.configure"
}
standardTile("heatLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false, decoration: "flat") {
state "heatLevelUp", label:' ', action:"heatLevelUp", icon:"st.thermostat.thermostat-up"
}
standardTile("heatLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false, decoration: "flat") {
state "heatLevelDown", label:' ', action:"heatLevelDown", icon:"st.thermostat.thermostat-down"
}
standardTile("coolLevelUp", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false, decoration: "flat") {
state "coolLevelUp", label:' ', action:"coolLevelUp", icon:"st.thermostat.thermostat-up"
}
standardTile("coolLevelDown", "device.heatingSetpoint", canChangeIcon: false, inactiveLabel: false, decoration: "flat") {
state "coolLevelDown", label:' ', action:"coolLevelDown", icon:"st.thermostat.thermostat-down"
}
main (["temperature", "humidity"])
details(["temperature", "humidity", "mode", "heatLevelDown", "heatingSetpoint", "heatLevelUp", "coolLevelDown", "coolingSetpoint", "coolLevelUp", "refresh", "configure"])
}
}
def coolLevelUp(){
int nextLevel = device.currentValue("coolingSetpoint") + 1
if( nextLevel > 99){
nextLevel = 99
}
log.debug "Setting cool set point up to: ${nextLevel}"
setCoolingSetpoint(nextLevel)
}
def coolLevelDown(){
int nextLevel = device.currentValue("coolingSetpoint") - 1
if( nextLevel < 50){
nextLevel = 50
}
log.debug "Setting cool set point down to: ${nextLevel}"
setCoolingSetpoint(nextLevel)
}
def heatLevelUp(){
int nextLevel = device.currentValue("heatingSetpoint") + 1
if( nextLevel > 90){
nextLevel = 90
}
log.debug "Setting heat set point up to: ${nextLevel}"
setHeatingSetpoint(nextLevel)
}
def heatLevelDown(){
int nextLevel = device.currentValue("heatingSetpoint") - 1
if( nextLevel < 40){
nextLevel = 40
}
log.debug "Setting heat set point down to: ${nextLevel}"
setHeatingSetpoint(nextLevel)
}
def parse(String description)
{
def map = createEvent(zwaveEvent(zwave.parse(description, [0x42:1, 0x43:2, 0x31: 3])))
if (!map) {
return null
}
def result = [map]
if (map.isStateChange && map.name in ["heatingSetpoint","coolingSetpoint","thermostatMode"]) {
def map2 = [
name: "thermostatSetpoint",
unit: "F"
]
if (map.name == "thermostatMode") {
updateState("lastTriedMode", map.value)
if (map.value == "cool") {
map2.value = device.latestValue("coolingSetpoint")
log.info "THERMOSTAT, latest cooling setpoint = ${map2.value}"
}
else {
map2.value = device.latestValue("heatingSetpoint")
log.info "THERMOSTAT, latest heating setpoint = ${map2.value}"
}
}
else {
def mode = device.latestValue("thermostatMode")
log.info "THERMOSTAT, latest mode = ${mode}"
if ((map.name == "heatingSetpoint" && mode == "heat") || (map.name == "coolingSetpoint" && mode == "cool")) {
map2.value = map.value
map2.unit = map.unit
}
}
if (map2.value != null) {
log.debug "THERMOSTAT, adding setpoint event: $map"
result << createEvent(map2)
}
} else if (map.name == "thermostatFanMode" && map.isStateChange) {
updateState("lastTriedFanMode", map.value)
}
log.debug "Parse returned $result"
result
}
// Event Generation
def zwaveEvent(physicalgraph.zwave.commands.thermostatsetpointv2.ThermostatSetpointReport cmd)
{
def map = [:]
map.value = cmd.scaledValue.toString()
map.unit = cmd.scale == 1 ? "F" : "C"
map.displayed = false
switch (cmd.setpointType) {
case 1:
map.name = "heatingSetpoint"
break;
case 2:
map.name = "coolingSetpoint"
break;
default:
return [:]
}
// So we can respond with same format
state.size = cmd.size
state.scale = cmd.scale
state.precision = cmd.precision
map
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv3.SensorMultilevelReport cmd)
{
def map = [:]
switch (cmd.sensorType) {
case 1:
// temperature
map.value = cmd.scaledSensorValue.toString()
map.unit = cmd.scale == 1 ? "F" : "C"
map.name = "temperature"
break;
case 5:
// humidity
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "%"
map.name = "humidity"
break;
}
map
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport cmd)
{
def map = [:]
switch (cmd.operatingState) {
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_IDLE:
map.value = "idle"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_HEATING:
map.value = "heating"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_COOLING:
map.value = "cooling"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_FAN_ONLY:
map.value = "fan only"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_HEAT:
map.value = "pending heat"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_PENDING_COOL:
map.value = "pending cool"
break
case physicalgraph.zwave.commands.thermostatoperatingstatev1.ThermostatOperatingStateReport.OPERATING_STATE_VENT_ECONOMIZER:
map.value = "vent economizer"
break
}
map.name = "thermostatOperatingState"
map
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport cmd) {
def map = [:]
switch (cmd.mode) {
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_OFF:
map.value = "off"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_HEAT:
map.value = "heat"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUXILIARY_HEAT:
map.value = "emergencyHeat"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_COOL:
map.value = "cool"
break
case physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeReport.MODE_AUTO:
map.value = "auto"
break
}
map.name = "thermostatMode"
map
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport cmd) {
def map = [:]
switch (cmd.fanMode) {
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
map.value = "fanAuto"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
map.value = "fanOn"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
map.value = "fanCirculate"
break
}
map.name = "thermostatFanMode"
map.displayed = false
map
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSupportedReport cmd) {
def supportedModes = ""
if(cmd.off) { supportedModes += "off " }
if(cmd.heat) { supportedModes += "heat " }
if(cmd.auxiliaryemergencyHeat) { supportedModes += "emergencyHeat " }
if(cmd.cool) { supportedModes += "cool " }
if(cmd.auto) { supportedModes += "auto " }
updateState("supportedModes", supportedModes)
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = ""
if(cmd.auto) { supportedFanModes += "fanAuto " }
if(cmd.low) { supportedFanModes += "fanOn " }
if(cmd.circulation) { supportedFanModes += "fanCirculate " }
updateState("supportedFanModes", supportedFanModes)
}
def updateState(String name, String value) {
state[name] = value
device.updateDataValue(name, value)
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
log.debug "Zwave event received: $cmd"
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.warn "Unexpected zwave command $cmd"
}
// Command Implementations
def poll() {
delayBetween([
zwave.sensorMultilevelV3.sensorMultilevelGet().format(), // current temperature
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format(),
zwave.thermostatOperatingStateV1.thermostatOperatingStateGet().format(),
setClock()
], 2300)
}
private setClock() { //once a day
def nowTime = new Date().time
def ageInMinutes = state.lastClockSet ? (nowTime - state.lastClockSet)/60000 : 1440
log.debug "Clock set age: ${ageInMinutes} minutes"
if (ageInMinutes >= 1440) {
log.debug "Setting clock"
state.lastClockSet = nowTime
def nowCal = Calendar.getInstance(TimeZone.getTimeZone("America/Chicago"));
zwave.clockV1.clockSet(hour: nowCal.get(Calendar.HOUR_OF_DAY), minute: nowCal.get(Calendar.MINUTE), weekday: nowCal.get(Calendar.DAY_OF_WEEK)).format()
} else "delay 87"
}
def setHeatingSetpoint(degreesF) {
setHeatingSetpoint(degreesF.toDouble())
}
def setHeatingSetpoint(Double degreesF) {
def p = (state.precision == null) ? 1 : state.precision
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 1, scale: 1, precision: p, scaledValue: degreesF).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 1).format()
])
}
def setCoolingSetpoint(degreesF) {
setCoolingSetpoint(degreesF.toDouble())
}
def setCoolingSetpoint(Double degreesF) {
def p = (state.precision == null) ? 1 : state.precision
delayBetween([
zwave.thermostatSetpointV1.thermostatSetpointSet(setpointType: 2, scale: 1, precision: p, scaledValue: degreesF).format(),
zwave.thermostatSetpointV1.thermostatSetpointGet(setpointType: 2).format()
])
}
def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format(),
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()
], 2300)
}
def modes() {
["off", "auto", "emergencyHeat", "heat", "cool"]
}
def switchMode() {
def currentMode = device.currentState("thermostatMode")?.value
def lastTriedMode = getDataByName("lastTriedMode") ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedModes")
def modeOrder = modes()
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
if (supportedModes?.contains(currentMode)) {
while (!supportedModes.contains(nextMode) && nextMode != "off") {
nextMode = next(nextMode)
}
}
log.debug "Switching to mode: ${nextMode}"
switchToMode(nextMode)
}
def switchToMode(nextMode) {
def supportedModes = getDataByName("supportedModes")
if(supportedModes && !supportedModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
if (nextMode in modes()) {
updateState("lastTriedMode", nextMode)
return "$nextMode"()
} else {
log.debug("no mode method '$nextMode'")
}
}
def switchFanMode() {
def currentMode = device.currentState("thermostatFanMode")?.value
def lastTriedMode = getDataByName("lastTriedFanMode") ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedFanModes") ?: "fanAuto fanOn"
def modeOrder = ["fanAuto", "fanCirculate", "fanOn"]
def next = { modeOrder[modeOrder.indexOf(it) + 1] ?: modeOrder[0] }
def nextMode = next(lastTriedMode)
while (!supportedModes?.contains(nextMode) && nextMode != "fanAuto") {
nextMode = next(nextMode)
}
switchToFanMode(nextMode)
}
def switchToFanMode(nextMode) {
def supportedFanModes = getDataByName("supportedFanModes")
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
def returnCommand
if (nextMode == "fanAuto") {
returnCommand = fanAuto()
} else if (nextMode == "fanOn") {
returnCommand = fanOn()
} else if (nextMode == "fanCirculate") {
returnCommand = fanCirculate()
} else {
log.debug("no fan mode '$nextMode'")
}
if(returnCommand) updateState("lastTriedFanMode", nextMode)
returnCommand
}
def getDataByName(String name) {
state[name] ?: device.getDataValue(name)
}
def getModeMap() { [
"off": 0,
"heat": 1,
"cool": 2,
"emergency heat": 4
]}
def setThermostatMode(String value) {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: modeMap[value]).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def getFanModeMap() { [
"auto": 0,
"on": 1,
"circulate": 6
]}
def setThermostatFanMode(String value) {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: fanModeMap[value]).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
])
}
def off() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 0).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def heat() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 1).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def emergencyHeat() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 4).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def cool() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 2).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def auto() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSet(mode: 3).format(),
zwave.thermostatModeV2.thermostatModeGet().format()
])
}
def fanOn() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 1).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
])
}
def fanAuto() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 0).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
])
}
def fanCirculate() {
delayBetween([
zwave.thermostatFanModeV3.thermostatFanModeSet(fanMode: 6).format(),
zwave.thermostatFanModeV3.thermostatFanModeGet().format()
])
}

View File

@@ -765,6 +765,7 @@ def turnOffSwitch() {
} else { } else {
device.off(); device.off();
return [Device_id: params.id, result_action: "200"] return [Device_id: params.id, result_action: "200"]
} }
} }
@@ -788,7 +789,6 @@ def getTempSensorsStatus(id) {
return [] return []
} else { } else {
def bat = getBatteryStatus(device.id) def bat = getBatteryStatus(device.id)
def scale = [Scale: location.temperatureScale] return [temperature: device.currentValue('temperature')] + bat
return [temperature: device.currentValue('temperature')] + bat + scale
} }
} }

View File

@@ -15,66 +15,66 @@ definition(
) )
preferences { preferences {
section("Light switches to turn off") { section("Light switches to turn off") {
input "switches", "capability.switch", title: "Choose light switches", multiple: true input "switches", "capability.switch", title: "Choose light switches", multiple: true
} }
section("Turn off when there is no motion and presence") { section("Turn off when there is no motion and presence") {
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor" input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
} }
section("Delay before turning off") { section("Delay before turning off") {
input "delayMins", "number", title: "Minutes of inactivity?" input "delayMins", "number", title: "Minutes of inactivity?"
} }
} }
def installed() { def installed() {
subscribe(motionSensor, "motion", motionHandler) subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler) subscribe(presenceSensors, "presence", presenceHandler)
} }
def updated() { def updated() {
unsubscribe() unsubscribe()
subscribe(motionSensor, "motion", motionHandler) subscribe(motionSensor, "motion", motionHandler)
subscribe(presenceSensors, "presence", presenceHandler) subscribe(presenceSensors, "presence", presenceHandler)
} }
def motionHandler(evt) { def motionHandler(evt) {
log.debug "handler $evt.name: $evt.value" log.debug "handler $evt.name: $evt.value"
if (evt.value == "inactive") { if (evt.value == "inactive") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true]) runIn(delayMins * 60, scheduleCheck, [overwrite: false])
} }
} }
def presenceHandler(evt) { def presenceHandler(evt) {
log.debug "handler $evt.name: $evt.value" log.debug "handler $evt.name: $evt.value"
if (evt.value == "not present") { if (evt.value == "not present") {
runIn(delayMins * 60, scheduleCheck, [overwrite: true]) runIn(delayMins * 60, scheduleCheck, [overwrite: false])
} }
} }
def isActivePresence() { def isActivePresence() {
// check all the presence sensors, make sure none are present // check all the presence sensors, make sure none are present
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
!noPresence !noPresence
} }
def scheduleCheck() { def scheduleCheck() {
log.debug "scheduled check" log.debug "scheduled check"
def motionState = motionSensor.currentState("motion") def motionState = motionSensor.currentState("motion")
if (motionState.value == "inactive") { if (motionState.value == "inactive") {
def elapsed = now() - motionState.rawDateCreated.time def elapsed = now() - motionState.rawDateCreated.time
def threshold = 1000 * 60 * delayMins - 1000 def threshold = 1000 * 60 * delayMins - 1000
if (elapsed >= threshold) { if (elapsed >= threshold) {
if (!isActivePresence()) { if (!isActivePresence()) {
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off" log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
switches.off() switches.off()
} else { } else {
log.debug "Presence is active: do nothing" log.debug "Presence is active: do nothing"
}
} else {
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
} }
} else {
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
}
} else { } else {
log.debug "Motion is active: do nothing" log.debug "Motion is active: do nothing"
} }
} }

View File

@@ -1,7 +1,3 @@
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
/** /**
* OpenT2T SmartApp Test * OpenT2T SmartApp Test
* *
@@ -43,7 +39,7 @@ definition(
* garageDoors | door | open, close | unknown, closed, open, closing, opening * garageDoors | door | open, close | unknown, closed, open, closing, opening
* cameras | image | take | <String> * cameras | image | take | <String>
* thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint, * thermostats | thermostat | setHeatingSetpoint, | temperature, heatingSetpoint, coolingSetpoint,
* | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode, * | | setCoolingSetpoint, | thermostatSetpoint, thermostatMode,
* | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState * | | off, heat, cool, auto,| thermostatFanMode, thermostatOperatingState
* | | emergencyHeat, | * | | emergencyHeat, |
* | | setThermostatMode, | * | | setThermostatMode, |
@@ -56,109 +52,86 @@ definition(
//Device Inputs //Device Inputs
preferences { preferences {
section("Allow OpenT2T to control these things...") { section("Allow OpenT2T to control these things...") {
input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false, hideWhenEmpty: true input "contactSensors", "capability.contactSensor", title: "Which Contact Sensors", multiple: true, required: false
input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false, hideWhenEmpty: true input "garageDoors", "capability.garageDoorControl", title: "Which Garage Doors?", multiple: true, required: false
input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false, hideWhenEmpty: true input "locks", "capability.lock", title: "Which Locks?", multiple: true, required: false
input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false, hideWhenEmpty: true input "cameras", "capability.videoCapture", title: "Which Cameras?", multiple: true, required: false
input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false, hideWhenEmpty: true input "motionSensors", "capability.motionSensor", title: "Which Motion Sensors?", multiple: true, required: false
input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false, hideWhenEmpty: true input "presenceSensors", "capability.presenceSensor", title: "Which Presence Sensors", multiple: true, required: false
input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false, hideWhenEmpty: true input "switches", "capability.switch", title: "Which Switches and Lights?", multiple: true, required: false
input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false, hideWhenEmpty: true input "thermostats", "capability.thermostat", title: "Which Thermostat?", multiple: true, required: false
input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false, hideWhenEmpty: true input "waterSensors", "capability.waterSensor", title: "Which Water Leak Sensors?", multiple: true, required: false
} }
} }
def getInputs() { def getInputs() {
def inputList = [] def inputList = []
inputList += contactSensors ?: [] inputList += contactSensors?: []
inputList += garageDoors ?: [] inputList += garageDoors?: []
inputList += locks ?: [] inputList += locks?: []
inputList += cameras ?: [] inputList += cameras?: []
inputList += motionSensors ?: [] inputList += motionSensors?: []
inputList += presenceSensors ?: [] inputList += presenceSensors?: []
inputList += switches ?: [] inputList += switches?: []
inputList += thermostats ?: [] inputList += thermostats?: []
inputList += waterSensors ?: [] inputList += waterSensors?: []
return inputList return inputList
} }
//API external Endpoints //API external Endpoints
mappings { mappings {
path("/subscriptionURL/:url") {
action: [
PUT: "updateEndpointURL"
]
}
path("/connectionId/:connId") {
action: [
PUT: "updateConnectionId"
]
}
path("/devices") { path("/devices") {
action: action: [
[
GET: "getDevices" GET: "getDevices"
] ]
} }
path("/devices/:id") { path("/devices/:id") {
action: action: [
[
GET: "getDevice" GET: "getDevice"
] ]
} }
path("/update/:id") { path("/update/:id") {
action: action: [
[
PUT: "updateDevice" PUT: "updateDevice"
] ]
} }
path("/deviceSubscription") { path("/subscription/:id") {
action: action: [
[ POST: "registerDeviceChange",
POST : "registerDeviceChange",
DELETE: "unregisterDeviceChange" DELETE: "unregisterDeviceChange"
] ]
} }
path("/locationSubscription") {
action:
[
POST : "registerDeviceGraph",
DELETE: "unregisterDeviceGraph"
]
}
} }
def installed() { def installed() {
log.debug "Installing with settings: ${settings}" log.debug "Installed with settings: ${settings}"
initialize() initialize()
} }
def updated() { def updated() {
log.debug "Updating with settings: ${settings}" log.debug "Updated with settings: ${settings}"
//Initialize state variables if didn't exist.
if (state.deviceSubscriptionMap == null) {
state.deviceSubscriptionMap = [:]
log.debug "deviceSubscriptionMap created."
}
if (state.locationSubscriptionMap == null) {
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
}
if (state.verificationKeyMap == null) {
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
}
unsubscribe() unsubscribe()
registerAllDeviceSubscriptions() registerSubscriptions()
} }
def initialize() { def initialize() {
log.debug "Initializing with settings: ${settings}" state.connectionId = ""
state.deviceSubscriptionMap = [:] state.endpointURL = "https://ifs.windows-int.com/v1/cb/81C7E77B-EABC-488A-B2BF-FEC42F0DABD2/notify"
log.debug "deviceSubscriptionMap created." registerSubscriptions()
state.locationSubscriptionMap = [:]
log.debug "locationSubscriptionMap created."
state.verificationKeyMap = [:]
log.debug "verificationKeyMap created."
registerAllDeviceSubscriptions()
} }
/*** Subscription Functions ***/
//Subscribe events for all devices //Subscribe events for all devices
def registerAllDeviceSubscriptions() { def registerSubscriptions() {
registerChangeHandler(inputs) registerChangeHandler(inputs)
} }
@@ -166,249 +139,102 @@ def registerAllDeviceSubscriptions() {
def registerChangeHandler(myList) { def registerChangeHandler(myList) {
myList.each { myDevice -> myList.each { myDevice ->
def theAtts = myDevice.supportedAttributes def theAtts = myDevice.supportedAttributes
theAtts.each { att -> theAtts.each {att ->
subscribe(myDevice, att.name, deviceEventHandler) subscribe(myDevice, att.name, eventHandler)
log.info "Registering for ${myDevice.displayName}.${att.name}" log.info "Registering ${myDevice.displayName}.${att.name}"
} }
} }
} }
//Endpoints function: Subscribe to events from a specific device //Endpoints function: Subscribe to events from a specific device
def registerDeviceChange() { def registerDeviceChange() {
def subscriptionEndpt = params.subscriptionURL def myDevice = findDevice(params.id)
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if (myDevice == null) {
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
def theAtts = myDevice.supportedAttributes def theAtts = myDevice.supportedAttributes
try { try {
theAtts.each { att -> theAtts.each {att ->
subscribe(myDevice, att.name, deviceEventHandler) subscribe(myDevice, att.name, eventHandler)
} log.info "Registering ${myDevice.displayName}.${att.name}"
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}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
} }
return ["succeed"]
} catch (e) { } catch (e) {
httpError(500, "something went wrong: $e") httpError(500, "something went wrong: $e")
} }
log.info "Current subscription map is ${state.deviceSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"]
} }
//Endpoints function: Unsubscribe to events from a specific device //Endpoints function: Unsubscribe to events from a specific device
def unregisterDeviceChange() { def unregisterDeviceChange() {
def subscriptionEndpt = params.subscriptionURL def myDevice = findDevice(params.id)
def deviceId = params.deviceId
def myDevice = findDevice(deviceId)
if (myDevice == null) {
httpError(404, "Cannot find device with device ID ${deviceId}.")
}
try { try {
if (subscriptionEndpt != null && subscriptionEndpt != "undefined") { unsubscribe(myDevice)
if (state.deviceSubscriptionMap[deviceId]?.contains(subscriptionEndpt)) { log.info "Unregistering ${myDevice.displayName}"
if (state.deviceSubscriptionMap[deviceId].size() == 1) {
state.deviceSubscriptionMap.remove(deviceId)
} else {
state.deviceSubscriptionMap[deviceId].remove(subscriptionEndpt)
}
state.verificationKeyMap.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}"
log.info "Current verification key map is ${state.verificationKeyMap}"
}
//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}"
}
if (params.key != null) {
state.verificationKeyMap[subscriptionEndpt] = params.key
log.info "Added verification key: ${params.key} for ${subscriptionEndpt}"
}
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
return ["succeed"] 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)
}
state.verificationKeyMap.remove(subscriptionEndpt)
log.info "Removed subscription URL: ${subscriptionEndpt} for Location ${location.name}"
}
} else {
httpError(400, "missing input parameter: subscriptionURL")
}
} catch (e) { } catch (e) {
httpError(500, "something went wrong: $e") httpError(500, "something went wrong: $e")
} }
log.info "Current location subscription map is ${state.locationSubscriptionMap}"
log.info "Current verification key map is ${state.verificationKeyMap}"
} }
//When events are triggered, send HTTP post to web socket servers //When events are triggered, send HTTP post to web socket servers
def deviceEventHandler(evt) { def eventHandler(evt) {
def evtDevice = evt.device def evt_device_id = evt.deviceId
def evtDeviceType = getDeviceType(evtDevice) def evt_device_value = evt.value
def deviceData = []; def evt_name = evt.name
def evt_device = evt.device
def evt_deviceType = getDeviceType(evt_device);
def deviceInfo
if (evt.data != null) { if(evt_deviceType == "thermostat")
def evtData = parseJson(evt.data) {
log.info "Received event for ${evtDevice.displayName}, data: ${evtData}, description: ${evt.descriptionText}" 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)]
} }
if (evtDeviceType == "thermostat") { def params = [
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationMode: getLocationModeInfo(), locationId: location.id] uri: "${state.endpointURL}/${state.connectionId}",
} else { body: [ deviceInfo ]
deviceData = [name: evtDevice.displayName, id: evtDevice.id, status: evtDevice.status, deviceType: evtDeviceType, manufacturer: evtDevice.manufacturerName, model: evtDevice.modelName, attributes: deviceAttributeList(evtDevice, evtDeviceType), locationId: location.id] ]
}
def params = [body: deviceData]
//send event to all subscriptions urls
log.debug "Current subscription urls for ${evtDevice.displayName} is ${state.deviceSubscriptionMap[evtDevice.id]}"
state.deviceSubscriptionMap[evtDevice.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
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"
}
}
}
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 evtDevice = evt.device
def evtDeviceType = getDeviceType(evtDevice)
def params = [body: [eventType: evt.name, deviceId: evtDevice.id, locationId: location.id]]
if (evt.name == "DeviceDeleted" && state.deviceSubscriptionMap[deviceId] != null) {
state.deviceSubscriptionMap.remove(evtDevice.id)
}
state.locationSubscriptionMap[location.id].each {
params.uri = "${it}"
if (state.verificationKeyMap[it] != null) {
def key = state.verificationKeyMap[it]
params.header = [Signature: ComputHMACValue(key, groovy.json.JsonOutput.toJson(params.body))]
}
log.trace "POST URI: ${params.uri}"
log.trace "Header: ${params.header}"
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
}
}
private ComputHMACValue(key, data) {
try { try {
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1") log.trace "POST URI: ${params.uri}"
Mac mac = Mac.getInstance("HmacSHA1") log.trace "Payload: ${params.body}"
mac.init(secretKeySpec) httpPostJson(params) { resp ->
byte[] digest = mac.doFinal(data.getBytes("UTF-8")) resp.headers.each {
return byteArrayToString(digest) log.debug "${it.name} : ${it.value}"
} catch (InvalidKeyException e) { }
log.error "Invalid key exception while converting to HMac SHA1" log.trace "response status code: ${resp.status}"
log.trace "response data: ${resp.data}"
}
} catch (e) {
log.debug "something went wrong: $e"
} }
} }
private def byteArrayToString(byte[] data) { //Endpoints function: update subcription endpoint url [state.endpoint]
BigInteger bigInteger = new BigInteger(1, data) void updateEndpointURL() {
String hash = bigInteger.toString(16) state.endpointURL = params.url
return hash log.info "Updated EndpointURL to ${state.endpointURL}"
} }
/*** Device Query/Update Functions ***/ //Endpoints function: update global variable [state.connectionId]
void updateConnectionId() {
def connId = params.connId
state.connectionId = connId
log.info "Updated ConnectionID to ${state.connectionId}"
}
//Endpoints function: return all device data in json format //Endpoints function: return all device data in json format
def getDevices() { def getDevices() {
def deviceData = [] def deviceData = []
inputs?.each { inputs?.each {
def deviceType = getDeviceType(it) def deviceType = getDeviceType(it)
if (deviceType == "thermostat") { if(deviceType == "thermostat")
deviceData << [name: it.displayName, id: it.id, 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.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
deviceData << [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType)] }
else
{
deviceData << [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it)]
} }
} }
@@ -421,12 +247,14 @@ def getDevice() {
def it = findDevice(params.id) def it = findDevice(params.id)
def deviceType = getDeviceType(it) def deviceType = getDeviceType(it)
def device def device
if (deviceType == "thermostat") { if(deviceType == "thermostat")
device = [name: it.displayName, id: it.id, 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.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it), locationMode: getLocationModeInfo()]
device = [name: it.displayName, id: it.id, status: it.status, deviceType: deviceType, manufacturer: it.manufacturerName, model: it.modelName, attributes: deviceAttributeList(it, deviceType)] }
else
{
device = [name: it.displayName, id: it.id, status:it.getStatus(), deviceType:deviceType, manufacturer:it.getManufacturerName(), model:it.getModelName(), attributes: deviceAttributeList(it)]
} }
log.debug "getDevice, return: ${device}" log.debug "getDevice, return: ${device}"
return device return device
} }
@@ -437,18 +265,18 @@ void updateDevice() {
request.JSON.each { request.JSON.each {
def command = it.key def command = it.key
def value = it.value def value = it.value
if (command) { if (command){
def commandList = mapDeviceCommands(command, value) def commandList = mapDeviceCommands(command, value)
command = commandList[0] command = commandList[0]
value = commandList[1] value = commandList[1]
if (command == "setAwayMode") { if (command == "setAwayMode") {
log.info "Setting away mode to ${value}" log.info "Setting away mode to ${value}"
if (location.modes?.find { it.name == value }) { if (location.modes?.find {it.name == value}) {
location.setMode(value) location.setMode(value)
} }
} else if (command == "thermostatSetpoint") { }else if (command == "thermostatSetpoint"){
switch (device.currentThermostatMode) { switch(device.currentThermostatMode){
case "cool": case "cool":
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device.setCoolingSetpoint(value) device.setCoolingSetpoint(value)
@@ -462,7 +290,7 @@ void updateDevice() {
httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.") httpError(501, "this mode: ${device.currentThermostatMode} does not allow changing thermostat setpoint.")
break break
} }
} else if (!device) { }else if (!device) {
log.error "updateDevice, Device not found" log.error "updateDevice, Device not found"
httpError(404, "Device not found") httpError(404, "Device not found")
} else if (!device.hasCommand(command)) { } else if (!device.hasCommand(command)) {
@@ -472,11 +300,11 @@ void updateDevice() {
if (command == "setColor") { if (command == "setColor") {
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(hex: value) device."$command"(hex: value)
} else if (value.isNumber()) { } else if(value.isNumber()) {
def intValue = value as Integer def intValue = value as Integer
log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]" log.info "Update: ${device.displayName}, [${command}, ${intValue}(int)]"
device."$command"(intValue) device."$command"(intValue)
} else if (value) { } else if (value){
log.info "Update: ${device.displayName}, [${command}, ${value}]" log.info "Update: ${device.displayName}, [${command}, ${value}]"
device."$command"(value) device."$command"(value)
} else { } else {
@@ -503,16 +331,17 @@ private getDeviceType(device) {
log.debug "supported commands: [${device}, ${device.supportedCommands}]" log.debug "supported commands: [${device}, ${device.supportedCommands}]"
//Loop through the device capability list to determine the device type. //Loop through the device capability list to determine the device type.
capabilities.each { capability -> capabilities.each {capability ->
switch (capability.name.toLowerCase()) { switch(capability.name.toLowerCase())
{
case "switch": case "switch":
deviceType = "switch" deviceType = "switch"
//If the device also contains "Switch Level" capability, identify it as a "light" device. //If the device also contains "Switch Level" capability, identify it as a "light" device.
if (capabilities.any { it.name.toLowerCase() == "switch level" }) { if (capabilities.any{it.name.toLowerCase() == "switch level"}){
//If the device also contains "Power Meter" capability, identify it as a "dimmerSwitch" device. //If the device also contains "Power Meter" capability, identify it as a "dimmerSwitch" device.
if (capabilities.any { it.name.toLowerCase() == "power meter" }) { if (capabilities.any{it.name.toLowerCase() == "power meter"}){
deviceType = "dimmerSwitch" deviceType = "dimmerSwitch"
return deviceType return deviceType
} else { } else {
@@ -521,6 +350,9 @@ private getDeviceType(device) {
} }
} }
break break
case "contact sensor":
deviceType = "contactSensor"
return deviceType
case "garageDoorControl": case "garageDoorControl":
deviceType = "garageDoor" deviceType = "garageDoor"
return deviceType return deviceType
@@ -530,15 +362,17 @@ private getDeviceType(device) {
case "video camera": case "video camera":
deviceType = "camera" deviceType = "camera"
return deviceType return deviceType
case "motion sensor":
deviceType = "motionSensor"
return deviceType
case "presence sensor":
deviceType = "presenceSensor"
return deviceType
case "thermostat": case "thermostat":
deviceType = "thermostat" deviceType = "thermostat"
return deviceType return deviceType
case "acceleration sensor":
case "contact sensor":
case "motion sensor":
case "presence sensor":
case "water sensor": case "water sensor":
deviceType = "genericSensor" deviceType = "waterSensor"
return deviceType return deviceType
default: default:
break break
@@ -553,33 +387,14 @@ private findDevice(deviceId) {
} }
//Return a list of device attributes //Return a list of device attributes
private deviceAttributeList(device, deviceType) { private deviceAttributeList(device) {
def attributeList = [:] device.supportedAttributes.collectEntries { attribute->
def allAttributes = device.supportedAttributes
allAttributes.each { attribute ->
try { try {
def currentState = device.currentState(attribute.name) [ (attribute.name): device.currentValue(attribute.name) ]
if (currentState != null) { } catch(e) {
switch (attribute.name) { [ (attribute.name): null ]
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) {
attributeList.putAll([(attribute.name): null]);
} }
} }
return attributeList
} }
//Map device command and value. //Map device command and value.
@@ -649,7 +464,8 @@ private mapDeviceCommands(command, value) {
if (value == 1 || value == "1" || value == "lock") { if (value == 1 || value == "1" || value == "lock") {
resultCommand = "lock" resultCommand = "lock"
resultValue = "" resultValue = ""
} else if (value == 0 || value == "0" || value == "unlock") { }
else if (value == 0 || value == "0" || value == "unlock") {
resultCommand = "unlock" resultCommand = "unlock"
resultValue = "" resultValue = ""
} }
@@ -658,5 +474,5 @@ private mapDeviceCommands(command, value) {
break break
} }
return [resultCommand, resultValue] return [resultCommand,resultValue]
} }

View File

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

View File

@@ -27,82 +27,84 @@ definition(
preferences { preferences {
section("Monitor this door or window") { section("Monitor this door or window") {
input "contact", "capability.contactSensor" input "contact", "capability.contactSensor"
} }
section("And notify me if it's open for more than this many minutes (default 10)") {
section("And notify me if it's open for more than this many minutes (default 10)") { input "openThreshold", "number", description: "Number of minutes", required: false
input "openThreshold", "number", description: "Number of minutes", required: false }
} section("Delay between notifications (default 10 minutes") {
input "frequency", "number", title: "Number of minutes", description: "", required: false
section("Delay between notifications (default 10 minutes") {
input "frequency", "number", title: "Number of minutes", description: "", required: false
}
section("Via text message at this number (or via push notification if not specified") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone number (optional)", required: false
} }
} section("Via text message at this number (or via push notification if not specified") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone number (optional)", required: false
}
}
} }
def installed() { def installed() {
log.trace "installed()" log.trace "installed()"
subscribe() subscribe()
} }
def updated() { def updated() {
log.trace "updated()" log.trace "updated()"
unsubscribe() unsubscribe()
subscribe() subscribe()
} }
def subscribe() { def subscribe() {
subscribe(contact, "contact.open", doorOpen) subscribe(contact, "contact.open", doorOpen)
subscribe(contact, "contact.closed", doorClosed) subscribe(contact, "contact.closed", doorClosed)
} }
def doorOpen(evt) { def doorOpen(evt)
log.trace "doorOpen($evt.name: $evt.value)" {
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600 log.trace "doorOpen($evt.name: $evt.value)"
runIn(delay, doorOpenTooLong, [overwrite: true]) def t0 = now()
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
runIn(delay, doorOpenTooLong, [overwrite: false])
log.debug "scheduled doorOpenTooLong in ${now() - t0} msec"
} }
def doorClosed(evt) { def doorClosed(evt)
log.trace "doorClosed($evt.name: $evt.value)" {
unschedule(doorOpenTooLong) log.trace "doorClosed($evt.name: $evt.value)"
} }
def doorOpenTooLong() { def doorOpenTooLong() {
def contactState = contact.currentState("contact") def contactState = contact.currentState("contact")
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600 def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
if (contactState.value == "open") { if (contactState.value == "open") {
def elapsed = now() - contactState.rawDateCreated.time def elapsed = now() - contactState.rawDateCreated.time
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000 def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
if (elapsed >= threshold) { if (elapsed >= threshold) {
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()" log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
sendMessage() sendMessage()
runIn(freq, doorOpenTooLong, [overwrite: false]) runIn(freq, doorOpenTooLong, [overwrite: false])
} else { } else {
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing" log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
} }
} else { } else {
log.warn "doorOpenTooLong() called but contact is closed: doing nothing" log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
} }
} }
void sendMessage() { void sendMessage()
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10 {
def msg = "${contact.displayName} has been left open for ${minutes} minutes." def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
log.info msg def msg = "${contact.displayName} has been left open for ${minutes} minutes."
if (location.contactBookEnabled) { log.info msg
sendNotificationToContacts(msg, recipients) if (location.contactBookEnabled) {
} else { sendNotificationToContacts(msg, recipients)
if (phone) { }
sendSms phone, msg else {
} else { if (phone) {
sendPush msg sendSms phone, msg
} else {
sendPush msg
}
} }
}
} }

View File

@@ -47,7 +47,6 @@ def getCallbackUrl() { return "${getServerUrl()}/oauth/callback" }
def apiURL(path = '/') { return "https://api.lifx.com/v1${path}" } def apiURL(path = '/') { return "https://api.lifx.com/v1${path}" }
def getSecretKey() { return appSettings.secretKey } def getSecretKey() { return appSettings.secretKey }
def getClientId() { return appSettings.clientId } def getClientId() { return appSettings.clientId }
private getVendorName() { "LIFX" }
def authPage() { def authPage() {
log.debug "authPage test1" log.debug "authPage test1"
@@ -77,7 +76,6 @@ def authPage() {
return dynamicPage(name:"Credentials", title:"", nextPage:"", install:true, uninstall: true) { return dynamicPage(name:"Credentials", title:"", nextPage:"", install:true, uninstall: true) {
section("Select your location") { section("Select your location") {
input "selectedLocationId", "enum", required:true, title:"Select location ({{count}} found)", messageArgs: [count: count], multiple:false, options:options, submitOnChange: true input "selectedLocationId", "enum", required:true, title:"Select location ({{count}} found)", messageArgs: [count: count], multiple:false, options:options, submitOnChange: true
paragraph "Devices will be added automatically from your ${vendorName} account. To add or delete devices please use the Official ${vendorName} App."
} }
} }
} }

View File

@@ -98,7 +98,7 @@ def motionHandler(evt) {
else { else {
state.motionStopTime = now() state.motionStopTime = now()
if(delayMinutes) { if(delayMinutes) {
runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: true]) runIn(delayMinutes*60, turnOffMotionAfterDelay, [overwrite: false])
} else { } else {
turnOffMotionAfterDelay() turnOffMotionAfterDelay()
} }

View File

@@ -136,20 +136,10 @@ def getDataForChild(child, startDate, endDate) {
def wattvisionURL = wattvisionURL(child.deviceNetworkId, startDate, endDate) def wattvisionURL = wattvisionURL(child.deviceNetworkId, startDate, endDate)
if (wattvisionURL) { if (wattvisionURL) {
try { httpGet(uri: wattvisionURL) { response ->
httpGet(uri: wattvisionURL) { response -> def json = new org.json.JSONObject(response.data.toString())
def json = new org.json.JSONObject(response.data.toString()) child.addWattvisionData(json)
child.addWattvisionData(json) return "success"
return "success"
}
} catch (groovyx.net.http.HttpResponseException httpE) {
log.error "Wattvision getDataForChild HttpResponseException: ${httpE} -> ${httpE.response.data}"
//log.debug "wattvisionURL = ${wattvisionURL}"
return "fail"
} catch (e) {
log.error "Wattvision getDataForChild General Exception: ${e}"
//log.debug "wattvisionURL = ${wattvisionURL}"
return "fail"
} }
} }
} }
@@ -174,14 +164,9 @@ def wattvisionURL(senorId, startDate, endDate) {
if (diff > 259200000) { // 3 days in milliseconds if (diff > 259200000) { // 3 days in milliseconds
// Wattvision only allows pulling 3 hours of data at a time // Wattvision only allows pulling 3 hours of data at a time
startDate = new Date(hours: endDate.hours - 3) startDate = new Date(hours: endDate.hours - 3)
} else if (diff < 10000) { // 10 seconds in milliseconds
// Wattvision throws errors when the difference between start_time and end_time is 5 seconds or less
// So we are going to make sure that we have a few more seconds of breathing room
use (groovy.time.TimeCategory) {
startDate = endDate - 10.seconds
}
} }
def params = [ def params = [
"sensor_id" : senorId, "sensor_id" : senorId,
"api_id" : wattvisionApiAccess.id, "api_id" : wattvisionApiAccess.id,
@@ -495,3 +480,4 @@ def connectionSuccessful(deviceName, iconSrc) {
render contentType: 'text/html', data: html render contentType: 'text/html', data: html
} }

View File

@@ -125,19 +125,19 @@
if(allOk) { if(allOk) {
if(everyoneIsAway() && (state.sunMode == "sunrise")) { if(everyoneIsAway() && (state.sunMode == "sunrise")) {
log.debug("Home is Empty Setting New Away Mode") log.info("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60 def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway") runIn(delay, "setAway")
} }
if(everyoneIsAway() && (state.sunMode == "sunset")) { if(everyoneIsAway() && (state.sunMode == "sunset")) {
log.debug("Home is Empty Setting New Away Mode") log.info("Home is Empty Setting New Away Mode")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60 def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway") runIn(delay, "setAway")
} }
else { else {
log.debug("Home is Occupied Setting New Home Mode") log.info("Home is Occupied Setting New Home Mode")
setHome() setHome()
@@ -152,7 +152,7 @@
log.debug("Checking if everyone is away") log.debug("Checking if everyone is away")
if(everyoneIsAway()) { if(everyoneIsAway()) {
log.debug("Nobody is home, running away sequence") log.info("Nobody is home, running away sequence")
def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60 def delay = (falseAlarmThreshold != null && falseAlarmThreshold != "") ? falseAlarmThreshold * 60 : 10 * 60
runIn(delay, "setAway") runIn(delay, "setAway")
} }
@@ -161,7 +161,7 @@
else { else {
def lastTime = state[evt.deviceId] def lastTime = state[evt.deviceId]
if (lastTime == null || now() - lastTime >= 1 * 60000) { if (lastTime == null || now() - lastTime >= 1 * 60000) {
log.debug("Someone is home, running home sequence") log.info("Someone is home, running home sequence")
setHome() setHome()
} }
state[evt.deviceId] = now() state[evt.deviceId] = now()
@@ -175,14 +175,14 @@
if(everyoneIsAway()) { if(everyoneIsAway()) {
if(state.sunMode == "sunset") { if(state.sunMode == "sunset") {
def message = "Performing \"${awayNight}\" for you as requested." def message = "Performing \"${awayNight}\" for you as requested."
log.debug(message) log.info(message)
sendAway(message) sendAway(message)
location.helloHome.execute(settings.awayNight) location.helloHome.execute(settings.awayNight)
} }
else if(state.sunMode == "sunrise") { else if(state.sunMode == "sunrise") {
def message = "Performing \"${awayDay}\" for you as requested." def message = "Performing \"${awayDay}\" for you as requested."
log.debug(message) log.info(message)
sendAway(message) sendAway(message)
location.helloHome.execute(settings.awayDay) location.helloHome.execute(settings.awayDay)
} }
@@ -192,19 +192,19 @@
} }
else { else {
log.debug("Somebody returned home before we set to '${newAwayMode}'") log.info("Somebody returned home before we set to '${newAwayMode}'")
} }
} }
//set home mode when house is occupied //set home mode when house is occupied
def setHome() { def setHome() {
sendOutOfDateNotification() sendOutOfDateNotification()
log.debug("Setting Home Mode!!") log.info("Setting Home Mode!!")
if(anyoneIsHome()) { if(anyoneIsHome()) {
if(state.sunMode == "sunset"){ if(state.sunMode == "sunset"){
if (location.mode != "${homeModeNight}"){ if (location.mode != "${homeModeNight}"){
def message = "Performing \"${homeNight}\" for you as requested." def message = "Performing \"${homeNight}\" for you as requested."
log.debug(message) log.info(message)
sendHome(message) sendHome(message)
location.helloHome.execute(settings.homeNight) location.helloHome.execute(settings.homeNight)
} }
@@ -213,7 +213,7 @@
if(state.sunMode == "sunrise"){ if(state.sunMode == "sunrise"){
if (location.mode != "${homeModeDay}"){ if (location.mode != "${homeModeDay}"){
def message = "Performing \"${homeDay}\" for you as requested." def message = "Performing \"${homeDay}\" for you as requested."
log.debug(message) log.info(message)
sendHome(message) sendHome(message)
location.helloHome.execute(settings.homeDay) location.helloHome.execute(settings.homeDay)
} }
@@ -329,4 +329,4 @@
sendNotification("Your version of Hello, Home Phrase Director is currently out of date. Please look for the new version of Hello, Home Phrase Director now called 'Routine Director' in the marketplace.") sendNotification("Your version of Hello, Home Phrase Director is currently out of date. Please look for the new version of Hello, Home Phrase Director now called 'Routine Director' in the marketplace.")
state.lastTime = (new Date() + 31).getTime() state.lastTime = (new Date() + 31).getTime()
} }
} }