Compare commits

...

43 Commits

Author SHA1 Message Date
Vinay Rao
01593c3973 Merge pull request #1229 from SmartThingsCommunity/staging
Rolling down hotfix to master
2016-09-08 19:34:52 -07:00
Vinay Rao
6862785d6c Merge pull request #1228 from SmartThingsCommunity/production
Rolling down hotfix to staging
2016-09-08 19:33:26 -07:00
Amol Mundayoor
763d7411e2 Merge pull request #1227 from munds/netatmo
Removing debug logs for netatmo
2016-09-08 11:22:42 -07:00
Amol Mundayoor
c703543f36 Commenting out log.debug instead of removing them 2016-09-08 11:20:27 -07:00
dsainteclaire
5db6ecda3e Merge pull request #1226 from dsainteclaire/DVCSMP-1959-remove-logging-of-phone-numbers
DVCSMP-1959 removed logging of device and phone information due to security concerns
2016-09-08 11:10:22 -07:00
Amol Mundayoor
43b836f413 Removing debug logs for netatmo 2016-09-08 11:07:31 -07:00
David Sainte-Claire
006b5e7bea removed logging of device and phone information due to security concerns 2016-09-08 10:54:04 -07:00
Rohan Desai
62c8c19805 Merge pull request #1225 from rohandesai/dynamic-execution-fix
DVCSMP-1959: fixes for dynamic execution (Curb-control)
2016-09-08 10:47:55 -07:00
Rohan Desai
48e9a4bd6a removed semi colons 2016-09-08 10:46:40 -07:00
dsainteclaire
07a4c0decc Merge pull request #1223 from dsainteclaire/DVCSMP-1959-remove-sensitive-information-withings
DVCSMP-1959 removed logging of sensitive access tokens from smartapp
2016-09-08 10:41:56 -07:00
Andrew Bresee
6aa09bb052 Change log statement to not log personal phone number (#1224) 2016-09-08 13:40:35 -04:00
Rohan Desai
2f889de11a fixes for dynamic execution 2016-09-08 10:36:28 -07:00
David Sainte-Claire
5584020e96 removed logging of sensitive access tokens from smartapp 2016-09-08 10:31:24 -07:00
Jim Anderson
4ef2e694c2 Merge pull request #1180 from jimmyjames/ecobee-async-http-polling
[DVCSMP-1979] Use async http for polling and refresh tokens.
2016-09-08 12:13:53 -05:00
Jim Anderson
826993cc45 [DVCSMP-1979] Use async http for polling and refresh tokens. 2016-09-08 12:11:21 -05:00
Luke Bredeson
ae3306928b Merge pull request #1220 from lbredeso/fix-smart-security
DVCSMP-2020: smart-security app contains invalid code
2016-09-08 10:14:01 -05:00
Luke Bredeson
8777ec5f6d DVCSMP-2020: smart-security app contains invalid code 2016-09-08 10:06:38 -05:00
Andrew Bresee
91eb59a10d DVCSMP-1959: Replace log logging personal phone number (#1217)
* Replace log logging personal phone number

* Removed commented out log
2016-09-08 07:45:30 -04:00
Andrew Bresee
324ac13afb DVCSMP-1959: Unsubscribe from a pointless method (#1215)
* Unsubscribe from a pointless method

* Remove subscription to pointless method
2016-09-07 18:07:01 -04:00
Andrew Bresee
878eb66b8b Remove log logging personal information about a device (#1214) 2016-09-07 16:30:35 -04:00
Rohan Desai
8dfc270c2d Merge pull request #1213 from rohandesai/log-security-fixes
DVCSMP-1959 security fixes for SAs
2016-09-07 12:58:25 -07:00
Rohan Desai
614573a15c security fixes for SAs 2016-09-07 11:28:08 -07:00
dsainteclaire
9c7b0875ba Merge pull request #1211 from dsainteclaire/DVCSMP-1959-remove-sensitive-information-bon-voyage
DVCSMP-1959 removed log messages from smartapp that may print sensitive information
2016-09-07 11:24:22 -07:00
Andrew Bresee
7568cbf781 DVCSMP-1959: Security review - removing potentially confidential log statements (#1210)
* Commented out log statement logging users access token

* Commented out log.info logging potentially confidential device information

* Remove log logging potentially confidential information on the app
2016-09-07 14:11:20 -04:00
Vinay Rao
1858c280a5 Merge pull request #1212 from workingmonk/bug/negative_battery_1
SSVD-2771 fix to avoid negative values
2016-09-07 11:09:02 -07:00
Vinay Rao
6b7d0968f6 chaning min battery percentage to 1 2016-09-07 11:07:30 -07:00
David Sainte-Claire
159d3acf4f removed log messages from smartapp that may print sensitive information 2016-09-07 10:56:25 -07:00
Vinay Rao
e8101630a3 Merge pull request #1209 from workingmonk/bug/negative_battery
SSVD-2771 fix to avoid negative values
2016-09-07 10:49:40 -07:00
Vinay Rao
f5ba78b221 fix to avoid negative values 2016-09-07 10:46:12 -07:00
tslagle13
19b8a7eeb9 Merge pull request #1167 from CosmicPuppy/CosmicPuppy-Netatmo-CapabilitySensor
MSA-1468 - To Netatmo DTHs, added Capability "Sensor"
2016-09-07 10:15:42 -07:00
twack
1b37d649a5 Merge pull request #1207 from twack/20160907_update_its_too_hot
(DVCSMP-1959) 20160907_update_its_to_hot_for_security
2016-09-07 09:22:09 -07:00
twack
dedb0f8465 Update its-too-hot.groovy 2016-09-07 09:20:13 -07:00
Juan Pablo Risso
06acc13575 DVCSMP-1959 - Remove sensitive information from logs (#1206) 2016-09-07 12:14:58 -04:00
twack
c051d719cc 20160907_update_its_to_hot_for_security 2016-09-07 09:14:19 -07:00
Vinay Rao
1e54b93b0c Merge pull request #1203 from SmartThingsCommunity/master
Rolling up master to staging
2016-09-06 17:15:57 -07:00
Vinay Rao
bac37f9ca2 Merge pull request #1202 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-09-06 17:08:39 -07:00
Vinay Rao
f0ecb65c09 Merge pull request #1201 from SmartThingsCommunity/revert-1197-revert_WWST-40_staging
Revert "Revert "WWST-40 Philips Hue: Implement device watch""
2016-09-06 17:07:33 -07:00
Vinay Rao
1c0ddd2571 Revert "Revert "WWST-40 Philips Hue: Implement device watch"" 2016-09-06 17:07:14 -07:00
Vinay Rao
b7e0cbda09 Merge pull request #1200 from SmartThingsCommunity/revert-1194-revert-latest-ecobee-changes
Revert "revert changes for DVCSMP-1980 and SSVD-2534 on staging"
2016-09-06 17:07:06 -07:00
Vinay Rao
f80e094bd9 Revert "revert changes for DVCSMP-1980 and SSVD-2534 on staging" 2016-09-06 17:06:38 -07:00
Juan Pablo Risso
383f72580a SSVD-2738 - SSVD-2734 - SSVD-2733 (#1187)
* SSVD-2738 - Count Down Bug

* SSVD-2734 - Copy text

* SSVD-2733 - Add Unit
2016-09-06 11:39:18 -04:00
Vinay Rao
090a306939 Merge pull request #1184 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-08-31 16:05:08 -07:00
CosmicPuppy
5e6b4f74e0 To Netatmo DTHs, added Capability "Sensor" per http://docs.smartthings.com/en/latest/device-type-developers-guide/overview.html?highlight=sensor%20actuator#actuator-and-sensor.
There are some SmartApps out there using the "Actuator" and "Sensor" Capabilities and this Device doesn't show up for them (e.g., SmartTiles V6).
2016-08-29 13:55:19 -07:00
41 changed files with 823 additions and 504 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -67,6 +67,6 @@ def refresh() {
void poll() { void poll() {
log.debug "Executing 'poll' using parent SmartApp" log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild() parent.poll()
} }

View File

@@ -133,7 +133,7 @@ def refresh() {
void poll() { void poll() {
log.debug "Executing 'poll' using parent SmartApp" log.debug "Executing 'poll' using parent SmartApp"
parent.pollChild() parent.poll()
} }
def generateEvent(Map results) { def generateEvent(Map results) {
@@ -152,11 +152,11 @@ def generateEvent(Map results) {
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
isChange = isTemperatureStateChange(device, name, value.toString()) isChange = isTemperatureStateChange(device, name, value.toString())
isDisplayed = isChange isDisplayed = isChange
event << [value: sendValue, isStateChange: isChange, displayed: isDisplayed] event << [value: sendValue, unit: temperatureScale, isStateChange: isChange, displayed: isDisplayed]
} else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") { } else if (name=="maxCoolingSetpoint" || name=="minCoolingSetpoint" || name=="maxHeatingSetpoint" || name=="minHeatingSetpoint") {
def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F def sendValue = convertTemperatureIfNeeded(value.toDouble(), "F", 1) //API return temperature value in F
sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue sendValue = location.temperatureScale == "C"? roundC(sendValue) : sendValue
event << [value: sendValue, displayed: false] event << [value: sendValue, unit: temperatureScale, displayed: false]
} else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){ } else if (name=="heatMode" || name=="coolMode" || name=="autoMode" || name=="auxHeatMode"){
isChange = isStateChange(device, name, value.toString()) isChange = isStateChange(device, name, value.toString())
event << [value: value.toString(), isStateChange: isChange, displayed: false] event << [value: value.toString(), isStateChange: isChange, displayed: false]
@@ -234,9 +234,9 @@ void setHeatingSetpoint(setpoint) {
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite" def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) { if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint) sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint) sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}" log.debug "Done setHeatingSetpoint> coolingSetpoint: ${coolingSetpoint}, heatingSetpoint: ${heatingSetpoint}"
generateSetpointEvent() generateSetpointEvent()
generateStatusEvent() generateStatusEvent()
@@ -271,9 +271,9 @@ void setCoolingSetpoint(setpoint) {
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite" def sendHoldType = holdType ? (holdType=="Temporary")? "nextTransition" : (holdType=="Permanent")? "indefinite" : "indefinite" : "indefinite"
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) { if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name":"heatingSetpoint", "value":heatingSetpoint) sendEvent("name":"heatingSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
sendEvent("name":"coolingSetpoint", "value":coolingSetpoint) sendEvent("name":"coolingSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}" log.debug "Done setCoolingSetpoint>> coolingSetpoint = ${coolingSetpoint}, heatingSetpoint = ${heatingSetpoint}"
generateSetpointEvent() generateSetpointEvent()
generateStatusEvent() generateStatusEvent()
@@ -287,14 +287,14 @@ void resumeProgram() {
log.debug "resumeProgram() is called" log.debug "resumeProgram() is called"
sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false) sendEvent("name":"thermostatStatus", "value":"resuming schedule", "description":statusText, displayed: false)
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.resumeProgram(this, deviceId)) { if (parent.resumeProgram(deviceId)) {
sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false) sendEvent("name":"thermostatStatus", "value":"setpoint is updating", "description":statusText, displayed: false)
runIn(5, "poll") runIn(5, "poll")
log.debug "resumeProgram() is done" log.debug "resumeProgram() is done"
sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true) sendEvent("name":"resumeProgram", "value":"resume", descriptionText: "resumeProgram is done", displayed: false, isStateChange: true)
} else { } else {
sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false) sendEvent("name":"thermostatStatus", "value":"failed resume click refresh", "description":statusText, displayed: false)
log.error "Error resumeProgram() check parent.resumeProgram(this, deviceId)" log.error "Error resumeProgram() check parent.resumeProgram(deviceId)"
} }
} }
@@ -406,7 +406,7 @@ def generateOperatingStateEvent(operatingState) {
def off() { def off() {
log.debug "off" log.debug "off"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode (this,"off", deviceId)) if (parent.setMode ("off", deviceId))
generateModeEvent("off") generateModeEvent("off")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -420,7 +420,7 @@ def off() {
def heat() { def heat() {
log.debug "heat" log.debug "heat"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode (this,"heat", deviceId)) if (parent.setMode ("heat", deviceId))
generateModeEvent("heat") generateModeEvent("heat")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -438,7 +438,7 @@ def emergencyHeat() {
def auxHeatOnly() { def auxHeatOnly() {
log.debug "auxHeatOnly" log.debug "auxHeatOnly"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode (this,"auxHeatOnly", deviceId)) if (parent.setMode ("auxHeatOnly", deviceId))
generateModeEvent("auxHeatOnly") generateModeEvent("auxHeatOnly")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -452,7 +452,7 @@ def auxHeatOnly() {
def cool() { def cool() {
log.debug "cool" log.debug "cool"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode (this,"cool", deviceId)) if (parent.setMode ("cool", deviceId))
generateModeEvent("cool") generateModeEvent("cool")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -466,7 +466,7 @@ def cool() {
def auto() { def auto() {
log.debug "auto" log.debug "auto"
def deviceId = device.deviceNetworkId.split(/\./).last() def deviceId = device.deviceNetworkId.split(/\./).last()
if (parent.setMode (this,"auto", deviceId)) if (parent.setMode ("auto", deviceId))
generateModeEvent("auto") generateModeEvent("auto")
else { else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -489,7 +489,7 @@ def fanOn() {
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) { if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode) generateFanModeEvent(fanMode)
} else { } else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -510,7 +510,7 @@ def fanAuto() {
def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint def coolingValue = location.temperatureScale == "C"? convertCtoF(coolingSetpoint) : coolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint def heatingValue = location.temperatureScale == "C"? convertCtoF(heatingSetpoint) : heatingSetpoint
if (parent.setFanMode(this, heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) { if (parent.setFanMode(heatingValue, coolingValue, deviceId, sendHoldType, fanMode)) {
generateFanModeEvent(fanMode) generateFanModeEvent(fanMode)
} else { } else {
log.debug "Error setting new mode." log.debug "Error setting new mode."
@@ -556,12 +556,12 @@ def generateSetpointEvent() {
if (mode == "heat") { if (mode == "heat") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint ) sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
} }
else if (mode == "cool") { else if (mode == "cool") {
sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint) sendEvent("name":"thermostatSetpoint", "value":coolingSetpoint, "unit":location.temperatureScale)
} else if (mode == "auto") { } else if (mode == "auto") {
@@ -573,7 +573,7 @@ def generateSetpointEvent() {
} else if (mode == "auxHeatOnly") { } else if (mode == "auxHeatOnly") {
sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint) sendEvent("name":"thermostatSetpoint", "value":heatingSetpoint, "unit":location.temperatureScale)
} }
@@ -608,7 +608,7 @@ void raiseSetpoint() {
targetvalue = maxCoolingSetpoint targetvalue = maxCoolingSetpoint
} }
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false) sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode raiseSetpoint() to $targetvalue" log.info "In mode $mode raiseSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -644,7 +644,7 @@ void lowerSetpoint() {
targetvalue = minCoolingSetpoint targetvalue = minCoolingSetpoint
} }
sendEvent("name":"thermostatSetpoint", "value":targetvalue, displayed: false) sendEvent("name":"thermostatSetpoint", "value":targetvalue, "unit":location.temperatureScale, displayed: false)
log.info "In mode $mode lowerSetpoint() to $targetvalue" log.info "In mode $mode lowerSetpoint() to $targetvalue"
runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite runIn(3, "alterSetpoint", [data: [value:targetvalue], overwrite: true]) //when user click button this runIn will be overwrite
@@ -690,10 +690,10 @@ void alterSetpoint(temp) {
def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint def coolingValue = location.temperatureScale == "C"? convertCtoF(targetCoolingSetpoint) : targetCoolingSetpoint
def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint def heatingValue = location.temperatureScale == "C"? convertCtoF(targetHeatingSetpoint) : targetHeatingSetpoint
if (parent.setHold(this, heatingValue, coolingValue, deviceId, sendHoldType)) { if (parent.setHold(heatingValue, coolingValue, deviceId, sendHoldType)) {
sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false) sendEvent("name": "thermostatSetpoint", "value": temp.value, displayed: false)
sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint) sendEvent("name": "heatingSetpoint", "value": targetHeatingSetpoint, "unit": location.temperatureScale)
sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint) sendEvent("name": "coolingSetpoint", "value": targetCoolingSetpoint, "unit": location.temperatureScale)
log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}" log.debug "alterSetpoint in mode $mode succeed change setpoint to= ${temp.value}"
} else { } else {
log.error "Error alterSetpoint()" log.error "Error alterSetpoint()"

View File

@@ -16,6 +16,7 @@ metadata {
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Health Check"
command "setAdjustedColor" command "setAdjustedColor"
command "reset" command "reset"
@@ -55,6 +56,10 @@ metadata {
} }
} }
void installed() {
sendEvent(name: "checkInterval", value: 60 * 30, data: [protocol: "lan"], displayed: false)
}
// parse events into attributes // parse events into attributes
def parse(description) { def parse(description) {
log.debug "parse() - $description" log.debug "parse() - $description"
@@ -166,3 +171,7 @@ def verifyPercent(percent) {
return false return false
} }
} }
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -17,6 +17,7 @@ metadata {
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Health Check"
command "setAdjustedColor" command "setAdjustedColor"
command "reset" command "reset"
@@ -64,6 +65,10 @@ metadata {
} }
} }
void installed() {
sendEvent(name: "checkInterval", value: 60 * 30, data: [protocol: "lan"], displayed: false)
}
// parse events into attributes // parse events into attributes
def parse(description) { def parse(description) {
log.debug "parse() - $description" log.debug "parse() - $description"
@@ -182,3 +187,7 @@ def verifyPercent(percent) {
return false return false
} }
} }
def ping() {
log.trace "${parent.ping(this)}"
}

View File

@@ -14,6 +14,7 @@ metadata {
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Health Check"
command "refresh" command "refresh"
} }
@@ -48,6 +49,10 @@ metadata {
} }
} }
void installed() {
sendEvent(name: "checkInterval", value: 60 * 30, data: [protocol: "lan"], displayed: false)
}
// parse events into attributes // parse events into attributes
def parse(description) { def parse(description) {
log.debug "parse() - $description" log.debug "parse() - $description"
@@ -87,3 +92,7 @@ void refresh() {
log.debug "Executing 'refresh'" log.debug "Executing 'refresh'"
parent.manualRefresh() parent.manualRefresh()
} }
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -15,6 +15,7 @@ metadata {
capability "Color Temperature" capability "Color Temperature"
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Health Check"
command "refresh" command "refresh"
} }
@@ -53,6 +54,10 @@ metadata {
} }
} }
void installed() {
sendEvent(name: "checkInterval", value: 60 * 30, data: [protocol: "lan"], displayed: false)
}
// parse events into attributes // parse events into attributes
def parse(description) { def parse(description) {
log.debug "parse() - $description" log.debug "parse() - $description"
@@ -101,3 +106,7 @@ void refresh() {
log.debug "Executing 'refresh'" log.debug "Executing 'refresh'"
parent.manualRefresh() parent.manualRefresh()
} }
def ping() {
log.debug "${parent.ping(this)}"
}

View File

@@ -233,6 +233,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
} }

View File

@@ -248,6 +248,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
} }

View File

@@ -206,6 +206,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "${linkText} battery was ${result.value}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }

View File

@@ -313,6 +313,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "{{ device.displayName }} battery was {{ value }}%" result.descriptionText = "{{ device.displayName }} battery was {{ value }}%"
} }

View File

@@ -206,6 +206,8 @@ def getTemperature(value) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "${linkText} battery was ${result.value}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }

View File

@@ -207,6 +207,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "${linkText} battery was ${result.value}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }

View File

@@ -214,6 +214,8 @@ private Map getBatteryResult(rawValue) {
def maxVolts = 3.0 def maxVolts = 3.0
def pct = (volts - minVolts) / (maxVolts - minVolts) def pct = (volts - minVolts) / (maxVolts - minVolts)
def roundedPct = Math.round(pct * 100) def roundedPct = Math.round(pct * 100)
if (roundedPct <= 0)
roundedPct = 1
result.value = Math.min(100, roundedPct) result.value = Math.min(100, roundedPct)
result.descriptionText = "${linkText} battery was ${result.value}%" result.descriptionText = "${linkText} battery was ${result.value}%"
} }

View File

@@ -65,7 +65,16 @@ void updateSwitch() {
private void updateAll(devices) { private void updateAll(devices) {
def command = request.JSON?.command def command = request.JSON?.command
if (command) { if (command) {
devices."$command"() switch(command) {
case "on":
devices.on()
break
case "off":
devices.off()
break
default:
httpError(403, "Access denied. This command is not supported by current capability.")
}
} }
} }
@@ -77,7 +86,16 @@ private void update(devices) {
if (!device) { if (!device) {
httpError(404, "Device not found") httpError(404, "Device not found")
} else { } else {
device."$command"() switch(command) {
case "on":
device.on()
break
case "off":
device.off()
break
default:
httpError(403, "Access denied. This command is not supported by current capability.")
}
} }
} }
} }

View File

@@ -58,7 +58,7 @@ def authPage() {
if (canInstallLabs()) { if (canInstallLabs()) {
def redirectUrl = getBuildRedirectUrl() def redirectUrl = getBuildRedirectUrl()
log.debug "Redirect url = ${redirectUrl}" // log.debug "Redirect url = ${redirectUrl}"
if (state.authToken) { if (state.authToken) {
description = "Tap 'Next' to proceed" description = "Tap 'Next' to proceed"
@@ -113,13 +113,13 @@ def oauthInitUrl() {
scope: "read_station" scope: "read_station"
] ]
log.debug "REDIRECT URL: ${getVendorAuthPath() + toQueryString(oauthParams)}" // log.debug "REDIRECT URL: ${getVendorAuthPath() + toQueryString(oauthParams)}"
redirect (location: getVendorAuthPath() + toQueryString(oauthParams)) redirect (location: getVendorAuthPath() + toQueryString(oauthParams))
} }
def callback() { def callback() {
log.debug "callback()>> params: $params, params.code ${params.code}" // log.debug "callback()>> params: $params, params.code ${params.code}"
def code = params.code def code = params.code
def oauthState = params.state def oauthState = params.state
@@ -135,7 +135,7 @@ def callback() {
scope: "read_station" scope: "read_station"
] ]
log.debug "TOKEN URL: ${getVendorTokenPath() + toQueryString(tokenParams)}" // log.debug "TOKEN URL: ${getVendorTokenPath() + toQueryString(tokenParams)}"
def tokenUrl = getVendorTokenPath() def tokenUrl = getVendorTokenPath()
def params = [ def params = [
@@ -144,7 +144,7 @@ def callback() {
body: tokenParams body: tokenParams
] ]
log.debug "PARAMS: ${params}" // log.debug "PARAMS: ${params}"
httpPost(params) { resp -> httpPost(params) { resp ->
@@ -156,7 +156,7 @@ def callback() {
state.refreshToken = data.refresh_token state.refreshToken = data.refresh_token
state.authToken = data.access_token state.authToken = data.access_token
state.tokenExpires = now() + (data.expires_in * 1000) state.tokenExpires = now() + (data.expires_in * 1000)
log.debug "swapped token: $resp.data" // log.debug "swapped token: $resp.data"
} }
} }
@@ -292,7 +292,7 @@ def refreshToken() {
response.data.each {key, value -> response.data.each {key, value ->
def data = slurper.parseText(key); def data = slurper.parseText(key);
log.debug "Data: $data" // log.debug "Data: $data"
state.refreshToken = data.refresh_token state.refreshToken = data.refresh_token
state.accessToken = data.access_token state.accessToken = data.access_token

View File

@@ -17,7 +17,7 @@ definition(
name: "Monitor on Sense", name: "Monitor on Sense",
namespace: "resteele", namespace: "resteele",
author: "Rachel Steele", author: "Rachel Steele",
description: "Turn on Monitor when vibration is sensed", description: "Turn on switch when vibration is sensed",
category: "My Apps", category: "My Apps",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png", iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
@@ -25,10 +25,10 @@ definition(
preferences { preferences {
section("When the keyboard is used...") { section("When vibration is sensed...") {
input "accelerationSensor", "capability.accelerationSensor", title: "Which Sensor?" input "accelerationSensor", "capability.accelerationSensor", title: "Which Sensor?"
} }
section("Turn on/off a light...") { section("Turn on switch...") {
input "switch1", "capability.switch" input "switch1", "capability.switch"
} }
} }
@@ -47,5 +47,3 @@ def updated() {
def accelerationActiveHandler(evt) { def accelerationActiveHandler(evt) {
switch1.on() switch1.on()
} }

View File

@@ -114,13 +114,16 @@ def beaconHandler(evt) {
if (allOk) { if (allOk) {
def data = new groovy.json.JsonSlurper().parseText(evt.data) def data = new groovy.json.JsonSlurper().parseText(evt.data)
log.debug "<beacon-control> data: $data - phones: " + phones*.deviceNetworkId // removed logging of device names. can be added back for debugging
//log.debug "<beacon-control> data: $data - phones: " + phones*.deviceNetworkId
def beaconName = getBeaconName(evt) def beaconName = getBeaconName(evt)
log.debug "<beacon-control> beaconName: $beaconName" // removed logging of device names. can be added back for debugging
//log.debug "<beacon-control> beaconName: $beaconName"
def phoneName = getPhoneName(data) def phoneName = getPhoneName(data)
log.debug "<beacon-control> phoneName: $phoneName" // removed logging of device names. can be added back for debugging
//log.debug "<beacon-control> phoneName: $phoneName"
if (phoneName != null) { if (phoneName != null) {
def action = data.presence == "1" ? "arrived" : "left" def action = data.presence == "1" ? "arrived" : "left"
def msg = "$phoneName has $action ${action == 'arrived' ? 'at ' : ''}the $beaconName" def msg = "$phoneName has $action ${action == 'arrived' ? 'at ' : ''}the $beaconName"

View File

@@ -49,13 +49,15 @@ preferences {
def installed() { def installed() {
log.debug "Installed with settings: ${settings}" log.debug "Installed with settings: ${settings}"
log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" // commented out log statement because presence sensor label could contain user's name
//log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
subscribe(people, "presence", presence) subscribe(people, "presence", presence)
} }
def updated() { def updated() {
log.debug "Updated with settings: ${settings}" log.debug "Updated with settings: ${settings}"
log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" // commented out log statement because presence sensor label could contain user's name
//log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
unsubscribe() unsubscribe()
subscribe(people, "presence", presence) subscribe(people, "presence", presence)
} }

View File

@@ -64,10 +64,12 @@ def meterHandler(evt) {
def lastValue = atomicState.lastValue as double def lastValue = atomicState.lastValue as double
atomicState.lastValue = meterValue atomicState.lastValue = meterValue
def dUnit ? evt.unit : "Watts"
def aboveThresholdValue = aboveThreshold as int def aboveThresholdValue = aboveThreshold as int
if (meterValue > aboveThresholdValue) { if (meterValue > aboveThresholdValue) {
if (lastValue < aboveThresholdValue) { // only send notifications when crossing the threshold if (lastValue < aboveThresholdValue) { // only send notifications when crossing the threshold
def msg = "${meter} reported ${evt.value} ${evt.unit} which is above your threshold of ${aboveThreshold}." def msg = "${meter} reported ${evt.value} ${dUnit} which is above your threshold of ${aboveThreshold}."
sendMessage(msg) sendMessage(msg)
} else { } else {
// log.debug "not sending notification for ${evt.description} because the threshold (${aboveThreshold}) has already been crossed" // log.debug "not sending notification for ${evt.description} because the threshold (${aboveThreshold}) has already been crossed"
@@ -78,7 +80,7 @@ def meterHandler(evt) {
def belowThresholdValue = belowThreshold as int def belowThresholdValue = belowThreshold as int
if (meterValue < belowThresholdValue) { if (meterValue < belowThresholdValue) {
if (lastValue > belowThresholdValue) { // only send notifications when crossing the threshold if (lastValue > belowThresholdValue) { // only send notifications when crossing the threshold
def msg = "${meter} reported ${evt.value} ${evt.unit} which is below your threshold of ${belowThreshold}." def msg = "${meter} reported ${evt.value} ${dUnit} which is below your threshold of ${belowThreshold}."
sendMessage(msg) sendMessage(msg)
} else { } else {
// log.debug "not sending notification for ${evt.description} because the threshold (${belowThreshold}) has already been crossed" // log.debug "not sending notification for ${evt.description} because the threshold (${belowThreshold}) has already been crossed"

View File

@@ -54,10 +54,10 @@ def waterWetHandler(evt) {
def alreadySentSms = recentEvents.count { it.value && it.value == "wet" } > 1 def alreadySentSms = recentEvents.count { it.value && it.value == "wet" } > 1
if (alreadySentSms) { if (alreadySentSms) {
log.debug "SMS already sent to $phone within the last $deltaSeconds seconds" log.debug "SMS already sent within the last $deltaSeconds seconds"
} else { } else {
def msg = "${alarm.displayName} is wet!" def msg = "${alarm.displayName} is wet!"
log.debug "$alarm is wet, texting $phone" log.debug "$alarm is wet, texting phone number"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients) sendNotificationToContacts(msg, recipients)

View File

@@ -90,7 +90,7 @@ def takeAction(){
} }
def sendTextMessage() { def sendTextMessage() {
log.debug "$multisensor was open too long, texting $phone" log.debug "$multisensor was open too long, texting phone"
updateSmsHistory() updateSmsHistory()
def openMinutes = maxOpenTime * (state.smsHistory?.size() ?: 1) def openMinutes = maxOpenTime * (state.smsHistory?.size() ?: 1)

View File

@@ -761,7 +761,7 @@ String displayableTime(timeRemaining) {
return "${minutes}:00" return "${minutes}:00"
} }
def fraction = "0.${parts[1]}" as double def fraction = "0.${parts[1]}" as double
def seconds = "${60 * fraction as int}".padRight(2, "0") def seconds = "${60 * fraction as int}".padLeft(2, "0")
return "${minutes}:${seconds}" return "${minutes}:${seconds}"
} }

View File

@@ -47,13 +47,13 @@ preferences {
def installed() { def installed() {
log.debug "Installed with settings: ${settings}" log.debug "Installed with settings: ${settings}"
log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" // log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
subscribe(people, "presence", presence) subscribe(people, "presence", presence)
} }
def updated() { def updated() {
log.debug "Updated with settings: ${settings}" log.debug "Updated with settings: ${settings}"
log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}" // log.debug "Current mode = ${location.mode}, people = ${people.collect{it.label + ': ' + it.currentPresence}}"
unsubscribe() unsubscribe()
subscribe(people, "presence", presence) subscribe(people, "presence", presence)
} }
@@ -71,11 +71,10 @@ def presence(evt)
def person = getPerson(evt) def person = getPerson(evt)
def recentNotPresent = person.statesSince("presence", t0).find{it.value == "not present"} def recentNotPresent = person.statesSince("presence", t0).find{it.value == "not present"}
if (recentNotPresent) { if (recentNotPresent) {
log.debug "skipping notification of arrival of ${person.displayName} because last departure was only ${now() - recentNotPresent.date.time} msec ago" log.debug "skipping notification of arrival of Person because last departure was only ${now() - recentNotPresent.date.time} msec ago"
} }
else { else {
def message = "${person.displayName} arrived at home, changing mode to '${newMode}'" def message = "${person.displayName} arrived at home, changing mode to '${newMode}'"
log.info message
send(message) send(message)
setLocationMode(newMode) setLocationMode(newMode)
} }
@@ -106,6 +105,4 @@ private send(msg) {
sendSms(phone, msg) sendSms(phone, msg)
} }
} }
log.debug msg
} }

View File

@@ -57,12 +57,11 @@ def scheduleCheck()
def message = message1 ?: "SmartThings - Habit Helper Reminder!" def message = message1 ?: "SmartThings - Habit Helper Reminder!"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
log.debug "Texting reminder: ($message) to contacts:${recipients?.size()}" log.debug "Texting reminder to contacts:${recipients?.size()}"
sendNotificationToContacts(message, recipients) sendNotificationToContacts(message, recipients)
} }
else { else {
log.debug "Texting reminder"
log.debug "Texting reminder: ($message) to $phone1"
sendSms(phone1, message) sendSms(phone1, message)
} }
} }

View File

@@ -95,8 +95,7 @@ def bridgeDiscoveryFailed() {
} }
} }
def bridgeLinking() def bridgeLinking() {
{
int linkRefreshcount = !state.linkRefreshcount ? 0 : state.linkRefreshcount as int int linkRefreshcount = !state.linkRefreshcount ? 0 : state.linkRefreshcount as int
state.linkRefreshcount = linkRefreshcount + 1 state.linkRefreshcount = linkRefreshcount + 1
def refreshInterval = 3 def refreshInterval = 3
@@ -328,7 +327,7 @@ def bulbListHandler(hub, data = "") {
def object = new groovy.json.JsonSlurper().parseText(data) def object = new groovy.json.JsonSlurper().parseText(data)
object.each { k,v -> object.each { k,v ->
if (v instanceof Map) if (v instanceof Map)
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub] bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub, online: v.state?.reachable]
} }
} }
def bridge = null def bridge = null
@@ -448,7 +447,6 @@ def addBridge() {
updateBridgeStatus(childDevice) updateBridgeStatus(childDevice)
childDevice.sendEvent(name: "idNumber", value: idNumber) childDevice.sendEvent(name: "idNumber", value: idNumber)
if (vbridge.value.ip && vbridge.value.port) { if (vbridge.value.ip && vbridge.value.port) {
if (vbridge.value.ip.contains(".")) { if (vbridge.value.ip.contains(".")) {
childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port) childDevice.sendEvent(name: "networkAddress", value: vbridge.value.ip + ":" + vbridge.value.port)
@@ -649,8 +647,7 @@ def locationHandler(evt) {
} }
} }
} }
} } else if (parsedEvent.headers && parsedEvent.body) {
else if (parsedEvent.headers && parsedEvent.body) {
log.trace "HUE BRIDGE RESPONSES" log.trace "HUE BRIDGE RESPONSES"
def headerString = parsedEvent.headers.toString() def headerString = parsedEvent.headers.toString()
if (headerString?.contains("xml")) { if (headerString?.contains("xml")) {
@@ -733,7 +730,7 @@ private void updateBridgeStatus(childDevice) {
private void checkBridgeStatus() { private void checkBridgeStatus() {
def bridges = getHueBridges() def bridges = getHueBridges()
// Check if each bridge has been heard from within the last 16 minutes (3 poll intervals times 5 minutes plus buffer) // Check if each bridge has been heard from within the last 16 minutes (3 poll intervals times 5 minutes plus buffer)
def time = now() - (1000 * 60 * 16) def time = now() - (1000 * 60 * 30)
bridges.each { bridges.each {
def d = getChildDevice(it.value.mac) def d = getChildDevice(it.value.mac)
if(d) { if(d) {
@@ -746,6 +743,8 @@ private void checkBridgeStatus() {
if (it.value.lastActivity < time) { // it.value.lastActivity != null && if (it.value.lastActivity < time) { // it.value.lastActivity != null &&
log.warn "Bridge $it.key is Offline" log.warn "Bridge $it.key is Offline"
d.sendEvent(name: "status", value: "Offline") d.sendEvent(name: "status", value: "Offline")
// set all lights to offline since bridge is not reachable
state.bulbs?.each {it.value.online = false}
} else { } else {
d.sendEvent(name: "status", value: "Online")//setOnline(false) d.sendEvent(name: "status", value: "Online")//setOnline(false)
} }
@@ -785,8 +784,7 @@ def parse(childDevice, description) {
if (body instanceof java.util.Map) { if (body instanceof java.util.Map) {
// get (poll) reponse // get (poll) reponse
return handlePoll(body) return handlePoll(body)
} } else {
else {
//put response //put response
return handleCommandResponse(body) return handleCommandResponse(body)
} }
@@ -883,36 +881,40 @@ private handleCommandResponse(body) {
// scan entire response before sending events to make sure they are always in the same order // scan entire response before sending events to make sure they are always in the same order
def updates = [:] def updates = [:]
body.each { payload -> body.each { payload ->
log.debug $payload log.debug $payload
if (payload?.success) { if (payload?.success) {
def childDeviceNetworkId = app.id + "/" def childDeviceNetworkId = app.id + "/"
def eventType def eventType
payload.success.each { k, v -> payload.success.each { k, v ->
def data = k.split("/") def data = k.split("/")
if (data.length == 5) { if (data.length == 5) {
childDeviceNetworkId = app.id + "/" + k.split("/")[2] childDeviceNetworkId = app.id + "/" + k.split("/")[2]
if (!updates[childDeviceNetworkId]) if (!updates[childDeviceNetworkId])
updates[childDeviceNetworkId] = [:] updates[childDeviceNetworkId] = [:]
eventType = k.split("/")[4] eventType = k.split("/")[4]
updates[childDeviceNetworkId]."$eventType" = v updates[childDeviceNetworkId]."$eventType" = v
} }
} }
} else if (payload.error) { } else if (payload.error) {
log.warn "Error returned from Hue bridge error = ${body?.error}" log.warn "Error returned from Hue bridge error = ${body?.error}"
} }
} }
// send events for each update found above (order of events should be same as handlePoll()) // send events for each update found above (order of events should be same as handlePoll())
updates.each { childDeviceNetworkId, params -> updates.each { childDeviceNetworkId, params ->
def device = getChildDevice(childDeviceNetworkId) def device = getChildDevice(childDeviceNetworkId)
sendBasicEvents(device, "on", params.on) def id = getId(device)
sendBasicEvents(device, "bri", params.bri) // If device is offline, then don't send events which will update device watch
sendColorEvents(device, params.xy, params.hue, params.sat, params.ct) if (isOnline(id)) {
} sendBasicEvents(device, "on", params.on)
sendBasicEvents(device, "bri", params.bri)
sendColorEvents(device, params.xy, params.hue, params.sat, params.ct)
}
}
return [] return []
} }
/** /**
* Handles a response to a poll (GET) sent to the Hue Bridge. * Handles a response to a poll (GET) sent to the Hue Bridge.
@@ -932,26 +934,32 @@ private handleCommandResponse(body) {
* @return empty array * @return empty array
*/ */
private handlePoll(body) { private handlePoll(body) {
if (state.updating) {
// If user just executed commands, then ignore poll to not confuse the turning on/off state
return []
}
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}"}
if (device) { if (device) {
if (bulb.value.state?.reachable) { if (bulb.value.state?.reachable) {
sendBasicEvents(device, "on", bulb.value?.state?.on) if (state.bulbs[bulb.key]?.online == false) {
sendBasicEvents(device, "bri", bulb.value?.state?.bri) // light just came back online, notify device watch
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode) def lastActivity = now()
device.sendEvent(name: "deviceWatch-status", value: "ONLINE", description: "Last Activity is on ${new Date((long) lastActivity)}", displayed: false, isStateChange: 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 (!state.updating) {
sendBasicEvents(device, "on", bulb.value?.state?.on)
sendBasicEvents(device, "bri", bulb.value?.state?.bri)
sendColorEvents(device, bulb.value?.state?.xy, bulb.value?.state?.hue, bulb.value?.state?.sat, bulb.value?.state?.ct, bulb.value?.state?.colormode)
}
} else { } else {
state.bulbs[bulb.key]?.online = false
log.warn "$device is not reachable by Hue bridge" log.warn "$device is not reachable by Hue bridge"
} }
} }
}
return []
} }
return []
}
private updateInProgress() { private updateInProgress() {
state.updating = true state.updating = true
@@ -980,22 +988,34 @@ def hubVerification(bodytext) {
def on(childDevice) { def on(childDevice) {
log.debug "Executing 'on'" log.debug "Executing 'on'"
def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/${getId(childDevice)}/state", [on: true]) put("lights/$id/state", [on: true])
return "Bulb is turning On" return "Bulb is turning On"
} }
def off(childDevice) { def off(childDevice) {
log.debug "Executing 'off'" log.debug "Executing 'off'"
def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
createSwitchEvent(childDevice, "off") createSwitchEvent(childDevice, "off")
put("lights/${getId(childDevice)}/state", [on: false]) put("lights/$id/state", [on: false])
return "Bulb is turning Off" return "Bulb is turning Off"
} }
def setLevel(childDevice, percent) { def setLevel(childDevice, percent) {
log.debug "Executing 'setLevel'" log.debug "Executing 'setLevel'"
def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
// 1 - 254 // 1 - 254
def level def level
@@ -1010,48 +1030,64 @@ def setLevel(childDevice, percent) {
// that means that the light will still be on when on is called next time // that means that the light will still be on when on is called next time
// Lets emulate that here // Lets emulate that here
if (percent > 0) { if (percent > 0) {
put("lights/${getId(childDevice)}/state", [bri: level, on: true]) put("lights/$id/state", [bri: level, on: true])
} else { } else {
put("lights/${getId(childDevice)}/state", [on: false]) put("lights/$id/state", [on: false])
} }
return "Setting level to $percent" return "Setting level to $percent"
} }
def setSaturation(childDevice, percent) { def setSaturation(childDevice, percent) {
log.debug "Executing 'setSaturation($percent)'" log.debug "Executing 'setSaturation($percent)'"
updateInProgress() def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
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)
// TODO should this be done by app only or should we default to on? // TODO should this be done by app only or should we default to on?
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/${getId(childDevice)}/state", [sat: level, on: true]) put("lights/$id/state", [sat: level, on: true])
return "Setting saturation to $percent" return "Setting saturation to $percent"
} }
def setHue(childDevice, percent) { def setHue(childDevice, percent) {
log.debug "Executing 'setHue($percent)'" log.debug "Executing 'setHue($percent)'"
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)
// TODO should this be done by app only or should we default to on? // TODO should this be done by app only or should we default to on?
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/${getId(childDevice)}/state", [hue: level, on: true]) put("lights/$id/state", [hue: level, on: true])
return "Setting hue to $percent" return "Setting hue to $percent"
} }
def setColorTemperature(childDevice, huesettings) { def setColorTemperature(childDevice, huesettings) {
log.debug "Executing 'setColorTemperature($huesettings)'" log.debug "Executing 'setColorTemperature($huesettings)'"
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)
createSwitchEvent(childDevice, "on") createSwitchEvent(childDevice, "on")
put("lights/${getId(childDevice)}/state", [ct: ct, on: true]) put("lights/$id/state", [ct: ct, on: true])
return "Setting color temperature to $percent" return "Setting color temperature to $percent"
} }
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'" log.debug "Executing 'setColor($huesettings)'"
def id = getId(childDevice)
if (!isOnline(id)) {
return "Bulb is unreachable"
}
updateInProgress() updateInProgress()
def value = [:] def value = [:]
@@ -1108,15 +1144,23 @@ def setColor(childDevice, huesettings) {
value.on = false value.on = false
createSwitchEvent(childDevice, value.on ? "on" : "off") createSwitchEvent(childDevice, value.on ? "on" : "off")
put("lights/${getId(childDevice)}/state", value) put("lights/$id/state", value)
return "Setting color to $value" return "Setting color to $value"
} }
def ping(childDevice) {
if (isOnline(getId(childDevice))) {
childDevice.sendEvent(name: "deviceWatch-ping", value: "ONLINE", description: "Hue Light is reachable", displayed: false, isStateChange: true)
return "Device is Online"
} else {
return "Device is Offline"
}
}
private getId(childDevice) { private getId(childDevice) {
if (childDevice.device?.deviceNetworkId?.startsWith("HUE")) { if (childDevice.device?.deviceNetworkId?.startsWith("HUE")) {
return childDevice.device?.deviceNetworkId[3..-1] return childDevice.device?.deviceNetworkId[3..-1]
} } else {
else {
return childDevice.device?.deviceNetworkId.split("/")[-1] return childDevice.device?.deviceNetworkId.split("/")[-1]
} }
} }
@@ -1127,10 +1171,13 @@ private poll() {
log.debug "GET: $host$uri" log.debug "GET: $host$uri"
sendHubCommand(new physicalgraph.device.HubAction("""GET ${uri} HTTP/1.1 sendHubCommand(new physicalgraph.device.HubAction("""GET ${uri} HTTP/1.1
HOST: ${host} HOST: ${host}
""", physicalgraph.device.Protocol.LAN, selectedHue)) """, physicalgraph.device.Protocol.LAN, selectedHue))
} }
private isOnline(id) {
return (state.bulbs[id].online != null && state.bulbs[id].online) || state.bulbs[id].online == null
}
private put(path, body) { private put(path, body) {
def host = getBridgeIP() def host = getBridgeIP()
def uri = "/api/${state.username}/$path" def uri = "/api/${state.username}/$path"
@@ -1198,7 +1245,7 @@ def convertBulbListToMap() {
if (state.bulbs instanceof java.util.List) { if (state.bulbs instanceof java.util.List) {
def map = [:] def map = [:]
state.bulbs.unique {it.id}.each { bulb -> state.bulbs.unique {it.id}.each { bulb ->
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub]] map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub, "online": bulb.online]]
} }
state.bulbs = map state.bulbs = map
} }

View File

@@ -53,14 +53,14 @@ def accelerationActiveHandler(evt) {
def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1
if (alreadySentSms) { if (alreadySentSms) {
log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" log.debug "SMS already sent within the last $deltaSeconds seconds"
} else { } else {
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
log.debug "$accelerationSensor has moved, texting contacts: ${recipients?.size()}" log.debug "accelerationSensor has moved, texting contacts: ${recipients?.size()}"
sendNotificationToContacts("${accelerationSensor.label ?: accelerationSensor.name} moved", recipients) sendNotificationToContacts("${accelerationSensor.label ?: accelerationSensor.name} moved", recipients)
} }
else { else {
log.debug "$accelerationSensor has moved, texting $phone1" log.debug "accelerationSensor has moved, sending text message"
sendSms(phone1, "${accelerationSensor.label ?: accelerationSensor.name} moved") sendSms(phone1, "${accelerationSensor.label ?: accelerationSensor.name} moved")
} }
} }

View File

@@ -69,10 +69,10 @@ def temperatureHandler(evt) {
def alreadySentSms = recentEvents.count { it.doubleValue >= tooHot } > 1 def alreadySentSms = recentEvents.count { it.doubleValue >= tooHot } > 1
if (alreadySentSms) { if (alreadySentSms) {
log.debug "SMS already sent to $phone1 within the last $deltaMinutes minutes" log.debug "SMS already sent within the last $deltaMinutes minutes"
// TODO: Send "Temperature back to normal" SMS, turn switch off // TODO: Send "Temperature back to normal" SMS, turn switch off
} else { } else {
log.debug "Temperature rose above $tooHot: sending SMS to $phone1 and activating $mySwitch" log.debug "Temperature rose above $tooHot: sending SMS and activating $mySwitch"
def tempScale = location.temperatureScale ?: "F" def tempScale = location.temperatureScale ?: "F"
send("${temperatureSensor1.displayName} is too hot, reporting a temperature of ${evt.value}${evt.unit?:tempScale}") send("${temperatureSensor1.displayName} is too hot, reporting a temperature of ${evt.value}${evt.unit?:tempScale}")
switch1?.on() switch1?.on()

View File

@@ -50,9 +50,9 @@ def authPage() {
} }
def description = "Tap to enter LIFX credentials" def description = "Tap to enter LIFX credentials"
def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" // this triggers oauthInit() below def redirectUrl = "${serverUrl}/oauth/initialize?appId=${app.id}&access_token=${state.accessToken}&apiServerUrl=${apiServerUrl}" // this triggers oauthInit() below
// def redirectUrl = "${apiServerUrl}" // def redirectUrl = "${apiServerUrl}"
log.debug "app id: ${app.id}" // log.debug "app id: ${app.id}"
log.debug "redirect url: ${redirectUrl}" // log.debug "redirect url: ${redirectUrl}"s
return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:true) { return dynamicPage(name: "Credentials", title: "Connect to LIFX", nextPage: null, uninstall: true, install:true) {
section { section {
href(url:redirectUrl, required:true, title:"Connect to LIFX", description:"Tap here to connect your LIFX account") href(url:redirectUrl, required:true, title:"Connect to LIFX", description:"Tap here to connect your LIFX account")
@@ -372,7 +372,7 @@ def updateDevices() {
def childDevice = getChildDevice(device.id) def childDevice = getChildDevice(device.id)
selectors.add("${device.id}") selectors.add("${device.id}")
if (!childDevice) { if (!childDevice) {
log.info("Adding device ${device.id}: ${device.product}") // log.info("Adding device ${device.id}: ${device.product}")
def data = [ def data = [
label: device.label, label: device.label,
level: Math.round((device.brightness ?: 1) * 100), level: Math.round((device.brightness ?: 1) * 100),

View File

@@ -41,10 +41,10 @@ def updated() {
def presenceHandler(evt) { def presenceHandler(evt) {
if (evt.value == "present") { if (evt.value == "present") {
log.debug "${presence.label ?: presence.name} has arrived at the ${location}" // log.debug "${presence.label ?: presence.name} has arrived at the ${location}"
sendPush("${presence.label ?: presence.name} has arrived at the ${location}") sendPush("${presence.label ?: presence.name} has arrived at the ${location}")
} else if (evt.value == "not present") { } else if (evt.value == "not present") {
log.debug "${presence.label ?: presence.name} has left the ${location}" // log.debug "${presence.label ?: presence.name} has left the ${location}"
sendPush("${presence.label ?: presence.name} has left the ${location}") sendPush("${presence.label ?: presence.name} has left the ${location}")
} }
} }

View File

@@ -47,7 +47,7 @@ def updated() {
def presenceHandler(evt) { def presenceHandler(evt) {
if (evt.value == "present") { if (evt.value == "present") {
log.debug "${presence.label ?: presence.name} has arrived at the ${location}" // log.debug "${presence.label ?: presence.name} has arrived at the ${location}"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts("${presence.label ?: presence.name} has arrived at the ${location}", recipients) sendNotificationToContacts("${presence.label ?: presence.name} has arrived at the ${location}", recipients)
@@ -56,7 +56,7 @@ def presenceHandler(evt) {
sendSms(phone1, "${presence.label ?: presence.name} has arrived at the ${location}") sendSms(phone1, "${presence.label ?: presence.name} has arrived at the ${location}")
} }
} else if (evt.value == "not present") { } else if (evt.value == "not present") {
log.debug "${presence.label ?: presence.name} has left the ${location}" // log.debug "${presence.label ?: presence.name} has left the ${location}"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts("${presence.label ?: presence.name} has left the ${location}", recipients) sendNotificationToContacts("${presence.label ?: presence.name} has left the ${location}", recipients)

View File

@@ -67,7 +67,7 @@ def updated() {
} }
def subscribe() { def subscribe() {
log.debug "present: ${cars.collect{it.displayName + ': ' + it.currentPresence}}" // log.debug "present: ${cars.collect{it.displayName + ': ' + it.currentPresence}}"
subscribe(doorSensor, "contact", garageDoorContact) subscribe(doorSensor, "contact", garageDoorContact)
subscribe(cars, "presence", carPresence) subscribe(cars, "presence", carPresence)

View File

@@ -71,7 +71,7 @@ def updated() {
private subscribeToEvents() private subscribeToEvents()
{ {
subscribe intrusionMotions, "motion", intruderMotion subscribe intrusionMotions, "motion", intruderMotion
subscribe residentMotions, "motion", residentMotion // subscribe residentMotions, "motion", residentMotion
subscribe intrusionContacts, "contact", contact subscribe intrusionContacts, "contact", contact
subscribe alarms, "alarm", alarm subscribe alarms, "alarm", alarm
subscribe(app, appTouch) subscribe(app, appTouch)
@@ -156,6 +156,7 @@ def residentMotion(evt)
// startReArmSequence() // startReArmSequence()
// } // }
//} //}
unsubscribe(residentMotions)
} }
def contact(evt) def contact(evt)

View File

@@ -48,7 +48,7 @@ def updated()
def contactOpenHandler(evt) { def contactOpenHandler(evt) {
log.trace "$evt.value: $evt, $settings" log.trace "$evt.value: $evt, $settings"
log.debug "$contact1 was opened, texting $phone1" log.debug "$contact1 was opened, sending text"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts("Your ${contact1.label ?: contact1.name} was opened", recipients) sendNotificationToContacts("Your ${contact1.label ?: contact1.name} was opened", recipients)
} }

View File

@@ -60,14 +60,14 @@ def motionActiveHandler(evt) {
def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1
if (alreadySentSms) { if (alreadySentSms) {
log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" log.debug "SMS already sent within the last $deltaSeconds seconds"
} else { } else {
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
log.debug "$motion1 has moved while you were out, sending notifications to: ${recipients?.size()}" log.debug "$motion1 has moved while you were out, sending notifications to: ${recipients?.size()}"
sendNotificationToContacts("${motion1.label} ${motion1.name} moved while you were out", recipients) sendNotificationToContacts("${motion1.label} ${motion1.name} moved while you were out", recipients)
} }
else { else {
log.debug "$motion1 has moved while you were out, texting $phone1" log.debug "$motion1 has moved while you were out, sending text"
sendSms(phone1, "${motion1.label} ${motion1.name} moved while you were out") sendSms(phone1, "${motion1.label} ${motion1.name} moved while you were out")
} }
} }

View File

@@ -53,13 +53,13 @@ def accelerationActiveHandler(evt) {
def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1 def alreadySentSms = recentEvents.count { it.value && it.value == "active" } > 1
if (alreadySentSms) { if (alreadySentSms) {
log.debug "SMS already sent to $phone1 within the last $deltaSeconds seconds" log.debug "SMS already sent to phone within the last $deltaSeconds seconds"
} else { } else {
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts("Gun case has moved!", recipients) sendNotificationToContacts("Gun case has moved!", recipients)
} }
else { else {
log.debug "$accelerationSensor has moved, texting $phone1" log.debug "$accelerationSensor has moved, texting phone"
sendSms(phone1, "Gun case has moved!") sendSms(phone1, "Gun case has moved!")
} }
} }

View File

@@ -60,7 +60,7 @@ def authPage() {
def oauthInitUrl() { def oauthInitUrl() {
def token = getToken() def token = getToken()
log.debug "initiateOauth got token: $token" //log.debug "initiateOauth got token: $token"
// store these for validate after the user takes the oauth journey // store these for validate after the user takes the oauth journey
state.oauth_request_token = token.oauth_token state.oauth_request_token = token.oauth_token
@@ -76,7 +76,7 @@ def getToken() {
] ]
def requestTokenBaseUrl = "https://oauth.withings.com/account/request_token" def requestTokenBaseUrl = "https://oauth.withings.com/account/request_token"
def url = buildSignedUrl(requestTokenBaseUrl, params) def url = buildSignedUrl(requestTokenBaseUrl, params)
log.debug "getToken - url: $url" //log.debug "getToken - url: $url"
return getJsonFromUrl(url) return getJsonFromUrl(url)
} }
@@ -182,7 +182,7 @@ def exchangeToken() {
def requestTokenBaseUrl = "https://oauth.withings.com/account/access_token" def requestTokenBaseUrl = "https://oauth.withings.com/account/access_token"
def url = buildSignedUrl(requestTokenBaseUrl, params, tokenSecret) def url = buildSignedUrl(requestTokenBaseUrl, params, tokenSecret)
log.debug "signed url: $url with secret $tokenSecret" //log.debug "signed url: $url with secret $tokenSecret"
def token = getJsonFromUrl(url) def token = getJsonFromUrl(url)
@@ -198,8 +198,8 @@ def exchangeToken() {
def load() { def load() {
def json = get(getMeasurement(new Date() - 30)) def json = get(getMeasurement(new Date() - 30))
// removed logging of actual json payload. Can be put back for debugging
log.debug "swapped, then received: $json" log.debug "swapped, then received json"
parse(data:json) parse(data:json)
def html = """ def html = """