Compare commits

..

22 Commits

Author SHA1 Message Date
William Gabor
38ee1bd866 MSA-1716: Gideon 2017-01-18 08:01:08 -08:00
Vinay Rao
5ad20fbd2a Merge pull request #1584 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2017-01-10 16:08:36 -08:00
Vinay Rao
076ffecd19 Merge pull request #1582 from SmartThingsCommunity/production
Rolling down production hotfix to staging
2017-01-10 15:00:27 -08:00
Duncan McKee
52357e4c50 Merge pull request #1580 from SmartThingsCommunity/DEVC-533
Add fingerprint for GE Smart Motion Sensor DEVC-533
2017-01-10 16:40:43 -05:00
Duncan McKee
f969027191 Add fingerprint for GE Smart Motion Sensor DEVC-533 2017-01-10 12:55:13 -05:00
Vinay Rao
8db0556696 Merge pull request #1562 from varzac/increase-delays
DPROT-223 Increase zigbee message delays
2017-01-10 09:35:46 -08:00
Juan Pablo Risso
5607a3e346 DVCSMP-2309 - Wemo Exceptions (#1579) 2017-01-10 12:29:53 -05:00
Vinay Rao
490ec329cb Merge pull request #1570 from workingmonk/feature/iris_button
DEVC-520 DEVC-525 Adding Iris Button after clearing certification
2017-01-06 09:34:49 -08:00
Vinay Rao
3109049122 Merge pull request #1569 from workingmonk/feature/certification_work
DEVC-518 Iris Smart Water Sensor
2017-01-06 09:34:25 -08:00
Zach Varberg
930c4ed914 Increase zigbee message delays
This changes our smartsense DTHs that don't use the ZigBee library for
everything to have larger delays between ZigBee messages.  This is to
reduce the network load to try to work around some of the poorer
behaving ZigBee routers we support.

This resolves: https://smartthings.atlassian.net/browse/DPROT-223
2017-01-06 10:45:13 -06:00
Vinay Rao
259516f21f DEVC-520 DEVC-525 Adding Iris Button after clearing certification 2017-01-05 16:54:46 -08:00
Vinay Rao
b7a08a88e0 DEVC-518 Iris Smart Water Sensor 2017-01-05 16:41:50 -08:00
Jack Chi
c028515fcd Merge pull request #1546 from skt123/dimmer_switch
[CHF-487] Health Check for Z-Wave Dimmer Switch
2016-12-29 10:29:43 -08:00
Jack Chi
751c98d123 Merge pull request #1550 from parijatdas/enerwave
[CHF-488] [CHF-489] [CHF-490] Implementation of HealthCheck for Enerwave Duplex Receptacle ZW15R, Enerwave On/Off Switch ZW15S and Leviton 15A Switch VRS15-1LZ
2016-12-29 10:27:18 -08:00
Jack Chi
5b874e8f3a Merge pull request #1545 from pchomal/dimmerswitch_generic
[CHF-477] Health Check for Z-Wave Dimmer Switch Generic
2016-12-27 11:36:51 -08:00
Parijat Das
9e10405527 Added fingerprints for the following devices:
1. Enerwave Duplex Receptacle ZW15R
2. Enerwave On/Off Switch ZW15S
3. Leviton 15A Switch VRS15-1LZ
2016-12-20 18:33:50 +05:30
sushant.k1
32ceaff54d [CHF-487]
Added Health Check Implementation for:
1. 1,000-Watt In-Wall Smart Dimmer Switch (GE 12725)
2. In-Wall Smart Fan Control (GE 12730)
2016-12-20 12:08:16 +05:30
piyush.c
5b1da30a47 [CHF-477]
Health Check implementation for Z-Wave Dimmer Switch Generic with checkinterval of 32min
2016-12-20 10:39:08 +05:30
bflorian
76e139153a Merge pull request #1532 from tslagle13/fix-color-coordinator-NPE
[DVCSMP-2273] Fix for NPE for slave/master settings
2016-12-15 17:11:01 -05:00
tslagle13
a4bc248006 One further fix for NPEs 2016-12-14 11:40:02 -08:00
tslagle13
e7eb461b4e [DVCSMP-2273] Fix for NPE for slave/master settings 2016-12-13 14:37:49 -08:00
Vinay Rao
083ed7cc9a Merge pull request #1518 from SmartThingsCommunity/staging
Rolling up staging to prod for deploy
2016-12-07 12:41:33 -08:00
20 changed files with 656 additions and 826 deletions

View File

@@ -1,486 +0,0 @@
/**
* Qubino Weatherstation
* Device Handler
* Version 1.0
* Date: 16.12.2016
* Author: Kristjan Jamšek (Kjamsek), Goap d.o.o.
* Copyright 2016 Kristjan Jamšek
*
* 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.
*
* - DEVICE HANDLER FOR QUBINO WEATHERSTATION Z-WAVE DEVICE -
* The handler supports all unsecure functions of the Qubino Weatherstation device. Configuration parameters and
* association groups can be set in the device's preferences screen, but they are applied on the device only after
* pressing the 'Set configuration' and 'Set associations' buttons on the bottom of the details view.
*
* This device handler supports data values that are currently not implemented as capabilities, so custom attribute
* states are used. Please use a SmartApp that supports custom attribute monitoring with this device in your rules.
* By default the 'Temperature Measurement' and 'Relative Humidity Measurement' capability states are mirrored from
* the custom attribute state values 'temperatureCh1' and 'humidityCh1'.
*
* This device handler uses hubAction in configure() method in order to set a MultiChannel Lifeline association to the
* device, so reports from all endpoints can be received.
*
*
* CHANGELOG:
* 0.99: Final release code cleanup and commenting
* 1.00: Added comments to code for readability
*/
metadata {
definition (name: "Qubino Weatherstation", namespace: "Goap", author: "Kristjan Jamšek") {
capability "Configuration" //Needed for configure() function to set MultiChannel Lifeline Association Set
capability "Temperature Measurement" //Used on main tile, needed in order to have the device appear in capabilities lists, mirrors temperatureCh1 attribute states
capability "Relative Humidity Measurement" //Needed in order to have the device appear in capabilities lists, mirrors humidityCh1 attribute states
capability "Sensor" // - Tagging capability
attribute "temperatureCh1", "number" // temperature attribute for Ch1 Temperature reported by device's endpoint 1
attribute "windDirection", "number" // wind direction attribute for Wind Gauge - Direction reported by device's endpoint 2
attribute "windVelocity", "number" // wind velocity attribute for Wind Gauge - Velocity reported by device's endpoint 3
attribute "windGust", "number" // wind gust velocity attribute for Wind Gauge - Wind gust reported by device's endpoint 4
attribute "windTemperature", "number" // wind temperature attribute for Wind Gauge - Temperature reported by device's endpoint 5
attribute "windChillTemperature", "number" // wind chill temperature attribute for Wind Gauge - Wind Chill reported by device's endpoint 6
attribute "rainRate", "number" // rain rate attribute for Rain Sensor data reported by device's endpoint 7
attribute "humidityCh1", "number" // humidity attribute for Ch1 Humidity reported by device's endpoint 8
attribute "temperatureCh2", "number" // temperature attribute for Ch2 Temperature reported by device's endpoint 9
attribute "humidityCh2", "number" // humidity attribute for Ch2 Humidity reported by device's endpoint 10
attribute "setConfigParams", "string" // attribute for tile element for setConfigurationParams command
attribute "setAssocGroups", "string" // attribute for tile element for setAssociations command
command "setConfigurationParams" // command to issue Configuration Set command sequence according to user's preferences
command "setAssociations" // command to issue Association Set command sequence according to user's preferences
fingerprint mfr:"0159", prod:"0007", model:"0053" //Manufacturer Information values for Qubino Weatherstation
}
simulator {
// TESTED WITH PHYSICAL DEVICE - UNNEEDED
}
tiles(scale: 2) {
valueTile("temperature", "device.temperature") {
state("temperature", label:'${currentValue} °', unit:"°", icon: "st.Weather.weather2", backgroundColors: [
// Celsius Color Range
[value: 0, color: "#153591"],
[value: 7, color: "#1e9cbb"],
[value: 15, color: "#90d2a7"],
[value: 23, color: "#44b621"],
[value: 29, color: "#f1d801"],
[value: 33, color: "#d04e00"],
[value: 36, color: "#bc2323"],
// Fahrenheit Color Range
[value: 40, color: "#153591"],
[value: 44, color: "#1e9cbb"],
[value: 59, color: "#90d2a7"],
[value: 74, color: "#44b621"],
[value: 84, color: "#f1d801"],
[value: 92, color: "#d04e00"],
[value: 96, color: "#bc2323"]
])
}
valueTile("humidity", "device.humidity") {
state("humidity", label:'${currentValue} %', unit:"%", display:false)
}
standardTile("temperatureCh1", "device.temperatureCh1", width: 3, height: 3) {
state("temperatureCh1", label:'Temperature Ch1: ${currentValue} °', unit:'°', icon: 'st.Weather.weather2')
}
standardTile("windDirection", "device.windDirection", width: 3, height: 3) {
state("windDirection", label:'Wind Direction: ${currentValue} °', unit: "°", icon: 'st.Outdoor.outdoor20')
}
standardTile("windVelocity", "device.windVelocity", width: 3, height: 3) {
state("windVelocity", label:'Wind Velocity: ${currentValue} m/s', unit:"m/s", icon: 'st.Weather.weather1')
}
standardTile("windGust", "device.windGust", width: 3, height: 3) {
state("windGust", label:'Wind Gust: ${currentValue} m/s', unit:"m/s", icon: 'st.Weather.weather1')
}
standardTile("windTemperature", "device.windTemperature", width: 3, height: 3) {
state("windTemperature", label:'Wind Temperature: ${currentValue} °', unit:'°', icon: 'st.Weather.weather2')
}
standardTile("windChillTemperature", "device.windChillTemperature", width: 3, height: 3) {
state("windChillTemperature", label:'Wind Chill: ${currentValue} °', unit:'°', icon: 'st.Weather.weather2')
}
standardTile("rainRate", "device.rainRate", width: 3, height: 3) {
state("rainRate", label:'Rain Sensor: ${currentValue} mm/h', unit:"mm/h", icon: 'st.Weather.weather10')
}
standardTile("humidityCh1", "device.humidityCh1", width: 3, height: 3) {
state("humidityCh1", label:'Humidity Ch1: ${currentValue} %', unit:"%", icon: 'st.Weather.weather12')
}
standardTile("temperatureCh2", "device.temperatureCh2", width: 3, height: 3) {
state("temperatureCh2", label:'Temperature Ch2: ${currentValue} °', unit:'°', icon: 'st.Weather.weather2')
}
standardTile("humidityCh2", "device.humidityCh2", width: 3, height: 3) {
state("humidityCh2", label:'Humidity Ch2: ${currentValue} %', unit:"%", icon: 'st.Weather.weather12')
}
standardTile("setConfigParams", "device.setConfigParams", decoration: "flat", width: 3, height: 3) {
state("setConfigParams", label:'Set configuration', action:'setConfigurationParams', icon: "st.secondary.tools")
}
standardTile("setAssocGroups", "device.setAssocGroups", decoration: "flat", width: 3, height: 3) {
state("setAssocGroups", label:'Set associations', action:'setAssociations', icon: "st.secondary.tools")
}
main("temperature")
details(["temperatureCh1", "humidityCh1", "windDirection", "windVelocity", "windGust", "windTemperature", "windChillTemperature", "rainRate", "temperatureCh2", "humidityCh2", "setConfigParams", "setAssocGroups"])
}
preferences {
/**
* -------- CONFIGURATION PARAMETER SECTION --------
*/
input name: "param1", type: "number", range: "0..8800", required: false,
title: "1. Wind Gauge, Wind Gust Top Value. " +
"If the Wind Gust is higher than the parameter value, the device triggers an association.\n" +
"Available settings:\n" +
"0 ... 8800 = value from 0,00 m/s to 88,00 m/s,\n" +
"Default value: 1000 (10,00 m/s)."
input name: "param2", type: "number", range: "0..30000", required: false,
title: "2. Rain Gauge, Rain Rate Top Value. " +
"If the Rain Sensor Rain Rate is higher than the parameter value, the device triggers an association.\n" +
"Available settings:\n" +
"0 ... 30000 = value from 0,00 mm/h to 300,00 mm/h,\n" +
"Default value: 200 (2,00 mm/h)."
input name: "param3", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "3. Wind Gauge, Wind Gust. " +
"Available settings:\n" +
"0 = If the Wind Gust is higher than the parameter number 1 value, then the device sends a Basic Set 0x00,\n" +
"1 = If the Wind Gust is higher than the parameter number 1 value, then the device sends a Basic Set 0xFF,\n" +
"Default value: 1."
input name: "param4", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "4. Rain Gauge, Rain Rate. " +
"Available settings:\n" +
"0 = If the Rain Rate is higher than the parameter number 2 value, then the device sends a Basic Set 0x00,\n" +
"1 = If the Rain Rate is higher than the parameter number 2 value, then the device sends a Basic Set 0xFF,\n" +
"Default value: 1."
input name: "param5", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "5. Endpoint 1 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param6", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "6. Endpoint 2 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param7", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "7. Endpoint 3 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param8", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "8. Endpoint 4 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param9", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "9. Endpoint 5 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param10", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "10. Endpoint 6 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param11", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "11. Endpoint 7 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param12", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "12. Endpoint 8 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param13", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "13. Endpoint 9 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param14", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "14. Endpoint 10 - Unsolicited Report enable/disable. " +
"Available settings:\n" +
"0 = Unsolicited Report disabled,\n" +
"1 = Unsolicited Report enabled,\n" +
"Default value: 1."
input name: "param15", type: "enum", required: false,
options: ["0" : "0",
"1" : "1"],
title: "15. Random ID enable/disable " +
"Available settings:\n" +
"0 = Random ID disabled,\n" +
"1 = Random ID enabled,\n" +
"Default value: 0."
/**
* -------- ASSOCIATION GROUP SECTION --------
*/
input name: "assocGroup2", type: "text", required: false,
title: "Association group 2: \n" +
"Basic On/Off command will be sent to associated nodes when the Wind Gust of the Wind Gauge exceeds the Configuration parameter 1 value. \n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
input name: "assocGroup3", type: "text", required: false,
title: "Association group 3: \n" +
"Basic On/Off command will be sent to associated nodes when the Rain Rate exceeds the Configuration parameter 2 value. \n" +
"NOTE: Insert the node Id value of the devices you wish to associate this group with. Multiple nodeIds can also be set at once by separating individual values by a comma (2,3,...)."
}
}
/**
* -------- HELPER METHODS SECTION --------
*/
/**
* Converts a list of String type node id values to Integer type.
*
* @param stringList - a list of String type node id values.
* @return stringList - a list of Integer type node id values.
*/
def convertStringListToIntegerList(stringList){
for(int i=0;i<stringList.size();i++){
stringList[i] = stringList[i].toInteger()
}
return stringList
}
/**
* Converts temperature values to fahrenheit or celsius scales accordign to user's setting.
*
* @param scaleParam user set scale parameter.
* @param encapCmd received temperature parsed value.
* @return String type value of the converted temperature value.
*/
def convertDegrees(scaleParam, encapCmd){
switch (scaleParam) {
default:
break;
case "F":
if(encapCmd.scale == 1){
return encapCmd.scaledSensorValue.toString()
}else{
return (encapCmd.scaledSensorValue * 9 / 5 + 32).toString()
}
break;
case "C":
if(encapCmd.scale == 0){
return encapCmd.scaledSensorValue.toString()
}else{
return (encapCmd.scaledSensorValue * 9 / 5 + 32).toString()
}
break;
}
}
/*
* -------- HANDLE COMMANDS SECTION --------
*/
/**
* Configuration capability command handler that executes after module inclusion to remove existing singlechannel association Lifeline and replace it
* with a multichannel Lifeline association setting for node id 1 and endpoint 1, which enables modules to report multichannel encapsulated frames.
*
* @param void
* @return List of commands that will be executed in sequence with 500 ms delay inbetween.
*/
def configure() {
log.debug "Qubino Weatherstation: configure()"
/** In this method we first clear the association group 1 that is set by SmartThings automatically.
* Afterwards we use physicalgraph.device.HubAction("8E0101000101") as a workaround for SmartThings' MultiChannel Association Command Class implementation,
* where we cannot set a node id and endpoint id. The hardcoded parameter "8E0101000101" should be interpreted in sequence as hexadecimal byte values:
* 8E010100 - Command class and command values, along with the field for singlechannel node id omitted
* 0101 - These two byte values represent the multichannel node id 01 followed by the endpoint id 01 (in general this value can be left as is unless
* multiple subordinated controllers are included in your network. In that case please adjust these two value to the correct id.
*/
def assocCmds = []
assocCmds << zwave.associationV1.associationRemove(groupingIdentifier:1, nodeId:zwaveHubNodeId).format()
assocCmds << new physicalgraph.device.HubAction("8E0101000101")
return delayBetween(assocCmds, 500)
}
/**
* setAssociations command handler that sets user selected association groups. In case no node id is insetred the group is instead cleared.
* Lifeline association hidden from user influence by design.
*
* @param void
* @return List of Association commands that will be executed in sequence with 500 ms delay inbetween.
*/
def setAssociations() {
log.debug "Qubino Weatherstation: setAssociations()"
def assocSet = []
if(settings.assocGroup2 != null){
def group2parsed = settings.assocGroup2.tokenize(",")
group2parsed = convertStringListToIntegerList(group2parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:2, nodeId:group2parsed).format()
}else{
assocSet << zwave.associationV1.associationRemove(groupingIdentifier:2, nodeId: 0).format()
}
if(settings.assocGroup3 != null){
def group3parsed = settings.assocGroup3.tokenize(",")
group3parsed = convertStringListToIntegerList(group3parsed)
assocSet << zwave.associationV1.associationSet(groupingIdentifier:3, nodeId:group3parsed).format()
}else{
assocSet << zwave.associationV1.associationRemove(groupingIdentifier:3, nodeId: 0).format()
}
return delayBetween(assocSet, 500)
}
/**
* setConfigurationParams command handler that sets user selected configuration parameters on the device.
* In case no value is set for a specific parameter the method skips setting that parameter.
* Secure mdoe setting hidden from user influence by design.
*
* @param void
* @return List of Configuration Set commands that will be executed in sequence with 500 ms delay inbetween.
*/
def setConfigurationParams() {
log.debug "Qubino Weatherstation: setConfigurationParams()"
def configSequence = []
if(settings.param1 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: settings.param1.toInteger()).format()
}
if(settings.param2 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 2, size: 2, scaledConfigurationValue: settings.param2.toInteger()).format()
}
if(settings.param3 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: settings.param3.toInteger()).format()
}
if(settings.param4 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 4, size: 1, scaledConfigurationValue: settings.param4.toInteger()).format()
}
if(settings.param5 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 5, size: 1, scaledConfigurationValue: settings.param5.toInteger()).format()
}
if(settings.param6 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 6, size: 1, scaledConfigurationValue: settings.param6.toInteger()).format()
}
if(settings.param7 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 7, size: 1, scaledConfigurationValue: settings.param7.toInteger()).format()
}
if(settings.param8 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: settings.param8.toInteger()).format()
}
if(settings.param9 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 9, size: 1, scaledConfigurationValue: settings.param9.toInteger()).format()
}
if(settings.param10 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: settings.param10.toInteger()).format()
}
if(settings.param11 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 11, size: 1, scaledConfigurationValue: settings.param11.toInteger()).format()
}
if(settings.param12 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 12, size: 1, scaledConfigurationValue: settings.param12.toInteger()).format()
}
if(settings.param13 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: settings.param13.toInteger()).format()
}
if(settings.param14 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 14, size: 1, scaledConfigurationValue: settings.param14.toInteger()).format()
}
if(settings.param15 != null){
configSequence << zwave.configurationV1.configurationSet(parameterNumber: 15, size: 1, scaledConfigurationValue: settings.param15.toInteger()).format()
}
return delayBetween(configSequence, 500)
}
/*
* -------- EVENT PARSER SECTION --------
*/
/**
* parse function takes care of parsing received bytes and passing them on to event methods.
*
* @param description String type value of the received bytes.
* @return Parsed result of the received bytes.
*/
def parse(String description) {
log.debug "Qubino Weatherstation: Parsing '${description}'"
def result = null
def cmd = zwave.parse(description)
if (cmd) {
result = zwaveEvent(cmd)
log.debug "Parsed ${cmd} to ${result.inspect()}"
} else {
log.debug "Non-parsed event: ${description}"
}
return result
}
/**
* Event method for MultiChannelCmdEncap encapsulation frames.
*
* @param cmd Type physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap received command.
* @return List of events that will update UI elements for data display.
*/
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1])
def tempScale = location.temperatureScale
def resultEvents = []
switch (cmd.sourceEndPoint) {
default:
break;
case 1:
resultEvents << createEvent(name:"temperatureCh1", value: convertDegrees(tempScale,encapsulatedCommand), unit:"°"+location.temperatureScale, descriptionText: "Temperature Ch1: "+convertDegrees(tempScale,encapsulatedCommand)+"°"+location.temperatureScale)
resultEvents << createEvent(name:"temperature", value: convertDegrees(tempScale,encapsulatedCommand), unit:"°"+location.temperatureScale, descriptionText: "Temperature Ch1: "+convertDegrees(tempScale,encapsulatedCommand)+"°"+location.temperatureScale, displayed: false)
break;
case 2:
resultEvents << createEvent(name:"windDirection", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"°", descriptionText: "Wind Direction: "+encapsulatedCommand.scaledSensorValue.toString()+" °")
break;
case 3:
resultEvents << createEvent(name:"windVelocity", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"m/s", descriptionText: "Wind Velocity: "+encapsulatedCommand.scaledSensorValue.toString()+" m/s")
break;
case 4:
resultEvents << createEvent(name:"windGust", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"m/s", descriptionText: "Wind Gust: "+encapsulatedCommand.scaledSensorValue.toString()+" m/s")
break;
case 5:
resultEvents << createEvent(name:"windTemperature", value: convertDegrees(tempScale,encapsulatedCommand), unit:"°"+location.temperatureScale, descriptionText: "Wind Temperature: "+convertDegrees(tempScale,encapsulatedCommand)+" °"+location.temperatureScale)
break;
case 6:
resultEvents << createEvent(name:"windChillTemperature", value: convertDegrees(tempScale,encapsulatedCommand), unit:"°"+location.temperatureScale, descriptionText: "Wind Chill: "+convertDegrees(tempScale,encapsulatedCommand)+" °"+location.temperatureScale)
break;
case 7:
resultEvents << createEvent(name:"rainRate", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"mm/h", descriptionText: "Rain Sensor: "+encapsulatedCommand.scaledSensorValue.toString()+" mm/h")
break;
case 8:
resultEvents << createEvent(name:"humidity", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"%", descriptionText: "Humidity Ch1: "+encapsulatedCommand.scaledSensorValue.toString()+" %", displayed: false)
resultEvents << createEvent(name:"humidityCh1", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"%", descriptionText: "Humidity Ch1: "+encapsulatedCommand.scaledSensorValue.toString()+" %")
break;
case 9:
resultEvents << createEvent(name:"temperatureCh2", value: convertDegrees(tempScale,encapsulatedCommand), unit:"°"+location.temperatureScale, descriptionText: "Temperature Ch2: "+convertDegrees(tempScale,encapsulatedCommand)+" °"+location.temperatureScale)
break;
case 10:
resultEvents << createEvent(name:"humidityCh2", value: encapsulatedCommand.scaledSensorValue.toString(), unit:"%", descriptionText: "Humidity Ch2: "+encapsulatedCommand.scaledSensorValue.toString()+" %")
break;
}
return resultEvents
}

View File

@@ -22,9 +22,10 @@ metadata {
capability "Sensor"
capability "Health Check"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "Z-Wave Wall Dimmer"
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "Z-Wave Plug-In Dimmer"
fingerprint mfr:"0063", prod:"4457", deviceJoinName: "GE In-Wall Smart Dimmer "
fingerprint mfr:"0063", prod:"4944", deviceJoinName: "GE In-Wall Smart Dimmer "
fingerprint mfr:"0063", prod:"5044", deviceJoinName: "GE Plug-In Smart Dimmer "
fingerprint mfr:"0063", prod:"4944", model:"3034", deviceJoinName: "GE In-Wall Smart Fan Control"
}
simulator {

View File

@@ -99,7 +99,7 @@ def parse(String description) {
def poll() {
def refreshCmds = [
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 500"
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 2000"
]
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh()
@@ -197,7 +197,7 @@ def off() {
def refresh() {
def refreshCmds = [
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 500"
"st wattr 0x${device.deviceNetworkId} 1 8 0x10 0x21 {${state?.dOnOff ?: '0000'}}", "delay 2000"
]
return refreshCmds + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.onOffConfig()

View File

@@ -128,9 +128,9 @@ def setLevel(value) {
def refresh() {
[
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 500",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0B04 0x050B", "delay 500"
"st rattr 0x${device.deviceNetworkId} ${endpointId} 6 0", "delay 2000",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 8 0", "delay 2000",
"st rattr 0x${device.deviceNetworkId} ${endpointId} 0x0B04 0x050B", "delay 2000"
]
}
@@ -313,9 +313,9 @@ def isDescriptionPower(descMap) {
def onOffConfig() {
[
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 6 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 6 0 0x10 0 600 {01}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 6 {${device.zigbeeId}} {}", "delay 2000",
"zcl global send-me-a-report 6 0 0x10 0 600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
]
}
@@ -323,9 +323,9 @@ def onOffConfig() {
//min level change is 01
def levelConfig() {
[
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 8 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 8 0 0x20 5 3600 {01}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 8 {${device.zigbeeId}} {}", "delay 2000",
"zcl global send-me-a-report 8 0 0x20 5 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
]
}
@@ -333,9 +333,10 @@ def levelConfig() {
//min change in value is 05
def powerConfig() {
[
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 2000",
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
"delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
]
}
@@ -344,7 +345,10 @@ def setLevelWithRate(level, rate) {
rate = "0000"
}
level = convertToHexString(level * 255 / 100) //Converting the 0-100 range to 0-FF range in hex
"st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {$level $rate}"
[
"st cmd 0x${device.deviceNetworkId} ${endpointId} 8 4 {$level $rate}",
"delay 2000"
]
}
String convertToHexString(value, width=2) {

View File

@@ -51,7 +51,7 @@ def on() {
'zcl on-off on',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
'delay 2000'
]
@@ -62,6 +62,6 @@ def off() {
'zcl on-off off',
'delay 200',
"send 0x${zigbee.deviceNetworkId} 0x01 0x${zigbee.endpointId}",
'delay 500'
'delay 2000'
]
}

View File

@@ -157,9 +157,10 @@ def configure() {
//min change in value is 01
def powerConfig() {
[
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 2000",
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
"delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000"
]
}

View File

@@ -29,9 +29,10 @@ metadata {
command "enrollResponse"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S", deviceJoinName: "Water Leak Sensor"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu", deviceJoinName: "Water Leak Sensor"
fingerprint inClusters: "0000,0001,0003,0020,0402,0500,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-L", deviceJoinName: "Iris Smart Water Sensor"
fingerprint inClusters: "0000,0001,0003,000F,0020,0402,0500", outClusters: "0019", manufacturer: "SmartThings", model: "moisturev4", deviceJoinName: "Water Leak Sensor"
}
@@ -285,8 +286,8 @@ def ping() {
def refresh() {
log.debug "Refreshing Temperature and Battery"
def refreshCmds = [
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
]
return refreshCmds + enrollResponse()
@@ -308,10 +309,10 @@ def enrollResponse() {
[
//Resending the CIE in case the enroll request is sent before CIE is written
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000",
//Enroll Response
"raw 0x500 {01 23 00 00 00}",
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
]
}

View File

@@ -298,8 +298,8 @@ def ping() {
def refresh() {
log.debug "refresh called"
def refreshCmds = [
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
]
return refreshCmds + enrollResponse()
@@ -321,10 +321,10 @@ def enrollResponse() {
[
//Resending the CIE in case the enroll request is sent before CIE is written
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000",
//Enroll Response
"raw 0x500 {01 23 00 00 00}",
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
]
}

View File

@@ -428,10 +428,10 @@ def enrollResponse() {
[
//Resending the CIE in case the enroll request is sent before CIE is written
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000",
//Enroll Response
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
]
}

View File

@@ -252,8 +252,8 @@ def ping() {
def refresh() {
log.debug "Refreshing Temperature and Battery"
def refreshCmds = [
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 2000",
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 2000"
]
return refreshCmds + enrollResponse()
@@ -277,10 +277,10 @@ def enrollResponse() {
[
//Resending the CIE in case the enroll request is sent before CIE is written
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 2000",
//Enroll Response
"raw 0x500 {01 23 00 00 00}",
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
]
}

View File

@@ -270,9 +270,9 @@ def configure() {
log.debug "Configuring Reporting and Bindings."
def humidityConfigCmds = [
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 2000",
"zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 2000"
]
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity

View File

@@ -86,7 +86,7 @@ def parse(String description) {
def bodyString = msg.body
if (bodyString) {
unschedule("setOffline")
def body = new XmlSlurper().parseText(bodyString)
def body = new XmlSlurper().parseText(bodyString.replaceAll("[^\\x20-\\x7e]", ""))
if (body?.property?.TimeSyncRequest?.text()) {
log.trace "Got TimeSyncRequest"

View File

@@ -78,7 +78,7 @@ def parse(String description) {
def bodyString = msg.body
if (bodyString) {
unschedule("setOffline")
def body = new XmlSlurper().parseText(bodyString)
def body = new XmlSlurper().parseText(bodyString.replaceAll("[^\\x20-\\x7e]", ""))
if (body?.property?.TimeSyncRequest?.text()) {
log.trace "Got TimeSyncRequest"
result << timeSyncResponse()

View File

@@ -84,7 +84,7 @@ def parse(String description) {
def bodyString = msg.body
if (bodyString) {
unschedule("setOffline")
def body = new XmlSlurper().parseText(bodyString)
def body = new XmlSlurper().parseText(bodyString.replaceAll("[^\\x20-\\x7e]", ""))
if (body?.property?.TimeSyncRequest?.text()) {
log.trace "Got TimeSyncRequest"
result << timeSyncResponse()
@@ -208,7 +208,7 @@ def subscribe(ip, port) {
def existingIp = getDataValue("ip")
def existingPort = getDataValue("port")
if (ip && ip != existingIp) {
log.debug "Updating ip from $existingIp to $ip"
log.debug "Updating ip from $existingIp to $ip"
updateDataValue("ip", ip)
def ipvalue = convertHexToIP(getDataValue("ip"))
sendEvent(name: "currentIP", value: ipvalue, descriptionText: "IP changed to ${ipvalue}")
@@ -291,4 +291,4 @@ User-Agent: CyberGarage-HTTP/1.0
</u:GetBinaryState>
</s:Body>
</s:Envelope>""", physicalgraph.device.Protocol.LAN)
}
}

View File

@@ -28,8 +28,8 @@ metadata {
fingerprint inClusters: "0000, 0001, 0003, 0020, 0402, 0B05", outClusters: "0003, 0006, 0008, 0019", manufacturer: "OSRAM", model: "LIGHTIFY Dimming Switch", deviceJoinName: "OSRAM LIGHTIFY Dimming Switch"
//fingerprint inClusters: "0000, 0001, 0003, 0020, 0500", outClusters: "0003,0019", manufacturer: "CentraLite", model: "3455-L", deviceJoinName: "Iris Care Pendant"
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Smart Button"
//fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris KeyFob"
fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0402, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model: "3460-L", deviceJoinName: "Iris Smart Button"
fingerprint inClusters: "0000, 0001, 0003, 0007, 0020, 0B05", outClusters: "0003, 0006, 0019", manufacturer: "CentraLite", model:"3450-L", deviceJoinName: "Iris KeyFob"
}
simulator {}

View File

@@ -24,6 +24,10 @@ metadata {
fingerprint inClusters: "0x26", deviceJoinName: "Z-Wave Dimmer"
fingerprint mfr:"001D", prod:"1902", deviceJoinName: "Z-Wave Dimmer"
fingerprint mfr:"001D", prod:"1B03", model:"0334", deviceJoinName: "Leviton Universal Dimmer"
fingerprint mfr:"011A", prod:"0102", model:"0201", deviceJoinName: "Enerwave In-Wall Dimmer"
fingerprint mfr:"001D", prod:"1001", model:"0334", deviceJoinName: "Leviton 3-Speed Fan Controller"
fingerprint mfr:"001D", prod:"0602", model:"0334", deviceJoinName: "Leviton Magnetic Low Voltage Dimmer"
fingerprint mfr:"001D", prod:"0401", model:"0334", deviceJoinName: "Leviton 600W Incandescent Dimmer"
}
simulator {

View File

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

View File

@@ -25,6 +25,9 @@ metadata {
fingerprint mfr:"0063", prod:"4F50", model:"3031", deviceJoinName: "GE Plug-in Outdoor Switch"
fingerprint mfr:"001D", prod:"1D04", model:"0334", deviceJoinName: "Leviton Outlet"
fingerprint mfr:"001D", prod:"1C02", model:"0334", deviceJoinName: "Leviton Switch"
fingerprint mfr:"001D", prod:"0301", model:"0334", deviceJoinName: "Leviton 15A Switch"
fingerprint mfr:"011A", prod:"0101", model:"0102", deviceJoinName: "Enerwave On/Off Switch"
fingerprint mfr:"011A", prod:"0101", model:"0603", deviceJoinName: "Enerwave Duplex Receptacle"
}
// simulator metadata

View File

@@ -1,253 +1,547 @@
/**
* Gideon
*
* Copyright 2016 Nicola Russo
*
* 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: "Gideon",
namespace: "gideon.api",
author: "Braindrain Solutions",
description: "Gideon AI Smart app allows you to connect and control all of your SmartThings devices through the Gideon AI app, making your SmartThings devices even smarter.",
category: "Family",
iconUrl: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX2Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX3Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
oauth: [displayName: "Gideon AI API", displayLink: "gideon.ai"])
preferences {
section("Control these switches...") {
input "switches", "capability.switch", multiple:true
}
section("Control these motion sensors...") {
input "motions", "capability.motionSensor", multiple:true
}
section("Control these presence sensors...") {
input "presence_sensors", "capability.presenceSensor", multiple:true
}
section("Control these outlets...") {
input "outlets", "capability.switch", multiple:true
}
section("Control these locks...") {
input "locks", "capability.lock", multiple:true
}
section("Control these locks...") {
input "temperature_sensors", "capability.temperatureMeasurement"
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
// TODO: subscribe to attributes, devices, locations, etc.
subscribe(outlet, "energy", outletHandler)
subscribe(outlet, "switch", outletHandler)
}
// TODO: implement event handlers
def outletHandler(evt) {
log.debug "$outlet.currentEnergy"
//TODO call G API
}
private device(it, type) {
it ? [id: it.id, label: it.label, type: type] : null
}
//API Mapping
mappings {
path("/getalldevices") {
action: [
GET: "getAllDevices"
]
}
path("/doorlocks/:id/:command") {
action: [
GET: "updateDoorLock"
]
}
path("/doorlocks/:id") {
action: [
GET: "getDoorLockStatus"
]
}
path("/tempsensors/:id") {
action: [
GET: "getTempSensorsStatus"
]
}
path("/presences/:id") {
action: [
GET: "getPresenceStatus"
]
}
path("/motions/:id") {
action: [
GET: "getMotionStatus"
]
}
path("/outlets/:id") {
action: [
GET: "getOutletStatus"
]
}
path("/outlets/:id/:command") {
action: [
GET: "updateOutlet"
]
}
path("/switches/:command") {
action: [
PUT: "updateSwitch"
]
}
}
//API Methods
def getAllDevices() {
def locks_list = locks.collect{device(it,"Lock")}
def presences_list = presence_sensors.collect{device(it,"Presence")}
def motions_list = motions.collect{device(it,"Motion")}
def outlets_list = outlets.collect{device(it,"Outlet")}
def switches_list = switches.collect{device(it,"Switch")}
def temp_list = temperature_sensors.collect{device(it,"Temperature")}
return [Locks: locks_list, Presences: presences_list, Motions: motions_list, Outlets: outlets_list, Switches: switches_list, Temperatures: temp_list]
}
//LOCKS
def getDoorLockStatus() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('lock')]
}
}
def updateDoorLock() {
def command = params.command
def device = locks.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
if(command == "toggle")
{
if(device.currentValue('lock') == "locked")
device.unlock();
else
device.lock();
return [Device_id: params.id, result_action: "200"]
}
}
}
}
//PRESENCE
def getPresenceStatus() {
def device = presence_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('presence')]
}
}
//MOTION
def getMotionStatus() {
def device = motions.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('motion')]
}
}
//OUTLET
def getOutletStatus() {
def device = outlets.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentSwitch, Current_watt: device.currentValue("energy")]
}
}
def updateOutlet() {
def command = params.command
def device = outlets.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
if(command == "toggle")
{
if(device.currentSwitch == "on")
device.off();
else
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
}
}
//SWITCH
def updateSwitch() {
def command = params.command
def device = switches.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
if(command == "toggle")
{
if(device.currentSwitch == "on")
device.off();
else
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
}
}
//TEMPERATURE
def getTempSensorsStatus() {
def device = temperature_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('temperature')]
}
}
/**
* Gideon
*
* Copyright 2016 Nicola Russo
*
* 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: "Gideon",
namespace: "gideon.api",
author: "Braindrain Solutions ltd",
description: "Gideon Smart Home SmartApp allows you to connect and control all of your SmartThings devices through the Gideon app, making your SmartThings devices even smarter.",
category: "Family",
iconUrl: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX2Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
iconX3Url: "http://s33.postimg.org/t77u7y7v3/logo.png",
oauth: [displayName: "Gideon Smart Home API app", displayLink: "gideon.ai"])
preferences {
section("Control these contact sensors...") {
input "contact", "capability.contactSensor", multiple:true, required:false
}
section("Control these switches...") {
input "switches", "capability.switch", multiple:true, required:false
}
section("Control these smoke alarms...") {
input "smoke_alarms", "capability.smokeDetector", multiple:true, required:false
}
section("Control these window shades...") {
input "shades", "capability.windowShade", multiple:true, required:false
}
section("Control these garage doors...") {
input "garage", "capability.garageDoorControl", multiple:true, required:false
}
section("Control these water sensors...") {
input "water_sensors", "capability.waterSensor", multiple:true, required:false
}
section("Control these motion sensors...") {
input "motions", "capability.motionSensor", multiple:true, required:false
}
section("Control these presence sensors...") {
input "presence_sensors", "capability.presenceSensor", multiple:true, required:false
}
/** section("Control these outlets...") {
input "outlets", "capability.switch", multiple:true, required:false
}
*/
section("Control these power meters...") {
input "meters", "capability.powerMeter", multiple:true, required:false
}
section("Control these locks...") {
input "locks", "capability.lock", multiple:true, required:false
}
section("Control these temperature sensors...") {
input "temperature_sensors", "capability.temperatureMeasurement", multiple:true, required:false
}
section("Control these batteries...") {
input "batteries", "capability.battery", multiple:true, required:false
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
}
private device(it, type) {
it ? [id: it.id, label: it.label, type: type] : null
}
//API Mapping
mappings {
path("/getalldevices") {
action: [
GET: "getAllDevices"
]
}
path("/doorlocks/lock/:id") {
action: [
GET: "lockDoorLock"
]
}
path("/doorlocks/unlock/:id") {
action: [
GET: "unlockDoorLock"
]
}
path("/doorlocks/:id") {
action: [
GET: "getDoorLockStatus"
]
}
path("/contacts/:id") {
action: [
GET: "getContactStatus"
]
}
path("/smoke/:id") {
action: [
GET: "getSmokeStatus"
]
}
path("/shades/open/:id") {
action: [
GET: "openShade"
]
}
path("/shades/preset/:id") {
action: [
GET: "presetShade"
]
}
path("/shades/close/:id") {
action: [
GET: "closeShade"
]
}
path("/shades/:id") {
action: [
GET: "getShadeStatus"
]
}
path("/garage/open/:id") {
action: [
GET: "openGarage"
]
}
path("/garage/close/:id") {
action: [
GET: "closeGarage"
]
}
path("/garage/:id") {
action: [
GET: "getGarageStatus"
]
}
path("/watersensors/:id") {
action: [
GET: "getWaterSensorStatus"
]
}
path("/tempsensors/:id") {
action: [
GET: "getTempSensorsStatus"
]
}
path("/meters/:id") {
action: [
GET: "getMeterStatus"
]
}
path("/batteries/:id") {
action: [
GET: "getBatteryStatus"
]
}
path("/presences/:id") {
action: [
GET: "getPresenceStatus"
]
}
path("/motions/:id") {
action: [
GET: "getMotionStatus"
]
}
/** path("/outlets/:id") {
action: [
GET: "getOutletStatus"
]
}
path("/outlets/turnon/:id") {
action: [
GET: "turnOnOutlet"
]
}
path("/outlets/turnoff/:id") {
action: [
GET: "turnOffOutlet"
]
}
*/
path("/switches/turnon/:id") {
action: [
GET: "turnOnSwitch"
]
}
path("/switches/turnoff/:id") {
action: [
GET: "turnOffSwitch"
]
}
path("/switches/:id") {
action: [
GET: "getSwitchStatus"
]
}
}
//API Methods
def getAllDevices() {
def locks_list = locks.collect{device(it,"Lock")}
def contact_list = contact.collect{device(it,"Contact Sensor")}
def smokes_list = smoke_alarms.collect{device(it,"Smoke Alarm")}
def shades_list = shades.collect{device(it,"Window Shade")}
def garage_list = garage.collect{device(it,"Garage Door")}
def water_sensors_list = water_sensors.collect{device(it,"Water Sensor")}
def presences_list = presence_sensors.collect{device(it,"Presence")}
def motions_list = motions.collect{device(it,"Motion")}
/** def outlets_list = outlets.collect{device(it,"Outlet")} */
def switches_list = switches.collect{device(it,"Switch")}
def temp_list = temperature_sensors.collect{device(it,"Temperature")}
def meters_list = meters.collect{device(it,"Power Meters")}
def battery_list = batteries.collect{device(it,"Batteries")}
return smokes_list + contact_list + water_sensors_list + shades_list + garage_list + locks_list + presences_list + motions_list + switches_list + temp_list + meters_list + battery_list
}
//contact sensors
def getContactStatus() {
def device = contact.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def args = getTempSensorsStatus(device.id)
return [Device_state: device.currentValue('contact')] + args
}
}
//smoke detectors
def getSmokeStatus() {
def device = smoke_alarms.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('smoke')] + bat
}
}
//garage
def getGarageStatus() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('door')]
}
}
def openGarage() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.open();
return [Device_id: params.id, result_action: "200"]
}
}
def closeGarage() {
def device = garage.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.close();
return [Device_id: params.id, result_action: "200"]
}
}
//shades
def getShadeStatus() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('windowShade')]
}
}
def openShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.open();
return [Device_id: params.id, result_action: "200"]
}
}
def presetShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.presetPosition();
return [Device_id: params.id, result_action: "200"]
}
}
def closeShade() {
def device = shades.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.close();
return [Device_id: params.id, result_action: "200"]
}
}
//water sensor
def getWaterSensorStatus() {
def device = water_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('water')] + bat
}
}
//batteries
def getBatteryStatus() {
def device = batteries.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.latestValue("battery")]
}
}
def getBatteryStatus(id) {
def device = batteries.find { it.id == id }
if (!device) {
return []
} else {
return [battery_state: device.latestValue("battery")]
}
}
//LOCKS
def getDoorLockStatus() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('lock')] + bat
}
}
def lockDoorLock() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.lock();
return [Device_id: params.id, result_action: "200"]
}
}
def unlockDoorLock() {
def device = locks.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
device.unlock();
return [Device_id: params.id, result_action: "200"]
}
}
//PRESENCE
def getPresenceStatus() {
def device = presence_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('presence')] + bat
}
}
//MOTION
def getMotionStatus() {
def device = motions.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def args = getTempSensorsStatus(device.id)
return [Device_state: device.currentValue('motion')] + args
}
}
//OUTLET
/**
def getOutletStatus() {
def device = outlets.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def watt = getMeterStatus(device.id)
return [Device_state: device.currentSwitch] + watt
}
}
*/
def getMeterStatus() {
def device = meters.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_id: device.id, Device_type: device.type, Current_watt: device.currentValue("power")]
}
}
def getMeterStatus(id) {
def device = meters.find { it.id == id }
if (!device) {
return []
} else {
return [Current_watt: device.currentValue("power")]
}
}
/**
def turnOnOutlet() {
def device = outlets.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
}
def turnOffOutlet() {
def device = outlets.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
}
*/
//SWITCH
def getSwitchStatus() {
def device = switches.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
return [Device_state: device.currentValue('switch')]
}
}
def turnOnSwitch() {
def device = switches.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
}
def turnOffSwitch() {
def device = switches.find { it.id == params.id }
if (command){
if (!device) {
httpError(404, "Device not found")
} else {
device.on();
return [Device_id: params.id, result_action: "200"]
}
}
}
//TEMPERATURE
def getTempSensorsStatus() {
def device = temperature_sensors.find { it.id == params.id }
if (!device) {
httpError(404, "Device not found")
} else {
def bat = getBatteryStatus(device.id)
return [Device_state: device.currentValue('temperature')] + bat
}
}
def getTempSensorsStatus(id) {
def device = temperature_sensors.find { it.id == id }
if (!device) {
return []
} else {
def bat = getBatteryStatus(device.id)
return [temperature: device.currentValue('temperature')] + bat
}
}

View File

@@ -1,10 +1,11 @@
/**
* Color Coordinator
* Version 1.1.0 - 11/9/16
* Version 1.1.1 - 11/9/16
* By Michael Struck
*
* 1.0.0 - Initial release
* 1.1.0 - Fixed issue where master can be part of slaves. This causes a loop that impacts SmartThings.
* 1.1.1 - Fix NPE being thrown for slave/master inputs being empty.
*
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
@@ -33,17 +34,17 @@ preferences {
def mainPage() {
dynamicPage(name: "mainPage", title: "", install: true, uninstall: false) {
def masterInList = slaves.id.find{it==master.id}
def masterInList = slaves?.id?.find{it==master?.id}
if (masterInList) {
section ("**WARNING**"){
paragraph "You have included the Master Light in the Slave Group. This will cause a loop in execution. Please remove this device from the Slave Group.", image: "https://raw.githubusercontent.com/MichaelStruck/SmartThingsPublic/master/img/caution.png"
}
}
section("Master Light") {
input "master", "capability.colorControl", title: "Colored Light"
input "master", "capability.colorControl", title: "Colored Light", required: true
}
section("Lights that follow the master settings") {
input "slaves", "capability.colorControl", title: "Colored Lights", multiple: true, required: false, submitOnChange: true
input "slaves", "capability.colorControl", title: "Colored Lights", multiple: true, required: true, submitOnChange: true
}
section([mobileOnly:true], "Options") {
input "randomYes", "bool",title: "When Master Turned On, Randomize Color", defaultValue: false
@@ -81,40 +82,44 @@ def init() {
}
//-----------------------------------
def onOffHandler(evt){
if (!slaves.id.find{it==master.id}){
if (master.currentValue("switch") == "on"){
if (randomYes) getRandomColorMaster()
else slaves?.on()
}
else {
slaves?.off()
}
if (slaves && master) {
if (!slaves?.id.find{it==master?.id}){
if (master?.currentValue("switch") == "on"){
if (randomYes) getRandomColorMaster()
else slaves?.on()
}
else {
slaves?.off()
}
}
}
}
def colorHandler(evt) {
if (!slaves.id.find{it==master.id} && master.currentValue("switch") == "on"){
log.debug "Changing Slave units H,S,L"
def dimLevel = master.currentValue("level")
def hueLevel = master.currentValue("hue")
def saturationLevel = master.currentValue("saturation")
def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
slaves?.setColor(newValue)
try {
log.debug "Changing Slave color temp"
def tempLevel = master.currentValue("colorTemperature")
slaves?.setColorTemperature(tempLevel)
}
catch (e){
log.debug "Color temp for master --"
}
if (slaves && master) {
if (!slaves?.id?.find{it==master?.id} && master?.currentValue("switch") == "on"){
log.debug "Changing Slave units H,S,L"
def dimLevel = master?.currentValue("level")
def hueLevel = master?.currentValue("hue")
def saturationLevel = master.currentValue("saturation")
def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
slaves?.setColor(newValue)
try {
log.debug "Changing Slave color temp"
def tempLevel = master?.currentValue("colorTemperature")
slaves?.setColorTemperature(tempLevel)
}
catch (e){
log.debug "Color temp for master --"
}
}
}
}
def getRandomColorMaster(){
def hueLevel = Math.floor(Math.random() *1000)
def saturationLevel = Math.floor(Math.random() * 100)
def dimLevel = master.currentValue("level")
def dimLevel = master?.currentValue("level")
def newValue = [hue: hueLevel, saturation: saturationLevel, level: dimLevel as Integer]
log.debug hueLevel
log.debug saturationLevel
@@ -123,12 +128,14 @@ def getRandomColorMaster(){
}
def tempHandler(evt){
if (!slaves.id.find{it==master.id} && master.currentValue("switch") == "on"){
if (evt.value != "--") {
log.debug "Changing Slave color temp based on Master change"
def tempLevel = master.currentValue("colorTemperature")
slaves?.setColorTemperature(tempLevel)
}
if (slaves && master) {
if (!slaves?.id?.find{it==master?.id} && master?.currentValue("switch") == "on"){
if (evt.value != "--") {
log.debug "Changing Slave color temp based on Master change"
def tempLevel = master.currentValue("colorTemperature")
slaves?.setColorTemperature(tempLevel)
}
}
}
}
@@ -139,7 +146,7 @@ private def textAppName() {
}
private def textVersion() {
def text = "Version 1.1.0 (11/09/2016)"
def text = "Version 1.1.1 (12/13/2016)"
}
private def textCopyright() {
@@ -166,4 +173,4 @@ private def textHelp() {
"This application will allow you to control the settings of multiple colored lights with one control. " +
"Simply choose a master control light, and then choose the lights that will follow the settings of the master, "+
"including on/off conditions, hue, saturation, level and color temperature. Also includes a random color feature."
}
}