Compare commits

..

12 Commits

Author SHA1 Message Date
John Haines
c19da1b496 MSA-1494: control smart home 2016-09-26 00:03:26 -05:00
Jason Botello
81cf1179ef Merge pull request #985 from SmartThingsCommunity/MSA-1351-2
MSA-1351: Gideon AI implementation
2016-09-23 13:38:52 -07:00
Juan Pablo Risso
79d20b0edb SSVD-2740 - Remove zipcode input (#1267)
Limit to samsungtv channel
2016-09-22 18:59:07 -04:00
twack
b6d862fdd4 Merge pull request #1283 from twack/update_generic_zigbee_for_yale
(PROD-736) Update generic zigbee lock for Yale Key-Free Deadbolt. Requested changes incorporated.
2016-09-22 14:40:30 -07:00
twack
d58084c438 Update zigbee-lock.groovy 2016-09-22 12:06:29 -07:00
Juan Pablo Risso
dbfaef3e69 DVCSMP-2076 - Async Update (#1279) 2016-09-22 14:55:25 -04:00
twack
40ed88e7fd Changed name to be consistent
Changed name to be consistent with "Yale Touch Screen Deadbolt Lock"
2016-09-22 11:34:33 -07:00
twack
1d6e22dc16 removed tabs 2016-09-22 11:23:29 -07:00
twack
1d180ac487 update generic zigbee lock for Yale Key-Free Deadbolt (PROD-736) 2016-09-22 10:19:23 -07:00
Jack Chi
71880e2644 Merge pull request #1246 from skt123/osram
CHF-356 : Modifying Readme for Core Devices
2016-09-20 14:24:27 -07:00
sushant.k1
ced03d746d Added Readme files for the following devices:
1. OSRAM Lightify LED On/Off/Dim
2. OSRAM Lightify LED RGBW
3. OSRAM Lightify Tunable 60 White

Modified Readme files for the following devices:
1. SmartSense Moisture Sensor
2. SmartSense Temp/Humidity Sensor
3. SmartSense Multi Sensor
4. SmartSense Open/closed Sensor
5. SmartPower Outlet
6. Connected Cree Bulb
7. SmartSense Motion Sensor

Added Readme files for the following devices:
1. OSRAM Lightify LED On/Off/Dim
2. OSRAM Lightify LED RGBW
3. OSRAM Lightify Tunable 60 White

Modified Readme files for the following devices:
1. SmartSense Moisture Sensor
2. SmartSense Temp/Humidity Sensor
3. SmartSense Multi Sensor
4. SmartSense Open/closed Sensor
5. SmartPower Outlet
6. Connected Cree Bulb
7. SmartSense Motion Sensor

Added Readme files for the following devices:
1. OSRAM Lightify LED On/Off/Dim
2. OSRAM Lightify LED RGBW
3. OSRAM Lightify Tunable 60 White

Modified Readme files for the following devices:
1. SmartSense Moisture Sensor
2. SmartSense Temp/Humidity Sensor
3. SmartSense Multi Sensor
4. SmartSense Open/closed Sensor
5. SmartPower Outlet
6. Connected Cree Bulb
7. SmartSense Motion Sensor

Added Readme files for the following devices:
1. OSRAM Lightify LED On/Off/Dim
2. OSRAM Lightify LED RGBW
3. OSRAM Lightify Tunable 60 White

Modified Readme files for the following devices:
1. SmartSense Moisture Sensor
2. SmartSense Temp/Humidity Sensor
3. SmartSense Multi Sensor
4. SmartSense Open/closed Sensor
5. SmartPower Outlet
6. Connected Cree Bulb
7. SmartSense Motion Sensor
2016-09-20 17:20:50 +05:30
Nicola Russo
4ad0a6fd9d MSA-1351: The Gideon AI smart app allows you to connect and control all of your smartThings devices with the Gideon AI app. Gideon AI smart app makes your smartThings device even smarter adding features like energy monitoring, vdeo surveillance history etc.. 2016-06-12 08:35:14 -05:00
27 changed files with 1379 additions and 188 deletions

View File

@@ -23,10 +23,8 @@ Works with:
## Device Health ## Device Health
A Category C6 Connected Cree LED Bulb with maxReportTime of 10 min. A Category C6 Connected Cree LED Bulb with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval = 12 mins
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*10 = 20 min
## Troubleshooting ## Troubleshooting

View File

@@ -23,10 +23,10 @@ Works with:
## Device Health ## Device Health
A Category C1 smart power outlet with maxReportTime of 10 min. A Category C1 smart power outlet with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*10 = 20 min Check-in interval = 12 mins
## Troubleshooting ## Troubleshooting

View File

@@ -23,10 +23,10 @@ Works with:
## Device Health ## Device Health
A Category C2 moisture sensor with maxReportTime of 1 hr. A Category C2 moisture sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*60 = 120 min Check-in interval = 12 mins
## Battery Specification ## Battery Specification

View File

@@ -180,9 +180,9 @@ private Map parseIasMessage(String description) {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -22,10 +22,10 @@ Works with:
## Device Health ## Device Health
A Category C2 motion sensor with maxReportTime of 1 hr. A Category C2 motion sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*60 = 120 min Check-in interval = 12 mins
## Battery Specification ## Battery Specification

View File

@@ -194,9 +194,9 @@ private Map parseIasMessage(String description) {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -26,10 +26,10 @@ Works with:
## Device Health ## Device Health
A Category C2 multi sensor with maxReportTime of 1 hr. A Category C2 multi sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*60 = 120 min Check-in interval = 12 mins
## Battery Specification ## Battery Specification

View File

@@ -261,9 +261,9 @@ def updated() {
def getTemperature(value) { def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100 def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){ if(getTemperatureScale() == "C"){
return Math.round(celsius) return celsius
} else { } else {
return Math.round(celsiusToFahrenheit(celsius)) return celsiusToFahrenheit(celsius) as Integer
} }
} }

View File

@@ -24,10 +24,10 @@ Works with:
## Device Health ## Device Health
A Category C2 open/closed sensor with maxReportTime of 1 hr. A Category C2 open/closed sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*60 = 120 min Check-in interval = 12 mins
## Battery Specification ## Battery Specification

View File

@@ -24,10 +24,10 @@ Works with:
## Device Health ## Device Health
A Category C2 SmartSense Temp/Humidity Sensor with maxReportTime of 1 hr. A Category C2 SmartSense Temp/Humidity Sensor with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime for Zigbee device. Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline. This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 2*60 = 120 min Check-in interval = 12 mins
## Battery Specification ## Battery Specification

View File

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

View File

@@ -0,0 +1,36 @@
# OSRAM Lightify LED On/Off/Dim
Works with:
* [OSRAM Lightify LED On/Off/Dim](https://shop.smartthings.com/#!/products/osram-led-smart-bulb-on-off-dim)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C1 Zigbee dimmer with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Other troubleshooting tips are listed as follows:
* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/207191763-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-On-Off-Dim)

View File

@@ -13,7 +13,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings") { definition (name: "ZigBee Dimmer", namespace: "smartthings", author: "SmartThings", category: "C1") {
capability "Actuator" capability "Actuator"
capability "Configuration" capability "Configuration"
capability "Refresh" capability "Refresh"

View File

@@ -31,7 +31,8 @@
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD210 PB DB", deviceJoinName: "Yale Push Button Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD220/240 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock" fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRL210 PB LL", deviceJoinName: "Yale Push Button Lever Lock"
} fingerprint profileId: "0104", inClusters: "0000,0001,0003,0009,000A,0101,0020", outClusters: "000A,0019", manufacturer: "Yale", model: "YRD226/246 TSDB", deviceJoinName: "Yale Touch Screen Deadbolt Lock"
}
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"toggle", type:"generic", width:6, height:4){ multiAttributeTile(name:"toggle", type:"generic", width:6, height:4){

View File

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

View File

@@ -0,0 +1,42 @@
# OSRAM LIGHTIFY LED RGBW Bulb
Works with:
* [OSRAM LIGHTIFY LED RGBW Bulb](https://support.smartthings.com/hc/en-us/articles/207728173-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-RGBW)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - It represents that a device has commands.
* **Color Control** - It represents that the color attributes of a device can be controlled (hue, saturation, color value).
* **Color Temperature** - It represents color temperature capability measured in degree Kelvin.
* **Polling** - It represents that a device can be polled.
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - can detect current light level (0-100 in percent)
* **Configuration** - _configure()_ command called when device is installed or device preferences updated
* **Refresh** - _refresh()_ command for status updates
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C6 OSRAM LIGHTIFY LED RGBW Bulb with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
It may also happen that you need to reset the device.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/207728173-OSRAM-LIGHTIFY-LED-Smart-Connected-Light-A19-RGBW)

View File

@@ -17,7 +17,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee RGBW Bulb", namespace: "smartthings", author: "SmartThings") { definition (name: "ZigBee RGBW Bulb", namespace: "smartthings", author: "SmartThings", category: "C6") {
capability "Actuator" capability "Actuator"
capability "Color Control" capability "Color Control"

View File

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

View File

@@ -0,0 +1,37 @@
# OSRAM Lightify Tunable 60 White
Works with:
* [OSRAM Lightify Tunable 60 White](http://www.osram.com/osram_com/tools-and-services/tools/lightify---smart-connected-light/lightify-for-home---what-is-light-to-you/lightify-products/lightify-classic-a60-tunable-white/index.jsp)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Battery](#battery-specification)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Color Temperature** - represents color temperature, measured in degrees Kelvin.
* **Configuration** - _configure()_ command called when device is installed or device preferences updated.
* **Refresh** - _refresh()_ command for status updates
* **Switch** - can detect state (possible values: on/off)
* **Switch Level** - represents current light level, usually 0-100 in percent
* **Health Check** - indicates ability to get device health notifications
## Device Health
A Category C1 OSRAM Lightify Tunable 60 White with maxReportTime of 5 mins.
Check-in interval is double the value of maxReportTime.
This gives the device twice the amount of time to respond before it is marked as offline.
Check-in interval = 12 mins
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Other troubleshooting tips are listed as follows:
* [Troubleshooting:](https://support.smartthings.com/hc/en-us/articles/204576454-OSRAM-LIGHTIFY-Tunable-White-60-Bulb)

View File

@@ -17,7 +17,7 @@
*/ */
metadata { metadata {
definition (name: "ZigBee White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings") { definition (name: "ZigBee White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings", category: "C1") {
capability "Actuator" capability "Actuator"
capability "Color Temperature" capability "Color Temperature"

View File

@@ -1,7 +1,7 @@
/** /**
* Smart Windows * Smart Windows
* Compares two temperatures indoor vs outdoor, for example then sends an alert if windows are open (or closed!). * Compares two temperatures indoor vs outdoor, for example then sends an alert if windows are open (or closed!).
* *
* Copyright 2014 Eric Gideon * Copyright 2014 Eric Gideon
* *
* Based in part on the "When it's going to rain" SmartApp by the SmartThings team, * Based in part on the "When it's going to rain" SmartApp by the SmartThings team,
@@ -21,13 +21,18 @@ definition(
name: "Smart Windows", name: "Smart Windows",
namespace: "egid", namespace: "egid",
author: "Eric Gideon", author: "Eric Gideon",
description: "Compares two temperatures indoor vs outdoor, for example then sends an alert if windows are open (or closed!). If you don't use an external temperature device, your zipcode will be used instead.", description: "Compares two temperatures indoor vs outdoor, for example then sends an alert if windows are open (or closed!). If you don't use an external temperature device, your location will be used instead.",
iconUrl: "https://s3.amazonaws.com/smartthings-device-icons/Home/home9-icn.png", iconUrl: "https://s3.amazonaws.com/smartthings-device-icons/Home/home9-icn.png",
iconX2Url: "https://s3.amazonaws.com/smartthings-device-icons/Home/home9-icn@2x.png" iconX2Url: "https://s3.amazonaws.com/smartthings-device-icons/Home/home9-icn@2x.png"
) )
preferences { preferences {
if (!(location.zipCode || ( location.latitude && location.longitude )) && location.channelName == 'samsungtv') {
section { paragraph title: "Note:", "Location is required for this SmartApp. Go to 'Location Name' settings to setup your correct location." }
}
section( "Set the temperature range for your comfort zone..." ) { section( "Set the temperature range for your comfort zone..." ) {
input "minTemp", "number", title: "Minimum temperature" input "minTemp", "number", title: "Minimum temperature"
input "maxTemp", "number", title: "Maximum temperature" input "maxTemp", "number", title: "Maximum temperature"
@@ -39,9 +44,11 @@ preferences {
input "inTemp", "capability.temperatureMeasurement", title: "Indoor" input "inTemp", "capability.temperatureMeasurement", title: "Indoor"
input "outTemp", "capability.temperatureMeasurement", title: "Outdoor (optional)", required: false input "outTemp", "capability.temperatureMeasurement", title: "Outdoor (optional)", required: false
} }
section( "Set your location" ) {
input "zipCode", "text", title: "Zip code" if (location.channelName != 'samsungtv') {
} section( "Set your location" ) { input "zipCode", "text", title: "Zip code" }
}
section( "Notifications" ) { section( "Notifications" ) {
input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false
input "retryPeriod", "number", title: "Minutes between notifications:" input "retryPeriod", "number", title: "Minutes between notifications:"
@@ -72,7 +79,7 @@ def temperatureHandler(evt) {
def currentInTemp = evt.doubleValue def currentInTemp = evt.doubleValue
def openWindows = sensors.findAll { it?.latestValue("contact") == 'open' } def openWindows = sensors.findAll { it?.latestValue("contact") == 'open' }
log.trace "Temp event: $evt" log.trace "Temp event: $evt"
log.info "In: $currentInTemp; Out: $currentOutTemp" log.info "In: $currentInTemp; Out: $currentOutTemp"
@@ -98,7 +105,7 @@ def temperatureHandler(evt) {
if ( currentOutTemp < maxTemp && !openWindows ) { if ( currentOutTemp < maxTemp && !openWindows ) {
send( "Open some windows to cool down the house! Currently ${currentInTemp}°F inside and ${currentOutTemp}°F outside." ) send( "Open some windows to cool down the house! Currently ${currentInTemp}°F inside and ${currentOutTemp}°F outside." )
} else if ( currentOutTemp > maxTemp && openWindows ) { } else if ( currentOutTemp > maxTemp && openWindows ) {
send( "It's gotten warmer outside! You should close these windows: ${openWindows.join(', ')}. Currently ${currentInTemp}°F inside and ${currentOutTemp}°F outside." ) send( "It's gotten warmer outside! You should close these windows: ${openWindows.join(', ')}. Currently ${currentInTemp}°F inside and ${currentOutTemp}°F outside." )
} else { } else {
log.debug "No notifications sent. Everything is in the right place." log.debug "No notifications sent. Everything is in the right place."
} }
@@ -125,7 +132,11 @@ def temperatureHandler(evt) {
} }
def weatherCheck() { def weatherCheck() {
def json = getWeatherFeature("conditions", zipCode) def json
if (location.channelName != 'samsungtv')
json = getWeatherFeature("conditions", zipCode)
else
json = getWeatherFeature("conditions")
def currentTemp = json?.current_observation?.temp_f def currentTemp = json?.current_observation?.temp_f
if ( currentTemp ) { if ( currentTemp ) {
@@ -150,4 +161,4 @@ private send(msg) {
} }
log.info msg log.info msg
} }

View File

@@ -0,0 +1,253 @@
/**
* 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')]
}
}

View File

@@ -18,8 +18,13 @@ definition(
) )
preferences { preferences {
section("Zip code?") {
input "zipcode", "text", title: "Zipcode?" if (!(location.zipCode || ( location.latitude && location.longitude )) && location.channelName == 'samsungtv') {
section { paragraph title: "Note:", "Location is required for this SmartApp. Go to 'Location Name' settings to setup your correct location." }
}
if (location.channelName != 'samsungtv') {
section( "Set your location" ) { input "zipCode", "text", title: "Zip code" }
} }
section("Things to check?") { section("Things to check?") {
@@ -60,7 +65,11 @@ def scheduleCheck(evt) {
// Only need to poll if we haven't checked in a while - and if something is left open. // Only need to poll if we haven't checked in a while - and if something is left open.
if((now() - (30 * 60 * 1000) > state.lastCheck["time"]) && open) { if((now() - (30 * 60 * 1000) > state.lastCheck["time"]) && open) {
log.info("Something's open - let's check the weather.") log.info("Something's open - let's check the weather.")
def response = getWeatherFeature("forecast", zipcode) def response
if (location.channelName != 'samsungtv')
response = getWeatherFeature("forecast", zipCode)
else
response = getWeatherFeature("forecast")
def weather = isStormy(response) def weather = isStormy(response)
if(weather) { if(weather) {

View File

@@ -4,6 +4,9 @@
* Author: Juan Risso * Author: Juan Risso
* Date: 2013-12-19 * Date: 2013-12-19
*/ */
include 'asynchttp_v1'
definition( definition(
name: "Jawbone UP (Connect)", name: "Jawbone UP (Connect)",
namespace: "juano2310", namespace: "juano2310",
@@ -303,7 +306,8 @@ def setup() {
def childDevice = addChildDevice('juano2310', "Jawbone User", "${app.id}.${member.xid}",null,[name:"Jawbone UP - " + member.first, completedSetup: true]) def childDevice = addChildDevice('juano2310', "Jawbone User", "${app.id}.${member.xid}",null,[name:"Jawbone UP - " + member.first, completedSetup: true])
if (childDevice) { if (childDevice) {
log.debug "Child Device Successfully Created" log.debug "Child Device Successfully Created"
generateInitialEvent (member, childDevice) childDevice?.generateSleepingEvent(false)
pollChild(childDevice)
} }
} }
} }
@@ -349,67 +353,67 @@ def uninstalled() {
} }
def pollChild(childDevice) { def pollChild(childDevice) {
def member = state.member def childMap = [ value: "$childDevice.device.deviceNetworkId}"]
generatePollingEvents (member, childDevice)
def params = [
uri: 'https://jawbone.com',
path: '/nudge/api/users/@me/goals',
headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ],
contentType: 'application/json'
]
asynchttp_v1.get('responseGoals', params, childMap)
def params2 = [
uri: 'https://jawbone.com',
path: '/nudge/api/users/@me/moves',
headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ],
contentType: 'application/json'
]
asynchttp_v1.get('responseMoves', params2, childMap)
} }
def generatePollingEvents (member, childDevice) { def responseGoals(response, dni) {
// lets figure out if the member is currently "home" (At the place) if (response.hasError()) {
def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" log.error "response has error: $response.errorMessage"
def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" } else {
def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" def goals
def goals = null try {
def moves = null // json response already parsed into JSONElement object
def sleeps = null goals = response.json.data
httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> } catch (e) {
goals = response.data.data log.error "error parsing json from response: $e"
} }
httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> if (goals) {
moves = response.data.data.items[0] def childDevice = getChildDevice(dni.value)
} log.debug "Goal = ${goals.move_steps} Steps"
childDevice?.sendEvent(name:"goal", value: goals.move_steps)
try { // we are going to just ignore any errors } else {
log.debug "Member = ${member.first}" log.debug "did not get json results from response body: $response.data"
log.debug "Moves Goal = ${goals.move_steps} Steps" }
log.debug "Moves = ${moves.details.steps} Steps" }
childDevice?.sendEvent(name:"steps", value: moves.details.steps)
childDevice?.sendEvent(name:"goal", value: goals.move_steps)
//setColor(moves.details.steps,goals.move_steps,childDevice)
}
catch (e) {
// eat it
}
} }
def generateInitialEvent (member, childDevice) { def responseMoves(response, dni) {
// lets figure out if the member is currently "home" (At the place) if (response.hasError()) {
def urlgoals = "https://jawbone.com/nudge/api/users/@me/goals" log.error "response has error: $response.errorMessage"
def urlmoves = "https://jawbone.com/nudge/api/users/@me/moves" } else {
def urlsleeps = "https://jawbone.com/nudge/api/users/@me/sleeps" def moves
def goals = null try {
def moves = null // json response already parsed into JSONElement object
def sleeps = null moves = response.json.data.items[0]
httpGet(uri: urlgoals, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> } catch (e) {
goals = response.data.data log.error "error parsing json from response: $e"
} }
httpGet(uri: urlmoves, headers: ["Authorization": "Bearer ${state.JawboneAccessToken}" ]) {response -> if (moves) {
moves = response.data.data.items[0] def childDevice = getChildDevice(dni.value)
} log.debug "Moves = ${moves.details.steps} Steps"
childDevice?.sendEvent(name:"steps", value: moves.details.steps)
try { // we are going to just ignore any errors } else {
log.debug "Member = ${member.first}" log.debug "did not get json results from response body: $response.data"
log.debug "Moves Goal = ${goals.move_steps} Steps" }
log.debug "Moves = ${moves.details.steps} Steps" }
log.debug "Sleeping state = false"
childDevice?.generateSleepingEvent(false)
childDevice?.sendEvent(name:"steps", value: moves.details.steps)
childDevice?.sendEvent(name:"goal", value: goals.move_steps)
//setColor(moves.details.steps,goals.move_steps,childDevice)
}
catch (e) {
// eat it
}
} }
def setColor (steps,goal,childDevice) { def setColor (steps,goal,childDevice) {
@@ -433,7 +437,7 @@ def hookEventHandler() {
// get some stuff we need // get some stuff we need
def userId = json.events.user_xid[0] def userId = json.events.user_xid[0]
def json_type = json.events.type[0] def json_type = json.events.type[0]
def json_action = json.events.action[0] def json_action = json.events.action[0]
//log.debug json //log.debug json
log.debug "Userid = ${userId}" log.debug "Userid = ${userId}"

View File

@@ -83,7 +83,7 @@ def bridgeDiscovery(params=[:])
return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) { return dynamicPage(name:"bridgeDiscovery", title:"Discovery Started!", nextPage:"bridgeBtnPush", refreshInterval:refreshInterval, uninstall: true) {
section("Please wait while we discover your Hue Bridge. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") { section("Please wait while we discover your Hue Bridge. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options, submitOnChange: true input "selectedHue", "enum", required:false, title:"Select Hue Bridge (${numFound} found)", multiple:false, options:options
} }
} }
} }
@@ -333,9 +333,9 @@ def bulbListHandler(hub, data = "") {
def bridge = null def bridge = null
if (selectedHue) { if (selectedHue) {
bridge = getChildDevice(selectedHue) bridge = getChildDevice(selectedHue)
bridge?.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
} }
msg = "${bulbs.size()} bulbs found. ${bulbs}" bridge.sendEvent(name: "bulbList", value: hub, data: bulbs, isStateChange: true, displayed: false)
msg = "${bulbs.size()} bulbs found. ${bulbs}"
return msg return msg
} }
@@ -490,25 +490,24 @@ def ssdpBridgeHandler(evt) {
def host = ip + ":" + port def host = ip + ":" + port
log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host." log.debug "Device ($parsedEvent.mac) was already found in state with ip = $host."
def dstate = bridges."${parsedEvent.ssdpUSN.toString()}" def dstate = bridges."${parsedEvent.ssdpUSN.toString()}"
def dniReceived = "${parsedEvent.mac}" def dni = "${parsedEvent.mac}"
def currentDni = dstate.mac def d = getChildDevice(dni)
def d = getChildDevice(dniReceived)
def networkAddress = null def networkAddress = null
if (!d) { if (!d) {
// There might be a mismatch between bridge DNI and the actual bridge mac address, correct that childDevices.each {
log.debug "Bridge with $dniReceived not found" if (it.getDeviceDataByName("mac")) {
def bridge = childDevices.find { it.deviceNetworkId == currentDni } def newDNI = "${it.getDeviceDataByName("mac")}"
if (bridge != null) { d = it
log.warn "Bridge is set to ${bridge.deviceNetworkId}, updating to $dniReceived" if (newDNI != it.deviceNetworkId) {
bridge.setDeviceNetworkId("${dniReceived}") def oldDNI = it.deviceNetworkId
dstate.mac = dniReceived log.debug "updating dni for device ${it} with $newDNI - previous DNI = ${it.deviceNetworkId}"
// Check to see if selectedHue is a valid bridge, otherwise update it it.setDeviceNetworkId("${newDNI}")
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue} if (oldDNI == selectedHue) {
if (isSelectedValid == null) { app.updateSetting("selectedHue", newDNI)
log.warn "Correcting selectedHue in state" }
app.updateSetting("selectedHue", dniReceived) doDeviceSync()
}
} }
doDeviceSync()
} }
} else { } else {
updateBridgeStatus(d) updateBridgeStatus(d)
@@ -526,18 +525,6 @@ def ssdpBridgeHandler(evt) {
d.sendEvent(name:"networkAddress", value: host) d.sendEvent(name:"networkAddress", value: host)
d.updateDataValue("networkAddress", host) d.updateDataValue("networkAddress", host)
} }
if (dstate.mac != dniReceived) {
log.warn "Correcting bridge mac address in state"
dstate.mac = dniReceived
}
if (selectedHue != dniReceived) {
// Check to see if selectedHue is a valid bridge, otherwise update it
def isSelectedValid = bridges?.find {it.value?.mac == selectedHue}
if (isSelectedValid == null) {
log.warn "Correcting selectedHue in state"
app.updateSetting("selectedHue", dniReceived)
}
}
} }
} }
} }
@@ -963,14 +950,6 @@ private handleCommandResponse(body) {
* @return empty array * @return empty array
*/ */
private handlePoll(body) { private handlePoll(body) {
// Used to track "unreachable" time
// Device is considered "offline" if it has been in the "unreachable" state for
// 11 minutes (e.g. two poll intervals)
// Note, Hue Bridge marks devices as "unreachable" often even when they accept commands
Calendar time11 = Calendar.getInstance()
time11.add(Calendar.MINUTE, -11)
Calendar currentTime = Calendar.getInstance()
def bulbs = getChildDevices() def bulbs = getChildDevices()
for (bulb in body) { for (bulb in body) {
def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"} def device = bulbs.find{it.deviceNetworkId == "${app.id}/${bulb.key}"}
@@ -980,10 +959,7 @@ private handlePoll(body) {
// light just came back online, notify device watch // light just came back online, notify device watch
def lastActivity = now() def lastActivity = now()
device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true) device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: true)
log.debug "$device is Online"
} }
// Mark light as "online"
state.bulbs[bulb.key]?.unreachableSince = null
state.bulbs[bulb.key]?.online = true state.bulbs[bulb.key]?.online = true
// If user just executed commands, then do not send events to avoid confusing the turning on/off state // If user just executed commands, then do not send events to avoid confusing the turning on/off state
@@ -993,18 +969,9 @@ private handlePoll(body) {
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode) sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode)
} }
} else { } else {
if (state.bulbs[bulb.key]?.unreachableSince == null) { state.bulbs[bulb.key]?.online = false
// Store the first time where device was reported as "unreachable" log.warn "$device is not reachable by Hue bridge"
state.bulbs[bulb.key]?.unreachableSince = currentTime.getTimeInMillis() device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
} else if (state.bulbs[bulb.key]?.online) {
// Check if device was "unreachable" for more than 11 minutes and mark "offline" if necessary
if (state.bulbs[bulb.key]?.unreachableSince < time11.getTimeInMillis()) {
log.warn "$device went Offline"
state.bulbs[bulb.key]?.online = false
device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
}
}
log.warn "$device may not reachable by Hue bridge"
} }
} }
} }
@@ -1039,6 +1006,9 @@ def hubVerification(bodytext) {
def on(childDevice) { def on(childDevice) {
log.debug "Executing 'on'" log.debug "Executing 'on'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/$id/state", [on: true]) put("lights/$id/state", [on: true])
@@ -1048,6 +1018,9 @@ def on(childDevice) {
def off(childDevice) { def off(childDevice) {
log.debug "Executing 'off'" log.debug "Executing 'off'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "off") createSwitchEvent(childDevice, "off")
put("lights/$id/state", [on: false]) put("lights/$id/state", [on: false])
@@ -1057,6 +1030,9 @@ def off(childDevice) {
def setLevel(childDevice, percent) { def setLevel(childDevice, percent) {
log.debug "Executing 'setLevel'" log.debug "Executing 'setLevel'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 1 - 254 // 1 - 254
def level def level
@@ -1081,6 +1057,10 @@ def setLevel(childDevice, percent) {
def setSaturation(childDevice, percent) { def setSaturation(childDevice, percent) {
log.debug "Executing 'setSaturation($percent)'" log.debug "Executing 'setSaturation($percent)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 0 - 254 // 0 - 254
def level = Math.min(Math.round(percent * 254 / 100), 254) def level = Math.min(Math.round(percent * 254 / 100), 254)
@@ -1093,6 +1073,9 @@ def setSaturation(childDevice, percent) {
def setHue(childDevice, percent) { def setHue(childDevice, percent) {
log.debug "Executing 'setHue($percent)'" log.debug "Executing 'setHue($percent)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 0 - 65535 // 0 - 65535
def level = Math.min(Math.round(percent * 65535 / 100), 65535) def level = Math.min(Math.round(percent * 65535 / 100), 65535)
@@ -1105,6 +1088,9 @@ def setHue(childDevice, percent) {
def setColorTemperature(childDevice, huesettings) { def setColorTemperature(childDevice, huesettings) {
log.debug "Executing 'setColorTemperature($huesettings)'" log.debug "Executing 'setColorTemperature($huesettings)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 153 (6500K) to 500 (2000K) // 153 (6500K) to 500 (2000K)
def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings) def ct = hueSettings == 6500 ? 153 : Math.round(1000000/huesettings)
@@ -1116,6 +1102,9 @@ def setColorTemperature(childDevice, huesettings) {
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'" log.debug "Executing 'setColor($huesettings)'"
def id = getId(childDevice) def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
def value = [:] def value = [:]
@@ -1131,7 +1120,7 @@ def setColor(childDevice, huesettings) {
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535) value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
if (huesettings.saturation != null) if (huesettings.saturation != null)
value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254) value.sat = Math.min(Math.round(huesettings.saturation * 254 / 100), 254)
} else if (huesettings.hex != null) { } else if (huesettings.hex != null && false) {
// For now ignore model to get a consistent color if same color is set across multiple devices // For now ignore model to get a consistent color if same color is set across multiple devices
// def model = state.bulbs[getId(childDevice)]?.modelid // def model = state.bulbs[getId(childDevice)]?.modelid
// value.xy = calculateXY(huesettings.hex, model) // value.xy = calculateXY(huesettings.hex, model)
@@ -1235,7 +1224,7 @@ private getBridgeIP() {
if (d) { if (d) {
if (d.getDeviceDataByName("networkAddress")) if (d.getDeviceDataByName("networkAddress"))
host = d.getDeviceDataByName("networkAddress") host = d.getDeviceDataByName("networkAddress")
else else
host = d.latestState('networkAddress').stringValue host = d.latestState('networkAddress').stringValue
} }
if (host == null || host == "") { if (host == null || host == "") {
@@ -1674,7 +1663,7 @@ private boolean checkPointInLampsReach(p, colorPoints) {
} }
/** /**
* Converts an RGB color in hex to HSV/HSB. * Converts an RGB color in hex to HSV.
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
* *
* @param colorStr color value in hex (#ff03d3) * @param colorStr color value in hex (#ff03d3)
@@ -1684,32 +1673,32 @@ private boolean checkPointInLampsReach(p, colorPoints) {
def hexToHsv(colorStr){ def hexToHsv(colorStr){
def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255 def r = Integer.valueOf( colorStr.substring( 1, 3 ), 16 ) / 255
def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255 def g = Integer.valueOf( colorStr.substring( 3, 5 ), 16 ) / 255
def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255 def b = Integer.valueOf( colorStr.substring( 5, 7 ), 16 ) / 255;
def max = Math.max(Math.max(r, g), b) def max = Math.max(Math.max(r, g), b)
def min = Math.min(Math.min(r, g), b) def min = Math.min(Math.min(r, g), b)
def h, s, v = max def h, s, v = max;
def d = max - min def d = max - min;
s = max == 0 ? 0 : d / max s = max == 0 ? 0 : d / max;
if(max == min){ if(max == min){
h = 0 h = 0;
}else{ }else{
switch(max){ switch(max){
case r: h = (g - b) / d + (g < b ? 6 : 0); break case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break case b: h = (r - g) / d + 4; break;
} }
h /= 6; h /= 6;
} }
return [Math.round(h * 100), Math.round(s * 100), Math.round(v * 100)] return [(h * 100).round(), (s * 100).round(), (v * 100).round()];
} }
/** /**
* Converts HSV/HSB color to RGB in hex. * Converts HSV color to RGB in hex.
* Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space. * Algorithm based on http://en.wikipedia.org/wiki/HSV_color_space.
* *
* @param hue hue 0-100 * @param hue hue 0-100
@@ -1724,11 +1713,11 @@ def hsvToHex(hue, sat, value = 100){
def s = sat / 100 def s = sat / 100
def v = value / 100 def v = value / 100
def i = Math.floor(h * 6) def i = Math.floor(h * 6);
def f = h * 6 - i def f = h * 6 - i;
def p = v * (1 - s) def p = v * (1 - s);
def q = v * (1 - f * s) def q = v * (1 - f * s);
def t = v * (1 - (1 - f) * s) def t = v * (1 - (1 - f) * s);
switch (i % 6) { switch (i % 6) {
case 0: case 0:
@@ -1764,9 +1753,9 @@ def hsvToHex(hue, sat, value = 100){
} }
// Converting float components to int components. // Converting float components to int components.
def r1 = String.format("%02X", (int) (r * 255.0f)) def r1 = String.format("%02X", (int) (r * 255.0f));
def g1 = String.format("%02X", (int) (g * 255.0f)) def g1 = String.format("%02X", (int) (g * 255.0f));
def b1 = String.format("%02X", (int) (b * 255.0f)) def b1 = String.format("%02X", (int) (b * 255.0f));
return "#$r1$g1$b1" return "#$r1$g1$b1"
} }

View File

@@ -26,17 +26,22 @@ definition(
) )
preferences { preferences {
section ("In addition to push notifications, send text alerts to...") {
input("recipients", "contact", title: "Send notifications to") { if (!(location.zipCode || ( location.latitude && location.longitude )) && location.channelName == 'samsungtv') {
input "phone1", "phone", title: "Phone Number 1", required: false section { paragraph title: "Note:", "Location is required for this SmartApp. Go to 'Location Name' settings to setup your correct location." }
input "phone2", "phone", title: "Phone Number 2", required: false
input "phone3", "phone", title: "Phone Number 3", required: false
}
} }
section ("Zip code (optional, defaults to location coordinates)...") { if (location.channelName != 'samsungtv') {
input "zipcode", "text", title: "Zip Code", required: false section( "Set your location" ) { input "zipCode", "text", title: "Zip code" }
} }
section ("In addition to push notifications, send text alerts to...") {
input("recipients", "contact", title: "Send notifications to") {
input "phone1", "phone", title: "Phone Number 1", required: false
input "phone2", "phone", title: "Phone Number 2", required: false
input "phone3", "phone", title: "Phone Number 3", required: false
}
}
} }
def installed() { def installed() {
@@ -61,7 +66,7 @@ def checkForSevereWeather() {
def alerts def alerts
if(locationIsDefined()) { if(locationIsDefined()) {
if(zipcodeIsValid()) { if(zipcodeIsValid()) {
alerts = getWeatherFeature("alerts", zipcode)?.alerts alerts = getWeatherFeature("alerts", zipCode)?.alerts
} else { } else {
log.warn "Severe Weather Alert: Invalid zipcode entered, defaulting to location's zipcode" log.warn "Severe Weather Alert: Invalid zipcode entered, defaulting to location's zipcode"
alerts = getWeatherFeature("alerts")?.alerts alerts = getWeatherFeature("alerts")?.alerts

View File

@@ -0,0 +1,800 @@
/**
* Home Remote
*
* Copyright 2015 The Home Remote
*
* 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: "Home Remote",
namespace: "thehomeremote.homeremote",
author: "The Home Remote",
description: "Web service that enables communication between the Home Remote app and a SmartThings hub.",
category: "My Apps",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
oauth: [displayName: "The Home Remote", displayLink: "http://thehomeremote.com/"])
preferences {
section() {
input "accelerationSensors", "capability.accelerationSensor",title: "Acceleration Sensors", multiple: true, required: false
input "alarms", "capability.alarm",title: "Alarms", multiple: true, required: false
input "batteries", "capability.battery",title: "Batteries", multiple: true, required: false
input "beacons", "capability.beacon",title: "Beacons", multiple: true, required: false
input "buttonGroup", "capability.button",title: "Buttons", multiple: true, required: false
input "carbonMonoxideDetectors", "capability.carbonMonoxideDetector",title: "CO Detectors", multiple: true, required: false
input "colorControls", "capability.colorControl",title: "Color Lights", multiple: true, required: false
input "contactSensors", "capability.contactSensor",title: "Contact Sensors", multiple: true, required: false
input "doorControls", "capability.doorControl",title: "Door Controllers", multiple: true, required: false
input "energyMeters", "capability.energyMeter",title: "Energy Meters", multiple: true, required: false
input "illuminanceMeasurements", "capability.illuminanceMeasurement",title: "Illuminance Sensors", multiple: true, required: false
input "imageCaptures", "capability.imageCapture",title: "Cameras", multiple: true, required: false
input "locks", "capability.lock",title: "Locks", multiple: true, required: false
input "mediaControllers", "capability.mediaController",title: "Media Controllers", multiple: true, required: false
input "momentaries", "capability.momentary",title: "Momentary Buttons", multiple: true, required: false
input "motionSensors", "capability.motionSensor",title: "Motion Sensors", multiple: true, required: false
input "musicPlayers", "capability.musicPlayer",title: "Music Players", multiple: true, required: false
input "powerMeters", "capability.powerMeter",title: "Power Meters", multiple: true, required: false
input "presenceSensors", "capability.presenceSensor",title: "Presence Sensors", multiple: true, required: false
input "relativeHumidityMeasurements", "capability.relativeHumidityMeasurement",title: "Humidity Sensors", multiple: true, required: false
input "relaySwitches", "capability.relaySwitch",title: "Relays", multiple: true, required: false
input "signalStrengths", "capability.signalStrength",title: "Signal Strengths", multiple: true, required: false
input "sleepSensors", "capability.sleepSensor",title: "Sleep Sensors", multiple: true, required: false
input "smokeDetectors", "capability.smokeDetector",title: "Smoke Detectors", multiple: true, required: false
input "speechSyntheses", "capability.speechSynthesis",title: "Speech Syntheses", multiple: true, required: false
input "stepSensors", "capability.stepSensor",title: "Step Sensors", multiple: true, required: false
input "switches", "capability.switch",title: "Switches", multiple: true, required: false
input "switchLevels", "capability.switchLevel",title: "Dimmers", multiple: true, required: false
input "temperatureMeasurements", "capability.temperatureMeasurement",title: "Temperature Sensors", multiple: true, required: false
input "thermostats", "capability.thermostat",title: "Thermostats", multiple: true, required: false
input "threeAxes", "capability.threeAxis",title: "Three axis Sensors", multiple: true, required: false
input "tones", "capability.tone",title: "Tones", multiple: true, required: false
input "touchSensors", "capability.touchSensor",title: "Touch Sensors", multiple: true, required: false
input "valves", "capability.valve",title: "Valves", multiple: true, required: false
input "waterSensors", "capability.waterSensor",title: "Water Sensors", multiple: true, required: false
}
}
mappings {
path("/GetCurrentValues") {
action: [
GET: "getCurrentValues"
]
}
path("/GetCurrentValuesWithDisplayName") {
action: [
GET: "getCurrentValuesWithDisplayName"
]
}
path("/GetRoutines") {
action: [
GET: "getRoutines"
]
}
path("/ExecuteCommand") {
action: [
PUT: "executeCommand"
]
}
path("/ExecuteRoutine") {
action: [
PUT: "executeRoutine"
]
}
}
def getCurrentValues() {
def resp = []
accelerationSensors.each {
resp << [id: it.id, capability: "AccelerationSensor", attribute: "acceleration", value: it.currentValue("acceleration")]
}
alarms.each {
resp << [id: it.id, capability: "Alarm", attribute: "alarm", value: it.currentValue("alarm")]
}
batteries.each {
resp << [id: it.id, capability: "Battery", attribute: "battery", value: it.currentValue("battery")]
}
beacons.each {
resp << [id: it.id, capability: "Beacon", attribute: "presence", value: it.currentValue("presence")]
}
buttonGroup.each {
resp << [id: it.id, capability: "Button", attribute: "button", value: it.currentValue("button")]
}
carbonMonoxideDetectors.each {
resp << [id: it.id, capability: "CarbonMonoxideDetector", attribute: "carbonMonoxide", value: it.currentValue("carbonMonoxide")]
}
colorControls.each {
resp << [id: it.id, capability: "ColorControl", attribute: "hue", value: it.currentValue("hue")]
}
colorControls.each {
resp << [id: it.id, capability: "ColorControl", attribute: "saturation", value: it.currentValue("saturation")]
}
colorControls.each {
resp << [id: it.id, capability: "ColorControl", attribute: "color", value: it.currentValue("color")]
}
contactSensors.each {
resp << [id: it.id, capability: "ContactSensor", attribute: "contact", value: it.currentValue("contact")]
}
doorControls.each {
resp << [id: it.id, capability: "DoorControl", attribute: "door", value: it.currentValue("door")]
}
energyMeters.each {
resp << [id: it.id, capability: "EnergyMeter", attribute: "energy", value: it.currentValue("energy")]
}
illuminanceMeasurements.each {
resp << [id: it.id, capability: "IlluminanceMeasurement", attribute: "illuminance", value: it.currentValue("illuminance")]
}
imageCaptures.each {
resp << [id: it.id, capability: "ImageCapture", attribute: "image", value: it.currentValue("image")]
}
locks.each {
resp << [id: it.id, capability: "Lock", attribute: "lock", value: it.currentValue("lock")]
}
mediaControllers.each {
resp << [id: it.id, capability: "MediaController", attribute: "activities", value: it.currentValue("activities")]
}
mediaControllers.each {
resp << [id: it.id, capability: "MediaController", attribute: "currentActivity", value: it.currentValue("currentActivity")]
}
motionSensors.each {
resp << [id: it.id, capability: "MotionSensor", attribute: "motion", value: it.currentValue("motion")]
}
musicPlayers.each {
resp << [id: it.id, capability: "MusicPlayer", attribute: "status", value: it.currentValue("status")]
}
musicPlayers.each {
resp << [id: it.id, capability: "MusicPlayer", attribute: "level", value: it.currentValue("level")]
}
musicPlayers.each {
resp << [id: it.id, capability: "MusicPlayer", attribute: "trackDescription", value: it.currentValue("trackDescription")]
}
musicPlayers.each {
resp << [id: it.id, capability: "MusicPlayer", attribute: "trackData", value: it.currentValue("trackData")]
}
musicPlayers.each {
resp << [id: it.id, capability: "MusicPlayer", attribute: "mute", value: it.currentValue("mute")]
}
powerMeters.each {
resp << [id: it.id, capability: "PowerMeter", attribute: "power", value: it.currentValue("power")]
}
presenceSensors.each {
resp << [id: it.id, capability: "PresenceSensor", attribute: "presence", value: it.currentValue("presence")]
}
relativeHumidityMeasurements.each {
resp << [id: it.id, capability: "RelativeHumidityMeasurement", attribute: "humidity", value: it.currentValue("humidity")]
}
relaySwitches.each {
resp << [id: it.id, capability: "RelaySwitch", attribute: "switch", value: it.currentValue("switch")]
}
signalStrengths.each {
resp << [id: it.id, capability: "SignalStrength", attribute: "lqi", value: it.currentValue("lqi")]
}
signalStrengths.each {
resp << [id: it.id, capability: "SignalStrength", attribute: "rssi", value: it.currentValue("rssi")]
}
sleepSensors.each {
resp << [id: it.id, capability: "SleepSensor", attribute: "sleeping", value: it.currentValue("sleeping")]
}
smokeDetectors.each {
resp << [id: it.id, capability: "SmokeDetector", attribute: "smoke", value: it.currentValue("smoke")]
}
stepSensors.each {
resp << [id: it.id, capability: "StepSensor", attribute: "steps", value: it.currentValue("steps")]
}
stepSensors.each {
resp << [id: it.id, capability: "StepSensor", attribute: "goal", value: it.currentValue("goal")]
}
switches.each {
resp << [id: it.id, capability: "Switch", attribute: "switch", value: it.currentValue("switch")]
}
switchLevels.each {
resp << [id: it.id, capability: "SwitchLevel", attribute: "level", value: it.currentValue("level")]
}
temperatureMeasurements.each {
resp << [id: it.id, capability: "TemperatureMeasurement", attribute: "temperature", value: it.currentValue("temperature")]
}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "temperature", value: it.currentValue("temperature")]
}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "heatingSetpoint", value: it.currentValue("heatingSetpoint")]
}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "coolingSetpoint", value: it.currentValue("coolingSetpoint")]
}
//Commented out on 7/23/2016. This randomly started throwing number format exceptions with either my ecobee or Lyric thermostat.
//thermostats.each {
// resp << [id: it.id, capability: "Thermostat", attribute: "thermostatSetpoint", value: it.currentValue("thermostatSetpoint")]
//}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatMode", value: it.currentValue("thermostatMode")]
}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatFanMode", value: it.currentValue("thermostatFanMode")]
}
thermostats.each {
resp << [id: it.id, capability: "Thermostat", attribute: "thermostatOperatingState", value: it.currentValue("thermostatOperatingState")]
}
threeAxes.each {
resp << [id: it.id, capability: "ThreeAxis", attribute: "threeAxis", value: it.currentValue("threeAxis")]
}
touchSensors.each {
resp << [id: it.id, capability: "TouchSensor", attribute: "touch", value: it.currentValue("touch")]
}
valves.each {
resp << [id: it.id, capability: "Valve", attribute: "contact", value: it.currentValue("contact")]
}
waterSensors.each {
resp << [id: it.id, capability: "WaterSensor", attribute: "water", value: it.currentValue("water")]
}
//resp << [id: 0, capability: "Heartbeat", attribute: "heartbeat", value: String.valueOf(state.heartbeat)]
state.heartbeat = !state.heartbeat
return resp
}
def getCurrentValuesWithDisplayName() {
def resp = []
accelerationSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "AccelerationSensor", attribute: "acceleration", value: it.currentValue("acceleration")]
}
alarms.each {
resp << [id: it.id, displayName: it.displayName, capability: "Alarm", attribute: "alarm", value: it.currentValue("alarm")]
}
batteries.each {
resp << [id: it.id, displayName: it.displayName, capability: "Battery", attribute: "battery", value: it.currentValue("battery")]
}
beacons.each {
resp << [id: it.id, displayName: it.displayName, capability: "Beacon", attribute: "presence", value: it.currentValue("presence")]
}
buttonGroup.each {
resp << [id: it.id, displayName: it.displayName, capability: "Button", attribute: "button", value: it.currentValue("button")]
}
carbonMonoxideDetectors.each {
resp << [id: it.id, displayName: it.displayName, capability: "CarbonMonoxideDetector", attribute: "carbonMonoxide", value: it.currentValue("carbonMonoxide")]
}
colorControls.each {
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "hue", value: it.currentValue("hue")]
}
colorControls.each {
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "saturation", value: it.currentValue("saturation")]
}
colorControls.each {
resp << [id: it.id, displayName: it.displayName, capability: "ColorControl", attribute: "color", value: it.currentValue("color")]
}
contactSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "ContactSensor", attribute: "contact", value: it.currentValue("contact")]
}
doorControls.each {
resp << [id: it.id, displayName: it.displayName, capability: "DoorControl", attribute: "door", value: it.currentValue("door")]
}
energyMeters.each {
resp << [id: it.id, displayName: it.displayName, capability: "EnergyMeter", attribute: "energy", value: it.currentValue("energy")]
}
illuminanceMeasurements.each {
resp << [id: it.id, displayName: it.displayName, capability: "IlluminanceMeasurement", attribute: "illuminance", value: it.currentValue("illuminance")]
}
imageCaptures.each {
resp << [id: it.id, displayName: it.displayName, capability: "ImageCapture", attribute: "image", value: it.currentValue("image")]
}
locks.each {
resp << [id: it.id, displayName: it.displayName, capability: "Lock", attribute: "lock", value: it.currentValue("lock")]
}
mediaControllers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MediaController", attribute: "activities", value: it.currentValue("activities")]
}
mediaControllers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MediaController", attribute: "currentActivity", value: it.currentValue("currentActivity")]
}
motionSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "MotionSensor", attribute: "motion", value: it.currentValue("motion")]
}
musicPlayers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "status", value: it.currentValue("status")]
}
musicPlayers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "level", value: it.currentValue("level")]
}
musicPlayers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "trackDescription", value: it.currentValue("trackDescription")]
}
musicPlayers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "trackData", value: it.currentValue("trackData")]
}
musicPlayers.each {
resp << [id: it.id, displayName: it.displayName, capability: "MusicPlayer", attribute: "mute", value: it.currentValue("mute")]
}
powerMeters.each {
resp << [id: it.id, displayName: it.displayName, capability: "PowerMeter", attribute: "power", value: it.currentValue("power")]
}
presenceSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "PresenceSensor", attribute: "presence", value: it.currentValue("presence")]
}
relativeHumidityMeasurements.each {
resp << [id: it.id, displayName: it.displayName, capability: "RelativeHumidityMeasurement", attribute: "humidity", value: it.currentValue("humidity")]
}
relaySwitches.each {
resp << [id: it.id, displayName: it.displayName, capability: "RelaySwitch", attribute: "switch", value: it.currentValue("switch")]
}
signalStrengths.each {
resp << [id: it.id, displayName: it.displayName, capability: "SignalStrength", attribute: "lqi", value: it.currentValue("lqi")]
}
signalStrengths.each {
resp << [id: it.id, displayName: it.displayName, capability: "SignalStrength", attribute: "rssi", value: it.currentValue("rssi")]
}
sleepSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "SleepSensor", attribute: "sleeping", value: it.currentValue("sleeping")]
}
smokeDetectors.each {
resp << [id: it.id, displayName: it.displayName, capability: "SmokeDetector", attribute: "smoke", value: it.currentValue("smoke")]
}
stepSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "StepSensor", attribute: "steps", value: it.currentValue("steps")]
}
stepSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "StepSensor", attribute: "goal", value: it.currentValue("goal")]
}
switches.each {
resp << [id: it.id, displayName: it.displayName, capability: "Switch", attribute: "switch", value: it.currentValue("switch")]
}
switchLevels.each {
resp << [id: it.id, displayName: it.displayName, capability: "SwitchLevel", attribute: "level", value: it.currentValue("level")]
}
temperatureMeasurements.each {
resp << [id: it.id, displayName: it.displayName, capability: "TemperatureMeasurement", attribute: "temperature", value: it.currentValue("temperature")]
}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "temperature", value: it.currentValue("temperature")]
}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "heatingSetpoint", value: it.currentValue("heatingSetpoint")]
}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "coolingSetpoint", value: it.currentValue("coolingSetpoint")]
}
//Commented out on 7/23/2016. This randomly started throwing number format exceptions with either my ecobee or Lyric thermostat.
//thermostats.each {
// resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatSetpoint", value: it.currentValue("thermostatSetpoint")]
//}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatMode", value: it.currentValue("thermostatMode")]
}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatFanMode", value: it.currentValue("thermostatFanMode")]
}
thermostats.each {
resp << [id: it.id, displayName: it.displayName, capability: "Thermostat", attribute: "thermostatOperatingState", value: it.currentValue("thermostatOperatingState")]
}
threeAxes.each {
resp << [id: it.id, displayName: it.displayName, capability: "ThreeAxis", attribute: "threeAxis", value: it.currentValue("threeAxis")]
}
touchSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "TouchSensor", attribute: "touch", value: it.currentValue("touch")]
}
valves.each {
resp << [id: it.id, displayName: it.displayName, capability: "Valve", attribute: "contact", value: it.currentValue("contact")]
}
waterSensors.each {
resp << [id: it.id, displayName: it.displayName, capability: "WaterSensor", attribute: "water", value: it.currentValue("water")]
}
momentaries.each {
resp << [id: it.id, displayName: it.displayName, capability: "Momentary", attribute: "", value: ""]
}
//resp << [id: 0, displayName: "Heartbeat", capability: "Heartbeat", attribute: "heartbeat", value: state.heartbeat]
return resp
}
def getDevices(capability){
def result
switch (capability) {
case "Alarm":
result = alarms
break
case "ColorControl":
result = colorControls
break
case "DoorControl":
result = doorControls
break
case "ImageCapture":
result = imageCaptures
break
case "Lock":
result = locks
break
case "MediaController":
result = mediaControllers
break
case "Momentary":
result = momentaries
break
case "MusicPlayer":
result = musicPlayers
break
case "RelaySwitch":
result = relaySwitches
break
case "SpeechSynthesis":
result = speechSyntheses
break
case "Switch":
result = switches
break
case "SwitchLevel":
result = switchLevels
break
case "Thermostat":
result = thermostats
break
case "ThermostatCoolingSetpoint":
result = thermostatCoolingSetpoints
break
case "ThermostatFanMode":
result = thermostatFanModes
break
case "ThermostatHeatingSetpoint":
result = thermostatHeatingSetpoints
break
case "ThermostatMode":
result = thermostatModes
break
case "Tone":
result = tones
break
case "Valve":
result = valves
break
default:
result = valves
}
return result
}
def getDoorControlCommand(value){
def result
switch (value) {
case "closed":
result = "close"
break
case "open":
result = "open"
break
default:
result = value
}
return result
}
def getLockCommand(value){
def result
switch (value) {
case "locked":
result = "lock"
break
case "unlocked":
result = "unlock"
break
default:
result = value
}
return result
}
def getMuteCommand(value){
def result
switch (value) {
case "muted":
result = "mute"
break
case "unmuted":
result = "unmute"
break
default:
result = value
}
return result
}
def getContactCommand(value){
def result
switch (value) {
case "closed":
result = "close"
break
case "open":
result = "open"
break
default:
result = value
}
return result
}
def getRoutines() {
return location.helloHome?.getPhrases()*.label
}
def getThermostatFanModeCommand(value){
def result
switch (value) {
case "on":
result = "fanOn"
break
case "auto":
result = "fanAuto"
break
case "circulate":
result = "fanCirculate"
break
default:
result = value
}
return result
}
void executeCommand() {
def deviceId = request.JSON?.deviceId
def capability = request.JSON?.capability
def attribute = request.JSON?.attribute
def value = request.JSON?.value
if (deviceId) {
def devices = getDevices(capability)
def command
def valueIsParameter = false
def valueIsInteger = false
switch (attribute) {
case "hue":
command = "setHue"
valueIsParameter = true
valueIsInteger = true
break
case "saturation":
command = "setSaturation"
valueIsParameter = true
valueIsInteger = true
break
case "color":
command = "setColor"
def rgb = hexToRgb(value)
def hsl = rgbToHSL(rgb)
value = [hue:hsl.h.toInteger(), saturation:hsl.s.toInteger()]
valueIsParameter = true
break
case "level":
command = "setLevel"
valueIsParameter = true
valueIsInteger = true
break
case "heatingSetpoint":
command = "setHeatingSetpoint"
valueIsParameter = true
break
case "coolingSetpoint":
command = "setCoolingSetpoint"
valueIsParameter = true
break
case "currentActivity":
command = "startActivity"
valueIsParameter = true
break
case "door":
command = getDoorControlCommand(value)
break
case "lock":
command = getLockCommand(value)
break
case "mute":
command = getMuteCommand(value)
break
case "thermostatFanMode":
command = getThermostatFanModeCommand(value)
break
case "thermostatMode":
if (value == "emergency heat") {
command = "emergencyHeat"
}
else
{
command = value
}
break
case "contact":
command = getContactCommand(value)
break
default:
command = value
}
devices.each {
if (it.id == deviceId) {
// check that the device supports the specified command
// If not, return an error using httpError, providing a HTTP status code.
if (!it.hasCommand(command)) {
httpError(501, "$command is not a valid command for the device")
}
if(valueIsParameter){
if(valueIsInteger){
it."$command"(value as int)
}
else{
it."$command"(value)
}
}
else{
it."$command"()
}
}
}
}
}
void executeRoutine() {
def routine = request.JSON?.routine
location.helloHome?.execute(routine)
}
def rgbToHSL(rgb) {
def r = rgb.r / 255
def g = rgb.g / 255
def b = rgb.b / 255
def h = 0
def s = 0
def l = 0
def var_min = [r,g,b].min()
def var_max = [r,g,b].max()
def del_max = var_max - var_min
l = (var_max + var_min) / 2
if (del_max == 0) {
h = 0
s = 0
} else {
if (l < 0.5) { s = del_max / (var_max + var_min) }
else { s = del_max / (2 - var_max - var_min) }
def del_r = (((var_max - r) / 6) + (del_max / 2)) / del_max
def del_g = (((var_max - g) / 6) + (del_max / 2)) / del_max
def del_b = (((var_max - b) / 6) + (del_max / 2)) / del_max
if (r == var_max) { h = del_b - del_g }
else if (g == var_max) { h = (1 / 3) + del_r - del_b }
else if (b == var_max) { h = (2 / 3) + del_g - del_r }
if (h < 0) { h += 1 }
if (h > 1) { h -= 1 }
}
def hsl = [:]
hsl = [h: h * 100, s: s * 100, l: l]
hsl
}
def hexToRgb(colorHex) {
def rrInt = Integer.parseInt(colorHex.substring(1,3),16)
def ggInt = Integer.parseInt(colorHex.substring(3,5),16)
def bbInt = Integer.parseInt(colorHex.substring(5,7),16)
def colorData = [:]
colorData = [r: rrInt, g: ggInt, b: bbInt]
colorData
}
def installed() {
state.heartbeat = false
}
def updated() {
state.heartbeat = false
}