Compare commits

...

69 Commits

Author SHA1 Message Date
Juan Pablo Risso
a6c7ab49b6 SSVD-2737 - Temperature Unit (#1247) 2016-09-14 09:43:26 -04:00
Vinay Rao
629d768575 Merge pull request #1243 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-09-13 13:44:38 -07:00
Andrew Bresee
4523498dab Add parens to unsubscribe method (#1231) 2016-09-13 13:23:55 -04:00
Jason Terhune
e89e45e000 Another circle fix: dependencies task needs artifactory creds too. 2016-09-13 08:47:22 -05:00
Jason Terhune
78ec280e83 Fix circle build. 2016-09-13 08:37:20 -05:00
Jason Terhune-Wold
1f144d36e4 Merge pull request #1221 from jterhune/gradle-compile
Configure gradle to compile devicetypes and smartapps.
2016-09-13 08:30:57 -05:00
Vinay Rao
f5bd580c9e Merge pull request #1240 from juano2310/staging
SSVD-2733 -  Typo fix
2016-09-12 18:00:11 -07:00
juano2310
d5329dbde3 SSVD-2733 - Typo fix 2016-09-12 20:58:36 -04:00
Vinay Rao
48818cfb06 Merge pull request #1239 from larsfinander/CHF-348_philips_hue_staging
CHF-348 Philips Hue: Change offline time to 16 min
2016-09-12 16:23:41 -07:00
Lars Finander
079919260b CHF-348 Philips Hue: Change offline time to 16 min 2016-09-12 17:19:14 -06:00
Vinay Rao
570922e2ac Merge pull request #1238 from jackchi/healthcheck-5min-reporting
[CHF-348] Set 10 VD required devices to report in at 5 minutes
2016-09-12 15:52:29 -07:00
Lars Finander
53ed9b4d2b Merge pull request #1237 from larsfinander/add_hue_offline_events_staging
Add offline events to Philips Hue
2016-09-12 16:49:57 -06:00
jackchi
7149a81c85 [CHF-348] Set 10 VD required devices to report in at 5 minutes 2016-09-12 14:51:57 -07:00
Vinay Rao
30274f0cd7 Merge pull request #914 from jazzslider/motion-labels
Newer Fibaro motion sensor handler needs motion state labels
2016-09-12 13:26:28 -07:00
Jack Chi
8869cd3af0 Merge pull request #1232 from jackchi/healthcheck-all
[CHF-201] Removing DTH workaround now that all events go to Kafka
2016-09-12 10:46:12 -07:00
Jack Chi
fb0caa6446 Merge pull request #1233 from jackchi/healthcheck-removehack
[CHF-201] Removing DTH workaround now that all events go to Kafka
2016-09-12 08:24:10 -07:00
Lars Finander
3d05d42cb8 Add offline events to Philips Hue
-Handles case when bridge goes offline
-Handles case when indiviudual lights go offline
2016-09-11 22:56:24 -06:00
Vinay Rao
3184615e87 Merge pull request #1235 from SmartThingsCommunity/staging
Rolling down staging hotfix to master
2016-09-09 16:50:50 -07:00
Vinay Rao
0f70362e0a Merge pull request #1234 from larsfinander/DVCSMP-2024_OSRAM_Hue_incorrect_staging
DVCSMP-2024 OSRAM: Hue is incorrectly set to be 0-360
2016-09-09 16:49:31 -07:00
Lars Finander
bc817f8530 DVCSMP-2024 OSRAM: Hue is incorrectly set to be 0-360
-Hue changed to handle 0-100 according to SmartThings API
2016-09-09 17:41:46 -06:00
jackchi
01b8399893 [CHF-201] Removing DTH workaround now that all events go to Kafka 2016-09-09 14:58:03 -07:00
jackchi
81318bafac [CHF-201] Removing DTH workaround now that all events go to Kafka 2016-09-09 14:48:19 -07:00
Lars Finander
60c2006bfc Merge pull request #1230 from larsfinander/SSVD-2798_Philips_Hue_discovery_issue
SSVD-2798 Philips Hue: Light discovery UI issue
2016-09-09 11:01:40 -06:00
Lars Finander
1e4f1223e7 SSVD-2798 Philips Hue: Light discovery UI issue
-Keep checked lights in "lights to add list" when page refreshes
2016-09-09 10:50:23 -06:00
Jason Terhune
b78bce55b2 Configure gradle to compile devicetypes and smartapps. 2016-09-09 09:41:11 -05:00
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
Adam Jensen
22185c5440 Added labels to the motion attribute in the main multiattributetile 2016-05-24 08:18:51 -05:00
53 changed files with 966 additions and 762 deletions

View File

@@ -19,7 +19,7 @@ buildscript {
username smartThingsArtifactoryUserName username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword password smartThingsArtifactoryPassword
} }
url "http://artifactory.smartthings.com/libs-release-local" url "https://artifactory.smartthings.com/libs-release-local"
} }
} }
} }
@@ -27,9 +27,37 @@ buildscript {
repositories { repositories {
mavenLocal() mavenLocal()
jcenter() jcenter()
maven {
credentials {
username smartThingsArtifactoryUserName
password smartThingsArtifactoryPassword
}
url "https://artifactory.smartthings.com/libs-release-local"
}
}
sourceSets {
devicetypes {
groovy {
srcDirs = ['devicetypes']
}
}
smartapps {
groovy {
srcDirs = ['smartapps']
}
}
} }
dependencies { dependencies {
devicetypesCompile 'org.codehaus.groovy:groovy-all:2.4.7'
devicetypesCompile 'smartthings:appengine-z-wave:0.1.2'
devicetypesCompile 'smartthings:appengine-zigbee:0.1.11'
smartappsCompile 'org.codehaus.groovy:groovy-all:2.4.7'
smartappsCompile 'smartthings:appengine-common:0.1.8'
smartappsCompile 'org.codehaus.groovy.modules.http-builder:http-builder:0.7.1'
smartappsCompile 'org.grails:grails-web:2.3.11'
smartappsCompile 'org.json:json:20140107'
} }
slackSendMessage { slackSendMessage {

View File

@@ -5,7 +5,9 @@ machine:
dependencies: dependencies:
override: override:
- echo "Nothing to do." - ./gradlew dependencies -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
post:
- ./gradlew compileSmartappsGroovy compileDevicetypesGroovy -PsmartThingsArtifactoryUserName="$ARTIFACTORY_USERNAME" -PsmartThingsArtifactoryPassword="$ARTIFACTORY_PASSWORD"
test: test:
override: override:

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

@@ -33,8 +33,8 @@ metadata {
tiles(scale: 2) { tiles(scale: 2) {
multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app multiAttributeTile(name:"FGMS", type:"lighting", width:6, height:4) {//with generic type secondary control text is not displayed in Android app
tileAttribute("device.motion", key:"PRIMARY_CONTROL") { tileAttribute("device.motion", key:"PRIMARY_CONTROL") {
attributeState("inactive", icon:"st.motion.motion.inactive", backgroundColor:"#79b821") attributeState("inactive", label:"no motion", icon:"st.motion.motion.inactive", backgroundColor:"#79b821")
attributeState("active", icon:"st.motion.motion.active", backgroundColor:"#ffa81e") attributeState("active", label:"motion", icon:"st.motion.motion.active", backgroundColor:"#ffa81e")
} }
tileAttribute("device.tamper", key:"SECONDARY_CONTROL") { tileAttribute("device.tamper", key:"SECONDARY_CONTROL") {
@@ -278,4 +278,4 @@ private encap(physicalgraph.zwave.Command cmd) {
} else { } else {
crc16(cmd) crc16(cmd)
} }
} }

View File

@@ -67,12 +67,6 @@ def parse(String description) {
def resultMap = zigbee.getEvent(description) def resultMap = zigbee.getEvent(description)
if (resultMap) { if (resultMap) {
sendEvent(resultMap) sendEvent(resultMap)
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
} }
else { else {
log.debug "DID NOT PARSE MESSAGE for description : $description" log.debug "DID NOT PARSE MESSAGE for description : $description"
@@ -96,15 +90,7 @@ def setLevel(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.levelRefresh()
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.levelRefresh()
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -117,6 +103,8 @@ def poll() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
sendEvent(name: "checkInterval", value: 1200, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
// minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
} }

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 * 15, 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 * 15, 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 * 15, 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 * 15, 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

@@ -91,7 +91,7 @@ def parse(String description) {
if (descMap.cluster == "0300") { if (descMap.cluster == "0300") {
if(descMap.attrId == "0000"){ //Hue Attribute if(descMap.attrId == "0000"){ //Hue Attribute
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 360) def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 100)
log.debug "Hue value returned is $hueValue" log.debug "Hue value returned is $hueValue"
sendEvent(name: "hue", value: hueValue, displayed:false) sendEvent(name: "hue", value: hueValue, displayed:false)
} }
@@ -203,7 +203,7 @@ def setLevel(value) {
//input Hue Integer values; returns color name for saturation 100% //input Hue Integer values; returns color name for saturation 100%
private getColorName(hueValue){ private getColorName(hueValue){
if(hueValue>360 || hueValue<0) if(hueValue>100 || hueValue<0)
return return
hueValue = Math.round(hueValue / 100 * 360) hueValue = Math.round(hueValue / 100 * 360)

View File

@@ -1,4 +1,4 @@
/* /*
Osram Flex RGBW Light Strip Osram Flex RGBW Light Strip
Osram bulbs have a firmware issue causing it to forget its dimming level when turned off (via commands). Handling Osram bulbs have a firmware issue causing it to forget its dimming level when turned off (via commands). Handling
@@ -8,7 +8,7 @@
metadata { metadata {
definition (name: "OSRAM LIGHTIFY LED Flexible Strip RGBW", namespace: "smartthings", author: "SmartThings") { definition (name: "OSRAM LIGHTIFY LED Flexible Strip RGBW", namespace: "smartthings", author: "SmartThings") {
capability "Color Temperature" capability "Color Temperature"
capability "Actuator" capability "Actuator"
capability "Switch" capability "Switch"
@@ -18,7 +18,7 @@ metadata {
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
capability "Color Control" capability "Color Control"
attribute "colorName", "string" attribute "colorName", "string"
command "setAdjustedColor" command "setAdjustedColor"
@@ -49,7 +49,7 @@ metadata {
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") { standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh" state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
} }
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..6500)") { controlTile("colorTempSliderControl", "device.colorTemperature", "slider", height: 1, width: 2, inactiveLabel: false, range:"(2700..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature" state "colorTemperature", action:"color temperature.setColorTemperature"
} }
@@ -118,7 +118,7 @@ def parse(String description) {
} }
} }
else if(descMap.attrId == "0000"){ //Hue Attribute else if(descMap.attrId == "0000"){ //Hue Attribute
def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 360) def hueValue = Math.round(convertHexToInt(descMap.value) / 255 * 100)
log.debug "Hue value returned is $hueValue" log.debug "Hue value returned is $hueValue"
sendEvent(name: "hue", value: hueValue, displayed:false) sendEvent(name: "hue", value: hueValue, displayed:false)
} }
@@ -274,7 +274,7 @@ private getGenericName(value){
//input Hue Integer values; returns color name for saturation 100% //input Hue Integer values; returns color name for saturation 100%
private getColorName(hueValue){ private getColorName(hueValue){
if(hueValue>360 || hueValue<0) if(hueValue>100 || hueValue<0)
return return
hueValue = Math.round(hueValue / 100 * 360) hueValue = Math.round(hueValue / 100 * 360)
@@ -449,7 +449,7 @@ def setColor(value){
def level = hex(value.level * 255 / 100) def level = hex(value.level * 255 / 100)
cmd << zigbeeSetLevel(level) cmd << zigbeeSetLevel(level)
} }
if (value.switch == "off") { if (value.switch == "off") {
cmd << "delay 150" cmd << "delay 150"
cmd << off() cmd << off()

View File

@@ -101,12 +101,6 @@ def parse(String description) {
else { else {
def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off' def descriptionText = finalResult.value == "on" ? '{{ device.displayName }} is On' : '{{ device.displayName }} is Off'
sendEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true) sendEvent(name: finalResult.type, value: finalResult.value, descriptionText: descriptionText, translatable: true)
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
} }
} }
else { else {
@@ -126,15 +120,7 @@ def on() {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.onOffRefresh()
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.onOffRefresh()
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -142,8 +128,10 @@ def refresh() {
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 1200, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
zigbee.onOffConfig() + powerConfig() + refresh() sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
// OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + powerConfig() + refresh()
} }
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s) //power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)

View File

@@ -101,13 +101,6 @@ def parse(String description) {
map = parseIasMessage(description) map = parseIasMessage(description)
} }
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : null def result = map ? createEvent(map) : null
@@ -233,6 +226,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 }}%"
} }
@@ -283,15 +278,7 @@ private Map getMoistureResult(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -305,23 +292,19 @@ def refresh() {
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 14400, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings." log.debug "Configuring Reporting, IAS CIE, and Bindings."
def configCmds = [ def enrollCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 500", "send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
] ]
return configCmds + refresh() // send refresh cmds as part of config
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
} }
def enrollResponse() { def enrollResponse() {

View File

@@ -105,13 +105,6 @@ def parse(String description) {
map = parseIasMessage(description) map = parseIasMessage(description)
} }
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : null def result = map ? createEvent(map) : null
@@ -248,6 +241,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 }}%"
} }
@@ -294,15 +289,7 @@ private Map getMotionResult(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -316,24 +303,19 @@ def refresh() {
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 14400, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings." log.debug "Configuring Reporting, IAS CIE, and Bindings."
def configCmds = [ def enrollCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500", "send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 200",
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
] ]
return configCmds + refresh() // send refresh cmds as part of config // temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
} }
def enrollResponse() { def enrollResponse() {

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

@@ -127,13 +127,6 @@ def parse(String description) {
map = parseIasMessage(description) map = parseIasMessage(description)
} }
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
def result = map ? createEvent(map) : null def result = map ? createEvent(map) : null
if (description?.startsWith('enroll request')) { if (description?.startsWith('enroll request')) {
@@ -313,6 +306,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 }}%"
} }
@@ -376,15 +371,7 @@ private getAccelerationResult(numValue) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -414,13 +401,16 @@ def refresh() {
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 14400, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
log.debug "Configuring Reporting" log.debug "Configuring Reporting"
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
def configCmds = enrollResponse() + def configCmds = enrollResponse() +
zigbee.batteryConfig() + zigbee.batteryConfig() +
zigbee.temperatureConfig() + zigbee.temperatureConfig(30, 300) +
zigbee.configureReporting(0xFC02, 0x0010, 0x18, 10, 3600, 0x01, [mfgCode: manufacturerCode]) + zigbee.configureReporting(0xFC02, 0x0010, 0x18, 10, 3600, 0x01, [mfgCode: manufacturerCode]) +
zigbee.configureReporting(0xFC02, 0x0012, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) + zigbee.configureReporting(0xFC02, 0x0012, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +
zigbee.configureReporting(0xFC02, 0x0013, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) + zigbee.configureReporting(0xFC02, 0x0013, 0x29, 1, 3600, 0x0001, [mfgCode: manufacturerCode]) +

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

@@ -92,13 +92,6 @@ def parse(String description) {
map = parseIasMessage(description) map = parseIasMessage(description)
} }
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
log.debug "Parse returned $map" log.debug "Parse returned $map"
def result = map ? createEvent(map) : null def result = map ? createEvent(map) : null
@@ -207,6 +200,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}%"
} }
@@ -246,15 +241,7 @@ private Map getContactResult(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -268,23 +255,19 @@ def refresh() {
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 14400, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui) String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
log.debug "Configuring Reporting, IAS CIE, and Bindings." log.debug "Configuring Reporting, IAS CIE, and Bindings."
def configCmds = [ def enrollCmds = [
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200", "zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1", "delay 500", "send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} ${endpointId} 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500"
] ]
return configCmds + refresh() // send refresh cmds as part of config
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
} }
def enrollResponse() { def enrollResponse() {

View File

@@ -83,13 +83,6 @@ def parse(String description) {
map = parseCustomMessage(description) map = parseCustomMessage(description)
} }
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
log.debug "Parse returned $map" log.debug "Parse returned $map"
return map ? createEvent(map) : null return map ? createEvent(map) : null
} }
@@ -214,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}%"
} }
@@ -251,14 +246,7 @@ private Map getHumidityResult(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){ return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.readAttribute(0x001, 0x0020) // Read the Battery Level
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() def refresh()
@@ -276,23 +264,19 @@ def refresh()
} }
def configure() { def configure() {
sendEvent(name: "checkInterval", value: 14400, displayed: false, data: [protocol: "zigbee"]) // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
def configCmds = [ def humidityConfigCmds = [
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 1 0x20 0x20 30 21600 {01}", //checkin time 6 hrs
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0x402 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500", "zdo bind 0x${device.deviceNetworkId} 1 1 0xFC45 {${device.zigbeeId}} {}", "delay 500",
"zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}", "zcl global send-me-a-report 0xFC45 0 0x29 30 3600 {6400}",
"send 0x${device.deviceNetworkId} 1 1", "delay 500" "send 0x${device.deviceNetworkId} 1 1", "delay 500"
] ]
return configCmds + refresh() // send refresh cmds as part of config
// temperature minReportTime 30 seconds, maxReportTime 5 min. Reporting interval if no activity
// battery minReport 30 seconds, maxReportTime 6 hrs by default
return humidityConfigCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config
} }
private hex(value) { private hex(value) {

View File

@@ -54,12 +54,6 @@ def parse(String description) {
def event = zigbee.getEvent(description) def event = zigbee.getEvent(description)
if (event) { if (event) {
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
if (event.name=="level" && event.value==0) {} if (event.name=="level" && event.value==0) {}
else { else {
sendEvent(event) sendEvent(event)
@@ -86,15 +80,7 @@ def setLevel(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.onOffRefresh()
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.onOffRefresh()
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -103,7 +89,8 @@ def refresh() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
// Enrolls device to Device-Watch with 3 x Reporting interval 30min // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 1800, displayed: false, data: [protocol: "zigbee"]) sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh()
} }

View File

@@ -85,12 +85,6 @@ def parse(String description) {
def event = zigbee.getEvent(description) def event = zigbee.getEvent(description)
if (event) { if (event) {
log.debug event log.debug event
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
if (event.name=="level" && event.value==0) {} if (event.name=="level" && event.value==0) {}
else { else {
if (event.name=="colorTemperature") { if (event.name=="colorTemperature") {
@@ -105,7 +99,7 @@ def parse(String description) {
if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) { if (zigbeeMap?.clusterInt == COLOR_CONTROL_CLUSTER) {
if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute if(zigbeeMap.attrInt == ATTRIBUTE_HUE){ //Hue Attribute
def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 360) def hueValue = Math.round(zigbee.convertHexToInt(zigbeeMap.value) / 255 * 100)
sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed") sendEvent(name: "hue", value: hueValue, descriptionText: "Color has changed")
} }
else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute else if(zigbeeMap.attrInt == ATTRIBUTE_SATURATION){ //Saturation Attribute
@@ -130,15 +124,7 @@ def off() {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.onOffRefresh()
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.onOffRefresh()
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -147,9 +133,10 @@ def refresh() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
// Enrolls device to Device-Watch with 3 x Reporting interval 30min // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 1800, displayed: false, data: [protocol: "zigbee"]) sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) + zigbee.readAttribute(0x0006, 0x00) + zigbee.readAttribute(0x0008, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION) // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE, 0x20, 1, 3600, 0x01) + zigbee.configureReporting(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION, 0x20, 1, 3600, 0x01) + zigbee.readAttribute(0x0006, 0x00) + zigbee.readAttribute(0x0008, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, 0x00) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_COLOR_TEMPERATURE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_HUE) + zigbee.readAttribute(COLOR_CONTROL_CLUSTER, ATTRIBUTE_SATURATION)
} }
def setColorTemperature(value) { def setColorTemperature(value) {

View File

@@ -74,12 +74,6 @@ def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description) def event = zigbee.getEvent(description)
if (event) { if (event) {
// Temporary fix for the case when Device is OFFLINE and is connected again
if (state.lastActivity == null){
state.lastActivity = now()
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
state.lastActivity = now()
if (event.name=="level" && event.value==0) {} if (event.name=="level" && event.value==0) {}
else { else {
if (event.name=="colorTemperature") { if (event.name=="colorTemperature") {
@@ -110,15 +104,7 @@ def setLevel(value) {
* PING is used by Device-Watch in attempt to reach the Device * PING is used by Device-Watch in attempt to reach the Device
* */ * */
def ping() { def ping() {
return zigbee.onOffRefresh()
if (state.lastActivity < (now() - (1000 * device.currentValue("checkInterval"))) ){
log.info "ping, alive=no, lastActivity=${state.lastActivity}"
state.lastActivity = null
return zigbee.onOffRefresh()
} else {
log.info "ping, alive=yes, lastActivity=${state.lastActivity}"
sendEvent(name: "deviceWatch-lastActivity", value: state.lastActivity, description: "Last Activity is on ${new Date((long)state.lastActivity)}", displayed: false, isStateChange: true)
}
} }
def refresh() { def refresh() {
@@ -127,9 +113,10 @@ def refresh() {
def configure() { def configure() {
log.debug "Configuring Reporting and Bindings." log.debug "Configuring Reporting and Bindings."
// Enrolls device to Device-Watch with 3 x Reporting interval 30min // Device-Watch allows 3 check-in misses from device. 300 seconds x 3 = 15min
sendEvent(name: "checkInterval", value: 1800, displayed: false, data: [protocol: "zigbee"]) sendEvent(name: "checkInterval", value: 900, displayed: false, data: [protocol: "zigbee"])
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() // OnOff minReportTime 0 seconds, maxReportTime 5 min. Reporting interval if no activity
zigbee.onOffConfig(0, 300) + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
} }
def setColorTemperature(value) { def setColorTemperature(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

@@ -26,9 +26,9 @@ preferences {
} }
section("Temperature monitor?") { section("Temperature monitor?") {
input "temp", "capability.temperatureMeasurement", title: "Temp Sensor", required: false input "temp", "capability.temperatureMeasurement", title: "Temperature Sensor", required: false
input "maxTemp", "number", title: "Max Temp?", required: false input "maxTemp", "number", title: "Max Temperature (°${location.temperatureScale})", required: false
input "minTemp", "number", title: "Min Temp?", required: false input "minTemp", "number", title: "Min Temperature (°${location.temperatureScale})", required: false
} }
section("When which people are away?") { section("When which people are away?") {

View File

@@ -14,7 +14,7 @@
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
*/ */
definition( definition(
name: "Smart Home Ventilation", name: "Smart Home Ventilation",
namespace: "MichaelStruck", namespace: "MichaelStruck",
@@ -164,7 +164,7 @@ def installed() {
def updated() { def updated() {
unschedule() unschedule()
turnOffSwitch() //Turn off all switches if the schedules are changed while in mid-schedule turnOffSwitch() //Turn off all switches if the schedules are changed while in mid-schedule
unsubscribe unsubscribe()
log.debug "Updated with settings: ${settings}" log.debug "Updated with settings: ${settings}"
init() init()
} }
@@ -174,12 +174,12 @@ def init() {
schedule (midnightTime, midNight) schedule (midnightTime, midNight)
subscribe(location, "mode", locationHandler) subscribe(location, "mode", locationHandler)
startProcess() startProcess()
} }
// Common methods // Common methods
def startProcess () { def startProcess () {
createDayArray() createDayArray()
state.dayCount=state.data.size() state.dayCount=state.data.size()
if (state.dayCount){ if (state.dayCount){
state.counter = 0 state.counter = 0
@@ -190,7 +190,7 @@ def startProcess () {
def startDay() { def startDay() {
def start = convertEpoch(state.data[state.counter].start) def start = convertEpoch(state.data[state.counter].start)
def stop = convertEpoch(state.data[state.counter].stop) def stop = convertEpoch(state.data[state.counter].stop)
runOnce(start, turnOnSwitch, [overwrite: true]) runOnce(start, turnOnSwitch, [overwrite: true])
runOnce(stop, incDay, [overwrite: true]) runOnce(stop, incDay, [overwrite: true])
} }
@@ -218,7 +218,7 @@ def locationHandler(evt) {
} }
if (!result) { if (!result) {
startProcess() startProcess()
} }
} }
def midNight(){ def midNight(){
@@ -238,7 +238,7 @@ def turnOffSwitch() {
} }
log.debug "Home ventilation switches are off." log.debug "Home ventilation switches are off."
} }
def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) { def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) {
def title = "" def title = ""
def dayListClean = "On " def dayListClean = "On "
@@ -252,7 +252,7 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) {
dayListClean = "${dayListClean}, " dayListClean = "${dayListClean}, "
} }
} }
} }
else { else {
dayListClean = "Every day" dayListClean = "Every day"
} }
@@ -272,7 +272,7 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) {
modeListClean = "${modeListClean} ${modePrefix}" modeListClean = "${modeListClean} ${modePrefix}"
} }
} }
} }
else { else {
modeListClean = "${modeListClean}all modes" modeListClean = "${modeListClean}all modes"
} }
@@ -283,16 +283,16 @@ def schedDesc(on1, off1, on2, off2, on3, off3, on4, off4, modeList, dayList) {
title += "\nSchedule 2: ${humanReadableTime(on2)} to ${humanReadableTime(off2)}" title += "\nSchedule 2: ${humanReadableTime(on2)} to ${humanReadableTime(off2)}"
} }
if (on3 && off3) { if (on3 && off3) {
title += "\nSchedule 3: ${humanReadableTime(on3)} to ${humanReadableTime(off3)}" title += "\nSchedule 3: ${humanReadableTime(on3)} to ${humanReadableTime(off3)}"
} }
if (on4 && off4) { if (on4 && off4) {
title += "\nSchedule 4: ${humanReadableTime(on4)} to ${humanReadableTime(off4)}" title += "\nSchedule 4: ${humanReadableTime(on4)} to ${humanReadableTime(off4)}"
} }
if (on1 || on2 || on3 || on4) { if (on1 || on2 || on3 || on4) {
title += "\n$modeListClean" title += "\n$modeListClean"
title += "\n$dayListClean" title += "\n$dayListClean"
} }
if (!on1 && !on2 && !on3 && !on4) { if (!on1 && !on2 && !on3 && !on4) {
title="Click to configure scenario" title="Click to configure scenario"
} }
@@ -374,7 +374,7 @@ def createDayArray() {
timeOk(timeOnD1, timeOffD1) timeOk(timeOnD1, timeOffD1)
timeOk(timeOnD2, timeOffD2) timeOk(timeOnD2, timeOffD2)
timeOk(timeOnD3, timeOffD3) timeOk(timeOnD3, timeOffD3)
timeOk(timeOnD4, timeOffD4) timeOk(timeOnD4, timeOffD4)
} }
} }
state.data.sort{it.start} state.data.sort{it.start}
@@ -384,7 +384,7 @@ def createDayArray() {
private def textAppName() { private def textAppName() {
def text = "Smart Home Ventilation" def text = "Smart Home Ventilation"
} }
private def textVersion() { private def textVersion() {
def text = "Version 2.1.2 (05/31/2015)" def text = "Version 2.1.2 (05/31/2015)"
@@ -416,4 +416,4 @@ private def textHelp() {
"that each scenario does not overlap and run in separate modes (i.e. Home, Out of town, etc). Also note that you should " + "that each scenario does not overlap and run in separate modes (i.e. Home, Out of town, etc). Also note that you should " +
"avoid scheduling the ventilation fan at exactly midnight; the app resets itself at that time. It is suggested to start any new schedule " + "avoid scheduling the ventilation fan at exactly midnight; the app resets itself at that time. It is suggested to start any new schedule " +
"at 12:15 am or later." "at 12:15 am or later."
} }

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}"
} }
@@ -1101,4 +1101,4 @@ def hasStartLevel() {
def hasEndLevel() { def hasEndLevel() {
return (endLevel != null && endLevel != "") return (endLevel != null && endLevel != "")
} }

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
@@ -171,7 +170,7 @@ def bulbDiscovery() {
return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) { return dynamicPage(name:"bulbDiscovery", title:"Light Discovery Started!", nextPage:"", refreshInterval:refreshInterval, install:true, uninstall: true) {
section("Please wait while we discover your Hue Lights. 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 Lights. Discovery can take five minutes or more, so sit back and relax! Select your device below once discovered.") {
input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, options:newLights input "selectedBulbs", "enum", required:false, title:"Select Hue Lights to add (${numFound} found)", multiple:true, submitOnChange: true, options:newLights
paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription paragraph title: "Previously added Hue Lights (${existingLights.size()} added)", existingLightsDescription
} }
section { section {
@@ -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")) {
@@ -727,13 +724,13 @@ private void updateBridgeStatus(childDevice) {
} }
/** /**
* Check if all Hue bridges have been heard from in the last 16 minutes, if not an Offline event will be sent * Check if all Hue bridges have been heard from in the last 11 minutes, if not an Offline event will be sent
* for the bridge. Also, set ID number on bridge if not done previously. * for the bridge and all connected lights. Also, set ID number on bridge if not done previously.
*/ */
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 11 minutes (2 poll intervals times 5 minutes plus buffer)
def time = now() - (1000 * 60 * 16) def time = now() - (1000 * 60 * 11)
bridges.each { bridges.each {
def d = getChildDevice(it.value.mac) def d = getChildDevice(it.value.mac)
if(d) { if(d) {
@@ -743,14 +740,21 @@ private void checkBridgeStatus() {
d.sendEvent(name: "idNumber", value: it.value.idNumber) d.sendEvent(name: "idNumber", value: it.value.idNumber)
} }
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")
} else {
state.bulbs?.each {
it.value.online = false
}
getChildDevices().each {
it.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", isStateChange: true, displayed: false)
}
} else {
d.sendEvent(name: "status", value: "Online")//setOnline(false) d.sendEvent(name: "status", value: "Online")//setOnline(false)
} }
} }
} }
} }
def isValidSource(macAddress) { def isValidSource(macAddress) {
@@ -785,8 +789,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 +886,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 +939,33 @@ 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"
} device.sendEvent(name: "DeviceWatch-DeviceOffline", value: "offline", displayed: false, isStateChange: true)
} }
} }
return []
} }
return []
}
private updateInProgress() { private updateInProgress() {
state.updating = true state.updating = true
@@ -980,22 +994,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 +1036,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 +1150,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 +1177,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 +1251,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)
@@ -214,7 +215,7 @@ def checkForReArm()
} }
else { else {
log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection" log.warn "checkForReArm: lastIntruderMotion was null, unable to check for re-arming intrusion detection"
} }
} }
private startAlarmSequence() private startAlarmSequence()

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

@@ -50,7 +50,7 @@ def updated() {
def motionActiveHandler(evt) { def motionActiveHandler(evt) {
log.trace "$evt.value: $evt, $settings" log.trace "$evt.value: $evt, $settings"
if (presence1.latestValue("presence") == "not present") { if (presence1.latestValue("presence") == "not present") {
// Don't send a continuous stream of text messages // Don't send a continuous stream of text messages
def deltaSeconds = 10 def deltaSeconds = 10
@@ -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 = """