Compare commits

..

1 Commits

Author SHA1 Message Date
Maria Jesus Cresci
d38516f779 MSA-1866: Test for starting with this 2017-03-30 14:15:37 -07:00
34 changed files with 325 additions and 959 deletions

View File

@@ -1,438 +0,0 @@
/**
* Strips by Sensative
* Device Handler by Don Caruana
*
* Date: 2017-2-19
* Supported Command Classes per device specs
*
* Association v2
* Association Group Information
* Battery
* Binary Sensor
* Configuration
* Device Reset Local
* Manufacturer Specific
* Notification v4
* Powerlevel
* Version v2
* Wake Up v2
* ZWavePlus Info v2
*
* Parm Size Description Value
* 1 1 Type of report to send 1 (Default)-Notification Report, 0-Binary Sensor report, 2-Basic report
* 2 1 LED Indication 1 (Default)-On for event (ex. door opened), 0-Off
*
* This device handler will just override the smartthings default wakeup interval of 4 hours and set to 24 hours (manufacturer default)
* and check the battery once a day (no sooner than every 23 hours)
*/
metadata {
definition (name: "Strips by Sensative", namespace: "doncaruana/Sensative", author: "Don Caruana, Sensative") {
capability "Contact Sensor"
capability "Configuration"
capability "Battery"
capability "Sensor"
capability "Refresh"
attribute "needUpdate", "string"
attribute "tamper" , "string"
fingerprint mfr:"019A", prod:"0003", model:"0003", deviceJoinName:"Strips by Sensative"
fingerprint deviceId:"0x0701", inClusters: "0x5E,0x86,0x72,0x30,0x70,0x71,0x5A,0x85,0x59,0x80,0x84,0x73"
fingerprint cc: "0x5E,0x86,0x72,0x30,0x70,0x71,0x5A,0x85,0x59,0x80,0x84,0x73", mfr:"019A", prod:"0003", model:"0003", deviceJoinName:"Strips by Sensative"
}
preferences {
section ("configuration settings") {
input(
title : "Changes in Settings marked with * will not take effect until the next device Wake Up."
,description : null
,type : "paragraph")
input "sendType", "enum",
title: "* Reporting Type",
description: "Notification Report",
options:["binary": "Sensor Binary Report", "notification": "Notification Report", "basic": "Basic Report"],
defaultValue: "notification",
displayDuringSetup: false
input "wakeupInterval","enum",
title: "* Device Wake Up Interval",
description: "24 hours",
defaultValue: "86400",
required: false,
displayDuringSetup: false,
options: buildInterval()
input "led", "bool",
title: "* LED On",
defaultValue: true,
displayDuringSetup: false
input "ignoreWakeup", "bool",
title: "Ignore Manual Wake Up",
defaultValue: false,
displayDuringSetup: false
input "invertOutput", "bool",
title: "Invert Open/Close Reporting",
defaultValue: false,
displayDuringSetup: false
}
}
tiles(scale: 2) {
multiAttributeTile(name:"contact", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
}
}
standardTile("tamper", "device.tamper", inactiveLabel: false, width: 4, height: 3) {
state "tamper", label:'${currentValue}', action:"refresh.refresh", backgroundColor:"#FFCC7B"
}
standardTile("configure", "device.needUpdate", inactiveLabel: false, width: 2, height: 2) {
state "NO" , label:'Synced', backgroundColor:"#B1D57D"
state "YES", label:'Pending changes', backgroundColor:"#FFCC7B"
}
standardTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 1) {
state "battery", label:'Battery: ${currentValue}%'
}
main (["contact"])
details(["contact","battery","tamper","configure"])
}
simulator {
// messages the device returns in response to commands it receives
status "open (basic)" : "command: 9881, payload: 00 20 01 FF"
status "closed (basic)" : "command: 9881 payload: 00 20 01 00"
status "open (notification)" : "command: 9881, payload: 00 71 05 06 FF 00 FF 06 16 00 00"
status "closed (notification)" : "command: 9881, payload: 00 71 05 06 00 00 FF 06 17 00 00"
status "wake up" : "command: 9881, payload: 00 84 07"
status "battery (100%)" : "command: 9881, payload: 00 80 03 64"
status "battery low" : "command: 9881, payload: 00 80 03 FF"
}
}
def configure() {
def commands = []
state.lastupdate = now()
sendEvent(name: "tamper", value: "No Tamper", displayed: false)
log.debug "Listing all device parameters and defaults since this is a new inclusion"
commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
commands << zwave.versionV1.versionGet().format()
commands << zwave.batteryV1.batteryGet().format()
commands << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
commands << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
commands << zwave.wakeUpV2.wakeUpIntervalSet(seconds: 86400, nodeid:zwaveHubNodeId).format()
commands << zwave.wakeUpV2.wakeUpIntervalGet().format()
commands << zwave.wakeUpV2.wakeUpNoMoreInformation().format()
delayBetween(commands, 1500)
}
private getCommandClassVersions() {
[
0x71: 3, // Notification
0x5E: 2, // ZwaveplusInfo
0x59: 1, // AssociationGrpInfo
0x85: 2, // Association
0x80: 1, // Battery
0x70: 1, // Configuration
0x5A: 1, // DeviceResetLocally
0x72: 1, // ManufacturerSpecific
0x73: 1, // Powerlevel
0x84: 2, // WakeUp
0x86: 1, // Version
0x30: 1, // Binary Sensor
]
}
// Parse incoming device messages to generate events
def parse(String description) {
def result = []
def cmd
if (description.startsWith("Err 106")) {
state.sec = 0
result = createEvent( name: "secureInclusion", value: "failed", eventType: "ALERT",
descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
} else if (description.startsWith("Err")) {
result = createEvent(descriptionText: "$device.displayName $description", isStateChange: true)
} else {
cmd = zwave.parse(description, commandClassVersions)
if (cmd) {
result = zwaveEvent(cmd)
}
}
if (result instanceof List) {
result = result.flatten()
}
log.debug "Parsed '$description' to $result"
return result
}
/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated()
{
if(now() - state.lastupdate > 3000){
def isUpdateNeeded = "NO"
if(wakeupInterval != null && state.wakeupInterval != wakeupInterval) {isUpdateNeeded = "YES"}
if (sendType != null && sendType != state.sendType) {isUpdateNeeded = "YES"}
if (led != null && led != state.led) {isUpdateNeeded = "YES"}
state.lastupdate = now()
sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)
}
}
/**
* Only device parameter changes require a state change
*/
def update_settings()
{
def cmds = []
def isUpdateNeeded = "NO"
if (state.wakeupInterval != wakeupInterval){
cmds << zwave.wakeUpV2.wakeUpIntervalSet(seconds: wakeupInterval.toInteger(), nodeid:zwaveHubNodeId).format()
cmds << "delay 1000"
cmds << zwave.wakeUpV2.wakeUpIntervalGet().format()
}
if (sendType != state.sendType){
cmds << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, configurationValue: [sendType == "binary" ? 0 : sendType == "basic" ? 2 : 1]).format()
cmds << "delay 1000"
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
}
if (led != state.led){
cmds << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, configurationValue: [led == true ? 1 : 0]).format()
cmds << "delay 1000"
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
}
cmds << "delay 1000"
sendEvent(name:"needUpdate", value: isUpdateNeeded, displayed:false, isStateChange: true)
return cmds
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
def name = ""
def value = ""
def tmpParm = cmd.parameterNumber
def reportValue = cmd.configurationValue[0]
switch (cmd.parameterNumber) {
case 1:
name = "sendType"
switch (reportValue) {
case 0:
value = "binary"
break
case 1:
value = "notification"
break
case 2:
value = "basic"
break
default:
break
}
state.sendType = value
log.debug "sendType = $value"
break
case 2:
name = "led"
value = reportValue
log.debug "led = $value"
state.led = reportValue == 1 ? true : false
break
default:
break
}
sendEvent(name: name, value: value, displayed: true)
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand(commandClassVersions)
log.debug "encapsulated: $encapsulatedCommand"
if (encapsulatedCommand) {
state.sec = 1
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
return [createEvent(descriptionText: cmd.toString())]
}
}
def sensorValueEvent(value) {
//If the invertOutput parameter is set, logically invert the output value
def flip = 0
if (state.sendType == "notification"){
flip = value ^ 0x1}
else{
flip = value ^ 0xFF}
if (invertOutput) {value = flip}
if (value) {
createEvent(name: "contact", value: "open", descriptionText: "$device.displayName is open")
} else {
createEvent(name: "contact", value: "closed", descriptionText: "$device.displayName is closed")
}
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
return sensorValueEvent(cmd.value)
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
return sensorValueEvent(cmd.value)
}
def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cmd) {
return sensorValueEvent(cmd.sensorValue)
}
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) {
return sensorValueEvent(cmd.sensorState)
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def result = []
if (cmd.notificationType == 0x06 && cmd.event == 0x16) {
result << sensorValueEvent(1)
} else if (cmd.notificationType == 0x06 && cmd.event == 0x17) {
result << sensorValueEvent(0)
} else if (cmd.notificationType == 0x07) {
if (cmd.event == 0x00) {
if (cmd.eventParametersLength == 0 || cmd.eventParameter[0] != 3) {
result << createEvent(descriptionText: "$device.displayName covering replaced", isStateChange: true, displayed: false)
} else {
result << sensorValueEvent(0)
}
} else if (cmd.event == 0x01 || cmd.event == 0x02) {
result << sensorValueEvent(1)
} else if (cmd.event == 0x03) {
result << createEvent(descriptionText: "$device.displayName covering was removed", isStateChange: true)
if (!device.currentState("ManufacturerCode")) {
result << response(secure(zwave.manufacturerSpecificV1.manufacturerSpecificGet()))
}
} else if (cmd.event == 0x04) {
def timeString1 = new Date().format("MMM d", location.timeZone)
def timeString2 = new Date().format("hh:mm:ss", location.timeZone)
result << createEvent(name: "tamper", value: "Tampered\n${timeString1}\n${timeString2}", descriptionText: "$device.displayName was tampered with at ${timeString1} ${timeString2}", isStateChange: true)
if (!ignoreWakeup) {
sendEvent(name:"WakeUp", value: "Manual Wakeup", descriptionText: "${device.displayName} woke up", isStateChange: true, displayed: true)
result << doWakeup()
}
} else if (cmd.event == 0x05 || cmd.event == 0x06) {
result << createEvent(descriptionText: "$device.displayName detected glass breakage", isStateChange: true)
} else {
result << createEvent(descriptionText: "$device.displayName event $cmd.event ${cmd.eventParameter.inspect()}", isStateChange: true, displayed: false)
}
} else if (cmd.notificationType) {
result << createEvent(descriptionText: "$device.displayName notification $cmd.notificationType event $cmd.event ${cmd.eventParameter.inspect()}", isStateChange: true, displayed: false)
} else {
def value = cmd.v1AlarmLevel == 255 ? "active" : cmd.v1AlarmLevel ?: "inactive"
result << createEvent(name: "alarm $cmd.v1AlarmType", value: value, isStateChange: true, displayed: false)
}
return result
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def event = createEvent(name: "WakeUp", value: "Auto Wakeup", descriptionText: "${device.displayName} woke up", isStateChange: true, displayed: true)
def cmds = []
if (!device.currentState("ManufacturerCode")) {
cmds << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
cmds << "delay 2000"
}
if (!state.lastbat || now() - state.lastbat > 23*60*60*1000) { //check no sooner than once every 23 hours (once a day)
log.debug "checking battery"
event.descriptionText += ", requesting battery"
cmds << zwave.batteryV1.batteryGet().format()
cmds << "delay 2000"
} else {
log.debug "not checking battery, was updated ${(now() - state.lastbat)/60000 as int} min ago"
}
if (device.currentValue("needUpdate") == "YES") { cmds += update_settings() }
cmds << zwave.wakeUpV2.wakeUpNoMoreInformation().format()
return [event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} has a low battery"
map.isStateChange = true
} else {
map.value = cmd.batteryLevel
}
def event = createEvent(map)
map.isStateChange = true
state.lastbat = now()
return [event]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv1.ManufacturerSpecificReport cmd) {
def result = []
def manufacturerCode = String.format("%04X", cmd.manufacturerId)
def productTypeCode = String.format("%04X", cmd.productTypeId)
def productCode = String.format("%04X", cmd.productId)
def wirelessConfig = "ZWP"
updateDataValue("Manufacturer", cmd.manufacturerName)
updateDataValue("Manufacturer ID", manufacturerCode)
updateDataValue("Product Type", productTypeCode)
updateDataValue("Product Code", productCode)
return result
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
return [createEvent(descriptionText: "$device.displayName: $cmd", displayed: false)]
}
private secure(physicalgraph.zwave.Command cmd) {
if (state.sec == 0) { // default to secure
cmd.format()
} else {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
}
private secureSequence(commands, delay=200) {
delayBetween(commands.collect{ secure(it) }, delay)
}
def buildInterval() {
def intervalList = []
intervalList << [ "0" : "Disabled" ]
intervalList << [ "1800" : "30 minutes" ]
intervalList << [ "3600" : "1 hour" ]
intervalList << [ "7200" : "2 hours" ]
intervalList << [ "10800" : "3 hours" ]
intervalList << [ "14400" : "4 hours" ]
intervalList << [ "18000" : "5 hours" ]
intervalList << [ "21600" : "6 hours" ]
intervalList << [ "36000" : "10 hours" ]
intervalList << [ "43200" : "12 hours" ]
intervalList << [ "86400" : "24 hours" ]
}
def doWakeup() {
def cmds = []
cmds << "delay 2000"
if (device.currentValue("needUpdate") == "YES") { cmds += update_settings() }
cmds << zwave.wakeUpV2.wakeUpNoMoreInformation().format()
return response(cmds)
}
def refresh() {
sendEvent(name: "tamper", value: "No Tamper", displayed: false)
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
def appversion = String.format("%02d.%02d", cmd.applicationVersion, cmd.applicationSubVersion)
def zprotoversion = String.format("%d.%02d", cmd.zWaveProtocolVersion, cmd.zWaveProtocolSubVersion)
updateDataValue("zWave Library", cmd.zWaveLibraryType.toString())
updateDataValue("Firmware", appversion)
updateDataValue("zWave Version", zprotoversion)
sendEvent(name: "Firmware", value: appversion, displayed: true)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) {
state.wakeupInterval = cmd.seconds.toString()
sendEvent(name: "wakeupInterval", value: state.wakeupInterval, displayed: true)
}

View File

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

View File

@@ -1,41 +0,0 @@
# Fibaro Door Window Sensor ZW5
Cloud Execution
Works with:
* [Fibaro Door/Window Sensor ZW5](https://www.smartthings.com/works-with-smartthings/sensors/fibaro-doorwindow-sensor)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Battery** - defines device uses a battery
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **Sensor** - detects sensor events
* **Tamper Alert** - detects tampers
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Health Check** - indicates ability to get device health notifications
## Device Health
Fibaro Door/Window Sensor ZW5 is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
One 1/2AA 3.6V battery is 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:
* [Fibaro Door/Window Sensor ZW5 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)

View File

@@ -20,7 +20,6 @@ metadata {
capability "Sensor"
capability "Configuration"
capability "Tamper Alert"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x86, 0x84", outClusters: ""
}
@@ -200,9 +199,7 @@ def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLoca
def configure() {
log.debug "Executing 'configure'"
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval

View File

@@ -34,13 +34,13 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"FGFS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.water", key:"PRIMARY_CONTROL") {
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc")
attributeState("dry", icon:"st.alarm.water.dry", backgroundColor:"#00a0dc")
attributeState("wet", icon:"st.alarm.water.wet", backgroundColor:"#e86d13")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#cccccc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#00A0DC")
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
}
}

View File

@@ -22,6 +22,7 @@ metadata {
command "clearObstruction"
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019"
fingerprint endpoint: "1", profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0006,0008,0020,0402,0403,0B05,FC01,FC02", outClusters: "0019", manufacturer: "Keen Home Inc", model: "SV01-410-DV-1.0", deviceJoinName: "Keen Home Smart Vent"
}
// simulator metadata

View File

@@ -0,0 +1,36 @@
/**
* motionJC
*
* Copyright 2017 Maria Jesus Cresci
*
* 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: "motionJC", namespace: "mcresci", author: "Maria Jesus Cresci") {
capability "Motion Sensor"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'motion' attribute
}

View File

@@ -0,0 +1,48 @@
/**
* Switch
*
* Copyright 2017 Maria Jesus Cresci
*
* 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", namespace: "mcresci", author: "Maria Jesus Cresci") {
capability "Switch"
}
}
simulator {
// TODO: define status and reply messages here
}
tiles{
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'switch' attribute
}
// handle commands
def on() {
log.debug "Executing 'on'"
// TODO: handle 'on' command
}
def off() {
log.debug "Executing 'off'"
// TODO: handle 'off' command
}

View File

@@ -0,0 +1,47 @@
/**
* testJC
*
* Copyright 2017 Maria Jesus Cresci
*
* 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: "testJC", namespace: "mcresci", author: "Maria Jesus Cresci") {
capability "Switch"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'switch' attribute
}
// handle commands
def on() {
log.debug "Executing 'on'"
theswitch.on()
}
def off() {
log.debug "Executing 'off'"
theswitch.off()
}

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Indicator"

View File

@@ -32,7 +32,7 @@ metadata {
command "switchMode"
command "switchFanMode"
attribute "displayThermostatSetpoint", "string" // Added to be able to show "Auto"/"Off" keeping attribute thermostatSetpoint a number
attribute "thermostatSetpoint", "number"
attribute "thermostatStatus", "string"
attribute "maxHeatingSetpoint", "number"
attribute "minHeatingSetpoint", "number"
@@ -43,8 +43,8 @@ metadata {
}
tiles {
standardTile("temperature", "device.temperature", width: 2, height: 2, decoration: "flat") {
state("temperature", label:'${currentValue}°', unit:"F", icon: "st.thermostat.ac.air-conditioning",
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
// Celsius
[value: 0, color: "#153591"],
@@ -70,7 +70,7 @@ metadata {
state "heat", action:"switchMode", nextState: "updating", icon: "st.thermostat.heat"
state "cool", action:"switchMode", nextState: "updating", icon: "st.thermostat.cool"
state "auto", action:"switchMode", nextState: "updating", icon: "st.thermostat.auto"
state "emergency heat", action:"switchMode", icon: "st.thermostat.emergency-heat" // emergency heat = auxHeatOnly
state "auxHeatOnly", action:"switchMode", icon: "st.thermostat.emergency-heat"
state "updating", label:"Working", icon: "st.secondary.secondary"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
@@ -81,8 +81,8 @@ metadata {
standardTile("upButtonControl", "device.thermostatSetpoint", inactiveLabel: false, decoration: "flat") {
state "setpoint", action:"raiseSetpoint", icon:"st.thermostat.thermostat-up"
}
valueTile("displayThermostatSetpoint", "device.displayThermostatSetpoint", width: 1, height: 1, decoration: "flat") {
state "displayThermostatSetpoint", label:'${currentValue}'
valueTile("thermostatSetpoint", "device.thermostatSetpoint", width: 1, height: 1, decoration: "flat") {
state "thermostatSetpoint", label:'${currentValue}'
}
valueTile("currentStatus", "device.thermostatStatus", height: 1, width: 2, decoration: "flat") {
state "thermostatStatus", label:'${currentValue}', backgroundColor:"#ffffff"
@@ -113,7 +113,7 @@ metadata {
state "humidity", label:'${currentValue}%'
}
main "temperature"
details(["temperature", "upButtonControl", "displayThermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
}
preferences {
@@ -185,11 +185,6 @@ def generateEvent(Map results) {
isChange = isStateChange(device, name, value.toString())
event['isStateChange'] = isChange
event['displayed'] = false
} else if (name == "thermostatMode") {
def mode = value.toString()
mode = (mode == "auxHeatOnly") ? "emergency heat" : mode
isChange = isStateChange(device, name, mode)
event << [value: mode, isStateChange: isChange, displayed: isDisplayed]
} else {
isChange = isStateChange(device, name, value.toString())
isDisplayed = isChange
@@ -457,10 +452,10 @@ def emergencyHeat() {
}
def auxHeatOnly() {
log.debug "auxHeatOnly = emergency heat"
log.debug "auxHeatOnly"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auxHeatOnly", deviceId))
generateModeEvent("emergency heat") // emergency heat = auxHeatOnly
generateModeEvent("auxHeatOnly")
else {
log.debug "Error setting new mode."
def currentMode = device.currentState("thermostatMode")?.value
@@ -579,23 +574,17 @@ def generateSetpointEvent() {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
def averageSetpoint = roundC((heatingSetpoint + coolingSetpoint) / 2)
if (mode == "heat") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
}
else if (mode == "cool") {
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale, displayed: false)
} else if (mode == "auto") {
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":"Auto", displayed: false)
sendEvent("name":"thermostatSetpoint", "value":"Auto")
} else if (mode == "off") {
sendEvent("name":"thermostatSetpoint", "value":averageSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":"Off", displayed: false)
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly
sendEvent("name":"thermostatSetpoint", "value":"Off")
} else if (mode == "auxHeatOnly") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
}
}
@@ -632,14 +621,13 @@ void raiseSetpoint() {
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5
if ((mode == "heat" || mode == "emergency heat") && targetvalue > maxHeatingSetpoint) { // emergency heat = auxHeatOnly
if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue > maxHeatingSetpoint) {
targetvalue = maxHeatingSetpoint
} else if (mode == "cool" && targetvalue > maxCoolingSetpoint) {
targetvalue = maxCoolingSetpoint
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode raiseSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -678,14 +666,13 @@ void lowerSetpoint() {
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5
if ((mode == "heat" || mode == "emergency heat") && targetvalue < minHeatingSetpoint) { // emergency heat = auxHeatOnly
if ((mode == "heat" || mode == "auxHeatOnly") && targetvalue < minHeatingSetpoint) {
targetvalue = minHeatingSetpoint
} else if (mode == "cool" && targetvalue < minCoolingSetpoint) {
targetvalue = minCoolingSetpoint
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode lowerSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -719,7 +706,7 @@ void alterSetpoint(temp) {
}
//step1: check thermostatMode, enforce limits before sending request to cloud
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly
if (mode == "heat" || mode == "auxHeatOnly"){
if (temp.value > coolingSetpoint){
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value
@@ -748,18 +735,15 @@ void alterSetpoint(temp) {
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale)
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
} else {
log.error "Error alterSetpoint()"
if (mode == "heat" || mode == "emergency heat"){ // emergency heat = auxHeatOnly
if (mode == "heat" || mode == "auxHeatOnly"){
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
} else if (mode == "cool") {
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
sendEvent("name": "displayThermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
}
}
@@ -775,7 +759,6 @@ def generateStatusEvent() {
def coolingSetpoint = device.currentValue("coolingSetpoint")
def temperature = device.currentValue("temperature")
def statusText
def operatingState = "idle"
log.debug "Generate Status Event for Mode = ${mode}"
log.debug "Temperature = ${temperature}"
@@ -784,29 +767,20 @@ def generateStatusEvent() {
log.debug "HVAC Mode = ${mode}"
if (mode == "heat") {
if (temperature >= heatingSetpoint) {
if (temperature >= heatingSetpoint)
statusText = "Right Now: Idle"
} else {
else
statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}"
operatingState = "heating"
}
} else if (mode == "cool") {
if (temperature <= coolingSetpoint) {
if (temperature <= coolingSetpoint)
statusText = "Right Now: Idle"
} else {
else
statusText = "Cooling to ${coolingSetpoint} ${location.temperatureScale}"
operatingState = "cooling"
}
} else if (mode == "auto") {
statusText = "Right Now: Auto"
if (temperature < heatingSetpoint) {
operatingState = "heating"
} else if (temperature > coolingSetpoint) {
operatingState = "cooling"
}
} else if (mode == "off") {
statusText = "Right Now: Off"
} else if (mode == "emergency heat") { // emergency heat = auxHeatOnly
} else if (mode == "auxHeatOnly") {
statusText = "Emergency Heat"
} else {
statusText = "?"
@@ -814,7 +788,6 @@ def generateStatusEvent() {
log.debug "Generate Status Event = ${statusText}"
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
sendEvent("name":"thermostatOperatingState", "value":operatingState, "description":operatingState, displayed: false)
}
def generateActivityFeedsEvent(notificationMessage) {

View File

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

View File

@@ -1,40 +0,0 @@
# Everspring Flood Sensor
Cloud Execution
Works with:
* [Everspring Water Detector](https://www.smartthings.com/works-with-smartthings/sensors/everspring-water-detector)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Water Sensor** - can detect presence of water (dry or wet)
* **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
Everspring Water Detector is a Z-wave sleepy device and wakes up every 4 hours.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*4*60 + 2)mins = 482 mins.
* __482min__ checkInterval
## Battery Specification
Three AA 1.5V 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:
* [Everspring Water Detector Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088304-Everspring-Water-Detector)

View File

@@ -17,7 +17,6 @@ metadata {
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71"
}
@@ -139,8 +138,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd)
def configure()
{
// Device wakes up every 4 hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
if (!device.currentState("battery")) {
sendEvent(name: "battery", value:100, unit:"%", descriptionText:"(Default battery event)", displayed:false)
}

View File

@@ -135,7 +135,10 @@ def refresh() {
return zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0x104E]) + // New firmware
zigbee.readAttribute(0xFC45, 0x0000, ["mfgCode": 0xC2DF]) + // Original firmware
zigbee.readAttribute(zigbee.TEMPERATURE_MEASUREMENT_CLUSTER, 0x0000) +
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020)
zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) +
zigbee.configureReporting(0xFC45, 0x0000, DataType.INT16, 30, 3600, 100) +
zigbee.batteryConfig() +
zigbee.temperatureConfig(30, 300)
}
def configure() {
@@ -147,10 +150,5 @@ def configure() {
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return refresh() +
zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0x104E]) + // New firmware
zigbee.configureReporting(0xFC45, 0x0000, DataType.UINT16, 30, 3600, 100, ["mfgCode": 0xC2DF]) + // Original firmware
zigbee.batteryConfig() +
zigbee.temperatureConfig(30, 300)
return refresh()
}

View File

@@ -1,57 +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.
*
*/
metadata {
definition (name: "Simulated Refrigerator Door", namespace: "smartthings/testing", author: "SmartThings") {
capability "Contact Sensor"
capability "Sensor"
command "open"
command "close"
}
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")
}
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")
}
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")
}
standardTile("control", "device.contact", width: 1, height: 1, decoration: "flat") {
state("closed", label:'${name}', icon:"st.contact.contact.closed", action: "open")
state("open", label:'${name}', icon:"st.contact.contact.open", action: "close")
}
main "contact"
details "contact"
}
}
def installed() {
sendEvent(name: "contact", value: "closed")
}
def open() {
sendEvent(name: "contact", value: "open")
parent.doorOpen(device.deviceNetworkId)
}
def close() {
sendEvent(name: "contact", value: "closed")
parent.doorClosed(device.deviceNetworkId)
}

View File

@@ -1,94 +0,0 @@
/**
* Simulated Refrigerator Temperature Control
*
* 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.
*
*/
metadata {
definition (name: "Simulated Refrigerator Temperature Control", namespace: "smartthings/testing", author: "SmartThings") {
capability "Temperature Measurement"
capability "Thermostat Cooling Setpoint"
command "tempUp"
command "tempDown"
command "setpointUp"
command "setpointDown"
}
tiles {
valueTile("refrigerator", "device.temperature", width: 2, height: 2, canChangeBackground: true) {
state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 0, color: "#153591"],
[value: 40, color: "#1e9cbb"],
[value: 45, color: "#f1d801"]
]
)
}
valueTile("freezer", "device.temperature", width: 2, height: 2, canChangeBackground: true) {
state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 0, color: "#153591"],
[value: 5, color: "#1e9cbb"],
[value: 15, color: "#f1d801"]
]
)
}
valueTile("freezerSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "setpoint", label:'Freezer Set: ${currentValue}°', unit:"F"
}
valueTile("refrigeratorSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'Fridge Set: ${currentValue}°', unit:"F"
}
standardTile("tempUp", "device.temperature", inactiveLabel: false, decoration: "flat") {
state "default", action:"tempUp", icon:"st.thermostat.thermostat-up"
}
standardTile("tempDown", "device.temperature", inactiveLabel: false, decoration: "flat") {
state "default", action:"tempDown", icon:"st.thermostat.thermostat-down"
}
standardTile("setpointUp", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "default", action:"setpointUp", icon:"st.thermostat.thermostat-up"
}
standardTile("setpointDown", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "default", action:"setpointDown", icon:"st.thermostat.thermostat-down"
}
}
}
def installed() {
sendEvent(name: "temperature", value: device.componentName == "freezer" ? 2 : 40)
sendEvent(name: "coolingSetpoint", value: device.componentName == "freezer" ? 2 : 40)
}
def updated() {
installed()
}
void tempUp() {
def value = device.currentValue("temperature") as Integer
sendEvent(name: "temperature", value: value + 1)
}
void tempDown() {
def value = device.currentValue("temperature") as Integer
sendEvent(name: "temperature", value: value - 1)
}
void setpointUp() {
def value = device.currentValue("coolingSetpoint") as Integer
sendEvent(name: "coolingSetpoint", value: value + 1)
}
void setpointDown() {
def value = device.currentValue("coolingSetpoint") as Integer
sendEvent(name: "coolingSetpoint", value: value - 1)
}

View File

@@ -1,91 +0,0 @@
/**
* Simulated Refrigerator
*
* Example composite device handler that simulates a refrigerator with a freezer compartment and a main compartment.
* Each of these compartments has its own door, temperature, and temperature setpoint. Each compartment modeled
* as a child device of the main refrigerator device so that temperature-based SmartApps can be used with each
* compartment
*
* 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.
*
*/
metadata {
definition (name: "Simulated Refrigerator", namespace: "smartthings/testing", author: "SmartThings") {
capability "Contact Sensor"
}
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")
}
childDeviceTile("freezerDoor", "freezerDoor", height: 2, width: 2, childTileName: "freezerDoor")
childDeviceTile("mainDoor", "mainDoor", height: 2, width: 2, childTileName: "mainDoor")
childDeviceTile("freezer", "freezer", height: 2, width: 2, childTileName: "freezer")
childDeviceTile("refrigerator", "refrigerator", height: 2, width: 2, childTileName: "refrigerator")
childDeviceTile("freezerSetpoint", "freezer", height: 1, width: 2, childTileName: "freezerSetpoint")
childDeviceTile("refrigeratorSetpoint", "refrigerator", height: 1, width: 2, childTileName: "refrigeratorSetpoint")
// for simulator
childDeviceTile("freezerUp", "freezer", height: 1, width: 1, childTileName: "tempUp")
childDeviceTile("freezerDown", "freezer", height: 1, width: 1, childTileName: "tempDown")
childDeviceTile("refrigeratorUp", "refrigerator", height: 1, width: 1, childTileName: "tempUp")
childDeviceTile("refrigeratorDown", "refrigerator", height: 1, width: 1, childTileName: "tempDown")
childDeviceTile("freezerDoorControl", "freezerDoor", height: 1, width: 1, childTileName: "control")
childDeviceTile("mainDoorControl", "mainDoor", height: 1, width: 1, childTileName: "control")
childDeviceTile("freezerSetpointUp", "freezer", height: 1, width: 1, childTileName: "setpointUp")
childDeviceTile("freezerSetpointDown", "freezer", height: 1, width: 1, childTileName: "setpointDown")
childDeviceTile("refrigeratorSetpointUp", "refrigerator", height: 1, width: 1, childTileName: "setpointUp")
childDeviceTile("refrigeratorSetpointDown", "refrigerator", height: 1, width: 1, childTileName: "setpointDown")
}
}
def installed() {
state.counter = state.counter ? state.counter + 1 : 1
if (state.counter == 1) {
addChildDevice(
"Simulated Refrigerator Door",
"${device.deviceNetworkId}.1",
null,
[completedSetup: true, label: "${device.label} (Freezer Door)", componentName: "freezerDoor", componentLabel: "Freezer Door"])
addChildDevice(
"Simulated Refrigerator Door",
"${device.deviceNetworkId}.2",
null,
[completedSetup: true, label: "${device.label} (Main Door)", componentName: "mainDoor", componentLabel: "Main Door"])
addChildDevice(
"Simulated Refrigerator Temperature Control",
"${device.deviceNetworkId}.3",
null,
[completedSetup: true, label: "${device.label} (Freezer)", componentName: "freezer", componentLabel: "Freezer"])
addChildDevice(
"Simulated Refrigerator Temperature Control",
"${device.deviceNetworkId}.3",
null,
[completedSetup: true, label: "${device.label} (Fridge)", componentName: "refrigerator", componentLabel: "Fridge"])
}
}
def doorOpen(dni) {
// If any door opens, then the refrigerator is considered to be open
sendEvent(name: "contact", value: "open")
}
def doorClosed(dni) {
// Both doors must be closed for the refrigerator to be considered closed
if (!childDevices.find{it.deviceNetworkId != dni && it.currentValue("contact") == "open"}) {
sendEvent(name: "contact", value: "closed")
}
}

View File

@@ -20,7 +20,6 @@ metadata {
definition(name: "Wattvision", namespace: "smartthings", author: "Steve Vlaminck") {
capability "Power Meter"
capability "Refresh"
capability "Sensor"
attribute "powerContent", "string"
}

View File

@@ -18,7 +18,7 @@
metadata {
definition (name: "Wemo Light Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Wemo Light Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Switch"
capability "Polling"

View File

@@ -16,7 +16,7 @@
* Date: 2015-10-11
*/
metadata {
definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.smartplug") {
definition (name: "Wemo Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Switch"
capability "Polling"

View File

@@ -13,7 +13,7 @@
*/
metadata {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Configuration"
capability "Refresh"

View File

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

View File

@@ -1,46 +0,0 @@
# Zigbee Lock
Cloud Execution
Works with:
* [Yale Push Button Deadbolt (YRD210-HA)](https://www.smartthings.com/works-with-smartthings/door-locks/yale-push-button-deadbolt-yrd210)
* [Yale Touchscreen Lever (YRL220-ZB)](https://www.smartthings.com/works-with-smartthings/door-locks/yale-touchscreen-lever-yrl220)
* [Yale Touchscreen Deadbolt (YRD220-HA))](https://www.smartthings.com/works-with-smartthings/door-locks/yale-touchscreen-deadbolt-yrd220)
* [Yale Key Free Touchscreen Deadbolt (YRD240-HA)](https://www.smartthings.com/works-with-smartthings/door-locks/yale-key-free-touchscreen-deadbolt-yrd240)
* [Yale Push Button Lever Lock (YRL210-HA)](https://www.smartthings.com/works-with-smartthings/door-locks/yale-push-button-lever-lock-yrl210)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Lock** - allows for the control of a lock device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **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
Yale Push Button Deadbolt (YRD210-HA) is a Zigbee device and checks in every 1 hour.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*60 + 2)mins = 122 mins.
* __122min__ checkInterval
## Battery Specification
Four AA 1.5V 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 sensor from SmartThings can be found in the following link:
* [Yale Locks Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205138400)

View File

@@ -24,7 +24,6 @@ import physicalgraph.zigbee.zcl.DataType
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Health Check"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_DEADBOLT_5", deviceJoinName: "Kwikset 5-Button Deadbolt"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0004,0005,0009,0020,0101,0402,0B05,FDBD", outClusters: "000A,0019", manufacturer: "Kwikset", model: "SMARTCODE_LEVER_5", deviceJoinName: "Kwikset 5-Button Lever"
@@ -84,9 +83,6 @@ def uninstalled() {
}
def configure() {
// Device-Watch allows 2 check-in misses from device + ping (plus 2 min lag time)
sendEvent(name: "checkInterval", value: 2 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
def cmds =
zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE,
DataType.ENUM8, 0, 3600, null) +
@@ -96,13 +92,6 @@ def configure() {
return refresh() + cmds // send refresh cmds as part of config
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE)
}
def refresh() {
def cmds =
zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE) +

View File

@@ -25,7 +25,6 @@ metadata {
capability "Refresh"
capability "Actuator"
capability "Sensor"
capability "Configuration"
fingerprint manufacturer: "015D", prod: "0651", model: "F51C", deviceJoinName: "Zooz ZEN 20 Power Strip"
}
@@ -66,10 +65,6 @@ def updated() {
}
}
def configure() {
refresh()
}
//////////////////////
// Event Generation //
@@ -112,17 +107,15 @@ def zwaveBinaryEvent(cmd, endpoint) {
def result = []
def children = childDevices
def childDevice = children.find{it.deviceNetworkId.endsWith("$endpoint")}
if (childDevice) {
childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
childDevice.sendEvent(name: "switch", value: cmd.value ? "on" : "off")
if (cmd.value) {
// One on and the strip is on
result << createEvent(name: "switch", value: "on")
} else {
// All off and the strip is off
if (!children.any { it.currentValue("switch") == "on" }) {
result << createEvent(name: "switch", value: "off")
}
if (cmd.value) {
// One on and the strip is on
result << createEvent(name: "switch", value: "on")
} else {
// All off and the strip is off
if (! children.any { it.currentValue("switch") == "on" }) {
result << createEvent(name: "switch", value: "off")
}
}
result

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Z-Wave Dimmer Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Health Check"

View File

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

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Z-Wave Metering Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Z-Wave Metering Switch", namespace: "smartthings", author: "SmartThings") {
capability "Energy Meter"
capability "Actuator"
capability "Switch"
@@ -27,7 +27,7 @@ metadata {
command "reset"
fingerprint inClusters: "0x25,0x32"
fingerprint mfr:"0086", prod:"0003", model:"0012", deviceJoinName: "Aeon Labs Micro Smart Switch"
fingerprint mfr:"0086", prod:"0003", model:"0012", deviceJoinName: "Aeon Labs Micro Smart Switch 2E"
}
// simulator metadata
@@ -86,7 +86,7 @@ def updated() {
def parse(String description) {
def result = null
if(description == "updated") return
if(description == "updated") return
def cmd = zwave.parse(description, [0x20: 1, 0x32: 1, 0x72: 2])
if (cmd) {
result = zwaveEvent(cmd)

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Z-Wave Switch Generic", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Health Check"
capability "Switch"

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Z-Wave Switch Secure", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Z-Wave Switch Secure", namespace: "smartthings", author: "SmartThings") {
capability "Switch"
capability "Refresh"
capability "Polling"

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Z-Wave Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.switch") {
definition (name: "Z-Wave Switch", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Indicator"
capability "Switch"

View File

@@ -42,9 +42,9 @@ metadata {
status "auto" : "command: 4003, payload: 03"
status "emergencyHeat" : "command: 4003, payload: 04"
status "auto" : "command: 4403, payload: 00" // "fanAuto"
status "on" : "command: 4403, payload: 01" // "fanOn"
status "circulate" : "command: 4403, payload: 06" // "fanCirculate
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 09 3C"
status "heat 68" : "command: 4303, payload: 01 09 44"
@@ -74,9 +74,8 @@ metadata {
}
tiles {
// Using standardTile instead of valueTile as it renders the icon better
standardTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', icon: "st.thermostat.ac.air-conditioning",
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
@@ -89,20 +88,19 @@ metadata {
)
}
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "off", action:"switchMode", nextState:"to_heat", icon: "st.thermostat.heating-cooling-off"
state "heat", action:"switchMode", nextState:"to_cool", icon: "st.thermostat.heat"
state "cool", action:"switchMode", nextState:"...", icon: "st.thermostat.cool"
state "auto", action:"switchMode", nextState:"...", icon: "st.thermostat.auto"
state "emergency heat", action:"switchMode", nextState:"...", icon: "st.thermostat.emergency-heat"
state "to_heat", action:"switchMode", nextState:"to_cool", icon: "st.thermostat.heat"
state "to_cool", action:"switchMode", nextState:"...", icon: "st.thermostat.cool"
state "off", label:'${name}', action:"switchMode", nextState:"to_heat"
state "heat", label:'${name}', action:"switchMode", nextState:"to_cool"
state "cool", label:'${name}', action:"switchMode", nextState:"..."
state "auto", label:'${name}', action:"switchMode", nextState:"..."
state "emergency heat", label:'${name}', action:"switchMode", nextState:"..."
state "to_heat", label: "heat", action:"switchMode", nextState:"to_cool"
state "to_cool", label: "cool", action:"switchMode", nextState:"..."
state "...", label: "...", action:"off", nextState:"off"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
state "auto", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-auto" // "fanAuto"
state "on", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-on" // "fanOn"
state "circulate", action:"switchFanMode", nextState:"...", icon: "st.thermostat.fan-circulate" // "fanCirculate"
state "...", label: "...", nextState:"..."
state "fanAuto", label:'${name}', action:"switchFanMode"
state "fanOn", label:'${name}', action:"switchFanMode"
state "fanCirculate", label:'${name}', action:"switchFanMode"
}
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
@@ -119,8 +117,11 @@ metadata {
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"
}
main "temperature"
details(["temperature", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "refresh"])
details(["temperature", "mode", "fanMode", "heatSliderControl", "heatingSetpoint", "coolSliderControl", "coolingSetpoint", "refresh", "configure"])
}
}
@@ -285,13 +286,13 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanMod
def map = [:]
switch (cmd.fanMode) {
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_AUTO_LOW:
map.value = "auto" // "fanAuto"
map.value = "fanAuto"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_LOW:
map.value = "on" // "fanOn"
map.value = "fanOn"
break
case physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeReport.FAN_MODE_CIRCULATION:
map.value = "circulate" // "fanCirculate"
map.value = "fanCirculate"
break
}
map.name = "thermostatFanMode"
@@ -308,19 +309,15 @@ def zwaveEvent(physicalgraph.zwave.commands.thermostatmodev2.ThermostatModeSuppo
if(cmd.auto) { supportedModes += "auto " }
state.supportedModes = supportedModes
// No events to be generated, return empty map
return [:]
}
def zwaveEvent(physicalgraph.zwave.commands.thermostatfanmodev3.ThermostatFanModeSupportedReport cmd) {
def supportedFanModes = ""
if(cmd.auto) { supportedFanModes += "auto " } // "fanAuto "
if(cmd.low) { supportedFanModes += "on " } // "fanOn"
if(cmd.circulation) { supportedFanModes += "circulate " } // "fanCirculate"
if(cmd.auto) { supportedFanModes += "fanAuto " }
if(cmd.low) { supportedFanModes += "fanOn " }
if(cmd.circulation) { supportedFanModes += "fanCirculate " }
state.supportedFanModes = supportedFanModes
// No events to be generated, return empty map
return [:]
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
@@ -415,13 +412,7 @@ def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),
zwave.thermostatFanModeV3.thermostatFanModeSupportedGet().format(),
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(),
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()
zwave.associationV1.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format()
], 2300)
}
@@ -462,11 +453,11 @@ def switchToMode(nextMode) {
def switchFanMode() {
def currentMode = device.currentState("thermostatFanMode")?.value
def lastTriedMode = state.lastTriedFanMode ?: currentMode ?: "off"
def supportedModes = getDataByName("supportedFanModes") ?: "auto on" // "fanAuto fanOn"
def modeOrder = ["auto", "circulate", "on"] // "fanAuto", "fanCirculate", "fanOn"
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 != "auto") { // "fanAuto"
while (!supportedModes?.contains(nextMode) && nextMode != "fanAuto") {
nextMode = next(nextMode)
}
switchToFanMode(nextMode)
@@ -477,11 +468,11 @@ def switchToFanMode(nextMode) {
if(supportedFanModes && !supportedFanModes.contains(nextMode)) log.warn "thermostat mode '$nextMode' is not supported"
def returnCommand
if (nextMode == "auto") { // "fanAuto"
if (nextMode == "fanAuto") {
returnCommand = fanAuto()
} else if (nextMode == "on") { // "fanOn"
} else if (nextMode == "fanOn") {
returnCommand = fanOn()
} else if (nextMode == "circulate") { // "fanCirculate"
} else if (nextMode == "fanCirculate") {
returnCommand = fanCirculate()
} else {
log.debug("no fan mode '$nextMode'")

View File

@@ -0,0 +1,110 @@
/**
* jcApp
*
* Copyright 2017 Maria Jesus Cresci
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
definition(
name: "jcApp",
namespace: "mcrescii",
author: "Maria Jesus Cresci",
description: "Description test",
category: "",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")
preferences {
section("Turn on when motion detected:") {
input "themotion", "capability.motionSensor", required: true, title: "Where?"
}
section("Send Push Notification?") {
input "sendPush", "bool", required: false,
title: "Send Push Notification when motion?"
}
section("Turn off when there's been no movement for") {
input "minutes", "number", required: true, title: "Minutes?"
}
section("Turn on this light") {
input "theswitch", "capability.switch", required: true
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
subscribe(themotion, "motion.active", motionDetectedHandler)
subscribe(themotion, "motion.inactive", motionStoppedHandler)
subscribe(theswitch, "switch.off", switchOFFHandler)
subscribe(theswitch, "switch.on", switchONHandler)
}
def switchOFFHandler(evt){
log.debug "switchOFFHandler called: $evt"
if (sendPush) {
sendPush("Switch OFF")
}
}
def switchONHandler(evt){
log.debug "switchOFFHandler called: $evt"
if (sendPush) {
sendPush("Switch ON")
}
}
def motionDetectedHandler(evt) {
log.debug "motionDetectedHandler called: $evt"
theswitch.on()
if (sendPush) {
sendPush("Atenti, se detecto movimiento!")
}
}
def motionStoppedHandler(evt) {
log.debug "motionStoppedHandler called: $evt"
runIn(60 * minutes, checkMotion)
}
def checkMotion() {
log.debug "In checkMotion scheduled method"
def motionState = themotion.currentState("motion")
if (motionState.value == "inactive") {
// get the time elapsed between now and when the motion reported inactive
def elapsed = now() - motionState.date.time
// elapsed time is in milliseconds, so the threshold must be converted to milliseconds too
def threshold = 1000 * 60 * minutes
if (elapsed >= threshold) {
log.debug "Motion has stayed inactive long enough since last check ($elapsed ms): turning switch off"
theswitch.off()
} else {
log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): doing nothing"
}
} else {
// Motion active; just log it and do nothing
log.debug "Motion is active, do nothing and wait for inactive"
}
}
// TODO: implement event handlers