Compare commits

..

1 Commits

Author SHA1 Message Date
Donald C. Kirker
d1a69d9344 MSA-877: Spruce deployment with fixes (going to attempt to get Nate's original pull request updated with this code and use that; this is fallback).
Revert value used for testing.
Update with bugfix from Plaid Systems.
2016-02-11 19:47:51 -08:00
488 changed files with 11168 additions and 27695 deletions

23
.gitignore vendored
View File

@@ -1,23 +0,0 @@
# Eclipse files
/.settings
/.classpath
/.project
/eclipse/
/target-eclipse
# IntelliJ files
*.iws
*.iml
.idea
/out
*.ipr
# Gradle files
.gradletasknamecache
.gradle/
# Mac OS files
.DS_Store
# Build files
/build

View File

@@ -1,10 +1,10 @@
# SmartThings Public GitHub Repo
# SmartThings Public Github Repo
An official list of SmartApps and Device Types from SmartThings.
Here are some links to help you get started coding right away:
* [GitHub-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
* [Github-specific Documentation](http://docs.smartthings.com/en/latest/tools-and-ide/github-integration.html)
* [Full Documentation](http://docs.smartthings.com)
* [IDE & Simulator](http://ide.smartthings.com)
* [Community Forums](http://community.smartthings.com)

View File

@@ -1,133 +0,0 @@
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
import com.smartthings.deployment.slack.FileUpload
import com.smartthings.deployment.slack.Message
apply plugin: 'groovy'
apply plugin: 'smartthings-executable-deployment'
apply plugin: 'smartthings-slack'
buildscript {
dependencies {
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.12"
}
repositories {
mavenLocal()
jcenter()
maven {
credentials {
username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword
}
url "https://smartthings.jfrog.io/smartthings/libs-release-local"
}
}
}
repositories {
mavenLocal()
jcenter()
maven {
credentials {
username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword
}
url "https://smartthings.jfrog.io/smartthings/libs-release-local"
}
}
sourceSets {
devicetypes {
groovy {
srcDirs = ['devicetypes']
}
}
smartapps {
groovy {
srcDirs = ['smartapps']
}
}
}
dependencies {
devicetypesCompile 'org.codehaus.groovy:groovy-all:2.4.7'
devicetypesCompile 'smartthings:appengine-z-wave:0.1.3'
devicetypesCompile 'smartthings:appengine-zigbee:0.1.12'
smartappsCompile 'org.codehaus.groovy:groovy-all:2.4.7'
smartappsCompile 'smartthings:appengine-common:0.1.9'
smartappsCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
smartappsCompile 'org.grails:grails-web:2.3.11'
smartappsCompile 'org.json:json:20140107'
}
slackSendMessage {
String branch = project.hasProperty('branch') ? project.property('branch') : 'unknown'
String token = project.hasProperty('slackToken') ? project.property('slackToken') : null
String webhookUrl = project.hasProperty('slackWebhookUrl') ? project.property('slackWebhookUrl') : null
String channel = project.hasProperty('slackChannel') ? project.property('slackChannel') : null
String drinks = 'https://dl.dropboxusercontent.com/s/m1z5mpd3c83lwev/minion_beer.jpeg?dl=0'
String wolverine = 'https://dl.dropboxusercontent.com/s/4lbjqzvm2v033u9/minion_wolverine.jpg?dl=0'
String beach = 'https://dl.dropboxusercontent.com/s/rqrfgxk53gfng69/minion_beach.png?dl=0'
String iconUrl
String color
String messageText
String username
switch (branch) {
case 'master':
username = 'DEV'
iconUrl = wolverine
color = '#35D0F2'
messageText = 'Began deployment of _SmartThingsPublic[master]_ branch to the _Dev_ environments.'
break
case 'staging':
username = 'STG'
iconUrl = beach
color = '#FFDE20'
messageText = 'Began deployment of _SmartThingsPublic[staging]_ branch to the _Staging_ environments.'
break
case 'production':
username = 'PRD'
iconUrl = drinks
color = '#FF1D23'
messageText = 'Began deployment of _SmartThingsPublic[production]_ branch to the _Prod_ environments.'
break
default:
username = 'Hickory'
iconUrl = wolverine
color = '#35D0F2'
messageText = "Began deployment of an _SmartThingsPublic[${branch}]_ branch. Have no idea what's going on."
}
List<String> archives = []
File rootDir = new File("${project.buildDir}/archives")
if (rootDir.exists()) {
// Create a list of archives which were deployed.
java.nio.file.Path rootPath = Paths.get(rootDir.absolutePath)
rootDir.eachFileRecurse { File file ->
if (file.name.endsWith('.tar.gz')) {
java.nio.file.Path archivePath = Paths.get(file.absolutePath)
archives.add(rootPath.relativize(archivePath).toString())
}
}
}
Date date = new Date()
String fileDate = date.format('yyyy-MM-dd_HH-mm-ss', TimeZone.getTimeZone('GMT'))
// Required Task Arguments.
file = new FileUpload(
data: archives.join('\n').getBytes(StandardCharsets.UTF_8),
filename: "deployment-notes-${fileDate}.txt",
title: 'Deployment Notes',
channels: channel,
token: token,
color: color
)
message = new Message(
webhookUrl: webhookUrl,
username: username,
asUser: true,
iconUrl: iconUrl,
channel: channel,
fallback: 'Deployment Notification',
text: messageText
)
}

View File

@@ -1,27 +0,0 @@
machine:
java:
version:
oraclejdk8
dependencies:
override:
- ./gradlew dependencies -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
post:
- ./gradlew compileSmartappsGroovy compileDevicetypesGroovy -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
test:
override:
- echo "We don't have any tests :-("
deployment:
develop:
branch: master
commands:
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_DEV"
- ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL" --stacktrace
stage:
branch: staging
commands:
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Ps3Buckets="$S3_BUCKETS_STAGE"
- ./gradlew slackSendMessage -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD" -Pbranch="$CIRCLE_BRANCH" -PslackToken="$SLACK_TOKEN" -PslackWebhookUrl="$SLACK_WEBHOOK_URL" -PslackChannel="$SLACK_CHANNEL" --stacktrace

View File

@@ -23,8 +23,8 @@ metadata {
tiles {
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#00A0DC")
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
}
main "acceleration"

View File

@@ -23,8 +23,8 @@ metadata {
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#00A0DC")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#e86d13")
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
}
main "contact"
details "contact"

View File

@@ -27,7 +27,7 @@ metadata {
tiles {
standardTile("toggle", "device.lock", width: 2, height: 2) {
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00A0DC"
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821"
}
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {
state "default", label:'lock', action:"lock.lock", icon:"st.locks.lock.locked"

View File

@@ -29,7 +29,7 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "on"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
}
main "switch"
details "switch"

View File

@@ -24,7 +24,7 @@ metadata {
tiles {
standardTile("motion", "device.motion", width: 2, height: 2) {
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
}
main "motion"
details "motion"

View File

@@ -24,7 +24,7 @@ metadata {
tiles {
standardTile("presence", "device.presence", width: 2, height: 2) {
state("not present", label:'not present', icon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
state("present", label:'present', icon:"st.presence.tile.present", backgroundColor:"#00A0DC")
state("present", label:'present', icon:"st.presence.tile.present", backgroundColor:"#53a7c0")
}
main "presence"
details "presence"

View File

@@ -31,7 +31,7 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
}
main "switch"
details "switch"

View File

@@ -35,8 +35,8 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2) {
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#00A0DC"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
}
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {

View File

@@ -79,8 +79,8 @@ metadata {
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
state "off", label:'${name}', action:"thermostat.emergencyHeat", backgroundColor:"#ffffff"
state "emergencyHeat", label:'${name}', action:"thermostat.heat", backgroundColor:"#e86d13"
state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#e86d13"
state "cool", label:'${name}', action:"thermostat.off", backgroundColor:"#00A0DC"
state "heat", label:'${name}', action:"thermostat.cool", backgroundColor:"#ffc000"
state "cool", label:'${name}', action:"thermostat.off", backgroundColor:"#269bd2"
}
standardTile("fanMode", "device.thermostatFanMode", inactiveLabel: false, decoration: "flat") {
state "fanAuto", label:'${name}', action:"thermostat.fanOn", backgroundColor:"#ffffff"

View File

@@ -24,7 +24,7 @@ metadata {
tiles {
standardTile("water", "device.water", width: 2, height: 2) {
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00A0DC"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
}
main "water"

View File

@@ -1,107 +0,0 @@
/**
* BeaconThing
*
* Copyright 2015 obycode
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*
*/
import groovy.json.JsonSlurper
metadata {
definition (name: "BeaconThing", namespace: "com.obycode", author: "obycode") {
capability "Beacon"
capability "Presence Sensor"
capability "Sensor"
attribute "inRange", "json_object"
attribute "inRangeFriendly", "string"
command "setPresence", ["string"]
command "arrived", ["string"]
command "left", ["string"]
}
simulator {
status "present": "presence: 1"
status "not present": "presence: 0"
}
tiles {
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
state("present", labelIcon:"st.presence.tile.present", backgroundColor:"#00A0DC")
state("not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff")
}
valueTile("inRange", "device.inRangeFriendly", inactiveLabel: true, height:1, width:3, decoration: "flat") {
state "default", label:'${currentValue}', backgroundColor:"#ffffff"
}
main "presence"
details (["presence","inRange"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
}
def installed() {
sendEvent(name: "presence", value: "not present")
def emptyList = []
def json = new groovy.json.JsonBuilder(emptyList)
sendEvent(name:"inRange", value:json.toString())
}
def setPresence(status) {
log.debug "Status is $status"
sendEvent(name:"presence", value:status)
}
def arrived(id) {
log.debug "$id has arrived"
def theList = device.latestValue("inRange")
def inRangeList = new JsonSlurper().parseText(theList)
if (inRangeList.contains(id)) {
return
}
inRangeList += id
def json = new groovy.json.JsonBuilder(inRangeList)
log.debug "Now in range: ${json.toString()}"
sendEvent(name:"inRange", value:json.toString())
// Generate human friendly string for tile
def friendlyList = "Nearby: " + inRangeList.join(", ")
sendEvent(name:"inRangeFriendly", value:friendlyList)
if (inRangeList.size() == 1) {
setPresence("present")
}
}
def left(id) {
log.debug "$id has left"
def theList = device.latestValue("inRange")
def inRangeList = new JsonSlurper().parseText(theList)
inRangeList -= id
def json = new groovy.json.JsonBuilder(inRangeList)
log.debug "Now in range: ${json.toString()}"
sendEvent(name:"inRange", value:json.toString())
// Generate human friendly string for tile
def friendlyList = "Nearby: " + inRangeList.join(", ")
if (inRangeList.empty) {
setPresence("not present")
friendlyList = "No one is nearby"
}
sendEvent(name:"inRangeFriendly", value:friendlyList)
}

View File

@@ -38,7 +38,7 @@ metadata {
// Main
standardTile("main", "device.status", width: 1, height: 1, canChangeIcon: true) {
state "paused", label:'Paused', action:"music Player.play", icon:"st.Electronics.electronics19", nextState:"playing", backgroundColor:"#ffffff"
state "playing", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"paused", backgroundColor:"#00A0DC"
state "playing", label:'Playing', action:"music Player.pause", icon:"st.Electronics.electronics19", nextState:"paused", backgroundColor:"#79b821"
}
// Row 1

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Additional Module", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Basestation", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"

View File

@@ -15,7 +15,6 @@
*/
metadata {
definition (name: "Netatmo Outdoor Module", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"
}

View File

@@ -15,8 +15,6 @@
*/
metadata {
definition (name: "Netatmo Rain", namespace: "dianoga", author: "Brian Steere") {
capability "Sensor"
attribute "rain", "number"
attribute "rainSumHour", "number"
attribute "rainSumDay", "number"

View File

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

View File

@@ -1,44 +0,0 @@
# Express Controls EZMultiPli
Works with:
* [Express Controls EZMultiPli](https://www.smartthings.com/works-with-smartthings/)
## Table of contents
* [Release Notes](#release-notes)
* [Capabilities](#capabilities)
* [Troubleshooting](#troubleshooting)
## Release Notes
* **2017-04-19** - _dkirker_ - Update default config values in config value range check functions, use lux if lum option is null, fix NullPointerException on initial pairing when color data has not been set (and set the default color data!)
* **2017-04-10** - _DrZwave_ (with help from Donald Kirker) - changed fingerprint to the new format, lowered the OnTime and other parameters to be "more in line with ST user expectations", get the luminance in LUX so it reports in lux all the time.
* **2016-10-06** - _erocm1231_ - Added "updated" method to run when configuration options are changed. Depending on model of unit, luminance is being reported as a relative percentace or as a lux value. Added the option to configure this in the handler.
* **2016-01-28** - _erocm1231_ - Changed the configuration method to use scaledConfiguration so that it properly formatted negative numbers. Also, added configurationGet and a configurationReport method so that config values can be verified.
* **2015-12-04** - _erocm1231_ - added range value to preferences as suggested by @Dela-Rick.
* **2015-11-26** - _erocm1231_ - Fixed null condition error when adding as a new device.
* **2015-11-24** - _erocm1231_ - Added refresh command. Made a few changes to how the handler maps colors to the LEDs. Fixed the device not having its on/off status updated when colors are changed.
* **2015-11-23** - _erocm1231_ - Changed the look to match SmartThings v2 devices.
* **2015-11-21** - _erocm1231_ - Made code much more efficient. Also made it compatible when setColor is passed a hex value. Mapping of special colors: Soft White - Default - Yellow, White - Concentrate - White, Daylight - Energize - Teal, Warm White - Relax - Yellow
* **2015-11-19** - _erocm1231_ - Fixed a couple incorrect colors, changed setColor to be more compatible with other apps
* **2015-11-18** - _erocm1231_ - Added to setColor for compatibility with Smart Lighting
* **v0.1.0** - _DrZWave_ - chose better icons, Got color LED to work - first fully functional version
* **v0.0.9** - _jrs_ - got the temp and luminance to work. Motion works. Debugging the color wheel.
* **v0.0.8** - _DrZWave_ 2/25/2015 - change the color control to be tiles since there are only 8 colors.
* **v0.0.7** - _jrs_ - 02/23/2015 - Jim Sulin
## Capabilities
* **Actuator** - represents that a Device has commands
* **Sensor** - detects sensor events
* **Motion Sensor** - can detect motion
* **Temperature Measurement** - defines device measures current temperature
* **Illuminance Measurement** - gives the illuminance reading from devices that support it
* **Switch** - can detect state (possible values: on/off)
* **Color Control** - represents that the color attributes of a device can be controlled (hue, saturation, color value
* **Configuration** - configure() command called when device is installed or device preferences updated
* **Refresh** - refresh() command for status updates
## Troubleshooting

View File

@@ -1,405 +0,0 @@
// Express Controls EZMultiPli Multi-sensor
// Motion Sensor - Temperature - Light level - 8 Color Indicator LED - Z-Wave Range Extender - Wall Powered
// driver for SmartThings
// The EZMultiPli is also known as the HSM200 from HomeSeer.com
metadata {
definition (name: "EZmultiPli", namespace: "DrZWave", author: "Eric Ryherd", oauth: true) {
capability "Actuator"
capability "Sensor"
capability "Motion Sensor"
capability "Temperature Measurement"
capability "Illuminance Measurement"
capability "Switch"
capability "Color Control"
capability "Configuration"
capability "Refresh"
fingerprint mfr: "001E", prod: "0004", model: "0001" // new format for Fingerprint which is unique for every certified Z-Wave product
} // end definition
simulator {
// messages the device returns in response to commands it receives
status "motion" : "command: 7105000000FF07, payload: 07"
status "no motion" : "command: 7105000000FF07, payload: 00"
for (int i = 0; i <= 100; i += 20) {
status "temperature ${i}F": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 1, sensorType: 1, scale: 1).incomingMessage()
}
for (int i = 0; i <= 100; i += 20) {
status "luminance ${i} %": new physicalgraph.zwave.Zwave().sensorMultilevelV5.sensorMultilevelReport(
scaledSensorValue: i, precision: 0, sensorType: 3).incomingMessage()
}
} //end simulator
tiles (scale: 2){
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL", icon: "st.Lighting.light18") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', icon:"st.switches.light.on", backgroundColor:"#00A0DC"
attributeState "turningOff", label:'${name}', icon:"st.switches.light.off", backgroundColor:"#ffffff"
}
tileAttribute ("device.color", key: "COLOR_CONTROL") {
attributeState "color", action:"setColor"
}
tileAttribute ("statusText", key: "SECONDARY_CONTROL") {
attributeState "statusText", label:'${currentValue}'
}
}
standardTile("motion", "device.motion", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
}
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state "temperature", label:'${currentValue}°', unit:"F", icon:"", // would be better if the units would switch to the desired units of the system (imperial or metric)
backgroundColors:[
[value: 0, color: "#153591"], // blue=cold
[value: 65, color: "#44b621"], // green
[value: 70, color: "#44b621"], // green
[value: 75, color: "#f1d801"], // yellow
[value: 80, color: "#f1d801"], // yellow
[value: 85, color: "#f1d801"], // yellow
[value: 90, color: "#d04e00"], // red
[value: 95, color: "#bc2323"] // red=hot
]
}
// icons to use would be st.Weather.weather2 or st.alarm.temperature.normal - see http://scripts.3dgo.net/smartthings/icons/ for a list of icons
valueTile("illuminance", "device.illuminance", width: 2, height: 2, inactiveLabel: false) {
// jrs 4/7/2015 - Null on display
//state "luminosity", label:'${currentValue} ${unit}'
state "luminosity", label:'${currentValue}', unit:'${currentValue}', icon:"",
backgroundColors:[
[value: 25, color: "#404040"],
[value: 50, color: "#808080"],
[value: 75, color: "#a0a0a0"],
[value: 90, color: "#e0e0e0"],
//lux measurement values
[value: 150, color: "#404040"],
[value: 300, color: "#808080"],
[value: 600, color: "#a0a0a0"],
[value: 900, color: "#e0e0e0"]
]
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("configure", "device.configure", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main (["temperature","motion", "switch"])
details(["switch", "motion", "temperature", "illuminance", "refresh", "configure"])
} // end tiles
preferences {
input "OnTime", "number", title: "No Motion Interval", description: "N minutes lights stay on after no motion detected [0, 1-127]", range: "0..127", defaultValue: 2, displayDuringSetup: true, required: false
input "OnLevel", "number", title: "Dimmer Onlevel", description: "Dimmer OnLevel for associated node 2 lights [-1, 0, 1-99]", range: "-1..99", defaultValue: -1, displayDuringSetup: true, required: false
input "LiteMin", "number", title: "Luminance Report Frequency", description: "Luminance report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
input "TempMin", "number", title: "Temperature Report Frequency", description: "Temperature report sent every N minutes [0-127]", range: "0..127", defaultValue: 6, displayDuringSetup: true, required: false
input "TempAdj", "number", title: "Temperature Calibration", description: "Adjust temperature up/down N tenths of a degree F [(-127)-(+128)]", range: "-127..128", defaultValue: 0, displayDuringSetup: true, required: false
input("lum", "enum", title:"Illuminance Measurement", description: "Percent or Lux", defaultValue: 2 ,required: false, displayDuringSetup: true, options:
[1:"Percent",
2:"Lux"])
}
} // end metadata
// Parse incoming device messages from device to generate events
def parse(String description){
//log.debug "==> New Zwave Event: ${description}"
def result = []
def cmd = zwave.parse(description, [0x31: 5]) // 0x31=SensorMultilevel which we force to be version 5
if (cmd) {
def cmdData = zwaveEvent(cmd)
if (cmdData != [:])
result << createEvent(cmdData)
}
def statusTextmsg = ""
if (device.currentState('temperature') != null && device.currentState('illuminance') != null) {
statusTextmsg = "${device.currentState('temperature').value} ° - ${device.currentState('illuminance').value} ${(lum == 1) ? "%" : "LUX"}"
sendEvent("name":"statusText", "value":statusTextmsg, displayed:false)
}
if (result != [null] && result != []) log.debug "Parse returned ${result}"
return result
}
// Event Generation
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd){
def map = [:]
switch (cmd.sensorType) {
case 0x01: // SENSOR_TYPE_TEMPERATURE_VERSION_1
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
log.debug "Temperature report"
break;
case 0x03 : // SENSOR_TYPE_LUMINANCE_VERSION_1
map.value = cmd.scaledSensorValue.toInteger().toString()
if(lum == 1) map.unit = "%"
else map.unit = "lux"
map.name = "illuminance"
log.debug "Luminance report"
break;
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport cmd) {
log.debug "${device.displayName} parameter '${cmd.parameterNumber}' with a byte size of '${cmd.size}' is set to '${cmd.configurationValue}'"
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType==0x07) { // NOTIFICATION_TYPE_BURGLAR
if (cmd.event==0x07 || cmd.event==0x08) {
map.name = "motion"
map.value = "active"
map.descriptionText = "$device.displayName motion detected"
log.debug "motion recognized"
} else if (cmd.event==0) {
map.name = "motion"
map.value = "inactive"
map.descriptionText = "$device.displayName no motion detected"
log.debug "No motion recognized"
}
}
if (map.name != "motion") {
log.debug "unmatched parameters for cmd: ${cmd.toString()}}"
}
return map
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
// The EZMultiPli sets the color back to #ffffff on "off" or at init, so update the ST device to reflect this.
if (device.latestState("color") == null || (cmd.value == 0 && device.latestState("color").value != "#ffffff")) {
sendEvent(name: "color", value: "#ffffff", displayed: true)
}
[name: "switch", value: cmd.value ? "on" : "off", type: "digital"]
}
def updated()
{
log.debug "updated() is being called"
def cmds = configure()
if (cmds != []) response(cmds)
}
def on() {
log.debug "Turning Light 'on'"
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def off() {
log.debug "Turning Light 'off'"
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.basicV1.basicGet().format()
], 500)
}
def setColor(value) {
log.debug "setColor() : ${value}"
def myred
def mygreen
def myblue
def hexValue
def cmds = []
if ( value.level == 1 && value.saturation > 20) {
def rgb = huesatToRGB(value.hue as Integer, 100)
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else if ( value.level > 1 ) {
def rgb = huesatToRGB(value.hue as Integer, value.saturation as Integer)
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else if (value.hex) {
def rgb = value.hex.findAll(/[0-9a-fA-F]{2}/).collect { Integer.parseInt(it, 16) }
myred = rgb[0] >=128 ? 255 : 0
mygreen = rgb[1] >=128 ? 255 : 0
myblue = rgb[2] >=128 ? 255 : 0
}
else {
myred=value.red >=128 ? 255 : 0 // the EZMultiPli has just on/off for each of the 3 channels RGB so convert the 0-255 value into 0 or 255.
mygreen=value.green >=128 ? 255 : 0
myblue=value.blue>=128 ? 255 : 0
}
//log.debug "Red: ${myred} Green: ${mygreen} Blue: ${myblue}"
//cmds << zwave.colorControlV1.stateSet(stateDataLength: 3, VariantGroup1: [0x02, myred], VariantGroup2:[ 0x03, mygreen], VariantGroup3:[0x04,myblue]).format() // ST support for this command as of 2015/02/23 does not support the color IDs so this command cannot be used.
// So instead we'll use these commands to hack around the lack of support of the above command
cmds << zwave.basicV1.basicSet(value: 0x00).format() // As of 2015/02/23 ST is not supporting stateSet properly but found this hack that works.
if (myred!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x02, startState: myred, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x02).format()
}
if (mygreen!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x03, startState: mygreen, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x03).format()
}
if (myblue!=0) {
cmds << zwave.colorControlV1.startCapabilityLevelChange(capabilityId: 0x04, startState: myblue, ignoreStartState: True, updown: True).format()
cmds << zwave.colorControlV1.stopStateChange(capabilityId: 0x04).format()
}
cmds << zwave.basicV1.basicGet().format()
hexValue = rgbToHex([r:myred, g:mygreen, b:myblue])
if(hexValue) sendEvent(name: "color", value: hexValue, displayed: true)
delayBetween(cmds, 100)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}
// ensure we are passing acceptable param values for LiteMin & TempMin configs
def checkLiteTempInput(value) {
if (value == null) {
value=6
}
def liteTempVal = value.toInteger()
switch (liteTempVal) {
case { it < 0 }:
return 6 // bad value, set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return liteTempVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnTime config
def checkOnTimeInput(value) {
if (value == null) {
value=2
}
def onTimeVal = value.toInteger()
switch (onTimeVal) {
case { it < 0 }:
return 2 // bad value set to default
break
case { it > 127 }:
return 127 // bad value, greater then MAX, set to MAX
break
default:
return onTimeVal // acceptable value
}
}
// ensure we are passing acceptable param value for OnLevel config
def checkOnLevelInput(value) {
if (value == null) {
value=99
}
def onLevelVal = value.toInteger()
switch (onLevelVal) {
case { it < -1 }:
return -1 // bad value set to default
break
case { it > 99 }:
return 99 // bad value, greater then MAX, set to MAX
break
default:
return onLevelVal // acceptable value
}
}
// ensure we are passing an acceptable param value for TempAdj configs
def checkTempAdjInput(value) {
if (value == null) {
value=0
}
def tempAdjVal = value.toInteger()
switch (tempAdjVal) {
case { it < -127 }:
return 0 // bad value, set to default
break
case { it > 128 }:
return 128 // bad value, greater then MAX, set to MAX
break
default:
return tempAdjVal // acceptable value
}
}
def refresh() {
def cmd = []
cmd << zwave.switchColorV3.switchColorGet().format()
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:1, scale:1).format()
cmd << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType:3, scale:1).format()
cmd << zwave.basicV1.basicGet().format()
delayBetween(cmd, 1000)
}
def configure() {
log.debug "OnTime=${settings.OnTime} OnLevel=${settings.OnLevel} TempAdj=${settings.TempAdj}"
def cmd = delayBetween([
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 1, scaledConfigurationValue: checkOnTimeInput(settings.OnTime)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: checkOnLevelInput(settings.OnLevel)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.LiteMin)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: checkLiteTempInput(settings.TempMin)).format(),
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: checkTempAdjInput(settings.TempAdj)).format(),
zwave.configurationV1.configurationGet(parameterNumber: 1).format(),
zwave.configurationV1.configurationGet(parameterNumber: 2).format(),
zwave.configurationV1.configurationGet(parameterNumber: 3).format(),
zwave.configurationV1.configurationGet(parameterNumber: 4).format(),
zwave.configurationV1.configurationGet(parameterNumber: 5).format()
], 100)
//log.debug cmd
cmd + refresh()
}
def huesatToRGB(float hue, float sat) {
while(hue >= 100) hue -= 100
int h = (int)(hue / 100 * 6)
float f = hue / 100 * 6 - h
int p = Math.round(255 * (1 - (sat / 100)))
int q = Math.round(255 * (1 - (sat / 100) * f))
int t = Math.round(255 * (1 - (sat / 100) * (1 - f)))
switch (h) {
case 0: return [255, t, p]
case 1: return [q, 255, p]
case 2: return [p, 255, t]
case 3: return [p, q, 255]
case 4: return [t, p, 255]
case 5: return [255, p, q]
}
}
def rgbToHex(rgb) {
def r = hex(rgb.r)
def g = hex(rgb.g)
def b = hex(rgb.b)
def hexColor = "#${r}${g}${b}"
hexColor
}
private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = "0" + s
}
s
}

View File

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

View File

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

View File

@@ -1,272 +0,0 @@
/**
* Fibaro Door/Window Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* 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 Door/Window Sensor ZW5 with Temperature", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.contact") {
capability "Battery"
capability "Contact Sensor"
capability "Sensor"
capability "Configuration"
capability "Tamper Alert"
capability "Temperature Measurement"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86", outClusters: ""
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x85, 0x59, 0x22, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x2B, 0x9C, 0x30, 0x31, 0x86, 0x84", outClusters: ""//actual NIF
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#e86d13")
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#00a0dc")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
}
}
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
main "FGK"
details(["FGK","battery", "temperature"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK 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, [0x31: 5, 0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x80: 1, 0x86: 1]
def version = versions[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.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
//it is assumed that default notification events are used
//(parameter 20 was not changed before device's re-inclusion)
def map = [:]
if (cmd.notificationType == 6) {
switch (cmd.event) {
case 22:
map.name = "contact"
map.value = "open"
map.descriptionText = "${device.displayName}: is open"
break
case 23:
map.name = "contact"
map.value = "closed"
map.descriptionText = "${device.displayName}: is closed"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:]
if (cmd.sensorType == 1) {
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
def cmds = []
cmds += zwave.wakeUpV2.wakeUpIntervalSet(seconds:21600, nodeid: zwaveHubNodeId)//FGK's default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x2B, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

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

@@ -1,242 +0,0 @@
/**
* Fibaro Door/Window Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* 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 Door/Window Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.contact") {
capability "Battery"
capability "Contact Sensor"
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: ""
}
simulator {
}
tiles(scale: 2) {
multiAttributeTile(name:"FGK", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.contact", key:"PRIMARY_CONTROL") {
attributeState("open", icon:"st.contact.contact.open", backgroundColor:"#e86d13")
attributeState("closed", icon:"st.contact.contact.closed", backgroundColor:"#00a0dc")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00A0DC")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#CCCCCC")
}
}
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGK"
details(["FGK","battery"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK 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, [0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x72: 2, 0x80: 1, 0x86: 1]
def version = versions[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.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
//it is assumed that default notification events are used
//(parameter 20 was not changed before device's re-inclusion)
def map = [:]
if (cmd.notificationType == 6) {
switch (cmd.event) {
case 22:
map.name = "contact"
map.value = "open"
map.descriptionText = "${device.displayName}: is open"
break
case 23:
map.name = "contact"
map.value = "closed"
map.descriptionText = "${device.displayName}: is closed"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
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
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x2B, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,286 +0,0 @@
/**
* Fibaro Flood Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* 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 Flood Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.moisture") {
capability "Battery"
capability "Configuration"
capability "Sensor"
capability "Tamper Alert"
capability "Temperature Measurement"
capability "Water Sensor"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x22, 0x85, 0x59, 0x20, 0x80, 0x70, 0x56, 0x5A, 0x7A, 0x72, 0x8E, 0x71, 0x73, 0x98, 0x9C, 0x31, 0x86", outClusters: ""
fingerprint mfr:"010F", prod:"0B01", model:"2002"
fingerprint mfr:"010F", prod:"0B01", model:"1002"
}
simulator {
}
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")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#cccccc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#00A0DC")
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGFS"
details(["FGFS","battery", "temperature"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGFS 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, [0x31: 5, 0x56: 1, 0x71: 3, 0x72:2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x72: 2, 0x80: 1]
def version = versions[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.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
// cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
// cmds << "delay 500"
cmds << encap(zwave.batteryV1.batteryGet())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) { //serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
def response_cmds = []
if (!device.currentState("temperature")) {
response_cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
}
if (!getDataValue("version") && !zwaveInfo.ver) {
log.debug "Requesting Version Report"
response_cmds << "delay 500"
response_cmds << encap(zwave.versionV1.versionGet())
}
response_cmds << "delay 1000"
response_cmds << encap(zwave.wakeUpV2.wakeUpNoMoreInformation())
[[:], response(response_cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def result = []
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
result << createEvent(map)
if (!getDataValue("serialNumber")) {
result << response(encap(zwave.manufacturerSpecificV2.deviceSpecificGet()))
} else {
result << response(encap(zwave.wakeUpV2.wakeUpNoMoreInformation()))
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType == 5) {
switch (cmd.event) {
case 2:
map.name = "water"
map.value = "wet"
map.descriptionText = "${device.displayName} is ${map.value}"
break
case 0:
map.name = "water"
map.value = "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
break
}
} else if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:]
if (cmd.sensorType == 1) {
// temperature
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
map.unit = getTemperatureScale()
map.name = "temperature"
map.displayed = true
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
// Device wakes up every 4 hours, this interval of 8h 2m 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])
// default initial state
sendEvent(name: "water", value: "dry")
def cmds = []
cmds << zwave.associationV2.associationSet(groupingIdentifier:1, nodeId: [zwaveHubNodeId])
cmds << zwave.batteryV1.batteryGet() // other queries sent as response to BatteryReport
encapSequence(cmds, 200)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16EncapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
if (zwaveInfo.zw && !zwaveInfo.zw.contains("s")) {
// Secure inclusion failed
crc16(cmd)
} else {
secure(cmd)
}
}

View File

@@ -1,285 +0,0 @@
/**
* Fibaro Motion Sensor ZW5
*
* Copyright 2016 Fibar Group S.A.
*
* 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 Motion Sensor ZW5", namespace: "fibargroup", author: "Fibar Group S.A.", ocfDeviceType: "x.com.st.d.sensor.motion") {
capability "Battery"
capability "Configuration"
capability "Illuminance Measurement"
capability "Motion Sensor"
capability "Sensor"
capability "Tamper Alert"
capability "Temperature Measurement"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E, 0x20, 0x86, 0x72, 0x5A, 0x59, 0x85, 0x73, 0x84, 0x80, 0x71, 0x56, 0x70, 0x31, 0x8E, 0x22, 0x30, 0x9C, 0x98, 0x7A", outClusters: ""
}
simulator {
}
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:"#cccccc")
attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
}
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
attributeState("active", label:'tamper active', backgroundColor:"#00a0dc")
attributeState("inactive", label:'tamper inactive', backgroundColor:"#cccccc")
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
state "temperature", label:'${currentValue}°',
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
}
valueTile("battery", "device.battery", inactiveLabel: false, width: 2, height: 2, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
main "FGMS"
details(["FGMS","battery","temperature","illuminance"])
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
def result = []
if (description.startsWith("Err 106")) {
if (state.sec) {
result = createEvent(descriptionText:description, displayed:false)
} else {
result = createEvent(
descriptionText: "FGK 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, [0x31: 5, 0x56: 1, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (cmd) {
log.debug "Parsed '${cmd}'"
zwaveEvent(cmd)
}
}
}
//security
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x71: 3, 0x84: 2, 0x85: 2, 0x86: 1, 0x98: 1])
if (encapsulatedCommand) {
return zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
//crc16
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
{
def versions = [0x31: 5, 0x71: 3, 0x72: 2, 0x80: 1, 0x84: 2, 0x85: 2, 0x86: 1]
def version = versions[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.debug "Could not extract command from $cmd"
} else {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [ displayed: true ]
switch (cmd.sensorType) {
case 1:
def cmdScale = cmd.scale == 1 ? "F" : "C"
map.name = "temperature"
map.unit = getTemperatureScale()
map.value = convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision)
break
case 3:
map.name = "illuminance"
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
break
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
def map = [:]
if (cmd.notificationType == 7) {
switch (cmd.event) {
case 0:
if (cmd.eventParameter[0] == 3) {
map.name = "tamper"
map.value = "inactive"
map.descriptionText = "${device.displayName}: tamper alarm has been deactivated"
}
if (cmd.eventParameter[0] == 8) {
map.name = "motion"
map.value = "inactive"
map.descriptionText = "${device.displayName}: motion has stopped"
}
break
case 3:
map.name = "tamper"
map.value = "active"
map.descriptionText = "${device.displayName}: tamper alarm activated"
break
case 8:
map.name = "motion"
map.value = "active"
map.descriptionText = "${device.displayName}: motion detected"
break
}
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.value = cmd.batteryLevel == 255 ? 1 : cmd.batteryLevel.toString()
map.unit = "%"
map.displayed = true
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd)
{
def event = createEvent(descriptionText: "${device.displayName} woke up", displayed: false)
def cmds = []
cmds << encap(zwave.batteryV1.batteryGet())
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0))
cmds << "delay 500"
cmds << encap(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1))
cmds << "delay 1200"
cmds << encap(zwave.wakeUpV1.wakeUpNoMoreInformation())
[event, response(cmds)]
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.DeviceSpecificReport cmd) {
log.debug "deviceIdData: ${cmd.deviceIdData}"
log.debug "deviceIdDataFormat: ${cmd.deviceIdDataFormat}"
log.debug "deviceIdDataLengthIndicator: ${cmd.deviceIdDataLengthIndicator}"
log.debug "deviceIdType: ${cmd.deviceIdType}"
if (cmd.deviceIdType == 1 && cmd.deviceIdDataFormat == 1) {//serial number in binary format
String serialNumber = "h'"
cmd.deviceIdData.each{ data ->
serialNumber += "${String.format("%02X", data)}"
}
updateDataValue("serialNumber", serialNumber)
log.debug "${device.displayName} - serial number: ${serialNumber}"
}
}
def zwaveEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd) {
updateDataValue("version", "${cmd.applicationVersion}.${cmd.applicationSubVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
log.debug "zWaveLibraryType: ${cmd.zWaveLibraryType}"
log.debug "zWaveProtocolVersion: ${cmd.zWaveProtocolVersion}"
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def zwaveEvent(physicalgraph.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
log.info "${device.displayName}: received command: $cmd - device has reset itself"
}
def configure() {
log.debug "Executing 'configure'"
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
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: 7200, nodeid: zwaveHubNodeId)//FGMS' default wake up interval
cmds += zwave.manufacturerSpecificV2.manufacturerSpecificGet()
cmds += zwave.manufacturerSpecificV2.deviceSpecificGet()
cmds += zwave.versionV1.versionGet()
cmds += zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId])
cmds += zwave.batteryV1.batteryGet()
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 1, scale: 0)
cmds += zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1)
cmds += zwave.wakeUpV2.wakeUpNoMoreInformation()
encapSequence(cmds, 500)
}
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
private crc16(physicalgraph.zwave.Command cmd) {
//zwave.crc16encapV1.crc16Encap().encapsulate(cmd).format()
"5601${cmd.format()}0000"
}
private encapSequence(commands, delay=200) {
delayBetween(commands.collect{ encap(it) }, delay)
}
private encap(physicalgraph.zwave.Command cmd) {
def secureClasses = [0x20, 0x30, 0x5A, 0x70, 0x71, 0x84, 0x85, 0x8E, 0x9C]
//todo: check if secure inclusion was successful
//if not do not send security-encapsulated command
if (secureClasses.find{ it == cmd.commandClassId }) {
secure(cmd)
} else {
crc16(cmd)
}
}

View File

@@ -1,795 +0,0 @@
/**
* CoopBoss H3Vx
* 02/29/16 Fixed app crash with Android by changing the syntax of default state in tile definition.
* Fixed null value errors during join process. Added 3 new commands to refresh data.
*
* 01/18/16 Masked invalid temperature reporting when TempProbe1 is below 0C
* Added setBaseCurrentNE, readBaseCurrentNE, commands as well as baseCurrentNE attribute.
*
* Copyright 2016 John Rucker
*
* 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.
* Icon location = http://scripts.3dgo.net/smartthings/icons/
*/
metadata {
definition (name: "CoopBoss H3Vx", namespace: "JohnRucker", author: "John.Rucker@Solar-Current.com") {
capability "Refresh"
capability "Polling"
capability "Sensor"
capability "Actuator"
capability "Configuration"
capability "Temperature Measurement"
capability "Door Control"
capability "Switch"
command "closeDoor"
command "closeDoorHiI"
command "openDoor"
command "autoCloseOn"
command "autoCloseOff"
command "autoOpenOn"
command "autoOpenOff"
command "setCloseLevelTo"
command "setOpenLevelTo"
command "setSensitivityLevel"
command "Aux1On"
command "Aux1Off"
command "Aux2On"
command "Aux2Off"
command "updateTemp1"
command "updateTemp2"
command "updateSun"
command "setNewBaseCurrent"
command "setNewPhotoCalibration"
command "readNewPhotoCalibration"
command "readBaseCurrentNE"
command "setBaseCurrentNE"
command "updateSensitivity"
command "updateCloseLightLevel"
command "updateOpenLightLevel"
attribute "doorState","string"
attribute "currentLightLevel","number"
attribute "closeLightLevel","number"
attribute "openLightLevel","number"
attribute "autoCloseEnable","string"
attribute "autoOpenEnable","string"
attribute "TempProb1","number"
attribute "TempProb2","number"
attribute "dayOrNight","string"
attribute "doorSensitivity","number"
attribute "doorCurrent","number"
attribute "doorVoltage","number"
attribute "Aux1","string"
attribute "Aux2","string"
attribute "coopStatus","string"
attribute "baseDoorCurrent","number"
attribute "photoCalibration","number"
attribute "baseCurrentNE","string"
fingerprint profileId: "0104", inClusters: "0000,0101,0402", manufacturer: "Solar-Current", model: "Coop Boss"
}
// simulator metadata
simulator {
}
preferences {
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
input "tempOffsetCoop", "number", title: "Coop Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
input "tempOffsetOutside", "number", title: "Outside Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
}
// UI tile definitions
tiles(scale: 2){
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: "#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"
}
tileAttribute ("device.coopStatus", key: "SECONDARY_CONTROL") {
attributeState "device.coopStatus", label:'${currentValue}'
}
}
multiAttributeTile(name:"dtlsDoorCtrl", type:"generic", width:6, height:4) {tileAttribute("device.doorState", key: "PRIMARY_CONTROL")
{
attributeState "unknown", label: '${name}', action:"openDoor", icon: "st.secondary.tools", nextState:"Sent"
attributeState "open", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-open", backgroundColor: "#00A0DC", nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-opening", backgroundColor: "#00A0DC"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#ffffff", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffffff"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.doors.garage.garage-open", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: "forced", action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "fault", label: 'FAULT', action:"openDoor", icon: "st.secondary.tools", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
tileAttribute ("device.doorState", key: "SECONDARY_CONTROL") {
attributeState "unknown", label: 'Door is in unknown state. Push to open.'
attributeState "open", label: 'Coop door is open. Push to close.'
attributeState "opening", label: 'Caution, door is opening!'
attributeState "closed", label: 'Coop door is closed. Push to open.'
attributeState "closing", label: 'Caution, door is closing!'
attributeState "jammed", label: 'Door open! Push for high-force close'
attributeState "forced close", label: "Door is closed. Push to open."
attributeState "fault", label: 'Door fault check electrical connection.'
attributeState "Sent", label: 'Command sent to CoopBoss...'
}
}
standardTile("autoClose", "device.autoCloseEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoCloseOff", icon: "st.doors.garage.garage-closing", backgroundColor: "#00A0DC", nextState:"Sent"
state "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: "#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"
}
valueTile("TempProb1", "device.TempProb1", width: 2, height: 2, decoration: "flat"){
state "default", label:'Coop\r${currentValue}°', unit:"F", action:"updateTemp1"}
valueTile("TempProb2", "device.TempProb2", width: 2, height: 2, decoration: "flat"){
state "default", label:'Outside\r${currentValue}°', unit:"F", action:"updateTemp2"}
valueTile("currentLevel", "device.currentLightLevel", width: 2, height: 2, decoration: "flat") {
state "default", label:'Sun\r${currentValue}', action:"updateSun"}
valueTile("dayOrNight", "device.dayOrNight", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "default", label:'${currentValue}.'
}
controlTile("SetClSlider", "device.closeLightLevel", "slider", height: 2, width: 4, inactiveLabel: false, range:"(1..100)") {
state "closeLightLevel", action:"setCloseLevelTo", backgroundColor:"#d04e00"
}
valueTile("SetClValue", "device.closeLightLevel", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "default", label:'Close\nSunlight\n${currentValue}', action:'updateCloseLightLevel'
}
controlTile("SetOpSlider", "device.openLightLevel", "slider", height: 2, width: 4, inactiveLabel: false, range:"(1..100)") {
state "openLightLevel", action:"setOpenLevelTo", backgroundColor:"#d04e00"
}
valueTile("SetOpValue", "device.openLightLevel", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "default", label:'Open\nSunlight\n${currentValue}', action:'updateOpenLightLevel'
}
controlTile("SetSensitivitySlider", "device.doorSensitivity", "slider", height: 2, width: 4, inactiveLabel: false, range:"(1..100)") {
state "openLightLevel", action:"setSensitivityLevel", backgroundColor:"#d04e00"
}
valueTile("SetSensitivityValue", "device.doorSensitivity", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
state "default", label:'Door\nSensitivity\n${currentValue}', action:'updateSensitivity'
}
standardTile("refresh", "device.refresh", width: 2, height: 2, decoration: "flat", inactiveLabel: false) {
state "default", label:'All', action:"refresh.refresh", icon:"st.secondary.refresh-icon"
}
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:"#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:"#00A0DC", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
main "doorCtrl"
details (["dtlsDoorCtrl", "TempProb1", "TempProb2", "currentLevel", "autoClose", "autoOpen", "dayOrNight",
"SetClSlider", "SetClValue", "SetOpSlider", "SetOpValue", "SetSensitivitySlider", "SetSensitivityValue",
"aux1", "aux2", "refresh"])
}
}
// Parse incoming device messages to generate events def parse(String description) {
def parse(String description) {
log.debug "description: $description"
Map map = [:]
if (description?.startsWith('catchall:')) {
map = parseCatchAllMessage(description)
}
else if (description?.startsWith('read attr -')) {
map = parseReportAttributeMessage(description)
}
else if (description?.startsWith('temperature: ') || description?.startsWith('humidity: ')) {
map = parseCustomMessage(description)
}
log.debug map
//return map ? createEvent(map) : null
sendEvent(map)
callUpdateStatusTxt()
}
private Map parseCatchAllMessage(String description) {
Map resultMap = [:]
def cluster = zigbee.parse(description)
log.debug cluster
if (cluster.clusterId == 0x0402) {
switch(cluster.sourceEndpoint) {
case 0x39: // Endpoint 0x39 is the temperature of probe 1
String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
resultMap.name = "TempProb1"
def celsius = Integer.valueOf(temp,16).shortValue()
if (celsius == -32768){ // This number is used to indicate an error in the temperature reading
resultMap.value = "---"
}else{
celsius = celsius / 100 // Temperature value is sent X 100.
resultMap.value = celsiusToFahrenheit(celsius)
if (tempOffsetOutside) {
def offset = tempOffsetOutside as int
resultMap.value = resultMap.value + offset
}
}
sendEvent(name: "temperature", value: resultMap.value, displayed: false) // set the temperatureMeasurment capability to temperature
break
case 0x40: // Endpoint 0x40 is the temperature of probe 2
String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
resultMap.name = "TempProb2"
def celsius = Integer.valueOf(temp,16).shortValue()
//resultMap.descriptionText = "Prob2 celsius value = ${celsius}"
if (celsius == -32768){ // This number is used to indicate an error in the temperature reading
resultMap.value = "---"
}else{
celsius = celsius / 100 // Temperature value is sent X 100.
resultMap.value = celsiusToFahrenheit(celsius)
if (tempOffsetCoop) {
def offset = tempOffsetCoop as int
resultMap.value = resultMap.value + offset
}
}
break
}
}
if (cluster.clusterId == 0x0101 && cluster.command == 0x0b) { // This is a default response to a command sent to cluster 0x0101 door control
//log.debug "Default Response Data = $cluster.data"
switch(cluster.data) {
case "[10, 0]": // 0x0a turn auto close on command verified
resultMap.name = "autoCloseEnable"
resultMap.value = "on"
break
case "[11, 0]": // 0x0b turn auto close off command verified
resultMap.name = "autoCloseEnable"
resultMap.value = "off"
break
case "[12, 0]": // 0x0C turn auto open on command verified
resultMap.name = "autoOpenEnable"
resultMap.value = "on"
break
case "[13, 0]": // 0x0d turn auto open off command verified
resultMap.name = "autoOpenEnable"
resultMap.value = "off"
break
case "[20, 0]": // 0x14 Aux1 On command verified
log.info "verified Aux1 On"
sendEvent(name: "switch", value: "on", displayed: false)
resultMap.name = "Aux1"
resultMap.value = "on"
break
case "[21, 0]": // 0x15 Aux1 Off command verified
log.info "verified Aux1 Off"
sendEvent(name: "switch", value: "off", displayed: false)
resultMap.name = "Aux1"
resultMap.value = "off"
break
case "[22, 0]": // 0x16 Aux2 On command verified
log.info "verified Aux2 On"
resultMap.name = "Aux2"
resultMap.value = "on"
break
case "[23, 0]": // 0x17 Aux2 Off command verified
log.info "verified Aux2 Off"
resultMap.name = "Aux2"
resultMap.value = "off"
break
}
}
return resultMap
}
private Map parseReportAttributeMessage(String description) {
Map resultMap = [:]
def descMap = parseDescriptionAsMap(description)
//log.debug "read attr descMap --> $descMap"
if (descMap.cluster == "0101" && descMap.attrId == "0003") {
resultMap.name = "doorState"
if (descMap.value == "00"){
resultMap.value = "unknown"
sendEvent(name: "door", value: "unknown", displayed: false)
}else if(descMap.value == "01"){
resultMap.value = "closed"
sendEvent(name: "door", value: "closed", displayed: false)
}else if(descMap.value == "02"){
resultMap.value = "open"
sendEvent(name: "door", value: "open", displayed: false)
}else if(descMap.value == "03"){
resultMap.value = "jammed"
}else if(descMap.value == "04"){
resultMap.value = "forced close"
}else if(descMap.value == "05"){
resultMap.value = "forced close"
}else if(descMap.value == "06"){
resultMap.value = "closing"
sendEvent(name: "door", value: "closing", displayed: false)
}else if(descMap.value == "07"){
resultMap.value = "opening"
sendEvent(name: "door", value: "opening", displayed: false)
}else if(descMap.value == "08"){
resultMap.value = "fault"
}else {
resultMap.value = "unknown"
}
resultMap.descriptionText = "Door State Changed to ${resultMap.value}"
} else if (descMap.cluster == "0101" && descMap.attrId == "0400") {
resultMap.name = "currentLightLevel"
resultMap.value = (Integer.parseInt(descMap.value, 16))
resultMap.displayed = false
} else if (descMap.cluster == "0101" && descMap.attrId == "0401") {
resultMap.name = "closeLightLevel"
resultMap.value = (Integer.parseInt(descMap.value, 16))
} else if (descMap.cluster == "0101" && descMap.attrId == "0402") {
resultMap.name = "openLightLevel"
resultMap.value = (Integer.parseInt(descMap.value, 16))
} else if (descMap.cluster == "0101" && descMap.attrId == "0403") {
resultMap.name = "autoCloseEnable"
if (descMap.value == "01"){resultMap.value = "on"}
else{resultMap.value = "off"}
} else if (descMap.cluster == "0101" && descMap.attrId == "0404") {
resultMap.name = "autoOpenEnable"
if (descMap.value == "01"){resultMap.value = "on"}
else{resultMap.value = "off"}
} else if (descMap.cluster == "0101" && descMap.attrId == "0405") {
resultMap.name = "doorCurrent"
resultMap.value = (Integer.parseInt(descMap.value, 16))
resultMap.value = resultMap.value * 0.001
} else if (descMap.cluster == "0101" && descMap.attrId == "0408") {
resultMap.name = "doorSensitivity"
resultMap.value = (100 - Integer.parseInt(descMap.value, 16))
} else if (descMap.cluster == "0101" && descMap.attrId == "0409") {
resultMap.name = "baseDoorCurrent"
resultMap.value = (Integer.parseInt(descMap.value, 16))
resultMap.value = resultMap.value * 0.001
} else if (descMap.cluster == "0101" && descMap.attrId == "040a") {
resultMap.name = "doorVoltage"
resultMap.value = (Integer.parseInt(descMap.value, 16))
resultMap.value = resultMap.value * 0.001
} else if (descMap.cluster == "0101" && descMap.attrId == "040b") {
resultMap.name = "Aux1"
if(descMap.value == "01"){
resultMap.value = "on"
sendEvent(name: "switch", value: "on", displayed: false)
}else{
resultMap.value = "off"
sendEvent(name: "switch", value: "off", displayed: false)
}
} else if (descMap.cluster == "0101" && descMap.attrId == "040c") {
resultMap.name = "Aux2"
if(descMap.value == "01"){
resultMap.value = "on"
}else{
resultMap.value = "off"
}
} else if (descMap.cluster == "0101" && descMap.attrId == "040d") {
resultMap.name = "photoCalibration"
resultMap.value = (Integer.parseInt(descMap.value, 16))
} else if (descMap.cluster == "0101" && descMap.attrId == "040e") {
resultMap.name = "baseCurrentNE"
resultMap.value = (Integer.parseInt(descMap.value, 16))
}
return resultMap
}
private Map parseCustomMessage(String description) {
//log.info "ParseCustomMessage called with ${description}"
Map resultMap = [:]
if (description?.startsWith('temperature: ')) {
resultMap.name = "temperature"
def rawT = (description - "temperature: ").trim()
resultMap.descriptionText = "Temperature celsius value = ${rawT}"
def rawTint = Float.parseFloat(rawT)
if (rawTint > 65){
resultMap.name = null
resultMap.value = null
resultMap.descriptionText = "Temperature celsius value = ${rawT} is invalid not updating"
log.warn "Invalid temperature value detected! rawT = ${rawT}, description = ${description}"
}else if (rawT == -32768){ // This number is used to indicate an error in the temperature reading
resultMap.value = "ERR"
}else{
resultMap.value = celsiusToFahrenheit(rawT.toFloat()) as Float
sendEvent(name: "TempProb1", value: resultMap.value, displayed: false) // Workaround for lack of access to endpoint information for Temperature report
}
}
resultMap.displayed = false
log.info "Temperature reported = ${resultMap.value}"
return resultMap
}
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
// Added for Temeperature parse
def getFahrenheit(value) {
def celsius = Integer.parseInt(value, 16)
return celsiusToFahrenheit(celsius) as Integer
}
// Private methods
def callUpdateStatusTxt(){
def cTemp = device.currentState("TempProb1")?.value
def cLight = 0
def testNull = device.currentState("currentLightLevel")?.value
if (testNull != null){
cLight = device.currentState("currentLightLevel")?.value as int
}
updateStatusTxt(cTemp, cLight)
}
def updateStatusTxt(currentTemp, currentLight){
//log.info "called updateStatusTxt with ${currentTemp}, ${currentLight}"
def cTmp = currentTemp
def cLL = 10
def oLL = 10
def testNull = device.currentState("closeLightLevel")?.value
if (testNull != null){
cLL = device.currentState("closeLightLevel")?.value as int
}
testNull = device.currentState("openLightLevel")?.value
if (testNull != null){
oLL = device.currentState("openLightLevel")?.value as int
}
def aOpnEn = device.currentState("autoOpenEnable")?.value
def aClsEn = device.currentState("autoCloseEnable")?.value
if (currentLight < cLL){
if (aOpnEn == "on"){
sendEvent(name: "dayOrNight", value: "Sun must be > ${oLL} to auto open", displayed: false)
sendEvent(name: "coopStatus", value: "Sunlight ${currentLight} open at ${oLL}. Coop ${cTmp}°", displayed: false)
}else{
sendEvent(name: "dayOrNight", value: "Auto Open is turned off.", displayed: false)
sendEvent(name: "coopStatus", value: "Sunlight ${currentLight} auto open off. Coop ${cTmp}°", displayed: false)
}
}else {
if (aClsEn == "on"){
sendEvent(name: "dayOrNight", value: "Sun must be < ${cLL} to auto close", displayed: false)
sendEvent(name: "coopStatus", value: "Sunlight ${currentLight} close at ${cLL}. Coop ${cTmp}°", displayed: false)
}else{
sendEvent(name: "dayOrNight", value: "Auto Close is turned off.", displayed: false)
sendEvent(name: "coopStatus", value: "Sunlight ${currentLight} auto close off. Coop ${cTmp}°", displayed: false)
}
}
}
// Commands to device
def on() {
log.debug "on calling Aux1On"
Aux1On()
}
def off() {
log.debug "off calling Aux1Off"
Aux1Off()
}
def close() {
log.debug "close calling closeDoor"
closeDoor()
}
def open() {
log.debug "open calling openDoor"
openDoor()
}
def Aux1On(){
log.debug "Sending Aux1 = on command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x14 {}"
}
def Aux1Off(){
log.debug "Sending Aux1 = off command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x15 {}"
}
def Aux2On(){
log.debug "Sending Aux2 = on command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x16 {}"
}
def Aux2Off(){
log.debug "Sending Aux2 = off command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x17 {}"
}
def openDoor() {
log.debug "Sending Open command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x1 {}"
}
def closeDoor() {
log.debug "Sending Close command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x0 {}"
}
def closeDoorHiI() {
log.debug "Sending High Current Close command"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x4 {}"
}
def autoOpenOn() {
log.debug "Setting Auto Open On"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x0C {}"
}
def autoOpenOff() {
log.debug "Setting Auto Open Off"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x0D {}"
}
def autoCloseOn() {
log.debug "Setting Auto Close On"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x0A {}"
}
def autoCloseOff() {
log.debug "Setting Auto Close Off"
"st cmd 0x${device.deviceNetworkId} 0x38 0x0101 0x0B {}"
}
def setOpenLevelTo(cValue) {
def cX = cValue
log.debug "Setting Open Light Level to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x402 0x23 {${Integer.toHexString(cX)}}"
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x402" // Read light value
cmd
}
def setCloseLevelTo(cValue) {
def cX = cValue
log.debug "Setting Close Light Level to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x401 0x23 {${Integer.toHexString(cX)}}"
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x401" // Read light value
cmd
}
def setSensitivityLevel(cValue) {
def cX = 100 - cValue
log.debug "Setting Door sensitivity level to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x408 0x23 {${Integer.toHexString(cX)}}" // Write attribute. 0x23 is a 32 bit integer value.
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x408" // Read attribute
cmd
}
def setNewBaseCurrent(cValue) {
def cX = cValue as int
log.info "Setting new BaseCurrent to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x409 0x23 {${Integer.toHexString(cX)}}" // Write attribute. 0x23 is a 32 bit integer value.
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x409" // Read attribute
cmd
}
def setNewPhotoCalibration(cValue) {
def cX = cValue as int
log.info "Setting new Photoresister calibration to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40D 0x2B {${Integer.toHexString(cX)}}" // Write attribute. 0x2B is a 32 bit signed integer value.
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40D" // Read attribute
cmd
}
def readNewPhotoCalibration() {
log.info "Requesting current Photoresister calibration "
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40D" // Read attribute
cmd
}
def readBaseCurrentNE() {
log.info "Requesting base current never exceed setting "
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40E" // Read attribute
cmd
}
def setBaseCurrentNE(cValue) {
def cX = cValue as int
log.info "Setting new base Current Never Exceed to ${cX} Hex = 0x${Integer.toHexString(cX)}"
def cmd = []
cmd << "st wattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40E 0x23 {${Integer.toHexString(cX)}}" // Write attribute. 0x23 is a 32 bit unsigned integer value.
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x40E" // Read attribute
cmd
}
def poll(){
log.debug "Polling Device"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0003" // Read Door State
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0400" // Read Current Light Level
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x39 0x0402 0x0000" // Read probe 1 Temperature
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x40 0x0402 0x0000" // Read probe 2 Temperature
cmd
}
def updateTemp1() {
log.debug "Sending attribute read request for Temperature Probe1"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x39 0x0402 0x0000" // Read Current Temperature from Coop Probe 1
cmd
}
def updateTemp2() {
log.debug "Sending attribute read request for Temperature Probe2"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x40 0x0402 0x0000" // Read Current Temperature from Coop Probe 2
cmd
}
def updateSun() {
log.debug "Sending attribute read request for Sun Light Level"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0400" // Read Current Light Level
cmd
}
def updateSensitivity() {
log.debug "Sending attribute read request for door sensitivity"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0408" // Read Door sensitivity
cmd
}
def updateCloseLightLevel() {
log.debug "Sending attribute read close light level"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0401"
cmd
}
def updateOpenLightLevel() {
log.debug "Sending attribute read open light level"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0402"
cmd
}
def refresh() {
log.debug "sending refresh command"
def cmd = []
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0003" // Read Door State
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0400" // Read Current Light Level
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0401" // Read Door Close Light Level
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0402" // Read Door Open Light Level
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0403" // Read Auto Door Close Settings
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0404" // Read Auto Door Open Settings
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x39 0x0402 0x0000" // Read Current Temperature from Coop Probe 1
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0408" // Object detection sensitivity
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x40 0x0402 0x0000" // Read Current Temperature from Coop Probe 2
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x0405" // Current required to close door
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x040B" // Aux1 Status
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x040C" // Aux2 Status
cmd << "delay 150"
cmd << "st rattr 0x${device.deviceNetworkId} 0x38 0x0101 0x409" // Read Base current
cmd
}
def configure() {
log.debug "Binding SEP 0x38 DEP 0x01 Cluster 0x0101 Lock cluster to hub"
log.debug "Binding SEP 0x39 DEP 0x01 Cluster 0x0402 Temperature cluster to hub"
log.debug "Binding SEP 0x40 DEP 0x01 Cluster 0x0402 Temperature cluster to hub"
def cmd = []
cmd << "zdo bind 0x${device.deviceNetworkId} 0x38 0x01 0x0101 {${device.zigbeeId}} {}" // Bind to end point 0x38 and the lock cluster
cmd << "delay 150"
cmd << "zdo bind 0x${device.deviceNetworkId} 0x39 0x01 0x0402 {${device.zigbeeId}} {}" // Bind to end point 0x39 and the temperature cluster
cmd << "delay 150"
cmd << "zdo bind 0x${device.deviceNetworkId} 0x40 0x01 0x0402 {${device.zigbeeId}} {}" // Bind to end point 0x40 and the temperature cluster
cmd << "delay 1500"
log.info "Sending ZigBee Configuration Commands to Coop Control"
return cmd + refresh()
}

View File

@@ -24,7 +24,7 @@ metadata {
tiles {
standardTile("sleeping", "device.sleeping", width: 1, height: 1, canChangeIcon: false, canChangeBackground: false) {
state("sleeping", label: "Sleeping", icon:"st.Bedroom.bedroom12", backgroundColor:"#ffffff")
state("not sleeping", label: "Awake", icon:"st.Health & Wellness.health12", backgroundColor:"#00A0DC")
state("not sleeping", label: "Awake", icon:"st.Health & Wellness.health12", backgroundColor:"#79b821")
}
standardTile("steps", "device.steps", width: 2, height: 2, canChangeIcon: false, canChangeBackground: false) {
state("steps", label: '${currentValue} Steps', icon:"st.Health & Wellness.health11", backgroundColor:"#ffffff")

View File

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

View File

@@ -1,39 +0,0 @@
# Keen Home Smart Vent
Cloud Execution
Works with:
* [Keen Home Smart Vent](https://www.smartthings.com/works-with-smartthings/keen-home/keen-home-smart-vent)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Sensor** - detects sensor events
* **Temperature Measurement** - represents capability to measure temperature
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Battery** - defines device uses a battery
* **Refresh** - _refresh()_ command for status updates
* **Health Check** - indicates ability to get device health notifications
## Device Health
Keen Home Smart Vent with reporting interval of 10 mins.
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __22min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the different motion sensors from SmartThings can be found in the following links
for the different models:
* [Keen Home Smart Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/205302050-Keen-Home-Smart-Vent)

View File

@@ -11,7 +11,6 @@ metadata {
capability "Sensor"
capability "Temperature Measurement"
capability "Battery"
capability "Health Check"
command "getLevel"
command "getOnOff"
@@ -21,7 +20,10 @@ metadata {
command "setZigBeeIdTile"
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"
}
// simulator metadata
@@ -38,10 +40,10 @@ metadata {
// UI tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#00a0dc"
state "on", action: "switch.off", icon: "st.vents.vent-open-text", backgroundColor: "#53a7c0"
state "off", action: "switch.on", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#e86d13"
state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffffff"
state "obstructed", action: "clearObstruction", icon: "st.vents.vent-closed", backgroundColor: "#ff0000"
state "clearing", action: "", icon: "st.vents.vent-closed", backgroundColor: "#ffff33"
}
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false) {
state "level", action:"switch level.setLevel"
@@ -272,7 +274,6 @@ private Map makeTemperatureResult(value) {
name: 'temperature',
value: "" + value,
descriptionText: "${linkText} is ${value}°${temperatureScale}",
unit: temperatureScale
]
}
@@ -464,27 +465,15 @@ def refresh() {
getBattery()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return refresh()
}
def configure() {
log.debug "CONFIGURE"
// Device-Watch allows 2 check-in misses from device + ping (plus 1 min lag time)
// enrolls with default periodic reporting until newer 5 min interval is confirmed
sendEvent(name: "checkInterval", value: 2 * 10 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
// get ZigBee ID by hidden tile because that's the only way we can do it
setZigBeeIdTile()
def configCmds = [
// bind reporting clusters to hub
//commenting out switch cluster bind as using wrapper onOffConfig of zigbee class
//"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0006 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0008 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0402 {${device.zigbeeId}} {}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0403 {${device.zigbeeId}} {}", "delay 500",
@@ -520,5 +509,5 @@ def configure() {
// "send 0x${device.deviceNetworkId} 1 1", "delay 1500",
]
return configCmds + zigbee.onOffConfig() + refresh()
return configCmds + refresh()
}

View File

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

View File

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

View File

@@ -24,7 +24,6 @@ import groovy.json.JsonBuilder
metadata {
definition (name: "PlantLink", namespace: "OsoTech", author: "Oso Technologies") {
capability "Sensor"
capability "Health Check"
command "setStatusIcon"
command "setPlantFuelLevel"
@@ -71,16 +70,6 @@ metadata {
}
}
def updated() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def installed() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
def setStatusIcon(value){
def status = ''
switch (value) {
@@ -131,7 +120,7 @@ def setInstallSmartApp(value){
}
def parse(String description) {
log.debug description
def description_map = parseDescriptionAsMap(description)
def event_name = ""
def measurement_map = [
@@ -140,7 +129,10 @@ def parse(String description) {
zigbeedeviceid: device.zigbeeId,
created: new Date().time /1000 as int
]
if (description_map.cluster == "0001"){
if (description_map.cluster == "0000"){
/* version number, not used */
} else if (description_map.cluster == "0001"){
/* battery voltage in mV (device needs minimium 2.1v to run) */
log.debug "PlantLink - id ${device.zigbeeId} battery ${description_map.value}"
event_name = "battery_status"
@@ -166,10 +158,6 @@ def parse(String description) {
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
if(nameAndValue.length == 2){
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}else{
map += []
}
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
}

View File

@@ -1,5 +1,6 @@
/**
* Spruce Controller V2_4 Big Tiles *
* Spruce Controller - Pre Release V2 10/11/2015
*
* Copyright 2015 Plaid Systems
*
* Author: NC
@@ -20,96 +21,82 @@
*/
metadata {
definition (name: 'Spruce Controller', namespace: 'plaidsystems', author: 'Plaid Systems') {
capability 'Switch'
capability 'Configuration'
capability 'Refresh'
capability 'Actuator'
capability 'Valve'
definition (name: "Spruce Controller", namespace: "plaidsystems", author: "NCauffman") {
capability "Switch"
capability "Configuration"
capability "Refresh"
capability "Actuator"
capability "Valve"
attribute 'switch', 'string'
attribute 'switch1', 'string'
attribute 'switch2', 'string'
attribute 'switch8', 'string'
attribute 'switch5', 'string'
attribute 'switch3', 'string'
attribute 'switch4', 'string'
attribute 'switch6', 'string'
attribute 'switch7', 'string'
attribute 'switch9', 'string'
attribute 'switch10', 'string'
attribute 'switch11', 'string'
attribute 'switch12', 'string'
attribute 'switch13', 'string'
attribute 'switch14', 'string'
attribute 'switch15', 'string'
attribute 'switch16', 'string'
attribute 'rainsensor', 'string'
attribute 'status', 'string'
attribute 'tileMessage', 'string'
attribute 'minutes', 'string'
attribute 'VALUE_UP', 'string'
attribute 'VALUE_DOWN', 'string'
attribute "switch", "string"
attribute "switch1", "string"
attribute "switch2", "string"
attribute "switch8", "string"
attribute "switch5", "string"
attribute "switch3", "string"
attribute "switch4", "string"
attribute "switch6", "string"
attribute "switch7", "string"
attribute "switch9", "string"
attribute "switch10", "string"
attribute "switch11", "string"
attribute "switch12", "string"
attribute "switch13", "string"
attribute "switch14", "string"
attribute "switch15", "string"
attribute "switch16", "string"
attribute "status", "string"
command 'levelUp'
command 'levelDown'
command 'programOn'
command 'programOff'
command 'programWait'
command 'programEnd'
command "programOn"
command "programOff"
command "on"
command "off"
command "z1on"
command "z1off"
command "z2on"
command "z2off"
command "z3on"
command "z3off"
command "z4on"
command "z4off"
command "z5on"
command "z5off"
command "z6on"
command "z6off"
command "z7on"
command "z7off"
command "z8on"
command "z8off"
command "z9on"
command "z9off"
command "z10on"
command "z10off"
command "z11on"
command "z11off"
command "z12on"
command "z12off"
command "z13on"
command "z13off"
command "z14on"
command "z14off"
command "z15on"
command "z15off"
command "z16on"
command "z16off"
command "offtime"
command 'on'
command 'off'
command 'zon'
command 'zoff'
command 'z1on'
command 'z1off'
command 'z2on'
command 'z2off'
command 'z3on'
command 'z3off'
command 'z4on'
command 'z4off'
command 'z5on'
command 'z5off'
command 'z6on'
command 'z6off'
command 'z7on'
command 'z7off'
command 'z8on'
command 'z8off'
command 'z9on'
command 'z9off'
command 'z10on'
command 'z10off'
command 'z11on'
command 'z11off'
command 'z12on'
command 'z12off'
command 'z13on'
command 'z13off'
command 'z14on'
command 'z14off'
command 'z15on'
command 'z15off'
command 'z16on'
command 'z16off'
command "refresh"
command "rain"
command "manual"
command "setDisplay"
command 'config'
command 'refresh'
command 'rain'
command 'manual'
command 'manualTime'
command 'settingsMap'
command 'writeTime'
command 'writeType'
command 'notify'
command 'updated'
//ST release
//fingerprint endpointId: '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18', profileId: '0104', deviceId: '0002', deviceVersion: '00', inClusters: '0000,0003,0004,0005,0006,000F', outClusters: '0003, 0019', manufacturer: 'PLAID SYSTEMS', model: 'PS-SPRZ16-01'
//new release
fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,0009,000A,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
command "settingsMap"
command "writeTime"
command "writeType"
command "notify"
command "updated"
fingerprint endpointId: "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18", profileId: "0104", deviceId: "0002", deviceVersion: "00", inClusters: "0000,0003,0004,0005,0006,000F", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZ16-01"
}
@@ -117,230 +104,162 @@ metadata {
simulator {
// status messages
// reply messages
// reply messages
}
preferences {
input description: 'If you have a rain sensor wired to the rain sensor input on the Spruce controller, turn it on here.', displayDuringSetup: true, type: 'paragraph', element: 'paragraph', title: 'Rain Sensor'
input description: 'The SYNC SETTINGS button must be pressed after making a change to the Rain sensor:', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: ''
input 'RainEnable', 'bool', title: 'Rain Sensor Attached?', required: false, displayDuringSetup: true
input description: 'Adjust manual water time with arrows on main tile. The time indicated in the first small tile indicates the time the zone will water when manually switched on.', displayDuringSetup: false, type: 'paragraph', element: 'paragraph', title: ''
}
input description: "Press Configure button after making changes to these preferences", displayDuringSetup: true, type: "paragraph", element: "paragraph", title: ""
input "RainEnable", "bool", title: "Rain Sensor Attached?", required: false, displayDuringSetup: true
input "ManualTime", "number", title: "Automatic shutoff time when a zone is turned on manually?", required: false, displayDuringSetup: true
}
// UI tile definitions
tiles {
multiAttributeTile(name:"switchall", type:"generic", width:6, height:4) {
tileAttribute('device.status', key: 'PRIMARY_CONTROL') {
attributeState 'schedule', label: 'Ready', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top.png'
attributeState 'finished', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#46c2e8'
attributeState 'raintoday', label: 'Rain Today', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
attributeState 'rainy', label: 'Rain', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
attributeState 'raintom', label: 'Rain Tomorrow', icon: 'http://www.plaidsystems.com/smartthings/st_rain.png', backgroundColor: '#d65fe3'
attributeState 'donewweek', label: 'Finished', icon: 'st.Outdoor.outdoor5', backgroundColor: '#00A0DC'
attributeState 'skipping', label: 'Skip', icon: 'st.Outdoor.outdoor20', backgroundColor: '#46c2e8'
attributeState 'moisture', label: 'Ready', icon: 'st.Weather.weather2', backgroundColor: '#46c2e8'
attributeState 'pause', label: 'PAUSE', icon: 'st.contact.contact.open', backgroundColor: '#e86d13'
attributeState 'delayed', label: 'Delayed', icon: 'st.contact.contact.open', backgroundColor: '#e86d13'
attributeState 'active', label: 'Active', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E'
attributeState 'season', label: 'Adjust', icon: 'st.Outdoor.outdoor17', backgroundColor: '#ffb900'
attributeState 'disable', label: 'Off', icon: 'st.secondary.off', backgroundColor: '#cccccc'
attributeState 'warning', label: 'Warning', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_top_yellow.png'
attributeState 'alarm', label: 'Alarm', icon: 'http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_s_red.png', backgroundColor: '#e66565'
}
tileAttribute("device.minutes", key: "VALUE_CONTROL") {
attributeState "VALUE_UP", action: "levelUp"
attributeState "VALUE_DOWN", action: "levelDown"
}
tileAttribute("device.tileMessage", key: "SECONDARY_CONTROL") {
attributeState "tileMessage", label: '${currentValue}'
}
standardTile("status", "device.status") {
state "schedule", label: 'Schedule Set', icon: "http://www.plaidsystems.com/smartthings/st_spruce_leaf_225_t.png"
state "finished", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#46c2e8"
state "raintoday", label: 'Rain Today', icon: "st.custom.wuk.nt_chancerain"
state "rainy", label: 'Previous Rain', icon: "st.custom.wuk.nt_chancerain"
state "raintom", label: 'Rain Tomorrow', icon: "st.custom.wuk.nt_chancerain"
state "donewweek", label: 'Spruce Finished', icon: "st.Outdoor.outdoor5", backgroundColor: "#52c435"
state "skipping", label: 'Skip Today', icon: "st.Outdoor.outdoor20", backgroundColor: "#36cfe3"
state "moisture", label: '', icon: "st.Weather.weather2", backgroundColor: "#36cfe3"
state "pause", label: 'PAUSE', icon: "st.contact.contact.open", backgroundColor: "#f2a51f"
state "active", label: 'Active', icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
state "season", label: 'Seasonal Adjustment', icon: "st.Outdoor.outdoor17", backgroundColor: "#ffb900"
state "disable", label: 'Disabled', icon: "st.secondary.off", backgroundColor: "#888888"
state "warning", label: '', icon: "st.categories.damageAndDanger", backgroundColor: "#ffff7f"
state "alarm", label: 'Alarm', icon: "st.categories.damageAndDanger", backgroundColor: "#f9240c"
}
valueTile('minutes', 'device.minutes'){
state 'minutes', label: '${currentValue} min'
}
valueTile('dummy', 'device.minutes'){
state 'minutes', label: ''
}
standardTile('switch', 'device.switch', width:2, height:2) {
state 'off', label: 'Start', action: 'programOn', icon: 'st.Outdoor.outdoor12', backgroundColor: '#a9a9a9'
state 'programOn', label: 'Wait', action: 'programOff', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e'
state 'programWait', label: 'Wait', action: 'programEnd', icon: 'st.contact.contact.open', backgroundColor: '#f6e10e'
state 'on', label: 'Running', action: 'programEnd', icon: 'st.Outdoor.outdoor12', backgroundColor: '#3DC72E'
standardTile("switch", "device.switch") {
//state "programOff", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
state "off", label: 'Start Program', action: "programOn", icon: "st.sonos.play-icon", backgroundColor: "#a9a9a9"
state "programOn", label: 'Initialize Program', action: "programOff", icon: "st.contact.contact.open", backgroundColor: "#f6e10e"
state "on", label: 'Program Running', action: "off", icon: "st.Outdoor.outdoor12", backgroundColor: "#3DC72E"
}
standardTile("rainsensor", "device.rainsensor") {
state "rainSensrooff", label: 'Rain Sensor Clear', icon: "st.Weather.weather14", backgroundColor: "#a9a9a9"
state "rainSensoron", label: 'Rain Detected', icon: "st.Weather.weather10", backgroundColor: "#f6e10e"
}
standardTile("switch1", "device.switch1") {
state "z1off", label: '1', action: "z1on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z1on", label: '1', action: "z1off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch2", "device.switch2") {
state "z2off", label: '2', action: "z2on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z2on", label: '2', action: "z2off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("rainsensor", "device.rainsensor", decoration: 'flat') {
state "rainSensoroff", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png'
state "rainSensoron", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on_blue_small.png'
state "disable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_x_small.png'
state "enable", label: 'sensor', icon: 'http://www.plaidsystems.com/smartthings/st_drop_on.png'
standardTile("switch3", "device.switch3", inactiveLabel: false) {
state "z3off", label: '3', action: "z3on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z3on", label: '3', action: "z3off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch1', 'device.switch1', inactiveLabel: false) {
state 'z1off', label: '1', action: 'z1on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z1on', label: '1', action: 'z1off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch4", "device.switch4", inactiveLabel: false) {
state "z4off", label: '4', action: "z4on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z4on", label: '4', action: "z4off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch2', 'device.switch2', inactiveLabel: false) {
state 'z2off', label: '2', action: 'z2on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z2on', label: '2', action: 'z2off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch5", "device.switch5", inactiveLabel: false) {
state "z5off", label: '5', action: "z5on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z5on", label: '5', action: "z5off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch6", "device.switch6", inactiveLabel: false) {
state "z6off", label: '6', action: "z6on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z6on", label: '6', action: "z6off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch7", "device.switch7", inactiveLabel: false) {
state "z7off", label: '7', action: "z7on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z7on", label: '7', action: "z7off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch8", "device.switch8", inactiveLabel: false) {
state "z8off", label: '8', action: "z8on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z8on", label: '8', action: "z8off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch9", "device.switch9", inactiveLabel: false) {
state "z9off", label: '9', action: "z9on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z9on", label: '9', action: "z9off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile("switch10", "device.switch10", inactiveLabel: false) {
state "z10off", label: '10', action: "z10on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z10on", label: '10', action: "z10off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch3', 'device.switch3', inactiveLabel: false) {
state 'z3off', label: '3', action: 'z3on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z3on', label: '3', action: 'z3off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch11", "device.switch11", inactiveLabel: false) {
state "z11off", label: '11', action: "z11on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z11on", label: '11', action: "z11off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch4', 'device.switch4', inactiveLabel: false) {
state 'z4off', label: '4', action: 'z4on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z4on', label: '4', action: 'z4off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch12", "device.switch12", inactiveLabel: false) {
state "z12off", label: '12', action: "z12on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z12on", label: '12', action: "z12off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch5', 'device.switch5', inactiveLabel: false) {
state 'z5off', label: '5', action: 'z5on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z5on', label: '5', action: 'z5off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch13", "device.switch13", inactiveLabel: false) {
state "z13off", label: '13', action: "z13on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z13on", label: '13', action: "z13off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch6', 'device.switch6', inactiveLabel: false) {
state 'z6off', label: '6', action: 'z6on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z6on', label: '6', action: 'z6off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch14", "device.switch14", inactiveLabel: false) {
state "z14off", label: '14', action: "z14on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z14on", label: '14', action: "z14off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch7', 'device.switch7', inactiveLabel: false) {
state 'z7off', label: '7', action: 'z7on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z7on', label: '7', action: 'z7off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch8', 'device.switch8', inactiveLabel: false) {
state 'z8off', label: '8', action: 'z8on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z8on', label: '8', action: 'z8off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch9', 'device.switch9', inactiveLabel: false) {
state 'z9off', label: '9', action: 'z9on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z9on', label: '9', action: 'z9off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch10', 'device.switch10', inactiveLabel: false) {
state 'z10off', label: '10', action: 'z10on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z10on', label: '10', action: 'z10off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch11', 'device.switch11', inactiveLabel: false) {
state 'z11off', label: '11', action: 'z11on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z11on', label: '11', action: 'z11off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch12', 'device.switch12', inactiveLabel: false) {
state 'z12off', label: '12', action: 'z12on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z12on', label: '12', action: 'z12off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch13', 'device.switch13', inactiveLabel: false) {
state 'z13off', label: '13', action: 'z13on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z13on', label: '13', action: 'z13off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch14', 'device.switch14', inactiveLabel: false) {
state 'z14off', label: '14', action: 'z14on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z14on', label: '14', action: 'z14off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
}
standardTile('switch15', 'device.switch15', inactiveLabel: false) {
state 'z15off', label: '15', action: 'z15on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z15on', label: '15', action: 'z15off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch15", "device.switch15", inactiveLabel: false) {
state "z15off", label: '15', action: "z15on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z15on", label: '15', action: "z15off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('switch16', 'device.switch16', inactiveLabel: false) {
state 'z16off', label: '16', action: 'z16on', icon: 'st.valves.water.closed', backgroundColor: '#ffffff'
state 'z16on', label: '16', action: 'z16off', icon: 'st.valves.water.open', backgroundColor: '#00A0DC'
standardTile("switch16", "device.switch16", inactiveLabel: false) {
state "z16off", label: '16', action: "z16on", icon: "st.valves.water.closed", backgroundColor: "#ffffff"
state "z16on", label: '16', action: "z16off", icon: "st.valves.water.open", backgroundColor: "#46c2e8"
}
standardTile('refresh', 'device.switch', inactiveLabel: false, decoration: 'flat') {
state 'default', action: 'refresh', icon:'st.secondary.refresh'//-icon'
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", action: "refresh", icon:"st.secondary.refresh"
}
standardTile('configure', 'device.configure', inactiveLabel: false, decoration: 'flat') {
state 'configure', label:'', action:'configuration.configure', icon:'http://www.plaidsystems.com/smartthings/st_syncsettings.png'//sync_icon_small.png'
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
main (['switchall'])
details(['switchall','minutes','rainsensor','switch1','switch2','switch3','switch4','switch','switch5','switch6','switch7','switch8','switch9','switch10','switch11','switch12','refresh','configure','switch13','switch14','switch15','switch16'])
}
main (["status"])
details(["status","rainsensor","switch","switch1","switch2","switch3","switch4","switch5","switch6","switch7","switch8","switch9","switch10","switch11","switch12","switch13","switch14","switch15","switch16","refresh","configure"])
}
}
//used for schedule
def programOn(){
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Program turned on')
}
def programWait(){
sendEvent(name: 'switch', value: 'programWait', descriptionText: "Initializing Schedule")
}
def programEnd(){
//sets switch to off and tells schedule switch is off/schedule complete with manaual
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program manually turned off')
zoff()
sendEvent(name: "switch", value: "programOn", descriptionText: "Program turned on")
}
def programOff(){
sendEvent(name: 'switch', value: 'off', descriptionText: 'Program turned off')
sendEvent(name: "switch", value: "off", descriptionText: "Program turned off")
off()
}
//set minutes
def levelUp(){
def newvalue = 1
if (device.latestValue('minutes') != null) newvalue = device.latestValue('minutes').toInteger()+1
if (newvalue >= 60) newvalue = 60
def value = newvalue.toString()
log.debug value
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
}
def levelDown(){
def newvalue = device.latestValue('minutes').toInteger()-1
if (newvalue <= 0) newvalue = 1
def value = newvalue.toString()
log.debug value
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
def updated(){
log.debug "updated"
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "Parse description ${description}"
//log.debug "Parse description $description"
def result = null
def map = [:]
if (description?.startsWith('read attr -')) {
if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description)
//log.debug "Desc Map: $descMap"
//using 000F cluster instead of 0006 (switch) because ST does not differentiate between EPs and processes all as switch
if (descMap.cluster == '000F' && descMap.attrId == '0055') {
log.debug 'Zone'
if (descMap.cluster == "000F" && descMap.attrId == "0055") {
log.debug "Zone"
map = getZone(descMap)
}
else if (descMap.cluster == '0009' && descMap.attrId == '0000') {
log.debug 'Alarm'
else if (descMap.cluster == "0009" && descMap.attrId == "0000") {
log.debug "Alarm"
map = getAlarm(descMap)
}
}
if (map) {
result = createEvent(map)
}
else if (description?.startsWith('catchall: 0104 0009')){
log.debug 'Sync settings to controller complete'
if (device.latestValue('status') != 'alarm'){
def configEvt = createEvent(name: 'status', value: 'schedule', descriptionText: "Sync settings to controller complete")
def configMsg = createEvent(name: 'tileMessage', value: 'Sync settings to controller complete', descriptionText: "Sync settings to controller complete", displayed: false)
result = [configEvt, configMsg]
}
return result
}
if (map) {
result = createEvent(map)
//configure after reboot
if (map.value == 'warning' || map.value == 'alarm'){
def cmds = config()
def alarmEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
result = cmds?.collect { new physicalgraph.device.HubAction(it) } + createEvent(map) + alarmEvt
return result
}
else if (map.name == 'rainsensor'){
def rainEvt = createEvent(name: 'tileMessage', value: map.descriptionText, descriptionText: "${map.descriptionText}", displayed: false)
result = [createEvent(map), rainEvt]
return result
}
}
if (map) log.debug "Parse returned ${map} ${result}"
log.debug "Parse returned $map $result"
return result
}
def parseDescriptionAsMap(description) {
(description - 'read attr - ').split(',').inject([:]) { map, param ->
def nameAndValue = param.split(':')
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
@@ -351,28 +270,27 @@ def getZone(descMap){
def EP = Integer.parseInt(descMap.endpoint.trim(), 16)
String onoff
if(descMap.value == '00'){
onoff = 'off'
if(descMap.value == "00"){
onoff = "off"
}
else onoff = 'on'
else onoff = "on"
if (EP == 1){
map.name = 'switch'
map.name = "switch"
map.value = onoff
map.descriptionText = "${device.displayName} turned sprinkler program ${onoff}"
map.descriptionText = "${device.displayName} turned sprinkler program $onoff"
}
else if (EP == 18) {
map.name = 'rainsensor'
log.debug "Rain enable: ${RainEnable}, sensor: ${onoff}"
map.value = 'rainSensor' + onoff
map.descriptionText = "${device.displayName} rain sensor is ${onoff}"
map.name = "rainsensor"
map.value = "rainSensor" + onoff
map.descriptionText = "${device.displayName} rain sensor is $onoff"
}
else {
EP -= 1
map.name = 'switch' + EP
map.value = 'z' + EP + onoff
map.descriptionText = "${device.displayName} turned Zone $EP ${onoff}"
map.name = "switch" + EP
map.value = "z" + EP + onoff
map.descriptionText = "${device.displayName} turned Zone $EP $onoff"
}
map.isStateChange = true
@@ -382,59 +300,37 @@ def getZone(descMap){
def getAlarm(descMap){
def map = [:]
map.name = 'status'
map.name = "status"
def alarmID = Integer.parseInt(descMap.value.trim(), 16)
log.debug "${alarmID}"
map.value = 'alarm'
map.displayed = true
if(alarmID <= 0) map.descriptionText = "${device.displayName} has rebooted, no other alarms"
else map.descriptionText = "${device.displayName} rebooted, reported error on zone ${alarmID - 1}, please check zone is working correctly"
map.value = "alarm"
map.isStateChange = true
if(alarmID <= 0){
map.descriptionText = "${device.displayName} reboot, no other alarms"
map.value = 'warning'
//map.isStateChange = false
}
else map.descriptionText = "${device.displayName} reboot, reported zone ${alarmID - 1} error, please check zone is working correctly, press SYNC SETTINGS button to clear"
map.displayed = true
return map
}
//status notify and change status
def notify(String val, String txt){
sendEvent(name: 'status', value: val, descriptionText: txt, isStateChange: true, display: false)
//String txtShort = txt.take(100)
sendEvent(name: 'tileMessage', value: txt, descriptionText: "", isStateChange: true, display: false)
}
def notify(value, text){
sendEvent(name:"status", value:"$value", descriptionText:"$text", isStateChange: true, display: false)
def updated(){
log.debug "updated"
}
//prefrences - rain sensor, manual time
def rain() {
log.debug "Rain sensor: ${RainEnable}"
if (RainEnable) sendEvent(name: 'rainsensor', value: 'enable', descriptionText: "${device.displayName} rain sensor is enabled", isStateChange: true)
else sendEvent(name: 'rainsensor', value: 'disable', descriptionText: "${device.displayName} rain sensor is disabled", isStateChange: true)
log.debug "Rain $RainEnable"
if (RainEnable) "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {01}"
else "st wattr 0x${device.deviceNetworkId} 18 0x0F 0x51 0x10 {00}"
}
def manualTime(value){
sendEvent(name: 'minutes', value: "${value}", descriptionText: "Manual Time set to ${value}", display: false)
}
def manual(){
def newManaul = 10
if (device.latestValue('minutes')) newManaul = device.latestValue('minutes').toInteger()
log.debug "Manual Zone runtime ${newManaul} mins"
def manualTime = hex(newManaul)
def manual(){
log.debug "Time $ManualTime"
def mTime = 10
if (ManualTime) mTime = ManualTime
def manualTime = hex(mTime)
"st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}"
def sendCmds = []
sendCmds.push("st wattr 0x${device.deviceNetworkId} 1 6 0x4002 0x21 {00${manualTime}}")
return sendCmds
}
}
//write switch time settings map
def settingsMap(WriteTimes, attrType){
@@ -470,20 +366,13 @@ def writeTime(wEP, runTime){
//set reporting and binding
def configure() {
sendEvent(name: 'status', value: 'schedule', descriptionText: "Syncing settings to controller")
sendEvent(name: 'minutes', value: "10", descriptionText: "Manual Time set to 10 mins", display: false)
sendEvent(name: 'tileMessage', value: 'Syncing settings to controller', descriptionText: 'Syncing settings to controller')
config()
}
def config(){
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
log.debug "Configuring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}"
log.debug "Confuguring Reporting and Bindings ${device.deviceNetworkId} ${device.zigbeeId}"
sendEvent(name: 'configuration',value: 100, descriptionText: "Configuration initialized")
def configCmds = [
//program on/off
//program on/off
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 1000",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x09 {${device.zigbeeId}} {}", "delay 1000",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x0F {${device.zigbeeId}} {}", "delay 1000",
@@ -569,16 +458,38 @@ def config(){
"zcl global send-me-a-report 0x09 0x00 0x21 1 0 {00}", "delay 500",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
]
return configCmds + rain()
return configCmds + rain() + manual()
}
private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array
}
def refresh() {
log.debug "refresh pressed"
sendEvent(name: 'tileMessage', value: 'Refresh', descriptionText: 'Refresh')
def refreshCmds = [
log.debug "refresh"
def refreshCmds = [
"st rattr 0x${device.deviceNetworkId} 1 0x0F 0x55", "delay 500",
"st rattr 0x${device.deviceNetworkId} 2 0x0F 0x55", "delay 500",
@@ -602,96 +513,64 @@ def refresh() {
"st rattr 0x${device.deviceNetworkId} 18 0x0F 0x51","delay 500",
]
return refreshCmds
}
private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}
private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}
private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array
}
//on & off redefined for Alexa to start manual schedule
def on() {
log.debug 'Alexa on'
//schedule subscribes to programOn
sendEvent(name: 'switch', value: 'programOn', descriptionText: 'Alexa turned program on')
}
def off() {
log.debug 'Alexa off'
sendEvent(name: 'switch', value: 'off', descriptionText: 'Alexa turned program off')
zoff()
return refreshCmds + rain() + manual()
}
// Commands to device
//zones on - 8
def zon() {
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
def on() {
//sendEvent(name:"status", value:"active", descriptionText:"Program Running", isStateChange: true, display: false)
log.debug "on"
"st cmd 0x${device.deviceNetworkId} 1 6 1 {}"
}
def zoff() {
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
def off() {
log.debug "off"
"st cmd 0x${device.deviceNetworkId} 1 6 0 {}"
}
def z1on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 2 6 1 {}"
}
def z1off() {
"st cmd 0x${device.deviceNetworkId} 2 6 0 {}"
}
def z2on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 3 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 3 6 1 {}"
}
def z2off() {
"st cmd 0x${device.deviceNetworkId} 3 6 0 {}"
}
def z3on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 4 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 4 6 1 {}"
}
def z3off() {
"st cmd 0x${device.deviceNetworkId} 4 6 0 {}"
}
def z4on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 5 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 5 6 1 {}"
}
def z4off() {
"st cmd 0x${device.deviceNetworkId} 5 6 0 {}"
}
def z5on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 6 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 6 6 1 {}"
}
def z5off() {
"st cmd 0x${device.deviceNetworkId} 6 6 0 {}"
}
def z6on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 7 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 7 6 1 {}"
}
def z6off() {
"st cmd 0x${device.deviceNetworkId} 7 6 0 {}"
}
def z7on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 8 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 8 6 1 {}"
}
def z7off() {
"st cmd 0x${device.deviceNetworkId} 8 6 0 {}"
}
def z8on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 9 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 9 6 1 {}"
}
def z8off() {
"st cmd 0x${device.deviceNetworkId} 9 6 0 {}"
@@ -699,51 +578,50 @@ def z8off() {
//zones 9 - 16
def z9on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 10 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 10 6 1 {}"
}
def z9off() {
"st cmd 0x${device.deviceNetworkId} 10 6 0 {}"
}
def z10on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 11 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 11 6 1 {}"
}
def z10off() {
"st cmd 0x${device.deviceNetworkId} 11 6 0 {}"
}
def z11on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 12 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 12 6 1 {}"
}
def z11off() {
"st cmd 0x${device.deviceNetworkId} 12 6 0 {}"
}
def z12on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 13 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 13 6 1 {}"
}
def z12off() {
"st cmd 0x${device.deviceNetworkId} 13 6 0 {}"
}
def z13on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 14 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 14 6 1 {}"
}
def z13off() {
"st cmd 0x${device.deviceNetworkId} 14 6 0 {}"
}
def z14on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 15 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 15 6 1 {}"
}
def z14off() {
"st cmd 0x${device.deviceNetworkId} 15 6 0 {}"
}
def z15on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 16 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 16 6 1 {}"
}
def z15off() {
"st cmd 0x${device.deviceNetworkId} 16 6 0 {}"
}
def z16on() {
return manual() + "st cmd 0x${device.deviceNetworkId} 17 6 1 {}"
"st cmd 0x${device.deviceNetworkId} 17 6 1 {}"
}
def z16off() {
"st cmd 0x${device.deviceNetworkId} 17 6 0 {}"
}
}

View File

@@ -1,5 +1,5 @@
/**
* Spruce Sensor -updated with SLP model number 5/2017
* Spruce Sensor -Pre-release V2 10/8/2015
*
* Copyright 2014 Plaid Systems
*
@@ -14,33 +14,25 @@
*
-------10/20/2015 Updates--------
-Fix/add battery reporting interval to update
-remove polling and/or refresh
-------5/2017 Updates--------
-Add fingerprints for SLP
-add device health, check every 60mins + 2mins
-remove polling and/or refresh(?)
*/
metadata {
definition (name: "Spruce Sensor", namespace: "plaidsystems", author: "Plaid Systems") {
definition (name: "Spruce Sensor", namespace: "plaidsystems", author: "NCauffman") {
capability "Configuration"
capability "Battery"
capability "Relative Humidity Measurement"
capability "Temperature Measurement"
capability "Sensor"
capability "Health Check"
//capability "Polling"
attribute "maxHum", "string"
attribute "minHum", "string"
command "resetHumidity"
command "refresh"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01", deviceJoinName: "Spruce Sensor"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-SLP1", deviceJoinName: "Spruce Sensor"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0402,0405", outClusters: "0003, 0019", manufacturer: "PLAID SYSTEMS", model: "PS-SPRZMS-01"
}
preferences {
@@ -262,8 +254,7 @@ private Map getTemperatureResult(value) {
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
descriptionText: descriptionText
]
}
@@ -301,11 +292,6 @@ def setConfig(){
sendEvent(name: 'configuration',value: configInterval, descriptionText: "Configuration initialized")
}
def installed(){
//check every 1 hour + 2mins
sendEvent(name: "checkInterval", value: 1 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
//when device preferences are changed
def updated(){
log.debug "device updated"
@@ -316,8 +302,6 @@ def updated(){
sendEvent(name: 'configuration',value: 0, descriptionText: "Settings changed and will update at next report. Measure interval set to ${interval} mins")
}
}
//check every 1 hour + 2mins
sendEvent(name: "checkInterval", value: 1 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
}
//poll
@@ -410,4 +394,4 @@ private byte[] reverseArray(byte[] array) {
i++;
}
return array
}
}

View File

@@ -1,128 +0,0 @@
/**
* Simple Sync
*
* Copyright 2015 Roomie Remote, Inc.
*
* Date: 2015-09-22
*/
metadata
{
definition (name: "Simple Sync", namespace: "roomieremote-agent", author: "Roomie Remote, Inc.")
{
capability "Media Controller"
}
// simulator metadata
simulator
{
}
// UI tile definitions
tiles
{
standardTile("mainTile", "device.status", width: 1, height: 1, icon: "st.Entertainment.entertainment11")
{
state "default", label: "Simple Sync", icon: "st.Home.home2", backgroundColor: "#00a0dc"
}
def detailTiles = ["mainTile"]
main "mainTile"
details(detailTiles)
}
}
def parse(String description)
{
def results = []
try
{
def msg = parseLanMessage(description)
if (msg.headers && msg.body)
{
switch (msg.headers["X-Roomie-Echo"])
{
case "getAllActivities":
handleGetAllActivitiesResponse(msg)
break
}
}
}
catch (Throwable t)
{
sendEvent(name: "parseError", value: "$t", description: description)
throw t
}
results
}
def handleGetAllActivitiesResponse(response)
{
def body = parseJson(response.body)
if (body.status == "success")
{
def json = new groovy.json.JsonBuilder()
def root = json activities: body.data
def data = json.toString()
sendEvent(name: "activities", value: data)
}
}
def getAllActivities(evt)
{
def host = getHostAddress(device.deviceNetworkId)
def action = new physicalgraph.device.HubAction(method: "GET",
path: "/api/v1/activities",
headers: [HOST: host, "X-Roomie-Echo": "getAllActivities"])
action
}
def startActivity(evt)
{
def uuid = evt
def host = getHostAddress(device.deviceNetworkId)
def activity = new groovy.json.JsonSlurper().parseText(device.currentValue('activities') ?: "{ 'activities' : [] }").activities.find { it.uuid == uuid }
def toggle = activity["toggle"]
def jsonMap = ["activity_uuid": uuid]
if (toggle != null)
{
jsonMap << ["toggle_state": toggle ? "on" : "off"]
}
def json = new groovy.json.JsonBuilder(jsonMap)
def jsonBody = json.toString()
def headers = [HOST: host, "Content-Type": "application/json"]
def action = new physicalgraph.device.HubAction(method: "POST",
path: "/api/v1/runactivity",
body: jsonBody,
headers: headers)
action
}
def getHostAddress(d)
{
def parts = d.split(":")
def ip = convertHexToIP(parts[0])
def port = convertHexToInt(parts[1])
return ip + ":" + port
}
def String convertHexToIP(hex)
{
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}
def Integer convertHexToInt(hex)
{
Integer.parseInt(hex,16)
}

View File

@@ -47,9 +47,9 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00A0DC", nextState:"turningOff"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#00A0DC"
state "turningOn", label:'${name}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
state "turningOff", label:'${name}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
}
controlTile("levelSliderControl", "device.level", "slider", height: 2, width: 1, inactiveLabel: false) {

View File

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

View File

@@ -1,34 +0,0 @@
# Aeon Labs Key Fob
Cloud Execution
Works with:
* [Aeon Labs Key Fob](http://aeotec.com/z-wave-key-fob-remote-control)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents device has commands
* **Button** - represents a device with one or more buttons
* **Holdable Button** - represents a device with one or more holdable buttons
* **Configuration** - allows for configuration of devices
* **Sensor** - detects sensor events
* **Battery** - defines device uses a battery
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Key Fob is a ZWave totally sleepy device and is marked offline only in the case when Hub is offline.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the Aeon Labs Key Fob from SmartThings can be found in the following link:
* [Aeotec Key Fob Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202294120-Aeon-Labs-Key-Fob)

View File

@@ -1,4 +1,3 @@
import groovy.json.JsonOutput
/**
* Copyright 2015 SmartThings
*
@@ -16,14 +15,11 @@ metadata {
definition (name: "Aeon Key Fob", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Button"
capability "Holdable Button"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x80,0x84,0x85"
fingerprint mfr: "0086", prod: "0001", model: "0026", deviceJoinName: "Aeon Panic Button"
}
simulator {
@@ -40,14 +36,14 @@ metadata {
tiles {
standardTile("button", "device.button", width: 2, height: 2) {
state "default", label: "", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
state "button 2 pushed", label: "pushed #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
state "button 3 pushed", label: "pushed #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
state "button 4 pushed", label: "pushed #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#00A0DC"
state "button 1 held", label: "held #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
state "button 2 held", label: "held #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
state "button 3 held", label: "held #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
state "button 4 held", label: "held #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#e86d13"
state "button 1 pushed", label: "pushed #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
state "button 2 pushed", label: "pushed #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
state "button 3 pushed", label: "pushed #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
state "button 4 pushed", label: "pushed #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#79b821"
state "button 1 held", label: "held #1", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
state "button 2 held", label: "held #2", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
state "button 3 held", label: "held #3", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
state "button 4 held", label: "held #4", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffa81e"
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
@@ -122,26 +118,3 @@ def configure() {
log.debug("Sending configuration: $cmd")
return cmd
}
def installed() {
initialize()
}
def updated() {
initialize()
}
def initialize() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
def zwMap = getZwaveInfo()
def buttons = 4 // Default for Key Fob
// Only one button for Aeon Panic Button
if (zwMap && zwMap.mfr == "0086" && zwMap.prod == "0001" && zwMap.model == "0026") {
buttons = 1
}
sendEvent(name: "numberOfButtons", value: buttons)
}

View File

@@ -37,9 +37,9 @@ metadata {
}
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff"
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat") {

View File

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

View File

@@ -1,33 +0,0 @@
# Aeon Minimote
Cloud Execution
Works with:
* [Aeotec Minimote](http://aeotec.com/small-z-wave-remote-control)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Actuator** - represents device has commands
* **Button** - represents a device with one or more buttons
* **Holdable Button** - represents a device with one or more holdable buttons
* **Configuration** - allows for configuration of devices
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Aeon Minimote is a ZWave totally sleepy device and is marked offline only in the case when Hub is offline.
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the sensor is out of range.
Pairing needs to be tried again by placing the sensor closer to the hub.
Instructions related to pairing, resetting and removing the Aeotec Minimote from SmartThings can be found in the following link:
* [Aeotec Minimote Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202087904-Aeotec-Minimote)

View File

@@ -1,4 +1,3 @@
import groovy.json.JsonOutput
/**
* Copyright 2015 SmartThings
*
@@ -16,10 +15,8 @@ metadata {
definition (name: "Aeon Minimote", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Button"
capability "Holdable Button"
capability "Configuration"
capability "Sensor"
capability "Health Check"
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x9B", outClusters: "0x26,0x2B"
fingerprint deviceId: "0x0101", inClusters: "0x86,0x72,0x70,0x9B,0x85,0x84", outClusters: "0x26" // old style with numbered buttons
@@ -110,18 +107,3 @@ def configure() {
log.debug("Sending configuration: $cmds")
return cmds
}
def installed() {
initialize()
}
def updated() {
initialize()
}
def initialize() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
sendEvent(name: "numberOfButtons", value: 4)
}

View File

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

View File

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

View File

@@ -22,15 +22,12 @@ metadata {
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
attribute "tamper", "enum", ["detected", "clear"]
attribute "batteryStatus", "string"
attribute "powerSupply", "enum", ["USB Cable", "Battery"]
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A", outClusters: "0x5A"
fingerprint deviceId: "0x2101", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x7A,0x5A"
fingerprint mfr:"0086", prod:"0102", model:"0064", deviceJoinName: "Aeon Labs MultiSensor 6"
}
simulator {
@@ -84,8 +81,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
@@ -105,7 +102,7 @@ metadata {
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "illuminance", label:'${currentValue} lux', unit:""
state "illuminance", label:'${currentValue} ${unit}', unit:"lux"
}
valueTile("ultravioletIndex", "device.ultravioletIndex", inactiveLabel: false, width: 2, height: 2) {
@@ -129,14 +126,7 @@ metadata {
}
}
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
log.debug "Updated with settings: ${settings}"
log.debug "${device.displayName} is now ${device.latestValue("powerSupply")}"
@@ -335,13 +325,6 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
}
def configure() {
// This sensor joins as a secure device if you double-click the button to include it
log.debug "${device.displayName} is configuring its settings"
@@ -369,7 +352,7 @@ def configure() {
motionSensitivity == "minimum" ? 0 : 64)
//5. report every x minutes (threshold reports don't work on battery power, default 8 mins)
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: (8*60)) //association group 1
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: timeOptionValueMap[reportInterval] ?: 8*60) //association group 1
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 6*60*60) //association group 2
@@ -426,4 +409,4 @@ private command(physicalgraph.zwave.Command cmd) {
private commands(commands, delay=200) {
log.info "sending commands: ${commands}"
delayBetween(commands.collect{ command(it) }, delay)
}
}

View File

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

View File

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

View File

@@ -20,10 +20,8 @@ metadata {
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x59,0x85,0x73,0x71,0x84,0x80,0x30,0x31,0x70,0x98,0x7A", outClusters:"0x5A"
fingerprint mfr:"0086", prod:"0102", model:"004A", deviceJoinName: "Aeon Labs MultiSensor (Gen 5)"
}
simulator {
@@ -64,8 +62,8 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"motion", type: "generic", width: 6, height: 4){
tileAttribute ("device.motion", key: "PRIMARY_CONTROL") {
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
attributeState "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
attributeState "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
}
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
@@ -84,30 +82,20 @@ metadata {
state "humidity", label:'${currentValue}% humidity', unit:""
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, width: 2, height: 2) {
state "luminosity", label:'${currentValue} lux', unit:""
state "luminosity", label:'${currentValue} ${unit}', unit:"lux"
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "battery", label:'${currentValue}% battery', unit:""
}
standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label:'', action:"configure", icon:"st.secondary.configure"
standardTile("configureAfterSecure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label:'', action:"configureAfterSecure", icon:"st.secondary.configure"
}
main(["motion", "temperature", "humidity", "illuminance"])
details(["motion", "temperature", "humidity", "illuminance", "battery", "configure"])
details(["motion", "temperature", "humidity", "illuminance", "battery", "configureAfterSecure"])
}
}
def installed(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description)
{
def result = null
@@ -129,8 +117,8 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd)
if (!isConfigured()) {
// we're still in the process of configuring a newly joined device
log.debug("not sending wakeUpNoMoreInformation yet: late configure")
result += response(configure())
log.debug("not sending wakeUpNoMoreInformation yet")
result += response(configureAfterSecure())
} else {
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
}
@@ -148,6 +136,11 @@ def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulat
}
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
// log.debug "Received SecurityCommandsSupportedReport"
response(configureAfterSecure())
}
def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [ name: "battery", unit: "%" ]
if (cmd.batteryLevel == 0xFF) {
@@ -219,45 +212,39 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.batteryV1.batteryGet())
def configureAfterSecure() {
// log.debug "configureAfterSecure()"
def request = [
// send temperature, humidity, and illuminance every 8 minutes
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32),
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60),
// send battery every 20 hours
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1),
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60),
// send no-motion report 60 seconds after motion stops
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60),
// send binary sensor report instead of basic set for motion
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2),
// disable notification-style motion events
zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0),
zwave.batteryV1.batteryGet(),
zwave.sensorBinaryV2.sensorBinaryGet(sensorType:0x0C)
]
setConfigured()
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
}
def configure() {
// log.debug "configure()"
def request = []
// send temperature, humidity, and illuminance every 8 minutes
request << zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 128|64|32)
request << zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 8*60)
// send battery every 20 hours
request << zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1)
request << zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 20*60*60)
// send no-motion report 60 seconds after motion stops
request << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 60)
// send binary sensor report instead of basic set for motion
request << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: 2)
// Turn on the Multisensor Gen5 PIR sensor
request << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: 1)
// disable notification-style motion events
request << zwave.notificationV3.notificationSet(notificationType: 7, notificationStatus: 0)
request << zwave.batteryV1.batteryGet()
request << zwave.sensorBinaryV2.sensorBinaryGet(sensorType: 0x0C) //motion
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x01) //temperature
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03) //illuminance
request << zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x05) //humidity
setConfigured()
secureSequence(request) + ["delay 20000", zwave.wakeUpV1.wakeUpNoMoreInformation().format()]
//["delay 30000"] + secure(zwave.securityV1.securityCommandsSupportedGet())
}
private setConfigured() {
@@ -274,4 +261,5 @@ private secure(physicalgraph.zwave.Command cmd) {
private secureSequence(commands, delay=200) {
delayBetween(commands.collect{ secure(it) }, delay)
}
}

View File

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

View File

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

View File

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

View File

@@ -45,7 +45,7 @@ metadata {
// tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
valueTile("energy", "device.energy", decoration: "flat") {

View File

@@ -53,7 +53,7 @@ metadata {
// tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
valueTile("power", "device.power", decoration: "flat") {

View File

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

View File

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

View File

@@ -16,15 +16,14 @@
* Date: 2014-07-15
*/
metadata {
definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.smoke") {
definition (name: "Aeon Siren", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Alarm"
capability "Switch"
capability "Health Check"
command "test"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98", deviceJoinName: "Aeon Labs Siren (Gen 5)"
fingerprint deviceId: "0x1005", inClusters: "0x5E,0x98"
}
simulator {
@@ -58,17 +57,7 @@ metadata {
}
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(secure(zwave.basicV1.basicGet()))
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
if(!state.sound) state.sound = 1
if(!state.volume) state.volume = 3
@@ -159,10 +148,3 @@ def test() {
private secure(physicalgraph.zwave.Command cmd) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
secure(zwave.basicV1.basicGet())
}

View File

@@ -60,7 +60,7 @@ metadata {
// tile definitions
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
valueTile("power", "device.power", decoration: "flat") {
@@ -78,7 +78,7 @@ metadata {
(1..4).each { n ->
standardTile("switch$n", "switch$n", canChangeIcon: true) {
state "on", label: '${name}', action: "off$n", icon: "st.switches.switch.on", backgroundColor: "#00a0dc"
state "on", label: '${name}', action: "off$n", icon: "st.switches.switch.on", backgroundColor: "#79b821"
state "off", label: '${name}', action: "on$n", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
}
valueTile("power$n", "power$n", decoration: "flat") {

View File

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

View File

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

View File

@@ -1,7 +1,5 @@
import groovy.json.JsonOutput
/**
* Copyright 2017 SmartThings
* Copyright 2016 SmartThings
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
@@ -21,7 +19,6 @@ metadata {
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Health Check"
fingerprint inClusters: "0000,0001,0003,000F,0020", outClusters: "0003,0019",
manufacturer: "SmartThings", model: "tagv4", deviceJoinName: "Arrival Sensor"
@@ -35,14 +32,14 @@ metadata {
])
}
section {
input "checkInterval", "enum", title: "Presence timeout (minutes)", description: "Tap to set",
input "checkInterval", "enum", title: "Presence timeout (minutes)",
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
}
}
tiles {
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#00a0dc"
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
}
standardTile("beep", "device.beep", decoration: "flat") {
@@ -61,13 +58,8 @@ def updated() {
startTimer()
}
def installed() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
}
def configure() {
def cmds = zigbee.readAttribute(zigbee.POWER_CONFIGURATION_CLUSTER, 0x0020) + zigbee.batteryConfig(20, 20, 0x01)
def cmds = zigbee.configureReporting(0x0001, 0x0020, 0x20, 20, 20, 0x01)
log.debug "configure -- cmds: ${cmds}"
return cmds
}
@@ -90,6 +82,7 @@ def parse(String description) {
private handleReportAttributeMessage(String description) {
def descMap = zigbee.parseDescriptionAsMap(description)
if (descMap.clusterInt == 0x0001 && descMap.attrInt == 0x0020) {
handleBatteryEvent(Integer.parseInt(descMap.value, 16))
}
@@ -101,7 +94,6 @@ private handleReportAttributeMessage(String description) {
* @param volts Battery voltage in .1V increments
*/
private handleBatteryEvent(volts) {
def descriptionText
if (volts == 0 || volts == 255) {
log.debug "Ignoring invalid value for voltage (${volts/10}V)"
}
@@ -115,17 +107,15 @@ private handleBatteryEvent(volts) {
volts = minVolts
else if (volts > maxVolts)
volts = maxVolts
def value = batteryMap[volts]
if (value != null) {
def pct = batteryMap[volts]
if (pct != null) {
def linkText = getLinkText(device)
descriptionText = '{{ linkText }} battery was {{ value }}'
def eventMap = [
name: 'battery',
value: value,
descriptionText: descriptionText,
translatable: true
value: pct,
descriptionText: "${linkText} battery was ${pct}%"
]
log.debug "Creating battery event for voltage=${volts/10}V: ${linkText} ${eventMap.name} is ${eventMap.value}%"
log.debug "Creating battery event for voltage=${volts/10}V: ${eventMap}"
sendEvent(eventMap)
}
}
@@ -141,25 +131,19 @@ private handlePresenceEvent(present) {
stopTimer()
}
def linkText = getLinkText(device)
def descriptionText
if ( present )
descriptionText = "{{ linkText }} has arrived"
else
descriptionText = "{{ linkText }} has left"
def eventMap = [
name: "presence",
value: present ? "present" : "not present",
linkText: linkText,
descriptionText: descriptionText,
translatable: true
descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
]
log.debug "Creating presence event: ${device.displayName} ${eventMap.name} is ${eventMap.value}"
log.debug "Creating presence event: ${eventMap}"
sendEvent(eventMap)
}
private startTimer() {
log.debug "Scheduling periodic timer"
runEvery1Minute("checkPresenceCallback")
schedule("0 * * * * ?", checkPresenceCallback)
}
private stopTimer() {

View File

@@ -1,26 +0,0 @@
# Copyright 2016 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.
# Korean (ko)
# Device Preferences
'''Give your device a name'''.ko=기기 이름 설정
'''Set Device Image'''.ko=기기 이미지 설정
'''Presence timeout (minutes)'''.ko=알람 유예 시간 설정 (분)
'''Tap to set'''.ko=눌러서 설정
'''Arrival Sensor'''.ko=도착알림 센서
'''${currentValue}% battery'''.ko=${currentValue}% 배터리
# Events / Notifications
'''{{ linkText }} battery was {{ value }}'''.ko={{ linkText }}의 남은 배터리 {{ value }}
'''{{ linkText }} has arrived'''.ko={{ linkText }} 귀가
'''{{ linkText }} has left'''.ko={{ linkText }} 외출
#==============================================================================

View File

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

View File

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

View File

@@ -1,5 +1,3 @@
import groovy.json.JsonOutput
/**
* Copyright 2015 SmartThings
*
@@ -21,7 +19,6 @@ metadata {
capability "Presence Sensor"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint profileId: "FC01", deviceId: "019A"
fingerprint profileId: "FC01", deviceId: "0131", inClusters: "0000,0003", outClusters: "0003"
@@ -45,8 +42,8 @@ metadata {
tiles {
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#00a0dc"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ebeef2"
}
standardTile("beep", "device.beep", decoration: "flat") {
state "beep", label:'', action:"tone.beep", icon:"st.secondary.beep", backgroundColor:"#ffffff"
@@ -90,35 +87,19 @@ def beep() {
up to this long from the time you send the message to the time you hear a sound.
*/
// Used source endpoint of 0x02 because we are using smartthings manufacturer specific cluster.
[
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"delay 7000",
"raw 0xFC05 {15 0A 11 00 00 15 01}",
"delay 200",
"send 0x$zigbee.deviceNetworkId 0x02 0x$zigbee.endpointId",
"raw 0xFC05 {15 0A 11 00 00 15 01}"
]
}
def installed() {
// Arrival sensors only goes OFFLINE when Hub is off
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "zigbee", scheme:"untracked"]), displayed: false)
}
def parse(String description) {
def results
if (isBatteryMessage(description)) {

View File

@@ -1,5 +1,3 @@
//DEPRECATED. INTEGRATION MOVED TO SUPER LAN CONNECT
/**
* Bose SoundTouch
*
@@ -29,9 +27,7 @@ metadata {
capability "Switch"
capability "Refresh"
capability "Music Player"
capability "Health Check"
capability "Sensor"
capability "Actuator"
capability "Polling"
/**
* Define all commands, ie, if you have a custom action not
@@ -51,9 +47,6 @@ metadata {
command "everywhereJoin"
command "everywhereLeave"
command "forceOff"
command "forceOn"
}
/**
@@ -71,10 +64,8 @@ metadata {
}
standardTile("switch", "device.switch", width: 1, height: 1, canChangeIcon: true) {
state "on", label: '${name}', action: "forceOff", icon: "st.Electronics.electronics16", backgroundColor: "#00a0dc", nextState:"turningOff"
state "turningOff", label:'TURNING OFF', icon:"st.Electronics.electronics16", backgroundColor:"#ffffff"
state "off", label: '${name}', action: "forceOn", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff", nextState:"turningOn"
state "turningOn", label:'TURNING ON', icon:"st.Electronics.electronics16", backgroundColor:"#00a0dc"
state "off", label: '${name}', action: "switch.on", icon: "st.Electronics.electronics16", backgroundColor: "#ffffff"
state "on", label: '${name}', action: "switch.off", icon: "st.Electronics.electronics16", backgroundColor: "#79b821"
}
valueTile("1", "device.station1", decoration: "flat", canChangeIcon: false) {
state "station1", label:'${currentValue}', action:"preset1"
@@ -147,22 +138,8 @@ metadata {
* one place.
*
*/
def off() {
if (device.currentState("switch")?.value == "on") {
onAction("off")
}
}
def forceOff() {
onAction("off")
}
def on() {
if (device.currentState("switch")?.value == "off") {
onAction("on")
}
}
def forceOn() {
onAction("on")
}
def off() { onAction("off") }
def on() { onAction("on") }
def volup() { onAction("volup") }
def voldown() { onAction("voldown") }
def preset1() { onAction("1") }
@@ -240,33 +217,7 @@ def parse(String event) {
* @return action(s) to take or null
*/
def installed() {
// Notify health check about this device with timeout interval 12 minutes
sendEvent(name: "checkInterval", value: 12 * 60, data: [protocol: "lan", hubHardwareId: device.hub.hardwareID], displayed: false)
startPoll()
}
/**
* Called by health check if no events been generated in the last 12 minutes
* If device doesn't respond it will be marked offline (not available)
*/
def ping() {
TRACE("ping")
boseSendGetNowPlaying()
}
/**
* Schedule a 2 minute poll of the device to refresh the
* tiles so the user gets the correct information.
*/
def startPoll() {
TRACE("startPoll")
unschedule()
// Schedule 2 minute polling of speaker status (song average length is 3-4 minutes)
def sec = Math.round(Math.floor(Math.random() * 60))
//def cron = "$sec 0/5 * * * ?" // every 5 min
def cron = "$sec 0/2 * * * ?" // every 2 min
log.debug "schedule('$cron', boseSendGetNowPlaying)"
schedule(cron, boseSendGetNowPlaying)
onAction("refresh")
}
/**
@@ -287,11 +238,11 @@ def onAction(String user, data=null) {
def actions = null
switch (user) {
case "on":
boseSetPowerState(true)
actions = boseSetPowerState(true)
break
case "off":
boseSetNowPlaying(null, "STANDBY")
boseSetPowerState(false)
actions = boseSetPowerState(false)
break
case "volume":
actions = boseSetVolume(data)
@@ -346,6 +297,14 @@ def onAction(String user, data=null) {
return actions
}
/**
* Called every so often (every 5 minutes actually) to refresh the
* tiles so the user gets the correct information.
*/
def poll() {
return boseRefreshNowPlaying()
}
/**
* Joins this speaker into the everywhere zone
*/
@@ -788,16 +747,8 @@ def cb_boseSetInput(xml, input) {
*/
def boseSetPowerState(boolean enable) {
log.info "boseSetPowerState(${enable})"
// Fix to get faster update of power status back from speaker after sending on/off
// Instead of queuing the command to be sent after the refresh send it directly via sendHubCommand
// Note: This is a temporary hack that should be replaced by a re-design of the
// DTH to use sendHubCommand for all commands
sendHubCommand(bosePOST("/key", "<key state=\"press\" sender=\"Gabbo\">POWER</key>"))
sendHubCommand(bosePOST("/key", "<key state=\"release\" sender=\"Gabbo\">POWER</key>"))
sendHubCommand(boseGET("/now_playing"))
if (enable) {
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", 5)
}
queueCallback('nowPlaying', "cb_boseSetPowerState", enable ? "POWERON" : "POWEROFF")
return boseRefreshNowPlaying()
}
/**
@@ -836,11 +787,10 @@ def cb_boseSetPowerState(xml, state) {
*/
def cb_boseConfirmPowerOn(xml, tries) {
def result = []
def attempt = tries as Integer
log.warn "boseConfirmPowerOn() attempt #$attempt"
if (xml.attributes()['source'] == "STANDBY" && attempt > 0) {
log.warn "boseConfirmPowerOn() attempt #" + tries
if (xml.attributes()['source'] == "STANDBY" && tries > 0) {
result << boseRefreshNowPlaying()
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", attempt-1)
queueCallback('nowPlaying', "cb_boseConfirmPowerOn", tries-1)
}
return result
}
@@ -859,10 +809,6 @@ def boseRefreshNowPlaying(delay=0) {
return boseGET("/now_playing")
}
def boseSendGetNowPlaying() {
sendHubCommand(boseGET("/now_playing"))
}
/**
* Requests the list of presets
*
@@ -1040,8 +986,4 @@ def boseGetDeviceID() {
*/
def getDeviceIP() {
return parent.resolveDNI2Address(device.deviceNetworkId)
}
def TRACE(text) {
log.trace "${text}"
}

View File

@@ -0,0 +1,146 @@
/**
* Copyright 2015 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.
*
* CentraLite Dimmer
*
* Author: SmartThings
* Date: 2013-12-04
*/
//DEPRECATED - Using the generic DTH for this device. Users need to be moved before deleting this DTH
metadata {
definition (name: "CentraLite Dimmer", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Switch"
capability "Power Meter"
capability "Configuration"
capability "Refresh"
capability "Sensor"
}
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
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 "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 "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("power", key: "SECONDARY_CONTROL") {
attributeState "power", label:'${currentValue} W'
}
}
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
main "switch"
details(["switch","refresh"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "Parse description $description"
def name = null
def value = null
if (description?.startsWith("catchall:")) {
def msg = zigbee.parse(description)
log.trace msg
log.trace "data: $msg.data"
} else if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description)
log.debug "Read attr: $description"
if (descMap.cluster == "0006" && descMap.attrId == "0000") {
name = "switch"
value = descMap.value.endsWith("01") ? "on" : "off"
} else {
def reportValue = description.split(",").find {it.split(":")[0].trim() == "value"}?.split(":")[1].trim()
name = "power"
// assume 16 bit signed for encoding and power divisor is 10
value = Integer.parseInt(reportValue, 16) / 10
}
} else if (description?.startsWith("on/off:")) {
log.debug "Switch command"
name = "switch"
value = description?.endsWith(" 1") ? "on" : "off"
}
def result = createEvent(name: name, value: value)
log.debug "Parse returned ${result?.descriptionText}"
return result
}
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
// Commands to device
def on() {
'zcl on-off on'
}
def off() {
'zcl on-off off'
}
def setLevel(value) {
log.trace "setLevel($value)"
sendEvent(name: "level", value: value)
def level = hexString(Math.round(value * 255/100))
def cmd = "st cmd 0x${device.deviceNetworkId} 1 8 4 {${level} 2000}"
log.debug cmd
cmd
}
def meter() {
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
}
def refresh() {
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
}
def configure() {
[
"zdo bind 0x${device.deviceNetworkId} 1 1 8 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 1 0xB04 {${device.zigbeeId}} {}"
]
}
private hex(value, width=2) {
def s = new BigInteger(Math.round(value).toString()).toString(16)
while (s.size() < width) {
s = "0" + s
}
s
}

View File

@@ -55,13 +55,13 @@ metadata {
state "fanOn", label:'${name}', action:"thermostat.setThermostatFanMode"
}
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#e86d13"
state "setHeatingSetpoint", action:"thermostat.setHeatingSetpoint", backgroundColor:"#d04e00"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue}° heat', unit:"F", backgroundColor:"#ffffff"
}
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setCoolingSetpoint", action:"thermostat.setCoolingSetpoint", backgroundColor: "#00a0dc"
state "setCoolingSetpoint", action:"thermostat.setCoolingSetpoint", backgroundColor: "#1e9cbb"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue}° cool', unit:"F", backgroundColor:"#ffffff"
@@ -81,47 +81,48 @@ metadata {
// parse events into attributes
def parse(String description) {
log.debug "Parse description $description"
List result = []
def descMap = zigbee.parseDescriptionAsMap(description)
log.debug "Desc Map: $descMap"
List attrData = [[cluster: descMap.cluster ,attrId: descMap.attrId, value: descMap.value]]
descMap.additionalAttrs.each {
attrData << [cluster: descMap.cluster, attrId: it.attrId, value: it.value]
}
attrData.each {
def map = [:]
if (it.cluster == "0201" && it.attrId == "0000") {
def map = [:]
if (description?.startsWith("read attr -")) {
def descMap = parseDescriptionAsMap(description)
log.debug "Desc Map: $descMap"
if (descMap.cluster == "0201" && descMap.attrId == "0000") {
log.debug "TEMP"
map.name = "temperature"
map.value = getTemperature(it.value)
map.unit = temperatureScale
} else if (it.cluster == "0201" && it.attrId == "0011") {
map.value = getTemperature(descMap.value)
} else if (descMap.cluster == "0201" && descMap.attrId == "0011") {
log.debug "COOLING SETPOINT"
map.name = "coolingSetpoint"
map.value = getTemperature(it.value)
map.unit = temperatureScale
} else if (it.cluster == "0201" && it.attrId == "0012") {
map.value = getTemperature(descMap.value)
} else if (descMap.cluster == "0201" && descMap.attrId == "0012") {
log.debug "HEATING SETPOINT"
map.name = "heatingSetpoint"
map.value = getTemperature(it.value)
map.unit = temperatureScale
} else if (it.cluster == "0201" && it.attrId == "001c") {
map.value = getTemperature(descMap.value)
} else if (descMap.cluster == "0201" && descMap.attrId == "001c") {
log.debug "MODE"
map.name = "thermostatMode"
map.value = getModeMap()[it.value]
} else if (it.cluster == "0202" && it.attrId == "0000") {
map.value = getModeMap()[descMap.value]
} else if (descMap.cluster == "0202" && descMap.attrId == "0000") {
log.debug "FAN MODE"
map.name = "thermostatFanMode"
map.value = getFanModeMap()[it.value]
map.value = getFanModeMap()[descMap.value]
}
if (map) {
result << createEvent(map)
}
log.debug "Parse returned $map"
}
def result = null
if (map) {
result = createEvent(map)
}
log.debug "Parse returned $map"
return result
}
def parseDescriptionAsMap(description) {
(description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
}
def getModeMap() { [
"00":"off",
"03":"cool",
@@ -168,7 +169,7 @@ def setHeatingSetpoint(degrees) {
def degreesInteger = Math.round(degrees)
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent("name": "heatingSetpoint", "value": degreesInteger, "unit": temperatureScale)
sendEvent("name": "heatingSetpoint", "value": degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
@@ -179,7 +180,7 @@ def setCoolingSetpoint(degrees) {
if (degrees != null) {
def degreesInteger = Math.round(degrees)
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
sendEvent("name": "coolingSetpoint", "value": degreesInteger, "unit": temperatureScale)
sendEvent("name": "coolingSetpoint", "value": degreesInteger)
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
}

View File

@@ -16,7 +16,7 @@ metadata {
capability "Switch"
capability "Switch Level"
capability "Button"
capability "Actuator"
capability "Actuator"
//fingerprint deviceId: "0x1200", inClusters: "0x77 0x86 0x75 0x73 0x85 0x72 0xEF", outClusters: "0x26"
}
@@ -36,7 +36,7 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "off", label: '${name}', action: "switch.on", icon: "st.Home.home30", backgroundColor: "#ffffff"
state "on", label: '${name}', action: "switch.off", icon: "st.Home.home30", backgroundColor: "#00a0dc"
state "on", label: '${name}', action: "switch.off", icon: "st.Home.home30", backgroundColor: "#79b821"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
@@ -74,20 +74,20 @@ def off() {
}
def levelup() {
def curlevel = device.currentValue('level') as Integer
def curlevel = device.currentValue('level') as Integer
if (curlevel <= 90)
setLevel(curlevel + 10);
setLevel(curlevel + 10);
}
def leveldown() {
def curlevel = device.currentValue('level') as Integer
def curlevel = device.currentValue('level') as Integer
if (curlevel >= 10)
setLevel(curlevel - 10)
setLevel(curlevel - 10)
}
def setLevel(value) {
log.trace "setLevel($value)"
sendEvent(name: "level", value: value)
sendEvent(name: "level", value: value)
}
def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
@@ -106,11 +106,11 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelS
if (cmd.upDown == true) {
Integer buttonid = 2
leveldown()
checkbuttonEvent(buttonid)
checkbuttonEvent(buttonid)
} else if (cmd.upDown == false) {
Integer buttonid = 3
levelup()
checkbuttonEvent(buttonid)
checkbuttonEvent(buttonid)
}
}
@@ -140,12 +140,12 @@ def buttonEvent(button) {
def result = []
if (button == 1) {
def mystate = device.currentValue('switch');
if (mystate == "on")
if (mystate == "on")
off()
else
on()
on()
}
updateState("currentButton", "$button")
updateState("currentButton", "$button")
// update the device state, recording the button press
result << createEvent(name: "button", value: "pushed", data: [buttonNumber: button], descriptionText: "$device.displayName button $button was pushed", isStateChange: true)
result
@@ -182,16 +182,3 @@ def updateState(String name, String value) {
state[name] = value
device.updateDataValue(name, value)
}
def installed() {
initialize()
}
def updated() {
initialize()
}
def initialize() {
sendEvent(name: "numberOfButtons", value: 3)
}

View File

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

View File

@@ -1,36 +0,0 @@
# Connected Cree LED Bulb
Cloud Execution
Works with:
* [Connected Cree LED Bulb](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
Connected Cree LED Bulb with cloud polling it every __5min__
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __12min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Cree Connected LED Bulb Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204258280-Cree-Connected-LED-Bulb)

View File

@@ -1,7 +1,7 @@
/**
* Cree Bulb
*
* Copyright 2016 SmartThings
* Copyright 2014 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:
@@ -13,39 +13,37 @@
* for the specific language governing permissions and limitations under the License.
*
*/
metadata {
definition (name: "Cree Bulb", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") {
definition (name: "Cree Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Actuator"
capability "Configuration"
capability "Refresh"
capability "Switch"
capability "Switch Level"
capability "Health Check"
capability "Light"
capability "Refresh"
capability "Switch"
capability "Switch Level"
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
}
fingerprint profileId: "C05E", inClusters: "0000,0003,0004,0005,0006,0008,1000", outClusters: "0000,0019"
}
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// simulator metadata
simulator {
// status messages
status "on": "on/off: 1"
status "off": "on/off: 0"
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
// reply messages
reply "zcl on-off on": "on/off: 1"
reply "zcl on-off off": "on/off: 0"
}
// UI tile definitions
// UI tile definitions
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:"#00A0DC", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -64,12 +62,18 @@ metadata {
def parse(String description) {
log.debug "description is $description"
def resultMap = zigbee.getEvent(description)
def resultMap = zigbee.getKnownDescription(description)
if (resultMap) {
sendEvent(resultMap)
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else {
sendEvent(name: resultMap.type, value: resultMap.value)
}
}
else {
log.debug "DID NOT PARSE MESSAGE for description : $description"
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
}
@@ -83,30 +87,14 @@ def on() {
}
def setLevel(value) {
zigbee.setLevel(value) + zigbee.onOffRefresh() + zigbee.levelRefresh() //adding refresh because of ZLL bulb not conforming to send-me-a-report
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
return zigbee.levelRefresh()
zigbee.setLevel(value)
}
def refresh() {
zigbee.onOffRefresh() + zigbee.levelRefresh()
}
def healthPoll() {
log.debug "healthPoll()"
def cmds = zigbee.onOffRefresh() + zigbee.levelRefresh()
cmds.each{ sendHubCommand(new physicalgraph.device.HubAction(it))}
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig() + zigbee.levelConfig()
}
def configure() {
unschedule()
runEvery5Minutes("healthPoll")
// Device-Watch allows 2 check-in misses from device + ping
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
zigbee.onOffRefresh() + zigbee.levelRefresh()
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
}

View File

@@ -9,7 +9,6 @@ metadata {
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Health Check"
attribute "thermostatFanState", "string"
@@ -19,7 +18,6 @@ metadata {
command "quickSetHeat"
fingerprint deviceId: "0x08", inClusters: "0x43,0x40,0x44,0x31,0x80,0x85,0x60"
fingerprint mfr:"0098", prod:"6401", model:"0107", deviceJoinName: "2Gig CT100 Programmable Thermostat"
}
// simulator metadata
@@ -83,13 +81,13 @@ metadata {
state "fanCirculate", label:'${name}', action:"switchFanMode"
}
controlTile("heatSliderControl", "device.heatingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#e86d13"
state "setHeatingSetpoint", action:"quickSetHeat", backgroundColor:"#d04e00"
}
valueTile("heatingSetpoint", "device.heatingSetpoint", inactiveLabel: false, decoration: "flat") {
state "heat", label:'${currentValue}° heat', backgroundColor:"#ffffff"
}
controlTile("coolSliderControl", "device.coolingSetpoint", "slider", height: 1, width: 2, inactiveLabel: false) {
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#00a0dc"
state "setCoolingSetpoint", action:"quickSetCool", backgroundColor: "#1e9cbb"
}
valueTile("coolingSetpoint", "device.coolingSetpoint", inactiveLabel: false, decoration: "flat") {
state "cool", label:'${currentValue}° cool', backgroundColor:"#ffffff"
@@ -108,16 +106,6 @@ metadata {
}
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def parse(String description)
{
def result = []
@@ -451,14 +439,6 @@ def setCoolingSetpoint(Double degrees, Integer delay = 30000) {
], delay)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
log.debug "ping() called"
refresh()
}
def configure() {
delayBetween([
zwave.thermostatModeV2.thermostatModeSupportedGet().format(),

View File

@@ -33,10 +33,10 @@ metadata {
tiles {
standardTile("toggle", "device.lock", width: 2, height: 2) {
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#00a0dc", nextState:"unlocking"
state "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
state "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
state "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
state "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#00a0dc"
state "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
state "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
}
standardTile("lock", "device.lock", inactiveLabel: false, decoration: "flat") {

View File

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

View File

@@ -1,51 +0,0 @@
# Z-wave Dimmer Switch
Local Execution on V2 Hubs
Works with:
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724)](http://products.z-wavealliance.org/products/1197)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729)](http://products.z-wavealliance.org/products/1201)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718)](http://products.z-wavealliance.org/products/1191)
* [GE 1,000-Watt In-Wall Smart Dimmer Switch (GE 12725)](http://products.z-wavealliance.org/products/1198)
* [GE In-Wall Smart Fan Control (GE 12730)](http://products.z-wavealliance.org/products/1202)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Switch Level** - it's defined to accept two parameters, the level and the rate of dimming
* **Actuator** - represents that a Device has commands
* **Indicator** - gives you the ability to set the indicator LED light on a Z-Wave switch
* **Switch** - can detect state (possible values: on/off)
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Health Check** - indicates ability to get device health notifications
## Device Health
Z-Wave Smart Dimmers (In-Wall, In-Wall(Toggle), Plug-In), 1000-watt In-Wall Smart Dimmer Switch and In-Wall Smart Fan Control are polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Check-in interval = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [General Z-Wave Dimmer/Switch Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200955890-Troubleshooting-GE-in-wall-switch-or-dimmer-won-t-respond-to-commands-or-automations-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (GE 12724) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200902600-GE-In-Wall-Paddle-Dimmer-Switch-GE-12724-Z-Wave-)
* [GE Z-Wave In-Wall Smart Dimmer (Toggle) (GE 12729) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207568463-GE-In-Wall-Smart-Toggle-Dimmer-GE-12729-Z-Wave-)
* [GE Z-Wave Plug-in Smart Dimmer (GE 12718) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/202088474-GE-Plug-In-Smart-Dimmer-GE-12718-Z-Wave-)
* [GE 1,000-Watt In-Wall Smart Dimmer Switch (GE 12725) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200879274)
* [GE In-Wall Smart Fan Control (GE 12730) Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/200879274)

View File

@@ -12,7 +12,7 @@
*
*/
metadata {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light") {
definition (name: "Dimmer Switch", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level"
capability "Actuator"
capability "Indicator"
@@ -20,13 +20,8 @@ metadata {
capability "Polling"
capability "Refresh"
capability "Sensor"
capability "Health Check"
capability "Light"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer"
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer"
fingerprint mfr:"0063", prod:"4944", model:"3034", deviceJoinName: "GE In-Wall Smart Fan Control"
fingerprint inClusters: "0x26"
}
simulator {
@@ -47,16 +42,12 @@ metadata {
reply "200163,delay 5000,2602": "command: 2603, payload: 63"
}
preferences {
input "ledIndicator", "enum", title: "LED Indicator", description: "Turn LED indicator... ", required: false, options:["on": "When On", "off": "When Off", "never": "Never"], defaultValue: "off"
}
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:"#00a0dc", nextState:"turningOff"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
@@ -79,49 +70,16 @@ metadata {
}
main(["switch"])
details(["switch", "level", "refresh"])
details(["switch", "level", "indicator", "refresh"])
}
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated(){
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
switch (ledIndicator) {
case "on":
indicatorWhenOn()
break
case "off":
indicatorWhenOff()
break
case "never":
indicatorNever()
break
default:
indicatorWhenOn()
break
}
}
def getCommandClassVersions() {
[
0x20: 1, // Basic
0x26: 1, // SwitchMultilevel
0x56: 1, // Crc16Encap
0x70: 1, // Configuration
]
}
def parse(String description) {
def result = null
if (description != "updated") {
log.debug "parse() >> zwave.parse($description)"
def cmd = zwave.parse(description, commandClassVersions)
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
@@ -180,7 +138,6 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
updateDataValue("manufacturer", cmd.manufacturerName)
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
@@ -188,16 +145,6 @@ def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelS
[createEvent(name:"switch", value:"on"), response(zwave.switchMultilevelV1.switchMultilevelGet().format())]
}
def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) {
def versions = commandClassVersions
def version = versions[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) {
zwaveEvent(encapsulatedCommand)
}
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
@@ -244,13 +191,6 @@ def poll() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = []
@@ -261,19 +201,19 @@ def refresh() {
delayBetween(commands,100)
}
void indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on", displayed: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()))
def indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on")
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
}
void indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off", displayed: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()))
def indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off")
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
}
void indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never", displayed: false)
sendHubCommand(new physicalgraph.device.HubAction(zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()))
def indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never")
zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()
}
def invertSwitch(invert=true) {
@@ -283,4 +223,4 @@ def invertSwitch(invert=true) {
else {
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1).format()
}
}
}

View File

@@ -1,5 +1,7 @@
/**
* Copyright 2015 SmartThings
* Ecobee Sensor
*
* Copyright 2015 Juan Risso
*
* 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:
@@ -10,9 +12,6 @@
* 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.
*
* Ecobee Sensor
*
* Author: SmartThings
*/
metadata {
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
@@ -20,22 +19,18 @@ metadata {
capability "Temperature Measurement"
capability "Motion Sensor"
capability "Refresh"
capability "Polling"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
// Celsius
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 23, color: "#44b621"],
[value: 28, color: "#f1d801"],
[value: 35, color: "#d04e00"],
[value: 37, color: "#bc2323"],
// Fahrenheit
[value: 40, color: "#153591"],
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
@@ -47,8 +42,8 @@ metadata {
}
standardTile("motion", "device.motion") {
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc")
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00A0DC")
state("active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0")
state("inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff")
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat") {
@@ -61,12 +56,16 @@ metadata {
}
def refresh() {
log.debug "refresh called"
log.debug "refresh..."
poll()
}
void poll() {
log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild()
parent.pollChildren(this)
}
//generate custom mobile activity feeds event
def generateActivityFeedsEvent(notificationMessage) {
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
}

View File

@@ -19,50 +19,34 @@ metadata {
definition (name: "Ecobee Thermostat", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Thermostat"
capability "Temperature Measurement"
capability "Polling"
capability "Sensor"
capability "Refresh"
capability "Relative Humidity Measurement"
capability "Health Check"
capability "Refresh"
command "generateEvent"
command "raiseSetpoint"
command "lowerSetpoint"
command "resumeProgram"
command "switchMode"
command "switchFanMode"
command "generateEvent"
command "raiseSetpoint"
command "lowerSetpoint"
command "resumeProgram"
command "switchMode"
attribute "displayThermostatSetpoint", "string" // Added to be able to show "Auto"/"Off" keeping attribute thermostatSetpoint a number
attribute "thermostatStatus", "string"
attribute "maxHeatingSetpoint", "number"
attribute "minHeatingSetpoint", "number"
attribute "maxCoolingSetpoint", "number"
attribute "minCoolingSetpoint", "number"
attribute "deviceTemperatureUnit", "string"
attribute "deviceAlive", "enum", ["true", "false"]
attribute "thermostatSetpoint","number"
attribute "thermostatStatus","string"
}
tiles {
standardTile("temperature", "device.temperature", width: 2, height: 2, decoration: "flat") {
state("temperature", label:'${currentValue}°', unit:"F", icon: "st.thermostat.ac.air-conditioning",
backgroundColors:[
// Celsius
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 23, color: "#44b621"],
[value: 28, color: "#f1d801"],
[value: 35, color: "#d04e00"],
[value: 37, color: "#bc2323"],
// Fahrenheit
[value: 40, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
simulator { }
tiles {
valueTile("temperature", "device.temperature", width: 2, height: 2) {
state("temperature", label:'${currentValue}°', unit:"F",
backgroundColors:[
[value: 31, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 95, color: "#d04e00"],
[value: 96, color: "#bc2323"]
]
)
}
standardTile("mode", "device.thermostatMode", inactiveLabel: false, decoration: "flat") {
@@ -70,19 +54,20 @@ 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 "auxheatonly", action:"switchMode", icon: "st.thermostat.emergency-heat"
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") {
state "auto", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-auto"
state "on", action:"switchFanMode", nextState: "updating", icon: "st.thermostat.fan-on"
state "updating", label:"Working", icon: "st.secondary.secondary"
state "auto", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "on"
state "on", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "off"
state "off", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "circulate"
state "circulate", label:'Fan: ${currentValue}', action:"switchFanMode", nextState: "auto"
}
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"
@@ -106,14 +91,11 @@ metadata {
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
}
standardTile("resumeProgram", "device.resumeProgram", inactiveLabel: false, decoration: "flat") {
state "resume", action:"resumeProgram", nextState: "updating", label:'Resume', icon:"st.samsung.da.oven_ic_send"
state "resume", action:"resumeProgram", nextState: "updating", label:'Resume Schedule', icon:"st.samsung.da.oven_ic_send"
state "updating", label:"Working", icon: "st.secondary.secondary"
}
valueTile("humidity", "device.humidity", decoration: "flat") {
state "humidity", label:'${currentValue}%'
}
main "temperature"
details(["temperature", "upButtonControl", "displayThermostatSetpoint", "currentStatus", "downButtonControl", "mode", "fanMode","humidity", "resumeProgram", "refresh"])
details(["temperature", "upButtonControl", "thermostatSetpoint", "currentStatus", "downButtonControl", "mode", "resumeProgram", "refresh"])
}
preferences {
@@ -122,24 +104,11 @@ metadata {
}
void installed() {
// The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline
// Using 12 minutes because in testing, device health team found that there could be "jitter"
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud"], displayed: false)
}
// Device Watch will ping the device to proactively determine if the device has gone offline
// If the device was online the last time we refreshed, trigger another refresh as part of the ping.
def ping() {
def isAlive = device.currentValue("deviceAlive") == "true" ? true : false
if (isAlive) {
refresh()
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle '' attribute
}
def refresh() {
@@ -150,55 +119,37 @@ def refresh() {
void poll() {
log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild()
def results = parent.pollChild(this)
generateEvent(results) //parse received message from parent
}
def generateEvent(Map results) {
log.debug "parsing data $results"
if(results) {
results.each { name, value ->
def linkText = getLinkText(device)
def supportedThermostatModes = ["off"]
def thermostatMode = null
results.each { name, value ->
def isChange = false
def isDisplayed = true
def event = [name: name, linkText: linkText, descriptionText: getThermostatDescriptionText(name, value, linkText),
handlerName: name]
handlerName: name]
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint" ) {
def sendValue = location.temperatureScale == "C"? roundC(convertFtoC(value.toDouble())) : value.toInteger()
event << [value: sendValue, unit: temperatureScale]
} else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") {
def sendValue = location.temperatureScale == "C"? roundC(convertFtoC(value.toDouble())) : value.toInteger()
event << [value: sendValue, unit: temperatureScale, displayed: false]
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
if (value == true) {
supportedThermostatModes << ((name == "auxHeatMode") ? "auxheatonly" : name - "Mode")
}
return // as we don't want to send this event here, proceed to next name/value pair
} else if (name=="thermostatFanMode"){
sendEvent(name: "supportedThermostatFanModes", value: fanModes(), displayed: false)
event << [value: value.toString(), data:[supportedThermostatFanModes: fanModes()]]
} else if (name=="humidity") {
event << [value: value.toString(), displayed: false, unit: "%"]
} else if (name == "deviceAlive") {
event['displayed'] = false
} else if (name == "thermostatMode") {
thermostatMode = value.toLowerCase()
return // as we don't want to send this event here, proceed to next name/value pair
} else {
event << [value: value.toString()]
if (name=="temperature" || name=="heatingSetpoint" || name=="coolingSetpoint") {
def sendValue = value? convertTemperatureIfNeeded(value.toDouble(), "F", 1): value //API return temperature value in F
isChange = isTemperatureStateChange(device, name, value.toString())
isDisplayed = isChange
event << [value: sendValue, isStateChange: isChange, displayed: isDisplayed]
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false]
} else {
isChange = isStateChange(device, name, value.toString())
isDisplayed = isChange
event << [value: value.toString(), isStateChange: isChange, displayed: isDisplayed]
}
sendEvent(event)
}
if (state.supportedThermostatModes != supportedThermostatModes) {
state.supportedThermostatModes = supportedThermostatModes
sendEvent(name: "supportedThermostatModes", value: supportedThermostatModes, displayed: false)
}
if (thermostatMode) {
sendEvent(name: "thermostatMode", value: thermostatMode, data:[supportedThermostatModes:state.supportedThermostatModes], linkText: linkText,
descriptionText: getThermostatDescriptionText("thermostatMode", thermostatMode, linkText), handlerName: "thermostatMode")
}
generateSetpointEvent ()
generateStatusEvent ()
}
@@ -207,19 +158,13 @@ def generateEvent(Map results) {
//return descriptionText to be shown on mobile activity feed
private getThermostatDescriptionText(name, value, linkText) {
if(name == "temperature") {
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
return "$linkText temperature is $sendValue ${location.temperatureScale}"
return "$linkText temperature is $value°F"
} else if(name == "heatingSetpoint") {
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
return "heating setpoint is $sendValue ${location.temperatureScale}"
return "heating setpoint is $value°F"
} else if(name == "coolingSetpoint"){
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
return "cooling setpoint is $sendValue ${location.temperatureScale}"
return "cooling setpoint is $value°F"
} else if (name == "thermostatMode") {
return "thermostat mode is ${value}"
@@ -227,26 +172,26 @@ private getThermostatDescriptionText(name, value, linkText) {
} else if (name == "thermostatFanMode") {
return "thermostat fan mode is ${value}"
} else if (name == "humidity") {
return "humidity is ${value} %"
} else {
return "${name} = ${value}"
}
}
void setHeatingSetpoint(setpoint) {
log.debug "***heating setpoint $setpoint"
setHeatingSetpoint(setpoint.toDouble())
}
void setHeatingSetpoint(Double setpoint) {
// def mode = device.currentValue("thermostatMode")
def heatingSetpoint = setpoint
def coolingSetpoint = device.currentValue("coolingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint").toDouble()
def deviceId = device.deviceNetworkId.split(/\./).last()
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
//enforce limits of heatingSetpoint
if (heatingSetpoint > maxHeatingSetpoint) {
heatingSetpoint = maxHeatingSetpoint
} else if (heatingSetpoint < minHeatingSetpoint) {
heatingSetpoint = minHeatingSetpoint
if (heatingSetpoint > 79) {
heatingSetpoint = 79
} else if (heatingSetpoint < 45) {
heatingSetpoint = 45
}
//enforce limits of heatingSetpoint vs coolingSetpoint
@@ -256,33 +201,32 @@ void setHeatingSetpoint(setpoint) {
log.debug "Sending setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
if (parent.setHold (this, heatingSetpoint, coolingSetpoint, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
generateSetpointEvent()
generateStatusEvent()
} else {
log.error "Error setHeatingSetpoint(setpoint)"
log.error "Error setHeatingSetpoint(setpoint)" //This error is handled by the connect app
}
}
void setCoolingSetpoint(setpoint) {
log.debug "***cooling setpoint $setpoint"
def heatingSetpoint = device.currentValue("heatingSetpoint")
setCoolingSetpoint(setpoint.toDouble())
}
void setCoolingSetpoint(Double setpoint) {
// def mode = device.currentValue("thermostatMode")
def heatingSetpoint = device.currentValue("heatingSetpoint").toDouble()
def coolingSetpoint = setpoint
def deviceId = device.deviceNetworkId.split(/\./).last()
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
if (coolingSetpoint > maxCoolingSetpoint) {
coolingSetpoint = maxCoolingSetpoint
} else if (coolingSetpoint < minCoolingSetpoint) {
coolingSetpoint = minCoolingSetpoint
if (coolingSetpoint > 92) {
coolingSetpoint = 92
} else if (coolingSetpoint < 65) {
coolingSetpoint = 65
}
//enforce limits of heatingSetpoint vs coolingSetpoint
@@ -292,43 +236,49 @@ void setCoolingSetpoint(setpoint) {
log.debug "Sending setCoolingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
if (parent.setHold (this, heatingSetpoint, coolingSetpoint, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint)
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
generateSetpointEvent()
generateStatusEvent()
} else {
log.error "Error setCoolingSetpoint(setpoint)"
log.error "Error setCoolingSetpoint(setpoint)" //This error is handled by the connect app
}
}
void resumeProgram() {
log.debug "resumeProgram() is called"
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.resumeProgram(deviceId)) {
if (parent.resumeProgram(this, deviceId)) {
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
runIn(5, "poll")
log.debug "resumeProgram() is done"
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
} else {
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
log.error "Error resumeProgram() check parent.resumeProgram(deviceId)"
log.error "Error resumeProgram() check parent.resumeProgram(this, deviceId)"
}
}
def modes() {
return state.supportedThermostatModes
if (state.modes) {
log.debug "Modes = ${state.modes}"
return state.modes
}
else {
state.modes = parent.availableModes(this)
log.debug "Modes = ${state.modes}"
return state.modes
}
}
def fanModes() {
["on", "auto"]
["off", "on", "auto", "circulate"]
}
def switchMode() {
@@ -357,36 +307,44 @@ def switchFanMode() {
def returnCommand
switch (currentFanMode) {
case "on":
returnCommand = switchToFanMode("auto")
case "fanAuto":
returnCommand = switchToFanMode("fanOn")
break
case "auto":
returnCommand = switchToFanMode("on")
case "fanOn":
returnCommand = switchToFanMode("fanCirculate")
break
case "fanCirculate":
returnCommand = switchToFanMode("fanAuto")
break
}
if(!currentFanMode) { returnCommand = switchToFanMode("auto") }
if(!currentFanMode) { returnCommand = switchToFanMode("fanOn") }
returnCommand
}
def switchToFanMode(nextMode) {
log.debug "switching to fan mode: $nextMode"
def returnCommand
if(nextMode == "auto") {
if(!fanModes.contains("auto")) {
if(nextMode == "fanAuto") {
if(!fanModes.contains("fanAuto")) {
returnCommand = fanAuto()
} else {
returnCommand = switchToFanMode("on")
returnCommand = switchToFanMode("fanOn")
}
} else if(nextMode == "on") {
if(!fanModes.contains("on")) {
} else if(nextMode == "fanOn") {
if(!fanModes.contains("fanOn")) {
returnCommand = fanOn()
} else {
returnCommand = switchToFanMode("auto")
returnCommand = switchToFanMode("fanCirculate")
}
} else if(nextMode == "fanCirculate") {
if(!fanModes.contains("fanCirculate")) {
returnCommand = fanCirculate()
} else {
returnCommand = switchToFanMode("fanAuto")
}
}
returnCommand
}
@@ -394,26 +352,23 @@ def getDataByName(String name) {
state[name] ?: device.getDataValue(name)
}
def setThermostatMode(String mode) {
log.debug "setThermostatMode($mode)"
mode = mode.toLowerCase()
switchToMode(mode)
def setThermostatMode(String value) {
log.debug "setThermostatMode({$value})"
}
def setThermostatFanMode(String mode) {
log.debug "setThermostatFanMode($mode)"
mode = mode.toLowerCase()
switchToFanMode(mode)
def setThermostatFanMode(String value) {
log.debug "setThermostatFanMode({$value})"
}
def generateModeEvent(mode) {
sendEvent(name: "thermostatMode", value: mode, data:[supportedThermostatModes: state.supportedThermostatModes],
descriptionText: "$device.displayName is in ${mode} mode")
sendEvent(name: "thermostatMode", value: mode, descriptionText: "$device.displayName is in ${mode} mode", displayed: true)
}
def generateFanModeEvent(fanMode) {
sendEvent(name: "thermostatFanMode", value: fanMode, data:[supportedThermostatFanModes: fanModes()],
descriptionText: "$device.displayName fan is in ${fanMode} mode")
sendEvent(name: "thermostatFanMode", value: fanMode, descriptionText: "$device.displayName fan is in ${mode} mode", displayed: true)
}
def generateOperatingStateEvent(operatingState) {
@@ -423,7 +378,7 @@ def generateOperatingStateEvent(operatingState) {
def off() {
log.debug "off"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("off", deviceId))
if (parent.setMode (this,"off", deviceId))
generateModeEvent("off")
else {
log.debug "Error setting new mode."
@@ -437,7 +392,7 @@ def off() {
def heat() {
log.debug "heat"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("heat", deviceId))
if (parent.setMode (this,"heat", deviceId))
generateModeEvent("heat")
else {
log.debug "Error setting new mode."
@@ -448,15 +403,11 @@ def heat() {
generateStatusEvent()
}
def emergencyHeat() {
auxheatonly()
}
def auxheatonly() {
log.debug "auxheatonly()"
def auxHeatOnly() {
log.debug "auxHeatOnly"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auxHeatOnly", deviceId))
generateModeEvent("auxheatonly")
if (parent.setMode (this,"auxHeatOnly", deviceId))
generateModeEvent("auxHeatOnly")
else {
log.debug "Error setting new mode."
def currentMode = device.currentState("thermostatMode")?.value
@@ -469,7 +420,7 @@ def auxheatonly() {
def cool() {
log.debug "cool"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("cool", deviceId))
if (parent.setMode (this,"cool", deviceId))
generateModeEvent("cool")
else {
log.debug "Error setting new mode."
@@ -483,7 +434,7 @@ def cool() {
def auto() {
log.debug "auto"
def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode ("auto", deviceId))
if (parent.setMode (this,"auto", deviceId))
generateModeEvent("auto")
else {
log.debug "Error setting new mode."
@@ -496,146 +447,92 @@ def auto() {
def fanOn() {
log.debug "fanOn"
String fanMode = "on"
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
// parent.setFanMode (this,"on")
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
def currentFanMode = device.currentState("thermostatFanMode")?.value
generateFanModeEvent(currentFanMode) // reset the tile back
}
}
def fanAuto() {
log.debug "fanAuto"
String fanMode = "auto"
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
// parent.setFanMode (this,"auto")
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
}
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def fanCirculate() {
log.debug "fanCirculate"
// parent.setFanMode (this,"circulate")
}
def fanOff() {
log.debug "fanOff"
// parent.setFanMode (this,"off")
if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode)
} else {
log.debug "Error setting new mode."
def currentFanMode = device.currentState("thermostatFanMode")?.value
generateFanModeEvent(currentFanMode) // reset the tile back
}
}
def generateSetpointEvent() {
log.debug "Generate SetPoint Event"
def mode = device.currentValue("thermostatMode")
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
if(location.temperatureScale == "C") {
maxHeatingSetpoint = maxHeatingSetpoint > 40 ? roundC(convertFtoC(maxHeatingSetpoint)) : roundC(maxHeatingSetpoint)
maxCoolingSetpoint = maxCoolingSetpoint > 40 ? roundC(convertFtoC(maxCoolingSetpoint)) : roundC(maxCoolingSetpoint)
minHeatingSetpoint = minHeatingSetpoint > 40 ? roundC(convertFtoC(minHeatingSetpoint)) : roundC(minHeatingSetpoint)
minCoolingSetpoint = minCoolingSetpoint > 40 ? roundC(convertFtoC(minCoolingSetpoint)) : roundC(minCoolingSetpoint)
heatingSetpoint = heatingSetpoint > 40 ? roundC(convertFtoC(heatingSetpoint)) : roundC(heatingSetpoint)
coolingSetpoint = coolingSetpoint > 40 ? roundC(convertFtoC(coolingSetpoint)) : roundC(coolingSetpoint)
} else {
maxHeatingSetpoint = maxHeatingSetpoint < 40 ? roundC(convertCtoF(maxHeatingSetpoint)) : maxHeatingSetpoint
maxCoolingSetpoint = maxCoolingSetpoint < 40 ? roundC(convertCtoF(maxCoolingSetpoint)) : maxCoolingSetpoint
minHeatingSetpoint = minHeatingSetpoint < 40 ? roundC(convertCtoF(minHeatingSetpoint)) : minHeatingSetpoint
minCoolingSetpoint = minCoolingSetpoint < 40 ? roundC(convertCtoF(minCoolingSetpoint)) : minCoolingSetpoint
heatingSetpoint = heatingSetpoint < 40 ? roundC(convertCtoF(heatingSetpoint)) : heatingSetpoint
coolingSetpoint = coolingSetpoint < 40 ? roundC(convertCtoF(coolingSetpoint)) : coolingSetpoint
}
log.debug "Current Mode = ${mode}"
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
log.debug "Heating Setpoint = ${heatingSetpoint}"
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
log.debug "Cooling Setpoint = ${coolingSetpoint}"
sendEvent("name":"maxHeatingSetpoint", "value":maxHeatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"maxCoolingSetpoint", "value":maxCoolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"minHeatingSetpoint", "value":minHeatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"minCoolingSetpoint", "value":minCoolingSetpoint, "unit":location.temperatureScale)
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)
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString())
}
else if (mode == "cool") {
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint.toString())
} 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 == "auxheatonly") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"displayThermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":"Off")
} else if (mode == "emergencyHeat") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint.toString())
}
}
void raiseSetpoint() {
def mode = device.currentValue("thermostatMode")
def targetvalue
def maxHeatingSetpoint = device.currentValue("maxHeatingSetpoint")
def maxCoolingSetpoint = device.currentValue("maxCoolingSetpoint")
if (mode == "off" || mode == "auto") {
log.warn "this mode: $mode does not allow raiseSetpoint"
} else {
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
if (location.temperatureScale == "C") {
maxHeatingSetpoint = maxHeatingSetpoint > 40 ? convertFtoC(maxHeatingSetpoint) : maxHeatingSetpoint
maxCoolingSetpoint = maxCoolingSetpoint > 40 ? convertFtoC(maxCoolingSetpoint) : maxCoolingSetpoint
heatingSetpoint = heatingSetpoint > 40 ? convertFtoC(heatingSetpoint) : heatingSetpoint
coolingSetpoint = coolingSetpoint > 40 ? convertFtoC(coolingSetpoint) : coolingSetpoint
thermostatSetpoint = thermostatSetpoint > 40 ? convertFtoC(thermostatSetpoint) : thermostatSetpoint
} else {
maxHeatingSetpoint = maxHeatingSetpoint < 40 ? convertCtoF(maxHeatingSetpoint) : maxHeatingSetpoint
maxCoolingSetpoint = maxCoolingSetpoint < 40 ? convertCtoF(maxCoolingSetpoint) : maxCoolingSetpoint
heatingSetpoint = heatingSetpoint < 40 ? convertCtoF(heatingSetpoint) : heatingSetpoint
coolingSetpoint = coolingSetpoint < 40 ? convertCtoF(coolingSetpoint) : coolingSetpoint
thermostatSetpoint = thermostatSetpoint < 40 ? convertCtoF(thermostatSetpoint) : thermostatSetpoint
}
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
def thermostatSetpoint = device.currentValue("thermostatSetpoint").toInteger()
log.debug "raiseSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue + 1 : targetvalue + 0.5
if (device.latestState('thermostatSetpoint')) {
targetvalue = device.latestState('thermostatSetpoint').value as Integer
} else {
targetvalue = 0
}
targetvalue = targetvalue + 1
if ((mode == "heat" || mode == "auxheatonly") && targetvalue > maxHeatingSetpoint) {
targetvalue = maxHeatingSetpoint
} else if (mode == "cool" && targetvalue > maxCoolingSetpoint) {
targetvalue = maxCoolingSetpoint
if (mode == "heat" && targetvalue > 79) {
targetvalue = 79
} else if (mode == "cool" && targetvalue > 92) {
targetvalue = 92
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":targetvalue, 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
@@ -646,42 +543,28 @@ void raiseSetpoint() {
void lowerSetpoint() {
def mode = device.currentValue("thermostatMode")
def targetvalue
def minHeatingSetpoint = device.currentValue("minHeatingSetpoint")
def minCoolingSetpoint = device.currentValue("minCoolingSetpoint")
if (mode == "off" || mode == "auto") {
log.warn "this mode: $mode does not allow lowerSetpoint"
} else {
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def thermostatSetpoint = device.currentValue("thermostatSetpoint")
if (location.temperatureScale == "C") {
minHeatingSetpoint = minHeatingSetpoint > 40 ? convertFtoC(minHeatingSetpoint) : minHeatingSetpoint
minCoolingSetpoint = minCoolingSetpoint > 40 ? convertFtoC(minCoolingSetpoint) : minCoolingSetpoint
heatingSetpoint = heatingSetpoint > 40 ? convertFtoC(heatingSetpoint) : heatingSetpoint
coolingSetpoint = coolingSetpoint > 40 ? convertFtoC(coolingSetpoint) : coolingSetpoint
thermostatSetpoint = thermostatSetpoint > 40 ? convertFtoC(thermostatSetpoint) : thermostatSetpoint
} else {
minHeatingSetpoint = minHeatingSetpoint < 40 ? convertCtoF(minHeatingSetpoint) : minHeatingSetpoint
minCoolingSetpoint = minCoolingSetpoint < 40 ? convertCtoF(minCoolingSetpoint) : minCoolingSetpoint
heatingSetpoint = heatingSetpoint < 40 ? convertCtoF(heatingSetpoint) : heatingSetpoint
coolingSetpoint = coolingSetpoint < 40 ? convertCtoF(coolingSetpoint) : coolingSetpoint
thermostatSetpoint = thermostatSetpoint < 40 ? convertCtoF(thermostatSetpoint) : thermostatSetpoint
}
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
def thermostatSetpoint = device.currentValue("thermostatSetpoint").toInteger()
log.debug "lowerSetpoint() mode = ${mode}, heatingSetpoint: ${heatingSetpoint}, coolingSetpoint:${coolingSetpoint}, thermostatSetpoint:${thermostatSetpoint}"
if (device.latestState('thermostatSetpoint')) {
targetvalue = device.latestState('thermostatSetpoint').value as Integer
} else {
targetvalue = 0
}
targetvalue = targetvalue - 1
targetvalue = thermostatSetpoint ? thermostatSetpoint : 0
targetvalue = location.temperatureScale == "F"? targetvalue - 1 : targetvalue - 0.5
if ((mode == "heat" || mode == "auxheatonly") && targetvalue < minHeatingSetpoint) {
targetvalue = minHeatingSetpoint
} else if (mode == "cool" && targetvalue < minCoolingSetpoint) {
targetvalue = minCoolingSetpoint
if (mode == "heat" && targetvalue.toInteger() < 45) {
targetvalue = 45
} else if (mode == "cool" && targetvalue.toInteger() < 65) {
targetvalue = 65
}
sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"displayThermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
sendEvent("name":"thermostatSetpoint", "value":targetvalue, 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
@@ -690,88 +573,64 @@ void lowerSetpoint() {
//called by raiseSetpoint() and lowerSetpoint()
void alterSetpoint(temp) {
def mode = device.currentValue("thermostatMode")
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
def deviceId = device.deviceNetworkId.split(/\./).last()
if (mode == "off" || mode == "auto") {
log.warn "this mode: $mode does not allow alterSetpoint"
} else {
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def deviceId = device.deviceNetworkId.split(/\./).last()
def targetHeatingSetpoint
def targetCoolingSetpoint
def targetHeatingSetpoint
def targetCoolingSetpoint
def temperatureScaleHasChanged = false
if (location.temperatureScale == "C") {
if ( heatingSetpoint > 40.0 || coolingSetpoint > 40.0 ) {
temperatureScaleHasChanged = true
}
//step1: check thermostatMode, enforce limits before sending request to cloud
if (mode == "heat"){
if (temp.value > coolingSetpoint){
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value
} else {
if ( heatingSetpoint < 40.0 || coolingSetpoint < 40.0 ) {
temperatureScaleHasChanged = true
}
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = coolingSetpoint
}
//step1: check thermostatMode, enforce limits before sending request to cloud
if (mode == "heat" || mode == "auxheatonly"){
if (temp.value > coolingSetpoint){
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value
} else {
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = coolingSetpoint
}
} else if (mode == "cool") {
//enforce limits before sending request to cloud
if (temp.value < heatingSetpoint){
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value
} else {
targetHeatingSetpoint = heatingSetpoint
targetCoolingSetpoint = temp.value
}
}
log.debug "alterSetpoint >> in mode ${mode} trying to change heatingSetpoint to $targetHeatingSetpoint " +
"coolingSetpoint to $targetCoolingSetpoint with holdType : ${holdType}"
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint
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 if (mode == "cool") {
//enforce limits before sending request to cloud
if (temp.value < heatingSetpoint){
targetHeatingSetpoint = temp.value
targetCoolingSetpoint = temp.value
} else {
log.error "Error alterSetpoint()"
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)
}
targetHeatingSetpoint = heatingSetpoint
targetCoolingSetpoint = temp.value
}
if ( temperatureScaleHasChanged )
generateSetpointEvent()
generateStatusEvent()
}
log.debug "alterSetpoint >> in mode ${mode} trying to change heatingSetpoint to ${targetHeatingSetpoint} " +
"coolingSetpoint to ${targetCoolingSetpoint} with holdType : ${holdType}"
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
//step2: call parent.setHold to send http request to 3rd party cloud
if (parent.setHold(this, targetHeatingSetpoint, targetCoolingSetpoint, deviceId, sendHoldType)) {
sendEvent("name": "thermostatSetpoint", "value": temp.value.toString(), displayed: false)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint)
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
} else {
log.error "Error alterSetpoint()"
if (mode == "heat"){
sendEvent("name": "thermostatSetpoint", "value": heatingSetpoint.toString(), displayed: false)
} else if (mode == "cool") {
sendEvent("name": "thermostatSetpoint", "value": coolingSetpoint.toString(), displayed: false)
}
}
generateStatusEvent()
}
def generateStatusEvent() {
def mode = device.currentValue("thermostatMode")
def heatingSetpoint = device.currentValue("heatingSetpoint")
def coolingSetpoint = device.currentValue("coolingSetpoint")
def temperature = device.currentValue("temperature")
def heatingSetpoint = device.currentValue("heatingSetpoint").toInteger()
def coolingSetpoint = device.currentValue("coolingSetpoint").toInteger()
def temperature = device.currentValue("temperature").toInteger()
def statusText
def operatingState = "idle"
log.debug "Generate Status Event for Mode = ${mode}"
log.debug "Temperature = ${temperature}"
@@ -779,50 +638,42 @@ def generateStatusEvent() {
log.debug "Cooling set point = ${coolingSetpoint}"
log.debug "HVAC Mode = ${mode}"
if (mode == "heat" || mode == "auxheatonly") {
if (temperature >= heatingSetpoint) {
statusText = "Right Now: Idle"
} else {
statusText = "Heating to ${heatingSetpoint} ${location.temperatureScale}"
operatingState = "heating"
}
} else if (mode == "cool") {
if (temperature <= coolingSetpoint) {
statusText = "Right Now: Idle"
} 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 {
statusText = "?"
}
if (mode == "heat") {
if (temperature >= heatingSetpoint)
statusText = "Right Now: Idle"
else
statusText = "Heating to ${heatingSetpoint}° F"
} else if (mode == "cool") {
if (temperature <= coolingSetpoint)
statusText = "Right Now: Idle"
else
statusText = "Cooling to ${coolingSetpoint}° F"
} else if (mode == "auto") {
statusText = "Right Now: Auto"
} else if (mode == "off") {
statusText = "Right Now: Off"
} else if (mode == "emergencyHeat") {
statusText = "Emergency Heat"
} else {
statusText = "?"
}
log.debug "Generate Status Event = ${statusText}"
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
sendEvent("name":"thermostatOperatingState", "value":operatingState, "description":operatingState, displayed: false)
}
//generate custom mobile activity feeds event
def generateActivityFeedsEvent(notificationMessage) {
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
}
def roundC (tempC) {
return (Math.round(tempC.toDouble() * 2))/2
}
def convertFtoC (tempF) {
return ((Math.round(((tempF - 32)*(5/9)) * 2))/2).toDouble()
}
def convertCtoF (tempC) {
return (Math.round(tempC * (9/5)) + 32).toInteger()
}

View File

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

View File

@@ -1,43 +0,0 @@
# EcoNet Vent
Cloud Execution
Works with:
* [EcoNet Controls Z-Wave Vent](https://www.smartthings.com/works-with-smartthings/econet-controls/econet-controls-z-wave-vent)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#troubleshooting)
## Capabilities
* **Switch Level** - allows for the control of the level attribute of a light
* **Actuator** - represents that a Device has commands
* **Switch** - allows for the control of a switch device
* **Battery** - defines that the device has a battery
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
* **Polling** - allows for the polling of devices that support it
* **Configuration** - allow configuration of devices that support it
* **Health Check** - indicates ability to get device health notifications
## Device Health
EcoNet Controls Z-Wave Vent is polled by the hub.
As of hubCore version 0.14.38 the hub sends up reports every 15 minutes regardless of whether the state changed.
Device-Watch allows 2 check-in misses from device plus some lag time. So Check-in interval = (2*15 + 2)mins = 32 mins.
Not to mention after going OFFLINE when the device is plugged back in, it might take a considerable amount of time for
the device to appear as ONLINE again. This is because if this listening device does not respond to two poll requests in a row,
it is not polled for 5 minutes by the hub. This can delay up the process of being marked ONLINE by quite some time.
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [EcoNet Controls Z-Wave Vent Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204556420-EcoNet-EV100-Vent)

View File

@@ -26,13 +26,11 @@ metadata {
capability "Sensor"
capability "Polling"
capability "Configuration"
capability "Health Check"
command "open"
command "close"
fingerprint deviceId: "0x1100", inClusters: "0x26,0x72,0x86,0x77,0x80,0x20"
fingerprint mfr:"0157", prod:"0100", model:"0100", deviceJoinName: "EcoNet Controls Z-Wave Vent"
}
simulator {
@@ -55,7 +53,7 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#00a0dc"
state "on", action:"switch.off", icon:"st.vents.vent-open-text", backgroundColor:"#53a7c0"
state "off", action:"switch.on", icon:"st.vents.vent-closed", backgroundColor:"#ffffff"
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
@@ -85,15 +83,8 @@ def parse(String description) {
result
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
//send the command to stop polling
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response("poll stop")
}
@@ -178,13 +169,6 @@ def setLevel(value, duration) {
setLevel(value)
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
delayBetween([
zwave.switchMultilevelV1.switchMultilevelGet().format(),

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

@@ -12,12 +12,11 @@
*
*/
metadata {
definition (name: "Everspring Flood Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.moisture") {
definition (name: "Everspring Flood Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Water Sensor"
capability "Configuration"
capability "Sensor"
capability "Battery"
capability "Health Check"
fingerprint deviceId: "0xA102", inClusters: "0x86,0x72,0x85,0x84,0x80,0x70,0x9C,0x20,0x71"
}
@@ -29,12 +28,12 @@ metadata {
status "battery ${i}%": new physicalgraph.zwave.Zwave().batteryV1.batteryReport(batteryLevel: i).incomingMessage()
}
}
tiles(scale: 2) {
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
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 "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
}
}
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
@@ -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

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

View File

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

View File

@@ -56,9 +56,9 @@ metadata {
tiles {
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
state "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#00a0dc", nextState:"turningOff"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {

View File

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

View File

@@ -1,40 +0,0 @@
# Fibaro Door Window Sensor
Cloud Execution
Works with:
* [Fibaro Door/Window Sensor](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
* **Contact Sensor** - can detect contact (possible values: open,closed)
* **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
Fibaro Door/Window Sensor 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 Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/204075194-Fibaro-Door-Window-Sensor)

View File

@@ -39,8 +39,7 @@
capability "Contact Sensor"
capability "Sensor"
capability "Battery"
capability "Configuration"
capability "Health Check"
capability "Configuration"
command "resetParams2StDefaults"
command "listCurrentParams"
@@ -68,8 +67,8 @@
tiles {
standardTile("contact", "device.contact", width: 2, height: 2) {
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
state "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#ffa81e"
state "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#79b821"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
@@ -86,7 +85,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:"#00a0dc")
state("tampered", label:'tampered', icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
@@ -267,9 +266,6 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
*/
def configure() {
log.debug "Configuring Device..."
// 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.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
// send associate to group 3 to get sensor data reported only to hub

View File

@@ -1,12 +1,12 @@
/**
* Device Type Definition File
*
* Device Type: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10
* @author: Todd Wackford
* Email: todd@wackford.net
* @version: 1.0
* Device Type: Fibaro Flood Sensor
* File Name: fibaro-flood-sensor.groovy
* Initial Release: 2014-12-10
* @author: Todd Wackford
* Email: todd@wackford.net
* @version: 1.0
*
* Copyright 2014 SmartThings
*
@@ -26,8 +26,8 @@
* not displayed to the user. We do this so we can receive events and display on device
* activity. If the user wants to display the tamper tile, adjust the tile display lines
* with the following:
* main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"])
* main(["water", "temperature", "tamper"])
* details(["water", "temperature", "battery", "tamper"])
*
* @param none
*
@@ -39,18 +39,13 @@ metadata {
capability "Temperature Measurement"
capability "Configuration"
capability "Battery"
capability "Health Check"
capability "Sensor"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
command "test"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
command "test"
fingerprint deviceId: "0xA102", inClusters: "0x30,0x9C,0x60,0x85,0x8E,0x72,0x70,0x86,0x80,0x84"
fingerprint mfr:"010F", prod:"0000", model:"2002"
fingerprint mfr:"010F", prod:"0000", model:"1002"
fingerprint mfr:"010F", prod:"0B00", model:"1001"
}
simulator {
@@ -77,7 +72,7 @@ metadata {
tiles {
standardTile("water", "device.water", width: 2, height: 2) {
state "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#00a0dc"
state "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
@@ -91,9 +86,9 @@ metadata {
[value: 96, color: "#bc2323"]
]
}
standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#00a0dc")
standardTile("tamper", "device.tamper") {
state("secure", label:"secure", icon:"st.locks.lock.locked", backgroundColor:"#ffffff")
state("tampered", label:"tampered", icon:"st.locks.lock.unlocked", backgroundColor:"#53a7c0")
}
valueTile("battery", "device.battery", inactiveLabel: false, decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
@@ -111,17 +106,26 @@ metadata {
def parse(String description)
{
def result = []
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
if (cmd) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
}
if ( result[0] != null ) {
if (description == "updated") {
if (!state.MSR) {
result << response(zwave.wakeUpV1.wakeUpIntervalSet(seconds: 60*60, nodeid:zwaveHubNodeId))
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
}
} else {
def cmd = zwave.parse(description, [0x31: 2, 0x30: 1, 0x70: 2, 0x71: 1, 0x84: 1, 0x80: 1, 0x9C: 1, 0x72: 2, 0x56: 2, 0x60: 3])
if (cmd) {
result += zwaveEvent(cmd) //createEvent(zwaveEvent(cmd))
}
}
result << response(zwave.batteryV1.batteryGet().format())
if ( result[0] != null ) {
log.debug "Parse returned ${result}"
result
}
}
}
@@ -138,9 +142,10 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def result = [createEvent(descriptionText: "${device.displayName} woke up", isStateChange: false)]
if (!isConfigured()) {
// we're still in the process of configuring a newly joined device
result << lateConfigure(true)
result += lateConfigure(true)
} else {
result << response(zwave.wakeUpV1.wakeUpNoMoreInformation())
result += response(zwave.wakeUpV1.wakeUpNoMoreInformation())
log.debug "We're done with WakeUp!"
}
result
}
@@ -148,7 +153,7 @@ def zwaveEvent(physicalgraph.zwave.commands.wakeupv1.WakeUpNotification cmd) {
def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv2.SensorMultilevelReport cmd)
{
def map = [:]
switch (cmd.sensorType) {
case 1:
// temperature
@@ -179,7 +184,7 @@ def zwaveEvent(physicalgraph.zwave.commands.sensorbinaryv1.SensorBinaryReport cm
def map = [:]
map.value = cmd.sensorValue ? "active" : "inactive"
map.name = "acceleration"
if (map.value == "active") {
map.descriptionText = "$device.displayName detected vibration"
}
@@ -194,49 +199,49 @@ def zwaveEvent(physicalgraph.zwave.commands.configurationv2.ConfigurationReport
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) {
def result = []
def map = [:]
map.name = "water"
log.debug "BasicSet with CMD = ${cmd}"
if (!isConfigured()) {
def result = []
def map = [:]
map.name = "water"
map.value = cmd.value ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true)
result << createEvent(map)
result
}
// If we are getting a BasicSet, and isConfigured == false, then we are likely NOT properly configured.
result += lateConfigure(true)
result << createEvent(map)
result
}
}
def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
{
def map = [:]
if (cmd.sensorType == 0x05) {
map.name = "water"
map.value = cmd.sensorState ? "wet" : "dry"
map.descriptionText = "${device.displayName} is ${map.value}"
log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured()
} else if ( cmd.sensorType == 0) {
map.name = "tamper"
map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) {
map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
log.debug "CMD = SensorAlarmReport: ${cmd}"
setConfigured()
} else if ( cmd.sensorType == 0) {
map.name = "tamper"
map.isStateChange = true
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else if ( cmd.sensorType == 1) {
map.name = "tamper"
map.value = cmd.sensorState ? "tampered" : "secure"
map.descriptionText = "${device.displayName} has been tampered with"
runIn(30, "resetTamper") //device does not send alarm cancelation
} else {
map.descriptionText = "${device.displayName}: ${cmd}"
}
@@ -245,10 +250,10 @@ def zwaveEvent(physicalgraph.zwave.commands.sensoralarmv1.SensorAlarmReport cmd)
def resetTamper() {
def map = [:]
map.name = "tamper"
map.value = "secure"
map.descriptionText = "$device.displayName is secure"
sendEvent(map)
map.name = "tamper"
map.value = "secure"
map.descriptionText = "$device.displayName is secure"
sendEvent(map)
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
@@ -262,10 +267,10 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
log.debug "msr: $msr"
device.updateDataValue(["MSR", msr])
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true)
}
if ( msr == "010F-0B00-2001" ) { //this is the msr and device type for the fibaro flood sensor
result += lateConfigure(true)
}
result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)
result
@@ -277,17 +282,17 @@ def setConfigured() {
def isConfigured() {
Boolean configured = device.getDataValue(["configured"]) as Boolean
return configured
return configured
}
def lateConfigure(setConf = False) {
def res = response(configure())
if (setConf)
setConfigured()
return res
if (setConf)
setConfigured()
return res
}
/**
@@ -299,34 +304,26 @@ def lateConfigure(setConf = False) {
*/
def configure() {
log.debug "Configuring Device..."
// 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])
// default initial state
sendEvent(name: "water", value: "dry")
def cmds = []
// send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// reporting frequency of temps and battery set to one hour
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
def cmds = []
// send associate to group 2 to get alarm data
cmds << zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// temp hysteresis set to .5 degrees celcius
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
// cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.batteryV1.batteryGet().format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
// reporting frequency of temps and battery set to one hour
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.wakeUpV1.wakeUpNoMoreInformation().format()
delayBetween(cmds, 100)
}
@@ -352,18 +349,18 @@ def test() {
* @return none
*/
def updateZwaveParam(params) {
if ( params ) {
def pNumber = params.paramNumber
def pSize = params.size
def pValue = [params.value]
log.debug "Make sure device is awake and in recieve mode (triple-click?)"
log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'"
if ( params ) {
def pNumber = params.paramNumber
def pSize = params.size
def pValue = [params.value]
log.debug "Make sure device is awake and in recieve mode (triple-click?)"
log.debug "Updating ${device.displayName} parameter number '${pNumber}' with value '${pValue}' with size of '${pSize}'"
def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000)
}
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000)
}
}
/**
@@ -380,26 +377,26 @@ def updateZwaveParam(params) {
def resetParams2StDefaults() {
log.debug "Resetting ${device.displayName} parameters to SmartThings compatible defaults"
def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200)
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 1, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [3], parameterNumber: 2, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 5, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [255], parameterNumber: 7, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 9, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,60*60], parameterNumber: 10, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,50], parameterNumber: 12, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 13, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [5,220], parameterNumber: 50, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [13,172], parameterNumber: 51, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0,0,225], parameterNumber: 61, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,255,0,0], parameterNumber: 62, size: 4).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 63, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 73, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 74, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 75, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0,0], parameterNumber: 76, size: 2).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 77, size: 1).format()
delayBetween(cmds, 1200)
}
/**
@@ -416,25 +413,25 @@ def resetParams2StDefaults() {
def listCurrentParams() {
log.debug "Listing of current parameter settings of ${device.displayName}"
def cmds = []
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 2).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 5).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 7).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 9).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 10).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 12).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 13).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 50).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 51).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 61).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 62).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 63).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 73).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 74).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 75).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 76).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 77).format()
delayBetween(cmds, 1200)
}

View File

@@ -29,7 +29,7 @@
* 2. 20150125 Todd Wackford
* Leaned out parse and moved most device info getting into configuration method.
*/
/**
* Sets up metadata, simulator info and tile definition.
*
@@ -38,7 +38,7 @@
* @return none
*/
metadata {
definition (name: "Fibaro Motion Sensor", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "x.com.st.d.sensor.motion") {
definition (name: "Fibaro Motion Sensor", namespace: "smartthings", author: "SmartThings") {
capability "Motion Sensor"
capability "Temperature Measurement"
capability "Acceleration Sensor"
@@ -46,8 +46,7 @@
capability "Illuminance Measurement"
capability "Sensor"
capability "Battery"
capability "Health Check"
command "resetParams2StDefaults"
command "listCurrentParams"
command "updateZwaveParam"
@@ -82,8 +81,8 @@
tiles {
standardTile("motion", "device.motion", width: 2, height: 2) {
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#00a0dc"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#cccccc"
state "active", label:'motion', icon:"st.motion.motion.active", backgroundColor:"#53a7c0"
state "inactive", label:'no motion', icon:"st.motion.motion.inactive", backgroundColor:"#ffffff"
}
valueTile("temperature", "device.temperature", inactiveLabel: false) {
state "temperature", label:'${currentValue}°',
@@ -107,10 +106,10 @@
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
standardTile("acceleration", "device.acceleration") {
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#00a0dc")
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#cccccc")
state("active", label:'vibration', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
state("inactive", label:'still', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
}
main(["motion", "temperature", "acceleration", "illuminance"])
details(["motion", "temperature", "acceleration", "battery", "illuminance", "configure"])
@@ -126,22 +125,19 @@
*/
def configure() {
log.debug "Configuring Device For SmartThings Use"
// Device-Watch simply pings if no device events received for 8 hrs & 2 minutes
sendEvent(name: "checkInterval", value: 8 * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
def cmds = []
// send associate to group 3 to get sensor data reported only to hub
cmds << zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format()
// turn on tamper sensor with active/inactive reports (use it as an acceleration sensor) default is 0, or off
cmds << zwave.configurationV1.configurationSet(configurationValue: [4], parameterNumber: 24, size: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 24).format()
// temperature change report threshold (0-255 = 0.1 to 25.5C) default is 1.0 Celcius, setting to .5 Celcius
cmds << zwave.configurationV1.configurationSet(configurationValue: [5], parameterNumber: 60, size: 1).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 60).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 60).format()
cmds << response(zwave.batteryV1.batteryGet())
cmds << response(zwave.versionV1.versionGet().format())
cmds << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())
@@ -155,20 +151,20 @@ def parse(String description)
{
def result = []
def cmd = zwave.parse(description, [0x72: 2, 0x31: 2, 0x30: 1, 0x84: 1, 0x9C: 1, 0x70: 2, 0x80: 1, 0x86: 1, 0x7A: 1, 0x56: 1])
if (description == "updated") {
result << response(zwave.wakeUpV1.wakeUpIntervalSet(seconds: 7200, nodeid:zwaveHubNodeId))
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
result << response(zwave.manufacturerSpecificV2.manufacturerSpecificGet())
}
if (cmd) {
if( cmd.CMD == "8407" ) {
if( cmd.CMD == "8407" ) {
result << response(zwave.batteryV1.batteryGet().format())
result << new physicalgraph.device.HubAction(zwave.wakeUpV1.wakeUpNoMoreInformation().format())
result << new physicalgraph.device.HubAction(zwave.wakeUpV1.wakeUpNoMoreInformation().format())
}
result << createEvent(zwaveEvent(cmd))
}
if ( result[0] != null ) {
log.debug "Parse returned ${result}"
result
@@ -189,14 +185,14 @@ def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd)
}
}
def createEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, Map item1) {
def createEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd, Map item1) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
}
def createEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, Map item1) {
def createEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, Map item1) {
updateDataValue("applicationVersion", "${cmd.applicationVersion}")
log.debug "applicationVersion: ${cmd.applicationVersion}"
log.debug "applicationSubVersion: ${cmd.applicationSubVersion}"
@@ -205,7 +201,7 @@ def createEvent(physicalgraph.zwave.commands.versionv1.VersionReport cmd, Map it
log.debug "zWaveProtocolSubVersion: ${cmd.zWaveProtocolSubVersion}"
}
def createEvent(physicalgraph.zwave.commands.firmwareupdatemdv1.FirmwareMdReport cmd, Map item1) {
def createEvent(physicalgraph.zwave.commands.firmwareupdatemdv1.FirmwareMdReport cmd, Map item1) {
log.debug "checksum: ${cmd.checksum}"
log.debug "firmwareId: ${cmd.firmwareId}"
log.debug "manufacturerId: ${cmd.manufacturerId}"
@@ -304,7 +300,7 @@ def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerS
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
log.debug "msr: $msr"
updateDataValue("MSR", msr)
if ( msr == "010F-0800-2001" ) { //this is the msr and device type for the fibaro motion sensor
configure()
}
@@ -334,7 +330,7 @@ def test() {
* @return none
*/
def updateZwaveParam(params) {
if ( params ) {
if ( params ) {
def pNumber = params.paramNumber
def pSize = params.size
def pValue = [params.value]
@@ -344,7 +340,7 @@ def updateZwaveParam(params) {
def cmds = []
cmds << zwave.configurationV1.configurationSet(configurationValue: pValue, parameterNumber: pNumber, size: pSize).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: pNumber).format()
delayBetween(cmds, 1000)
delayBetween(cmds, 1000)
}
}
@@ -388,13 +384,13 @@ def resetParams2StDefaults() {
cmds << zwave.configurationV1.configurationSet(configurationValue: [18], parameterNumber: 86, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [28], parameterNumber: 87, size: 1).format()
cmds << zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 89, size: 1).format()
delayBetween(cmds, 500)
}
/**
* Lists all of available Fibaro parameters and thier current settings out to the
* logging window in the IDE This will be called from the "Fibaro Tweaker" or
* Lists all of available Fibaro parameters and thier current settings out to the
* logging window in the IDE This will be called from the "Fibaro Tweaker" or
* user's own app.
*
* <p>THIS IS AN ADVANCED OPERATION. USE AT YOUR OWN RISK! READ OEM DOCUMENTATION!
@@ -433,6 +429,7 @@ def listCurrentParams() {
cmds << zwave.configurationV1.configurationGet(parameterNumber: 86).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 87).format()
cmds << zwave.configurationV1.configurationGet(parameterNumber: 89).format()
delayBetween(cmds, 500)
}

Some files were not shown because too many files have changed in this diff Show More