Compare commits

..

33 Commits

Author SHA1 Message Date
Vinay Rao
566425c531 Merge pull request #869 from SmartThingsCommunity/staging
Rolling up staging to production 05-10
2016-05-10 13:40:49 -07:00
Vinay Rao
e7448e7908 Merge pull request #848 from SmartThingsCommunity/master
Rolling up master to staging
2016-05-03 10:59:58 -07:00
Vinay Rao
973c16f088 Merge pull request #842 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-05-03 Release
2016-05-03 10:20:53 -07:00
Luke Bredeson
77f880af6e Merge pull request #841 from lbredeso/hue-connect-updated-failure
SHARD-174: Hue (Connect) updated() calls can fail in certain situations
2016-04-28 13:28:07 -05:00
Luke Bredeson
1c4386a67b SHARD-174: Hue (Connect) updated() calls can fail in certain situations 2016-04-28 11:09:52 -05:00
Matt Pennig
88dd510e72 Merge pull request #832 from SmartThingsCommunity/two-line-multiattribute-controls
Adding test cases for multi-line controls in multiattribute tiles
2016-04-26 13:49:57 -05:00
Vinay Rao
e278a3b57d Merge pull request #838 from SmartThingsCommunity/master
Rolling up master to staging
2016-04-26 11:34:03 -07:00
Vinay Rao
7786df3262 Merge pull request #837 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-04-26 11:25:59 -07:00
Matt Pennig
5ac08e5a92 adding multi-line text for standard and value tiles 2016-04-26 13:13:20 -05:00
Vinay Rao
b05d956d95 Merge pull request #830 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-04-26 Release
2016-04-26 10:59:05 -07:00
Donald C. Kirker
6cdb80db1f Merge pull request #836 from mckeed/staging
Add auto-retyping for Astralink sensors SING-44
2016-04-25 17:41:32 -07:00
Duncan McKee
4db99824af Add Astralink sensors to zw door/window retypeBasedOnMSR 2016-04-25 16:40:47 -04:00
Vinay Rao
72b51d50bc Merge pull request #834 from SmartThingsCommunity/staging
Rolling down hotfix for deploy tool to master
2016-04-25 12:33:13 -07:00
Vinay Rao
b2e245bd85 Merge pull request #833 from SmartThingsCommunity/production
Rolling down hotfix for deploy tool to staging
2016-04-25 12:28:55 -07:00
Vinay Rao
9a9854cf92 Merge pull request #831 from jord98716/DEVTOOLS-636-a
DEVTOOLS-636: Increment version of executable-deployment-scripts
2016-04-25 12:27:42 -07:00
Matt Pennig
1e27ff5d4a Adding test cases for multi-line controls in multiattribute tiles 2016-04-25 11:58:18 -05:00
Jordan Howe
37f1726ee6 DEVTOOLS-636: Increment version of executable-deployment-scripts 2016-04-25 09:57:53 -05:00
Jack Chi
c7e8079ff1 Merge pull request #757 from jackchi/add-healthcheck-smartsense
[CHF-112] Add Health Check capability to SmartThings SmartSense products
2016-04-22 11:11:59 -07:00
jackchi
481d13a571 [CHF-112] Add Health Check capability to SmartThings SmartSense products 2016-04-22 11:10:48 -07:00
Luke Bredeson
9d83b850ca Merge pull request #813 from lbredeso/updated-settings-state-fix
SHARD-159: Wemo (Connect) updated() fails in certain IP change scenarios
2016-04-20 16:31:36 -05:00
Luke Bredeson
84de336a1a SHARD-159: Wemo (Connect) updated() fails in certain IP change scenarios 2016-04-20 16:07:11 -05:00
Lars Finander
8b465b03b4 Merge pull request #808 from larsfinander/DVCSMP-1716_Philips_Hue_Invalid_parameter
DVCSMP-1716 Philips Hue: Invalid hue parameter used in setColor
2016-04-20 11:11:39 -07:00
Vinay Rao
2f81964479 Merge pull request #775 from motley74/nyce_hinge
Added fingerprint for NYCE door hinge sensor
2016-04-20 10:29:06 -07:00
Vinay Rao
d5ea735df7 Merge pull request #810 from SmartThingsCommunity/master
Rolling up master to staging
2016-04-19 15:50:22 -07:00
Vinay Rao
6428719c79 Merge pull request #809 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-04-19 15:41:56 -07:00
Lars Finander
327f8dfb00 DVCSMP-1716 Philips Hue: Invalid hue parameter used in setColor
-Replaced transition with transitiontime according to Hue API
2016-04-19 15:05:21 -07:00
Vinay Rao
e150ea4a59 Merge pull request #797 from SmartThingsCommunity/staging
Rolling up changes to production from staging 2016-04-19 Release
2016-04-19 14:41:39 -07:00
Donald C. Kirker
cdbcab6dad Merge pull request #806 from dkirker/CoopBoss
custom device types for the CoopBoss hardware version 3
2016-04-19 10:23:16 -07:00
John Rucker
dd99a024c2 custom device types for the CoopBoss hardware version 3
Prepping for submission to SmartThings.  Removed extra comments.

Submitting to public store for approval

Updated for new SmartThings interface

Release Candidate for CoopBoss H3V9

save

Update to fix invalid temperature reporting and added maxCurrentNE methods and attributes.

Made changes to defalutState:true to state "default" on smart tiles that had only one default state.  This was causing the Android version of the app to crash.

Updated comments

Added test for null values that were causing errors during join process

Fixed log errors during join process by testing for null values before init process.

Update fingerprint with Manufacturer data

SmartApps for CoopBoss hardware version 3

Updated Icons.

1

Updates to Prep for RC

Clean up

save
2016-04-19 10:06:33 -07:00
Lars Finander
810f3645d9 Merge pull request #784 from larsfinander/CHANGE-479-staging-hue-green-icon
CHANGE-479 Changing the lights on status for HUE DTH back to green
2016-04-15 13:25:07 -07:00
Lars Finander
2dcbcc84fc CHANGE-479 Changing the lights on status for HUE DTH back to green
-Change hue-bloom device type back to green
-Change hue-lux-bulb device type back to green
2016-04-14 20:49:59 -07:00
Vinay Rao
0c75c8806e Merge pull request #780 from SmartThingsCommunity/master
Rolling up master to staging
2016-04-13 23:35:44 -05:00
Michael Hudson
235e3f5507 Added fingerprint for NYCE door hinge sensor 2016-04-12 18:23:28 -06:00
20 changed files with 1147 additions and 517 deletions

View File

@@ -9,7 +9,7 @@ apply plugin: 'smartthings-slack'
buildscript {
dependencies {
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.7"
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.8"
}
repositories {
mavenLocal()

View File

@@ -1,442 +0,0 @@
/*
* Aeon HEM Gen5(zwave plus)
*
* Copyright 2016 Dillon A. Miller
*
* v0.8 of Aeon HEM Gen5(zwave plus) code, released 04/15/2016 for Aeotec Model zw095-a
* This Gen5 device handler is not backward compatible with the Aeon V1 or V2 device. If your model number is not zw095-a, don't use it.
*
* 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.
*
* Some code used from various SmartThings device handlers created by:
* Brock Haymond, Barry A. Burke, and Robert Vandervoort. Portions of the metering code came from ElasticDev.
*
* Link to find the latest version of the Device Handler code:
* https://gist.github.com/DuncanIdahoCT/deb2bafdd28af4fce3073b9d9f4ecafa
*
* General notes:
* You may need to change the device type to this device handler after you pair it to your hub. I'm not sure why it doesn't always automatically pair using this handler even though the fingerprint matches...
* Also, you need to hit the button on the back of the HEM Gen5 a couple (two-three) times to get it to flash the red light on the front rapidly to ensure it's in inclusion mode. It isn't in the right mode if it's just flashing slow.
* Once the red light is solid, look in your things list and find it, could be just called z-wave, then change it's name and device type using the graph api to this custom handler to make it start working.
* The config with default intervals will send right away after you set the HEM Gen5 to this handler, please wait a few minutes before sending the config again or changing the intervals under preferences.
* The purpose of the config button is just really to resend the config with monitor interval prefs, as sometimes the config isn't fully applied, See the list of config items at the bottom of this code.
* You may need to send the config a few times, with about 2 minutes delay between to get all the properties to take. Not sure why-but if you look in the debug log in the graph api for this device you can see if they all applied.
* I had to unplug and replug my device after extensive testing and repeatedly setting the config over and over. Could be it works for you the first time, or you may need to pull power and re plug too in order to get all the Pole 1/2 data to show in the app.
*
* Known Issues:
* Issue 1:
* Not sure if this is the device handler or just a general SmartThings IOS App issue but sometimes when you set the preferences, it just spins in the app.
* If you are watching the log you can see it did set the preferences. Not sure why the app gets stuck, but just reload the app and should be fine.
* Issue 2:
* Not really a problem, more like a limitation; the clamps 1/2 data packets are sent to the ST hub based on monitor intervals for reports groups 1-3 which you can set in the device preferences.
* What this means is that, if you are paying attention to the tile data, you'll notice the center Total values don't quite work out to be the sum of Pole 1/2 values.
* This is simply because the base HEM data can be "polled" whereas the clamp 1/2 data is sent. And only sent on a schedule.
*
* Change log:
* v0.1 - released 04/04/16:
* Added support for secure inclusion and command encapsulation
* v0.2 - released 04/05/16:
* Added configuration settings using some preference variables that you can control from the app
* v0.3 - released 04/05/16:
* Added clamp1 and clamp2 data display, may have to hit configure a few times (wait at least 2 minute each time) to make the top left and right boxes show data from the clamps.
* v0.4 - released 04/06/16:
* Changed the "main" tile to display a clean total kWh, although the ST app seems to make everything on the main Things list all CAPS so it's actually displayed as KWH...
* v0.5 - released 04/07/16:
* Changed the main thing list device icon to st.Lighting.light14 cause it has a leaf!.
* v0.6 - released 04/07/16:
* Added a cost per kWh preference and a cost tile that is calculated on kWh.
* Also added a timestamp of last reset button tap to work with above cost feature.
* v0.7 - released 04/08/16:
* Removed individual value tile polling actions and polling function.
* Cleaned up and well-formed code
* v0.8 - released 04/15/16:
* Slightly adjusted the size of the tiles to fit all tiles into the App screen without scrolling.
* Further commented and cleaned up the code in preparation for submission to SmartThings as an official device handler.
* Submitted for consideration by SmartThings.
*
* To do:
* Features:
* Color code tiles or tile values for hi/low usage conditions.
* Possibly integrate a second tile set page with peak/min usage of watts and/or amps values over time.
* Integrate PlotWatt or other online Energy tracking API based service.
* Fixes:
* Determine why app sometimes freezes when setting preferences, I have seen this with other devices, e.g. Arrival Sensor, Jasco Wall Switches, etc...
*
*/
// metadata
metadata {
definition (name: "Aeon HEM Gen5(zwave plus)", namespace: "DuncanIdahoCT", author: "Dillon A. Miller") {
capability "Energy Meter"
capability "Power Meter"
capability "Configuration"
capability "Polling"
capability "Refresh"
capability "Sensor"
command "reset"
fingerprint deviceId: "0x3101", inClusters: "0x98"
fingerprint inClusters: "0x5E,0x86,0x72,0x32,0x56,0x60,0x70,0x59,0x85,0x7A,0x73,0xEF,0x5A", outClusters: "0x82"
}
// simulator
simulator {
for (int i = 0; i <= 10000; i += 1000) {
status "power ${i} W":
new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 1, scale: 2, size: 4).incomingMessage()
}
for (int i = 0; i <= 100; i += 10) {
status "energy ${i} kWh":
new physicalgraph.zwave.Zwave().meterV3.meterReport(scaledMeterValue: i, precision: 3, meterType: 1, scale: 0, size: 4).incomingMessage()
}
}
// tile definitions
tiles (scale: 2) {
// This tile is not displayed on the tile screen for this device but rather in the Things list.
valueTile("list-energy", "device.energy") {
state "default", label:'${currentValue} kWh', icon: "st.Lighting.light14"
}
// Tiles with a digit below relate to Clamp 1 and Clamp 2. Tiles with no digit are totals for clamps or volts.
valueTile("current1", "device.current1", decoration: "flat", width: 2, height: 2) {
state "default", label:'Pole 1\n${currentValue}\nAmps'
}
valueTile("current", "device.current", decoration: "flat", width: 2, height: 2) {
state "default", label:'Total\n${currentValue}\nAmps'
}
valueTile("current2", "device.current2", decoration: "flat", width: 2, height: 2) {
state "default", label:'Pole 2\n${currentValue}\nAmps'
}
valueTile("power1", "device.power1", decoration: "flat", width: 2, height: 2) {
state "default", label:'Pole 1\n${currentValue}\nWatts'
}
valueTile("power", "device.power", decoration: "flat", width: 2, height: 2) {
state "default", label:'Total\n${currentValue}\nWatts'
}
valueTile("power2", "device.power2", decoration: "flat", width: 2, height: 2) {
state "default", label:'Pole 2\n${currentValue}\nWatts'
}
valueTile("voltage", "device.voltage", decoration: "flat", width: 2, height: 1) {
state "default", label:'${currentValue} V'
}
valueTile("energy", "device.energy", decoration: "flat", width: 2, height: 1) {
state "default", label:'${currentValue} kWh'
}
valueTile("cost", "device.cost", decoration: "flat", width: 2, height: 1) {
state "default", label:'\$${currentValue}'
}
valueTile("lastresetlabel", "device.lastresettime", decoration: "flat", width: 3, height: 1) {
state "default", label:'Last Reset Timestamp'
}
valueTile("lastresettime", "device.lastresettime", decoration: "flat", width: 3, height: 1) {
state "default", label:'${currentValue}'
}
standardTile("configure", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
}
standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:'reset kWh', action:"reset"
}
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
main "list-energy"
details(["current1","current","current2","power1","power","power2","voltage","energy","cost","lastresetlabel","lastresettime","configure","reset","refresh"])
}
preferences {
input "kWhCost", "string",
title: "Cost in \$/kWh",
description: "Your Electric Bill Cost Per kWh",
defaultValue: "0.19514" as String,
required: false,
displayDuringSetup: true
input "monitorInterval1", "integer",
title: "Volts & kWh Report",
description: "Interval (secs) for Volts & kWh Report",
defaultValue: 60,
range: "1..4294967295?",
required: false,
displayDuringSetup: true
input "monitorInterval2", "integer",
title: "Amps Report",
description: "Interval (secs) for Amps Report",
defaultValue: 30,
range: "1..4294967295?",
required: false,
displayDuringSetup: true
input "monitorInterval3", "integer",
title: "Watts Report",
description: "Interval (secs) for Watts Report",
defaultValue: 6,
range: "1..4294967295?",
required: false,
displayDuringSetup: true
}
}
def updated(){
if (state.sec && !isConfigured()) {
// in case we miss the SCSR
response(configure())
}
}
def parse(String description){
def result = null
if (description.startsWith("Err 106")) {
state.sec = 0
result = createEvent( name: "secureInclusion", value: "failed", isStateChange: true,
descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
} else if (description != "updated") {
def cmd = zwave.parse(description, [0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
}
//log.debug "Parsed '${description}' to ${result.inspect()}"
return result
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
state.sec = 1
//log.debug "encapsulated: ${encapsulatedCommand}"
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}
def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
response(configure())
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}"
}
def zwaveEvent(physicalgraph.zwave.commands.associationv2.AssociationReport cmd) {
log.debug "---ASSOCIATION REPORT V2--- ${device.displayName} groupingIdentifier: ${cmd.groupingIdentifier}, maxNodesSupported: ${cmd.maxNodesSupported}, nodeId: ${cmd.nodeId}, reportsToFollow: ${cmd.reportsToFollow}"
}
def zwaveEvent(physicalgraph.zwave.commands.meterv3.MeterReport cmd) {
def meterTypes = ["Unknown", "Electric", "Gas", "Water"]
def electricNames = ["energy", "energy", "power", "count", "voltage", "current", "powerFactor", "unknown"]
def electricUnits = ["kWh", "kVAh", "W", "pulses", "V", "A", "Power Factor", ""]
//NOTE ScaledPreviousMeterValue does not always contain a value
def previousValue = cmd.scaledPreviousMeterValue ?: 0
//Here is where all HEM polled values are defined. Scale(0-7) is in reference to the Aeon Labs HEM Gen5 data for kWh, kVAh, W, V, A, and M.S.T. respectively.
//If scale 7 (M.S.T.) is polled, you would receive Scale2(0-1) which is kVar, and kVarh respectively. We are ignoring the Scale2 ranges in this device handler.
def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display]
switch(cmd.scale) {
case 0: //kWh
previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0
BigDecimal costDecimal = cmd.scaledMeterValue * (kWhCost as BigDecimal)
def costDisplay = String.format("%5.2f",costDecimal)
sendEvent(name: "cost", value: costDisplay, unit: "", descriptionText: "Display Cost: \$${costDisp}")
map.value = cmd.scaledMeterValue
break;
case 1: //kVAh (not used in the U.S.)
map.value = cmd.scaledMeterValue
break;
case 2: //Watts
previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0
map.value = Math.round(cmd.scaledMeterValue)
break;
case 3: //pulses
map.value = Math.round(cmd.scaledMeterValue)
break;
case 4: //Volts
previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0
map.value = cmd.scaledMeterValue
break;
case 5: //Amps
previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0
map.value = cmd.scaledMeterValue
break;
case 6: //Power Factor
case 7: //Scale2 values (not currently implimented or needed)
map.value = cmd.scaledMeterValue
break;
default:
break;
}
createEvent(map)
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
//This is where the HEM clamp1 and clamp2 (subdevice) report values are defined. Scale(2,5) is in reference to the Aeon Labs HEM Gen5 (subdevice) data for W, and A respectively.
//Z-Wave Command Class 0x60 (multichannelv3) is necessary to interpret the subdevice data from the HEM clamps.
//In addition, "cmd.commandClass == 50" and "encapsulatedCommand([0x30: 1, 0x31: 1])" below is necessary to properly receive and inturpret the encasulated subdevice data sent to the SmartThings hub by the HEM.
//The numbered "command class" references: 50, 0x30v1, and 0x31v1 do not seem to be true Z-Wave Command Classes and any correlation is seemingly coincidental.
//It should also be noted that without the above, the data received will not be processed here under the 0x60 (multichannelv3) command class and you will see unhandled messages from the HEM along with references to command class 50 as well as Meter Types 33, and 161.
//sourceEndPoint 1, and 2 are the Clamps 1, and 2.
def dispValue
def newValue
def formattedValue
def MAX_AMPS = 220
def MAX_WATTS = 24000
if (cmd.commandClass == 50) { //50 is likely a manufacturer specific code, Z-Wave specifies this as a "Basic Window Covering" so it's not a true Z-Wave Command Class.
def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1]) // The documentation on working with Z-Wave subdevices and the technical specs from Aeon Labs do not explain this adequately, but it's necessary.
//log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
if (encapsulatedCommand) {
if (cmd.sourceEndPoint == 1) {
if (encapsulatedCommand.scale == 2 ) {
newValue = Math.round(encapsulatedCommand.scaledMeterValue)
if (newValue > MAX_WATTS) { return }
formattedValue = newValue
dispValue = "${formattedValue}"
sendEvent(name: "power1", value: dispValue as String, unit: "", descriptionText: "L1 Power: ${formattedValue} Watts")
}
if (encapsulatedCommand.scale == 5 ) {
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
if (newValue > MAX_AMPS) { return }
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}"
sendEvent(name: "current1", value: dispValue as String, unit: "", descriptionText: "L1 Current: ${formattedValue} Amps")
}
}
else if (cmd.sourceEndPoint == 2) {
if (encapsulatedCommand.scale == 2 ) {
newValue = Math.round(encapsulatedCommand.scaledMeterValue)
if (newValue > MAX_WATTS) { return }
formattedValue = newValue
dispValue = "${formattedValue}"
sendEvent(name: "power2", value: dispValue as String, unit: "", descriptionText: "L2 Power: ${formattedValue} Watts")
}
if (encapsulatedCommand.scale == 5 ) {
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
if (newValue > MAX_AMPS) { return }
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}"
sendEvent(name: "current2", value: dispValue as String, unit: "", descriptionText: "L2 Current: ${formattedValue} Amps")
}
}
}
}
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
//This will log any unhandled command output to the debug window.
log.debug "Unhandled: $cmd"
createEvent(descriptionText: cmd.toString(), isStateChange: false)
}
def refresh() {
def request = [
//This is where the tile action "refresh" is defined. Refresh is very basic. It simply gets and displays the latest values from the HEM exclusive of the clamp subdevices.
zwave.meterV3.meterGet(scale: 0), //kWh
zwave.meterV3.meterGet(scale: 2), //Wattage
zwave.meterV3.meterGet(scale: 4), //Volts
zwave.meterV3.meterGet(scale: 5), //Amps
]
commands(request)
}
def reset() {
//This is where the tile action "reset" is defined. Reset is only meant to be used once a month on the end/beginning of your electric utility billing cycle.
//Tapping reset will send the meter reset command to HEM and zero out the kWh data so you can start fresh.
//This will also clear the cost data and reset the last reset timestamp. Finally it will poll for latest values from the HEM.
//This has no impact on Pole1 or Pole2 (clamp1 and clamp2 subdevice) tile data as that is sent via reports from the HEM.
def dateString = new Date().format("M/d/YY", location.timeZone)
def timeString = new Date().format("h:mm a", location.timeZone)
state.lastresettime = dateString+" @ "+timeString
sendEvent(name: "lastresettime", value: state.lastresettime)
def request = [
zwave.meterV3.meterReset(),
zwave.meterV3.meterGet(scale: 0), //kWh
zwave.meterV3.meterGet(scale: 2), //Wattage
zwave.meterV3.meterGet(scale: 4), //Volts
zwave.meterV3.meterGet(scale: 5), //Amps
]
commands(request)
}
def configure() {
//This is where the tile action "configure" is defined. Configure resends the configuration commands below (using the variables set by the preferences section above) to the HEM Gen5 device.
//If you're watching the debug log when you tap configure, you should see the full configuration report come back slowly over about a minute.
//If you don't see the full configuration report (seven messages) followed by the association report, tap configure again.
def monitorInt1 = 60
if (monitorInterval1) {
monitorInt1=monitorInterval1.toInteger()
}
def monitorInt2 = 30
if (monitorInterval2) {
monitorInt2=monitorInterval2.toInteger()
}
def monitorInt3 = 6
if (monitorInterval3) {
monitorInt3=monitorInterval3.toInteger()
}
log.debug "Sending configure commands - kWhCost '${kWhCost}', monitorInterval1 '${monitorInt1}', monitorInterval2 '${monitorInt2}', monitorInterval3 '${monitorInt3}'"
def request = [
// Reset switch configuration to defaults.
//zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1),
// Disable selective reporting, so always update based on schedule below <set to 1 to reduce network traffic>.
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: 1),
// (DISABLED by first option) Don't send unless watts have changed by 50 <default>.
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: 10),
// (DISABLED by first option) Or by 10% <default>.
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 5),
// Which reports need to send in Report group 1.
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 6149),
// Which reports need to send in Report group 2.
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1572872),
// Which reports need to send in Report group 3.
zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 770),
// Interval to send Report group 1.
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt1),
// Interval to send Report group 2.
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: monitorInt2),
// Interval to send Report group 3.
zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: monitorInt3),
// Report which configuration commands were sent to and received by the HEM Gen5 successfully.
zwave.configurationV1.configurationGet(parameterNumber: 3),
zwave.configurationV1.configurationGet(parameterNumber: 4),
zwave.configurationV1.configurationGet(parameterNumber: 8),
zwave.configurationV1.configurationGet(parameterNumber: 101),
zwave.configurationV1.configurationGet(parameterNumber: 102),
zwave.configurationV1.configurationGet(parameterNumber: 103),
zwave.configurationV1.configurationGet(parameterNumber: 111),
zwave.configurationV1.configurationGet(parameterNumber: 112),
zwave.configurationV1.configurationGet(parameterNumber: 113),
zwave.associationV2.associationGet(groupingIdentifier: 1)
]
commands(request)
}
private setConfigured() {
updateDataValue("configured", "true")
}
private isConfigured() {
getDataValue("configured") == "true"
}
private command(physicalgraph.zwave.Command cmd) {
if (state.sec) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}
private commands(commands, delay=500) {
delayBetween(commands.collect{ command(it) }, delay)
}

View File

@@ -0,0 +1,795 @@
/**
* 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: "#0000ff" , nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#79b821", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ffa81e"
attributeState "jammed", label: '${name}', action:"closeDoorHiI", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff0000", nextState:"Sent"
attributeState "forced close", label: 'forced\rclose', action:"openDoor", icon: "st.Outdoor.outdoor20", backgroundColor: "#ff8000", nextState:"Sent"
attributeState "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: "#0000ff", nextState:"Sent"
attributeState "opening", label: '${name}', action:"closeDoor", icon: "st.doors.garage.garage-opening", backgroundColor: "#ffa81e"
attributeState "closed", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821", nextState:"Sent"
attributeState "closing", label: '${name}', action:"openDoor", icon: "st.doors.garage.garage-closing", backgroundColor: "#ffa81e"
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: "#79b821", nextState:"Sent"
state "off", label: 'Auto', action:"autoCloseOn", icon: "st.doors.garage.garage-closing", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("autoOpen", "device.autoOpenEnable", width: 2, height: 2){
state "on", label: 'Auto', action:"autoOpenOff", icon: "st.doors.garage.garage-opening", backgroundColor: "#79b821", nextState:"Sent"
state "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:"#79b821", nextState:"Sent"
state "Sent", label: 'wait', icon: "st.motion.motion.active", backgroundColor: "#ffa81e"
}
standardTile("aux2", "device.Aux2", width: 2, height: 2, canChangeIcon: true) {
state "off", label:'Aux 2', action:"Aux2On", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"Sent"
state "on", label:'Aux 2', action:"Aux2Off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"Sent"
state "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

@@ -29,10 +29,10 @@ metadata {
tiles (scale: 2){
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"

View File

@@ -25,10 +25,10 @@ metadata {
tiles(scale: 2) {
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel", range:"(0..100)"

View File

@@ -24,6 +24,7 @@ metadata {
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3010", deviceJoinName: "NYCE Door Hinge Sensor"
fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Door/Window Sensor"
fingerprint inClusters: "0000,0001,0003,0500,0020", manufacturer: "NYCE", model: "3011", deviceJoinName: "NYCE Door/Window Sensor"
fingerprint inClusters: "0000,0001,0003,0406,0500,0020", manufacturer: "NYCE", model: "3014", deviceJoinName: "NYCE Tilt Sensor"

View File

@@ -31,6 +31,7 @@ metadata {
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Health Check"
// indicates that device keeps track of heartbeat (in state.heartbeat)
attribute "heartbeat", "string"

View File

@@ -31,6 +31,7 @@ metadata {
capability "Refresh"
capability "Temperature Measurement"
capability "Water Sensor"
capability "Health Check"
command "enrollResponse"

View File

@@ -31,6 +31,7 @@ metadata {
capability "Battery"
capability "Temperature Measurement"
capability "Refresh"
capability "Health Check"
command "enrollResponse"

View File

@@ -35,6 +35,7 @@ metadata {
capability "Acceleration Sensor"
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"

View File

@@ -23,8 +23,9 @@
capability "Acceleration Sensor"
capability "Refresh"
capability "Temperature Measurement"
command "enrollResponse"
capability "Health Check"
command "enrollResponse"
}
simulator {

View File

@@ -20,6 +20,7 @@ metadata {
capability "Refresh"
capability "Temperature Measurement"
capability "Relative Humidity Measurement"
capability "Health Check"
fingerprint endpointId: "01", inClusters: "0001,0003,0020,0402,0B05,FC45", outClusters: "0019,0003"
}

View File

@@ -80,19 +80,31 @@ metadata {
state "default", label:''
}
main("standard1")
// multi-line text (explicit newlines)
standardTile("multiLine", "device.multiLine", width: 2, height: 2) {
state "default", label: '${currentValue}'
}
standardTile("multiLineWithIcon", "device.multiLine", width: 2, height: 2) {
state "default", label: '${currentValue}', icon: "st.switches.switch.off"
}
main("actionRings")
details([
"actionRings", "actionFlat", "noActionFlat",
"flatLabel", "flatIconLabel", "flatIcon",
"flatDefaultState", "flatImplicitDefaultState1", "flatImplicitDefaultState2",
"multiLine", "multiLineWithIcon"
])
}
}
def installed() {
sendEvent(name: "switch", value: "off")
sendEvent(name: "multiLine", value: "Line 1\nLine 2\nLine 3")
}
def parse(String description) {

View File

@@ -69,16 +69,25 @@ metadata {
]
}
valueTile("noValue", "device.nada", width: 2, height: 2) {
valueTile("noValue", "device.nada", width: 4, height: 2) {
state "default", label:'${currentValue}'
}
valueTile("multiLine", "device.multiLine", width: 3, height: 2) {
state "default", label: '${currentValue}'
}
valueTile("multiLineWithIcon", "device.multiLine", width: 3, height: 2) {
state "default", label: '${currentValue}', icon: "st.switches.switch.off"
}
main("text")
details([
"text", "longText", "integer",
"integerFloat", "pi", "floatAsText",
"bgColor", "bgColorRange", "bgColorRangeSingleItem",
"bgColorRangeConflict", "noValue"
"bgColorRangeConflict", "noValue",
"multiLine", "multiLineWithIcon"
])
}
}
@@ -90,6 +99,7 @@ def installed() {
sendEvent(name: "integerFloat", value: 47.0)
sendEvent(name: "pi", value: 3.14159)
sendEvent(name: "floatAsText", value: "3.14159")
sendEvent(name: "multiLine", value: "Line 1\nLine 2\nLine 3")
}
def parse(String description) {

View File

@@ -67,14 +67,47 @@ metadata {
attributeState "VALUE_DOWN", action: "levelDown"
}
}
multiAttributeTile(name:"lengthyTile", type:"generic", width:6, height:4) {
tileAttribute("device.lengthyText", key: "PRIMARY_CONTROL") {
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821"
}
tileAttribute("device.lengthyText", key: "SECONDARY_CONTROL") {
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821"
}
}
multiAttributeTile(name:"multilineTile", type:"generic", width:6, height:4) {
tileAttribute("device.multilineText", key: "PRIMARY_CONTROL") {
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821"
}
tileAttribute("device.multilineText", key: "SECONDARY_CONTROL") {
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821"
}
}
multiAttributeTile(name:"lengthyTileWithIcon", type:"generic", width:6, height:4) {
tileAttribute("device.lengthyText", key: "PRIMARY_CONTROL") {
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
tileAttribute("device.lengthyText", key: "SECONDARY_CONTROL") {
attributeState "default", label:'The value of this tile is long and should wrap to two lines', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
}
multiAttributeTile(name:"multilineTileWithIcon", type:"generic", width:6, height:4) {
tileAttribute("device.multilineText", key: "PRIMARY_CONTROL") {
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
tileAttribute("device.multilineText", key: "SECONDARY_CONTROL") {
attributeState "default", label:'Line 1 YES\nLine 2 YES\nLine 3 NO', backgroundColor:"#79b821", icon: "st.switches.switch.on"
}
}
main(["basicTile"])
details(["basicTile", "sliderTile", "valueTile"])
details(["basicTile", "sliderTile", "valueTile", "lengthyTile", "multilineTile", "lengthyTileWithIcon", "multilineTileWithIcon"])
}
}
def installed() {
sendEvent(name: "lengthyText", value: "The value of this tile is long and should wrap to two lines")
sendEvent(name: "multilineText", value: "Line 1 YES\nLine 2 YES\nLine 3 NO")
}
def parse() {

View File

@@ -25,7 +25,10 @@ metadata {
fingerprint deviceId: "0x2001", inClusters: "0x30,0x80,0x84,0x85,0x86,0x72"
fingerprint deviceId: "0x07", inClusters: "0x30"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x98"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x86,0x72,0x98", outClusters: "0x5A,0x82"
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x80,0x71,0x85,0x70,0x72,0x86,0x30,0x31,0x84,0x59,0x73,0x5A,0x8F,0x98,0x7A", outClusters:"0x20" // Philio multi+
fingerprint deviceId: "0x0701", inClusters: "0x5E,0x72,0x5A,0x80,0x73,0x86,0x84,0x85,0x59,0x71,0x70,0x7A,0x98" // Vision door/window
}
// simulator metadata
@@ -240,7 +243,7 @@ def batteryGetCommand() {
def retypeBasedOnMSR() {
switch (state.MSR) {
case "0086-0002-002D":
log.debug("Changing device type to Z-Wave Water Sensor")
log.debug "Changing device type to Z-Wave Water Sensor"
setDeviceType("Z-Wave Water Sensor")
break
case "011F-0001-0001": // Schlage motion
@@ -249,9 +252,16 @@ def retypeBasedOnMSR() {
case "0060-0001-0002": // Everspring SP814
case "0060-0001-0003": // Everspring HSP02
case "011A-0601-0901": // Enerwave ZWN-BPC
log.debug("Changing device type to Z-Wave Motion Sensor")
log.debug "Changing device type to Z-Wave Motion Sensor"
setDeviceType("Z-Wave Motion Sensor")
break
case "013C-0002-000D": // Philio multi +
log.debug "Changing device type to 3-in-1 Multisensor Plus (SG)"
setDeviceType("3-in-1 Multisensor Plus (SG)")
break
case "0109-2001-0106": // Vision door/window
log.debug "Changing device type to Door / Window Sensor Plus (SG)"
setDeviceType("Door / Window Sensor Plus (SG)")
break
}
}

View File

@@ -0,0 +1,66 @@
/**
* Door Jammed Notification
*
* Copyright 2015 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.
*
*/
definition(
name: "Door Jammed Notification",
namespace: "JohnRucker",
author: "John.Rucker@Solar-current.com",
description: "Sends a SmartThings notification and text messages when your CoopBoss detects a door jam.",
category: "My Apps",
iconUrl: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo.png",
iconX2Url: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo2x.png",
iconX3Url: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo3x.png")
preferences {
section("When the door state changes") {
paragraph "Send a SmartThings notification when the coop's door jammed and did not close."
input "doorSensor", "capability.doorControl", title: "Select CoopBoss", required: true, multiple: false
input("recipients", "contact", title: "Recipients", description: "Send notifications to") {
input "phone", "phone", title: "Phone number?", required: true}
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
subscribe(doorSensor, "doorState", coopDoorStateHandler)
}
def coopDoorStateHandler(evt) {
if (evt.value == "jammed"){
def msg = "WARNING ${doorSensor.displayName} door is jammed and did not close!"
log.debug "WARNING ${doorSensor.displayName} door is jammed and did not close, texting $phone"
if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients)
}
else {
sendPush(msg)
if (phone) {
sendSms(phone, msg)
}
}
}
}

View File

@@ -0,0 +1,141 @@
/**
* CoopBoss Door Status to color
*
* Copyright 2015 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.
*
*/
definition(
name: "Door State to Color Light (Hue Bulb)",
namespace: "JohnRucker",
author: "John Rucker",
description: "Change the color of your Hue bulbs based on your coop's door status.",
category: "My Apps",
iconUrl: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo.png",
iconX2Url: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo2x.png",
iconX3Url: "http://coopboss.com/images/SmartThingsIcons/coopbossLogo3x.png")
preferences {
section("When the door opens/closese...") {
paragraph "Sets a Hue bulb or bulbs to a color based on your coop's door status:\r unknown = white\r open = blue\r opening = purple\r closed = green\r closing = pink\r jammed = red\r forced close = orange."
input "doorSensor", "capability.doorControl", title: "Select CoopBoss", required: true, multiple: false
input "bulbs", "capability.colorControl", title: "pick a bulb", required: true, multiple: true
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
subscribe(doorSensor, "doorState", coopDoorStateHandler)
}
def coopDoorStateHandler(evt) {
log.debug "${evt.descriptionText}, $evt.value"
def color = "White"
def hueColor = 100
def saturation = 100
Map hClr = [:]
hClr.hex = "#FFFFFF"
switch(evt.value) {
case "open":
color = "Blue"
break;
case "opening":
color = "Purple"
break;
case "closed":
color = "Green"
break;
case "closing":
color = "Pink"
break;
case "jammed":
color = "Red"
break;
case "forced close":
color = "Orange"
break;
case "unknown":
color = "White"
break;
}
switch(color) {
case "White":
hueColor = 52
saturation = 19
break;
case "Daylight":
hueColor = 53
saturation = 91
break;
case "Soft White":
hueColor = 23
saturation = 56
break;
case "Warm White":
hueColor = 20
saturation = 80 //83
break;
case "Blue":
hueColor = 70
hClr.hex = "#0000FF"
break;
case "Green":
hueColor = 39
hClr.hex = "#00FF00"
break;
case "Yellow":
hueColor = 25
hClr.hex = "#FFFF00"
break;
case "Orange":
hueColor = 10
hClr.hex = "#FF6000"
break;
case "Purple":
hueColor = 75
hClr.hex = "#BF7FBF"
break;
case "Pink":
hueColor = 83
hClr.hex = "#FF5F5F"
break;
case "Red":
hueColor = 100
hClr.hex = "#FF0000"
break;
}
//bulbs*.on()
bulbs*.setHue(hueColor)
bulbs*.setSaturation(saturation)
bulbs*.setColor(hClr)
//bulbs.each{
//it.on() // Turn the bulb on when open (this method does not come directly from the colorControl capability)
//it.setLevel(100) // Make sure the light brightness is 100%
//it.setHue(hueColor)
//it.setSaturation(saturation)
//}
}

View File

@@ -332,8 +332,7 @@ private addChildBulb(dni, hueType, name, hub, update=false, device = null) {
if (deviceType) {
return addChildDevice("smartthings", deviceType, dni, hub, ["label": name])
}
else {
} else {
log.warn "Device type $hueType not supported"
return null
}
@@ -349,8 +348,10 @@ def addBulbs() {
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
if (newHueBulb != null) {
d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub)
log.debug "created ${d.displayName} with id $dni"
d.refresh()
if (d) {
log.debug "created ${d.displayName} with id $dni"
d.refresh()
}
} else {
log.debug "$dni in not longer paired to the Hue Bridge or ID changed"
}
@@ -358,7 +359,7 @@ def addBulbs() {
//backwards compatable
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
d.refresh()
d?.refresh()
}
} else {
log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'"
@@ -824,7 +825,7 @@ def setColor(childDevice, huesettings) {
value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
}
value.alert = huesettings.alert ? huesettings.alert : "none"
value.transition = huesettings.transition ? huesettings.transition : 4
value.transitiontime = huesettings.transitiontime ? huesettings.transitiontime : 4
// Make sure to turn off light if requested
if (huesettings.switch == "off")

View File

@@ -236,23 +236,22 @@ def addSwitches() {
d = getChildDevices()?.find {
it.deviceNetworkId == selectedSwitch.value.mac || it.device.getDataValue("mac") == selectedSwitch.value.mac
}
}
if (!d) {
log.debug "Creating WeMo Switch with dni: ${selectedSwitch.value.mac}"
d = addChildDevice("smartthings", "Wemo Switch", selectedSwitch.value.mac, selectedSwitch?.value.hub, [
"label": selectedSwitch?.value?.name ?: "Wemo Switch",
"data": [
"mac": selectedSwitch.value.mac,
"ip": selectedSwitch.value.ip,
"port": selectedSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
if (!d) {
log.debug "Creating WeMo Switch with dni: ${selectedSwitch.value.mac}"
d = addChildDevice("smartthings", "Wemo Switch", selectedSwitch.value.mac, selectedSwitch?.value.hub, [
"label": selectedSwitch?.value?.name ?: "Wemo Switch",
"data": [
"mac": selectedSwitch.value.mac,
"ip": selectedSwitch.value.ip,
"port": selectedSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
}
}
}
}
@@ -267,23 +266,22 @@ def addMotions() {
d = getChildDevices()?.find {
it.deviceNetworkId == selectedMotion.value.mac || it.device.getDataValue("mac") == selectedMotion.value.mac
}
}
if (!d) {
log.debug "Creating WeMo Motion with dni: ${selectedMotion.value.mac}"
d = addChildDevice("smartthings", "Wemo Motion", selectedMotion.value.mac, selectedMotion?.value.hub, [
"label": selectedMotion?.value?.name ?: "Wemo Motion",
"data": [
"mac": selectedMotion.value.mac,
"ip": selectedMotion.value.ip,
"port": selectedMotion.value.port
]
])
def ipvalue = convertHexToIP(selectedMotion.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
if (!d) {
log.debug "Creating WeMo Motion with dni: ${selectedMotion.value.mac}"
d = addChildDevice("smartthings", "Wemo Motion", selectedMotion.value.mac, selectedMotion?.value.hub, [
"label": selectedMotion?.value?.name ?: "Wemo Motion",
"data": [
"mac": selectedMotion.value.mac,
"ip": selectedMotion.value.ip,
"port": selectedMotion.value.port
]
])
def ipvalue = convertHexToIP(selectedMotion.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "Created ${d.displayName} with id: ${d.id}, dni: ${d.deviceNetworkId}"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
}
}
}
}
@@ -298,23 +296,22 @@ def addLightSwitches() {
d = getChildDevices()?.find {
it.deviceNetworkId == selectedLightSwitch.value.mac || it.device.getDataValue("mac") == selectedLightSwitch.value.mac
}
}
if (!d) {
log.debug "Creating WeMo Light Switch with dni: ${selectedLightSwitch.value.mac}"
d = addChildDevice("smartthings", "Wemo Light Switch", selectedLightSwitch.value.mac, selectedLightSwitch?.value.hub, [
"label": selectedLightSwitch?.value?.name ?: "Wemo Light Switch",
"data": [
"mac": selectedLightSwitch.value.mac,
"ip": selectedLightSwitch.value.ip,
"port": selectedLightSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedLightSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "created ${d.displayName} with id $dni"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
if (!d) {
log.debug "Creating WeMo Light Switch with dni: ${selectedLightSwitch.value.mac}"
d = addChildDevice("smartthings", "Wemo Light Switch", selectedLightSwitch.value.mac, selectedLightSwitch?.value.hub, [
"label": selectedLightSwitch?.value?.name ?: "Wemo Light Switch",
"data": [
"mac": selectedLightSwitch.value.mac,
"ip": selectedLightSwitch.value.ip,
"port": selectedLightSwitch.value.port
]
])
def ipvalue = convertHexToIP(selectedLightSwitch.value.ip)
d.sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP is ${ipvalue}")
log.debug "created ${d.displayName} with id $dni"
} else {
log.debug "found ${d.displayName} with id $dni already exists"
}
}
}
}