mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
Compare commits
12 Commits
PROD_2017.
...
MSA-1970-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b2baf1244 | ||
|
|
a99e050c6b | ||
|
|
5bf7caca0d | ||
|
|
3eddd68532 | ||
|
|
8d79379bba | ||
|
|
dd4da29bcd | ||
|
|
b6136bf1d5 | ||
|
|
68f5cda945 | ||
|
|
da42ee63fb | ||
|
|
c58132a69e | ||
|
|
f069ea3087 | ||
|
|
5b7a7097b8 |
@@ -0,0 +1,735 @@
|
||||
/**
|
||||
|
||||
* Fibaro Wall Plug ZW5
|
||||
|
||||
* Requires: Fibaro Double Switch 2 Child Device
|
||||
|
||||
*
|
||||
|
||||
* Copyright 2017 Artur Draga
|
||||
|
||||
*
|
||||
|
||||
* 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: "Fibaro Wall Plug ZW5", namespace: "ClassicGOD", author: "Artur Draga") {
|
||||
|
||||
capability "Switch"
|
||||
|
||||
capability "Energy Meter"
|
||||
|
||||
capability "Power Meter"
|
||||
|
||||
capability "Configuration"
|
||||
|
||||
capability "Health Check"
|
||||
|
||||
|
||||
|
||||
command "reset"
|
||||
|
||||
command "refresh"
|
||||
|
||||
|
||||
|
||||
fingerprint deviceId: "0x1001", inClusters:"0x5E,0x22,0x59,0x56,0x7A,0x32,0x71,0x73,0x98,0x31,0x85,0x70,0x72,0x5A,0x8E,0x25,0x86"
|
||||
|
||||
fingerprint deviceId: "0x1001", inClusters:"0x5E,0x22,0x59,0x56,0x7A,0x32,0x71,0x73,0x31,0x85,0x70,0x72,0x5A,0x8E,0x25,0x86"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
tiles (scale: 2) {
|
||||
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 3, height: 4, canChangeIcon: true){
|
||||
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
|
||||
attributeState "off", label: 'Off', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState:"turningOn"
|
||||
|
||||
attributeState "on", label: 'On', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc", nextState:"turningOff"
|
||||
|
||||
attributeState "turningOn", label:'Turning On', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
|
||||
|
||||
attributeState "turningOff", label:'Turning Off', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
|
||||
}
|
||||
|
||||
tileAttribute("device.combinedMeter", key:"SECONDARY_CONTROL") {
|
||||
|
||||
attributeState("combinedMeter", label:'${currentValue}')
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) {
|
||||
|
||||
state "power", label:'${currentValue}\nW', action:"refresh"
|
||||
|
||||
}
|
||||
|
||||
valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 2) {
|
||||
|
||||
state "energy", label:'${currentValue}\nkWh', action:"refresh"
|
||||
|
||||
}
|
||||
|
||||
valueTile("reset", "device.energy", decoration: "flat", width: 2, height: 2) {
|
||||
|
||||
state "reset", label:'reset\nkWh', action:"reset"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
preferences {
|
||||
|
||||
input ( name: "logging", title: "Logging", type: "boolean", required: false )
|
||||
|
||||
parameterMap().each {
|
||||
|
||||
input (
|
||||
|
||||
name: it.key,
|
||||
|
||||
title: "${it.num}. ${it.title}",
|
||||
|
||||
description: it.descr,
|
||||
|
||||
type: it.type,
|
||||
|
||||
options: it.options,
|
||||
|
||||
range: (it.min != null && it.max != null) ? "${it.min}..${it.max}" : null,
|
||||
|
||||
defaultValue: it.def,
|
||||
|
||||
required: false
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//UI and tile functions
|
||||
|
||||
def on() {
|
||||
|
||||
encap(zwave.basicV1.basicSet(value: 255))
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def off() {
|
||||
|
||||
encap(zwave.basicV1.basicSet(value: 0))
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def reset() {
|
||||
|
||||
def cmds = []
|
||||
|
||||
cmds << zwave.meterV3.meterReset()
|
||||
|
||||
cmds << zwave.meterV3.meterGet(scale: 0)
|
||||
|
||||
cmds << zwave.meterV3.meterGet(scale: 2)
|
||||
|
||||
encapSequence(cmds,1000)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def refresh() {
|
||||
|
||||
def cmds = []
|
||||
|
||||
cmds << zwave.meterV3.meterGet(scale: 0)
|
||||
|
||||
cmds << zwave.meterV3.meterGet(scale: 2)
|
||||
|
||||
cmds << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 4)
|
||||
|
||||
encapSequence(cmds,1000)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Configuration and synchronization
|
||||
|
||||
def updated() {
|
||||
|
||||
if ( state.lastUpdated && (now() - state.lastUpdated) < 500 ) return
|
||||
|
||||
def cmds = []
|
||||
|
||||
logging("${device.displayName} - Executing updated()","info")
|
||||
|
||||
|
||||
|
||||
def Integer cmdCount = 0
|
||||
|
||||
parameterMap().each {
|
||||
|
||||
if(settings."$it.key" != null) {
|
||||
|
||||
if (state."$it.key" == null) { state."$it.key" = [value: null, state: "synced"] }
|
||||
|
||||
if (state."$it.key".value != settings."$it.key" as Integer || state."$it.key".state == "notSynced") {
|
||||
|
||||
state."$it.key".value = settings."$it.key" as Integer
|
||||
|
||||
state."$it.key".state = "notSynced"
|
||||
|
||||
cmds << zwave.configurationV2.configurationSet(configurationValue: intToParam(state."$it.key".value, it.size), parameterNumber: it.num, size: it.size)
|
||||
|
||||
cmds << zwave.configurationV2.configurationGet(parameterNumber: it.num)
|
||||
|
||||
cmdCount = cmdCount + 1
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( cmdCount > 0 ) {
|
||||
|
||||
logging("${device.displayName} - sending config.", "info")
|
||||
|
||||
sendEvent(name: "combinedMeter", value: "SYNC IN PROGRESS.", displayed: false)
|
||||
|
||||
runIn((5+cmdCount*2), syncCheck)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
state.lastUpdated = now()
|
||||
|
||||
if (cmds) { response(encapSequence(cmds,1000)) }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def syncCheck() {
|
||||
|
||||
logging("${device.displayName} - Executing syncCheck()","info")
|
||||
|
||||
def Integer count = 0
|
||||
|
||||
if (device.currentValue("combinedMeter")?.contains("SYNC") && device.currentValue("combinedMeter") != "SYNC OK.") {
|
||||
|
||||
parameterMap().each {
|
||||
|
||||
if (state."$it.key".state == "notSynced" ) {
|
||||
|
||||
count = count + 1
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
|
||||
logging("${device.displayName} - Sync Complete","info")
|
||||
|
||||
sendEvent(name: "combinedMeter", value: "SYNC OK.", displayed: false)
|
||||
|
||||
} else {
|
||||
|
||||
logging("${device.displayName} Sync Incomplete","info")
|
||||
|
||||
if (device.currentValue("combinedMeter") != "SYNC FAILED!") {
|
||||
|
||||
sendEvent(name: "combinedMeter", value: "SYNC INCOMPLETE.", displayed: false)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//event handlers related to configuration and sync
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
|
||||
|
||||
def paramKey = parameterMap().find( {it.num == cmd.parameterNumber } ).key
|
||||
|
||||
logging("${device.displayName} - Parameter ${paramKey} value is ${cmd.scaledConfigurationValue} expected " + state."$paramKey".value, "info")
|
||||
|
||||
if (state."$paramKey".value == cmd.scaledConfigurationValue) {
|
||||
|
||||
state."$paramKey".state = "synced"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.applicationstatusv1.ApplicationRejectedRequest cmd) {
|
||||
|
||||
logging("${device.displayName} - rejected request!","warn")
|
||||
|
||||
if (device.currentValue("combinedMeter") == "SYNC IN PROGRESS.") {
|
||||
|
||||
sendEvent(name: "combinedMeter", value: "SYNC FAILED!", displayed: false)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//event handlers
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
|
||||
|
||||
//ignore
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
|
||||
|
||||
logging("${device.displayName} - SwitchBinaryReport received, value: ${cmd.value}","info")
|
||||
|
||||
sendEvent([name: "switch", value: (cmd.value == 0 ) ? "off": "on"])
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
|
||||
|
||||
logging("${device.displayName} - SensorMultilevelReport received, value: ${cmd.scaledSensorValue} scale: ${cmd.scale}","info")
|
||||
|
||||
if (cmd.sensorType == 4) {
|
||||
|
||||
sendEvent([name: "power", value: cmd.scaledSensorValue, unit: "W"])
|
||||
|
||||
updateCombinedMeter()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) {
|
||||
|
||||
logging("${device.displayName} - MeterReport received, value: ${cmd.scaledMeterValue} scale: ${cmd.scale}","info")
|
||||
|
||||
switch (cmd.scale) {
|
||||
|
||||
case 0:
|
||||
|
||||
sendEvent([name: "energy", value: cmd.scaledMeterValue, unit: "kWh"])
|
||||
|
||||
break
|
||||
|
||||
case 2:
|
||||
|
||||
sendEvent([name: "power", value: cmd.scaledMeterValue, unit: "W"])
|
||||
|
||||
break
|
||||
|
||||
}
|
||||
|
||||
updateCombinedMeter()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//other
|
||||
|
||||
private updateCombinedMeter() {
|
||||
|
||||
if (!device.currentValue("combinedMeter")?.contains("SYNC") || device.currentValue("combinedMeter") == "SYNC OK." || device.currentValue("combinedMeter") == null ) {
|
||||
|
||||
sendEvent([name: "combinedMeter", value: "${device.currentValue("power")} W / ${device.currentValue("energy")} kWh", displayed: false])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
####################
|
||||
|
||||
## Z-Wave Toolkit ##
|
||||
|
||||
####################
|
||||
|
||||
*/
|
||||
|
||||
def parse(String description) {
|
||||
|
||||
def result = []
|
||||
|
||||
logging("${device.displayName} - Parsing: ${description}")
|
||||
|
||||
if (description.startsWith("Err 106")) {
|
||||
|
||||
result = createEvent(
|
||||
|
||||
descriptionText: "Failed to complete the network security key exchange. If you are unable to receive data from it, you must remove it from your network and add it again.",
|
||||
|
||||
eventType: "ALERT",
|
||||
|
||||
name: "secureInclusion",
|
||||
|
||||
value: "failed",
|
||||
|
||||
displayed: true,
|
||||
|
||||
)
|
||||
|
||||
} else if (description == "updated") {
|
||||
|
||||
return null
|
||||
|
||||
} else {
|
||||
|
||||
def cmd = zwave.parse(description, cmdVersions())
|
||||
|
||||
if (cmd) {
|
||||
|
||||
logging("${device.displayName} - Parsed: ${cmd}")
|
||||
|
||||
zwaveEvent(cmd)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
|
||||
|
||||
def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions())
|
||||
|
||||
if (encapsulatedCommand) {
|
||||
|
||||
logging("${device.displayName} - Parsed SecurityMessageEncapsulation into: ${encapsulatedCommand}")
|
||||
|
||||
zwaveEvent(encapsulatedCommand)
|
||||
|
||||
} else {
|
||||
|
||||
log.warn "Unable to extract secure cmd from $cmd"
|
||||
|
||||
createEvent(descriptionText: cmd.toString())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) {
|
||||
|
||||
def version = cmdVersions()[cmd.commandClass as Integer]
|
||||
|
||||
def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
|
||||
|
||||
def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
|
||||
|
||||
if (!encapsulatedCommand) {
|
||||
|
||||
log.warn "Could not extract crc16 command from $cmd"
|
||||
|
||||
} else {
|
||||
|
||||
logging("${device.displayName} - Parsed Crc16Encap into: ${encapsulatedCommand}")
|
||||
|
||||
zwaveEvent(encapsulatedCommand)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
|
||||
|
||||
def encapsulatedCommand = cmd.encapsulatedCommand(cmdVersions())
|
||||
|
||||
if (encapsulatedCommand) {
|
||||
|
||||
logging("${device.displayName} - Parsed MultiChannelCmdEncap ${encapsulatedCommand}")
|
||||
|
||||
zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private logging(text, type = "debug") {
|
||||
|
||||
if (settings.logging == "true") {
|
||||
|
||||
log."$type" text
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private secEncap(physicalgraph.zwave.Command cmd) {
|
||||
|
||||
logging("${device.displayName} - encapsulating command using Secure Encapsulation, command: $cmd","info")
|
||||
|
||||
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private crcEncap(physicalgraph.zwave.Command cmd) {
|
||||
|
||||
logging("${device.displayName} - encapsulating command using CRC16 Encapsulation, command: $cmd","info")
|
||||
|
||||
zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format() // doesn't work righ now because SmartThings...
|
||||
|
||||
//"5601${cmd.format()}0000"
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private multiEncap(physicalgraph.zwave.Command cmd, Integer ep) {
|
||||
|
||||
logging("${device.displayName} - encapsulating command using Multi Channel Encapsulation, ep: $ep command: $cmd","info")
|
||||
|
||||
zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:ep).encapsulate(cmd)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encap(physicalgraph.zwave.Command cmd) {
|
||||
|
||||
if (zwaveInfo.zw.contains("s")) {
|
||||
|
||||
secEncap(cmd)
|
||||
|
||||
} else if (zwaveInfo.cc.contains("56")){
|
||||
|
||||
crcEncap(cmd)
|
||||
|
||||
} else {
|
||||
|
||||
logging("${device.displayName} - no encapsulation supported for command: $cmd","info")
|
||||
|
||||
cmd.format()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encap(physicalgraph.zwave.Command cmd, Integer ep) {
|
||||
|
||||
encap(multiEncap(cmd, ep))
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encap(List encapList) {
|
||||
|
||||
encap(encapList[0], encapList[1])
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encap(Map encapMap) {
|
||||
|
||||
encap(encapMap.cmd, encapMap.ep)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encapSequence(cmds, Integer delay=250) {
|
||||
|
||||
delayBetween(cmds.collect{ encap(it) }, delay)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private encapSequence(cmds, Integer delay, Integer ep) {
|
||||
|
||||
delayBetween(cmds.collect{ encap(it, ep) }, delay)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List intToParam(Long value, Integer size = 1) {
|
||||
|
||||
def result = []
|
||||
|
||||
size.times {
|
||||
|
||||
result = result.plus(0, (value & 0xFF) as Short)
|
||||
|
||||
value = (value >> 8)
|
||||
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
##########################
|
||||
|
||||
## Device Configuration ##
|
||||
|
||||
##########################
|
||||
|
||||
*/
|
||||
|
||||
private Map cmdVersions() {
|
||||
|
||||
//[0x5E: 2, 0x59: 1, 0x80: 1, 0x56: 1, 0x7A: 3, 0x73: 1, 0x98: 1, 0x22: 1, 0x85: 2, 0x5B: 1, 0x70: 2, 0x8E: 2, 0x86: 2, 0x84: 2, 0x75: 2, 0x72: 2] //Fibaro KeyFob
|
||||
|
||||
//[0x5E: 2, 0x86: 1, 0x72: 2, 0x59: 1, 0x80: 1, 0x73: 1, 0x56: 1, 0x22: 1, 0x31: 5, 0x98: 1, 0x7A: 3, 0x20: 1, 0x5A: 1, 0x85: 2, 0x84: 2, 0x71: 3, 0x8E: 2, 0x70: 2, 0x30: 1, 0x9C: 1] //Fibaro Motion Sensor ZW5
|
||||
|
||||
//[0x5E: 2, 0x86: 1, 0x72: 1, 0x59: 1, 0x73: 1, 0x22: 1, 0x56: 1, 0x32: 3, 0x71: 1, 0x98: 1, 0x7A: 1, 0x25: 1, 0x5A: 1, 0x85: 2, 0x70: 2, 0x8E: 2, 0x60: 3, 0x75: 1, 0x5B: 1] //Fibaro Double Switch 2
|
||||
|
||||
[0x5E: 2, 0x22: 1, 0x59: 1, 0x56: 1, 0x7A: 1, 0x32: 3, 0x71: 1, 0x73: 1, 0x98: 1, 0x31: 5, 0x85: 2, 0x70: 2, 0x72: 2, 0x5A: 1, 0x8E: 2, 0x25: 1, 0x86: 2] //Fibaro Wall Plug ZW5
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private parameterMap() {[
|
||||
|
||||
[key: "alwaysActive", num: 1, size: 1, type: "enum", options: [0: "0 - inactive", 1: "1 - activated"], def: "0", title: "Always on function", descr: null],
|
||||
|
||||
[key: "restoreState", num: 2, size: 1, type: "enum", options: [0: "0 - power off after power failure", 1: "1 - restore state"], def: "1", title: "Restore state after power failure", descr: null],
|
||||
|
||||
[key: "overloadSafety", num: 3, size: 2, type: "number", def: 0, min: 0, max: 30000 , title: "Overload safety switch", descr: null],
|
||||
|
||||
[key: "immediatePowerReports", num: 10, size: 1, type: "number", def: 80, min: 1, max: 100, title: "Immediate power reports", descr: null],
|
||||
|
||||
[key: "standardPowerReports", num: 11, size: 1, type: "number", def: 15, min: 1, max: 100, title: "Standard power reports", descr: null],
|
||||
|
||||
[key: "powerReportFrequency", num: 12, size: 2, type: "number", def: 30, min: 5, max: 600, title: "Power reporting interval", descr: null],
|
||||
|
||||
[key: "energyReport", num: 13, size: 2, type: "number", def: 10, min: 0, max: 500, title: "Energy reports", descr: null],
|
||||
|
||||
[key: "periodicReports", num: 14, size: 2, type: "number", def: 3600, min: 0, max: 32400, title: "Periodic power and energy reports", descr: null],
|
||||
|
||||
[key: "deviceEnergyConsumed", num: 15, size: 1, type: "enum", options: [0: "0 - don't measure", 1: "1 - measure"], def: "0", title: "Energy consumed by the device itself", descr: null],
|
||||
|
||||
[key: "powerLoad", num: 40, size: 2, type: "number", def: 25000, min: 1000, max: 30000, title: "Power load which makes the LED ring flash violet", descr: null],
|
||||
|
||||
[key: "ringColorOn", num: 41, size: 1, type: "enum", options: [
|
||||
|
||||
0: "0 - Off",
|
||||
|
||||
1: "1 - Load based - continuous",
|
||||
|
||||
2: "2 - Load based - steps",
|
||||
|
||||
3: "3 - White",
|
||||
|
||||
4: "4 - Red",
|
||||
|
||||
5: "5 - Green",
|
||||
|
||||
6: "6 - Blue",
|
||||
|
||||
7: "7 - Yellow",
|
||||
|
||||
8: "8 - Cyan",
|
||||
|
||||
9: "9 - Magenta"
|
||||
|
||||
], def: "1", title: "Ring LED color when on", descr: null],
|
||||
|
||||
[key: "ringColorOff", num: 42, size: 1, type: "enum", options: [
|
||||
|
||||
0: "0 - Off",
|
||||
|
||||
1: "1 - Last measured power",
|
||||
|
||||
3: "3 - White",
|
||||
|
||||
4: "4 - Red",
|
||||
|
||||
5: "5 - Green",
|
||||
|
||||
6: "6 - Blue",
|
||||
|
||||
7: "7 - Yellow",
|
||||
|
||||
8: "8 - Cyan",
|
||||
|
||||
9: "9 - Magenta"
|
||||
|
||||
], def: "0", title: "Ring LED color when off", descr: null]
|
||||
|
||||
]}
|
||||
@@ -38,9 +38,9 @@ metadata {
|
||||
tiles (scale: 2){
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "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:"#79b821"
|
||||
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") {
|
||||
@@ -52,20 +52,20 @@ metadata {
|
||||
}
|
||||
|
||||
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
|
||||
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
|
||||
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
|
||||
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: "#1010ff"], // blue=cold
|
||||
[value: 65, color: "#a0a0f0"],
|
||||
[value: 70, color: "#e0e050"],
|
||||
[value: 75, color: "#f0d030"], // yellow
|
||||
[value: 80, color: "#fbf020"],
|
||||
[value: 85, color: "#fbdc01"],
|
||||
[value: 90, color: "#fb3a01"],
|
||||
[value: 95, color: "#fb0801"] // red=hot
|
||||
[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
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
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") {
|
||||
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
|
||||
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
|
||||
attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
|
||||
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
|
||||
}
|
||||
|
||||
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
|
||||
|
||||
@@ -95,12 +95,12 @@ metadata {
|
||||
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 "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#0000ff" , nextState:"Sent"
|
||||
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
|
||||
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: "#ffa81e"
|
||||
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 "open", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC" , nextState:"Sent"
|
||||
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#00A0DC"
|
||||
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff", nextState:"Sent"
|
||||
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffffff"
|
||||
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 "fault", label: 'FAULT', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
|
||||
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||
}
|
||||
@@ -135,13 +135,13 @@ metadata {
|
||||
}
|
||||
|
||||
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
|
||||
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#79b821", nextState:"Sent"
|
||||
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#00A0DC", 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"
|
||||
}
|
||||
|
||||
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
|
||||
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821", nextState:"Sent"
|
||||
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC", 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"
|
||||
}
|
||||
@@ -189,13 +189,13 @@ metadata {
|
||||
|
||||
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 "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
|
||||
state "on", label:'Aux 1', action:"Aux1Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
|
||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||
}
|
||||
|
||||
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 "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
|
||||
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"Sent"
|
||||
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ metadata {
|
||||
}
|
||||
|
||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "illuminance", label:'${currentValue} ${unit}', unit:"lux"
|
||||
state "illuminance", label:'${currentValue} lux', unit:""
|
||||
}
|
||||
|
||||
valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) {
|
||||
@@ -410,4 +410,4 @@ private command(physicalgraph.zwave.Command cmd) {
|
||||
private commands(commands, delay=200) {
|
||||
log.info "sending commands: ${commands}"
|
||||
delayBetween(commands.collect{ command(it) }, delay)
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ metadata {
|
||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
||||
}
|
||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
|
||||
state "luminosity", label:'${currentValue} lux', unit:""
|
||||
}
|
||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
@@ -282,5 +282,4 @@ private secure(physicalgraph.zwave.Command cmd) {
|
||||
|
||||
private secureSequence(commands, delay=200) {
|
||||
delayBetween(commands.collect{ secure(it) }, delay)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -79,7 +79,7 @@ metadata {
|
||||
state "humidity", label:'${currentValue}% humidity', unit:""
|
||||
}
|
||||
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
|
||||
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
|
||||
state "luminosity", label:'${currentValue} lux', unit:""
|
||||
}
|
||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
@@ -193,4 +193,4 @@ def configure() {
|
||||
// set data reporting period to 5 minutes
|
||||
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300).format()
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -68,8 +68,8 @@
|
||||
|
||||
tiles {
|
||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
||||
}
|
||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
||||
state "temperature", label:'${currentValue}°',
|
||||
@@ -86,7 +86,7 @@
|
||||
}
|
||||
standardTile("tamper", "device.alarm") {
|
||||
state("secure", label:'secure', icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
|
||||
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
|
||||
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
|
||||
}
|
||||
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
|
||||
state "battery", label:'${currentValue}% battery', unit:""
|
||||
|
||||
@@ -62,8 +62,8 @@ metadata {
|
||||
state "off", label: '${name}', action: "on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
||||
}
|
||||
standardTile("contact", "device.contact", inactiveLabel: false) {
|
||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
|
||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
|
||||
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
|
||||
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
|
||||
}
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||
|
||||
@@ -44,9 +44,9 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", 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 "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", 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"
|
||||
}
|
||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||
|
||||
@@ -56,8 +56,8 @@ metadata {
|
||||
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#00A0DC")
|
||||
}
|
||||
standardTile("contact", "device.contact") {
|
||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||
}
|
||||
standardTile("acceleration", "device.acceleration", decoration: "flat") {
|
||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
|
||||
|
||||
@@ -22,16 +22,16 @@ metadata {
|
||||
|
||||
tiles {
|
||||
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821", action: "open")
|
||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e", action: "close")
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC", action: "open")
|
||||
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13", action: "close")
|
||||
}
|
||||
standardTile("freezerDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'Freezer', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||
state("open", label:'Freezer', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||
}
|
||||
standardTile("mainDoor", "device.contact", width: 2, height: 2, decoration: "flat") {
|
||||
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'Fridge', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
|
||||
state("open", label:'Fridge', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
|
||||
}
|
||||
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
|
||||
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
|
||||
|
||||
@@ -25,8 +25,8 @@ metadata {
|
||||
|
||||
tiles(scale: 2) {
|
||||
standardTile("contact", "device.contact", width: 4, height: 4) {
|
||||
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#79b821")
|
||||
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#ffa81e")
|
||||
state("closed", label:'${name}', icon:"st.fridge.fridge-closed", backgroundColor:"#00A0DC")
|
||||
state("open", label:'${name}', icon:"st.fridge.fridge-open", backgroundColor:"#e86d13")
|
||||
}
|
||||
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
|
||||
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
|
||||
|
||||
@@ -27,7 +27,7 @@ metadata {
|
||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||
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 "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", 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"
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ metadata {
|
||||
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "off", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
attributeState "turningOn", label:'${name}', backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
tileAttribute("device.level", key: "SECONDARY_CONTROL") {
|
||||
@@ -59,7 +59,7 @@ metadata {
|
||||
tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
|
||||
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 "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'…', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'…', action:"switch.on", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
tileAttribute("device.level", key: "VALUE_CONTROL") {
|
||||
|
||||
@@ -40,11 +40,11 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#ff0000"
|
||||
attributeState "offline", label:'${name}', icon:"st.Home.home30", backgroundColor:"#cccccc"
|
||||
}
|
||||
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||
attributeState "currentIP", label: ''
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"rich-control", type: "switch", canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#ff0000"
|
||||
attributeState "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
|
||||
}
|
||||
tileAttribute ("currentIP", key: "SECONDARY_CONTROL") {
|
||||
attributeState "currentIP", label: ''
|
||||
@@ -50,11 +50,11 @@
|
||||
}
|
||||
|
||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#79b821", nextState:"turningOff"
|
||||
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#ff0000"
|
||||
state "offline", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#cccccc"
|
||||
}
|
||||
|
||||
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
|
||||
|
||||
@@ -46,9 +46,9 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
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:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||
|
||||
@@ -41,9 +41,9 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||
|
||||
@@ -49,9 +49,9 @@ metadata {
|
||||
tiles(scale: 2) {
|
||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
|
||||
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||
}
|
||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||
|
||||
@@ -15,66 +15,66 @@ definition(
|
||||
)
|
||||
|
||||
preferences {
|
||||
section("Light switches to turn off") {
|
||||
input "switches", "capability.switch", title: "Choose light switches", multiple: true
|
||||
}
|
||||
section("Turn off when there is no motion and presence") {
|
||||
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
|
||||
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
|
||||
}
|
||||
section("Delay before turning off") {
|
||||
input "delayMins", "number", title: "Minutes of inactivity?"
|
||||
}
|
||||
section("Light switches to turn off") {
|
||||
input "switches", "capability.switch", title: "Choose light switches", multiple: true
|
||||
}
|
||||
section("Turn off when there is no motion and presence") {
|
||||
input "motionSensor", "capability.motionSensor", title: "Choose motion sensor"
|
||||
input "presenceSensors", "capability.presenceSensor", title: "Choose presence sensors", multiple: true
|
||||
}
|
||||
section("Delay before turning off") {
|
||||
input "delayMins", "number", title: "Minutes of inactivity?"
|
||||
}
|
||||
}
|
||||
|
||||
def installed() {
|
||||
subscribe(motionSensor, "motion", motionHandler)
|
||||
subscribe(presenceSensors, "presence", presenceHandler)
|
||||
subscribe(motionSensor, "motion", motionHandler)
|
||||
subscribe(presenceSensors, "presence", presenceHandler)
|
||||
}
|
||||
|
||||
def updated() {
|
||||
unsubscribe()
|
||||
subscribe(motionSensor, "motion", motionHandler)
|
||||
subscribe(presenceSensors, "presence", presenceHandler)
|
||||
unsubscribe()
|
||||
subscribe(motionSensor, "motion", motionHandler)
|
||||
subscribe(presenceSensors, "presence", presenceHandler)
|
||||
}
|
||||
|
||||
def motionHandler(evt) {
|
||||
log.debug "handler $evt.name: $evt.value"
|
||||
if (evt.value == "inactive") {
|
||||
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
||||
}
|
||||
log.debug "handler $evt.name: $evt.value"
|
||||
if (evt.value == "inactive") {
|
||||
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
||||
}
|
||||
}
|
||||
|
||||
def presenceHandler(evt) {
|
||||
log.debug "handler $evt.name: $evt.value"
|
||||
if (evt.value == "not present") {
|
||||
runIn(delayMins * 60, scheduleCheck, [overwrite: false])
|
||||
}
|
||||
log.debug "handler $evt.name: $evt.value"
|
||||
if (evt.value == "not present") {
|
||||
runIn(delayMins * 60, scheduleCheck, [overwrite: true])
|
||||
}
|
||||
}
|
||||
|
||||
def isActivePresence() {
|
||||
// check all the presence sensors, make sure none are present
|
||||
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
|
||||
!noPresence
|
||||
// check all the presence sensors, make sure none are present
|
||||
def noPresence = presenceSensors.find{it.currentPresence == "present"} == null
|
||||
!noPresence
|
||||
}
|
||||
|
||||
def scheduleCheck() {
|
||||
log.debug "scheduled check"
|
||||
def motionState = motionSensor.currentState("motion")
|
||||
log.debug "scheduled check"
|
||||
def motionState = motionSensor.currentState("motion")
|
||||
if (motionState.value == "inactive") {
|
||||
def elapsed = now() - motionState.rawDateCreated.time
|
||||
def threshold = 1000 * 60 * delayMins - 1000
|
||||
if (elapsed >= threshold) {
|
||||
if (!isActivePresence()) {
|
||||
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
|
||||
switches.off()
|
||||
} else {
|
||||
log.debug "Presence is active: do nothing"
|
||||
}
|
||||
} else {
|
||||
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): do nothing"
|
||||
def elapsed = now() - motionState.rawDateCreated.time
|
||||
def threshold = 1000 * 60 * delayMins - 1000
|
||||
if (elapsed >= threshold) {
|
||||
if (!isActivePresence()) {
|
||||
log.debug "Motion has stayed inactive since last check ($elapsed ms) and no presence: turning lights off"
|
||||
switches.off()
|
||||
} else {
|
||||
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 is active: do nothing"
|
||||
log.debug "Motion is active: do nothing"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,84 +27,82 @@ definition(
|
||||
|
||||
preferences {
|
||||
|
||||
section("Monitor this door or window") {
|
||||
input "contact", "capability.contactSensor"
|
||||
}
|
||||
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
|
||||
}
|
||||
section("Delay between notifications (default 10 minutes") {
|
||||
input "frequency", "number", title: "Number of minutes", description: "", required: false
|
||||
section("Monitor this door or window") {
|
||||
input "contact", "capability.contactSensor"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
log.trace "installed()"
|
||||
subscribe()
|
||||
log.trace "installed()"
|
||||
subscribe()
|
||||
}
|
||||
|
||||
def updated() {
|
||||
log.trace "updated()"
|
||||
unsubscribe()
|
||||
subscribe()
|
||||
log.trace "updated()"
|
||||
unsubscribe()
|
||||
subscribe()
|
||||
}
|
||||
|
||||
def subscribe() {
|
||||
subscribe(contact, "contact.open", doorOpen)
|
||||
subscribe(contact, "contact.closed", doorClosed)
|
||||
subscribe(contact, "contact.open", doorOpen)
|
||||
subscribe(contact, "contact.closed", doorClosed)
|
||||
}
|
||||
|
||||
def doorOpen(evt)
|
||||
{
|
||||
log.trace "doorOpen($evt.name: $evt.value)"
|
||||
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 doorOpen(evt) {
|
||||
log.trace "doorOpen($evt.name: $evt.value)"
|
||||
def delay = (openThreshold != null && openThreshold != "") ? openThreshold * 60 : 600
|
||||
runIn(delay, doorOpenTooLong, [overwrite: true])
|
||||
}
|
||||
|
||||
def doorClosed(evt)
|
||||
{
|
||||
log.trace "doorClosed($evt.name: $evt.value)"
|
||||
def doorClosed(evt) {
|
||||
log.trace "doorClosed($evt.name: $evt.value)"
|
||||
unschedule(doorOpenTooLong)
|
||||
}
|
||||
|
||||
def doorOpenTooLong() {
|
||||
def contactState = contact.currentState("contact")
|
||||
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
|
||||
def contactState = contact.currentState("contact")
|
||||
def freq = (frequency != null && frequency != "") ? frequency * 60 : 600
|
||||
|
||||
if (contactState.value == "open") {
|
||||
def elapsed = now() - contactState.rawDateCreated.time
|
||||
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
|
||||
if (elapsed >= threshold) {
|
||||
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
|
||||
sendMessage()
|
||||
runIn(freq, doorOpenTooLong, [overwrite: false])
|
||||
} else {
|
||||
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
|
||||
}
|
||||
} else {
|
||||
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
|
||||
}
|
||||
if (contactState.value == "open") {
|
||||
def elapsed = now() - contactState.rawDateCreated.time
|
||||
def threshold = ((openThreshold != null && openThreshold != "") ? openThreshold * 60000 : 60000) - 1000
|
||||
if (elapsed >= threshold) {
|
||||
log.debug "Contact has stayed open long enough since last check ($elapsed ms): calling sendMessage()"
|
||||
sendMessage()
|
||||
runIn(freq, doorOpenTooLong, [overwrite: false])
|
||||
} else {
|
||||
log.debug "Contact has not stayed open long enough since last check ($elapsed ms): doing nothing"
|
||||
}
|
||||
} else {
|
||||
log.warn "doorOpenTooLong() called but contact is closed: doing nothing"
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessage()
|
||||
{
|
||||
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
||||
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
||||
log.info msg
|
||||
if (location.contactBookEnabled) {
|
||||
sendNotificationToContacts(msg, recipients)
|
||||
}
|
||||
else {
|
||||
if (phone) {
|
||||
sendSms phone, msg
|
||||
} else {
|
||||
sendPush msg
|
||||
}
|
||||
void sendMessage() {
|
||||
def minutes = (openThreshold != null && openThreshold != "") ? openThreshold : 10
|
||||
def msg = "${contact.displayName} has been left open for ${minutes} minutes."
|
||||
log.info msg
|
||||
if (location.contactBookEnabled) {
|
||||
sendNotificationToContacts(msg, recipients)
|
||||
} else {
|
||||
if (phone) {
|
||||
sendSms phone, msg
|
||||
} else {
|
||||
sendPush msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user