Skip to content

Commit 7c38c5c

Browse files
marstorpworkingmonk
authored andcommitted
WWST-202, DVCSMP-3666 Refactor Ecobee service manger (SmartThingsCommunity#2963)
* WWST-202, DVCSMP-3666 Refactor Ecobee service manger WWST-202 - Refactor Ecobee service manger to not use DTH polling (being depreciated) Move device polling to be controlled by the Service Manager (Connect) app and implement device health in Switch, Thermostat and Sensor. Addition of event subscriptions can't be done until Ecobee releases an API that allows for that. DVCSMP-3666 - Ecobee (Connect) not able to re-authenticate ST subscription If, for some reason the authorization grant, token or credentials are invalid, expired or revoked, Ecobee (connect) may still try to poll the cloud and keep trying to refresh authToken. For a user to resolve this the ST Ecobee integration needs to re-authenticate the ST subscription in the Ecobee cloud, however as the connect app skips the login page if authToken exits, there's no check to see if the token is valid, there's no way for the user to re-authenticate. Also, changed use of atomicState to state to reduce possible data corruption and added a mechanism to stop and restart polling when user launches the SM to add/remove devices to avoid data corruption * Update ecobee-connect.groovy Adding support for testing in staging * Update ecobee-switch.groovy Added updated() method to ecobee switch on request from Vinay.
1 parent e9e37f7 commit 7c38c5c

File tree

4 files changed

+693
-297
lines changed

4 files changed

+693
-297
lines changed

devicetypes/smartthings/ecobee-sensor.src/ecobee-sensor.groovy

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*
1515
* Author: SmartThings
1616
*/
17+
import groovy.json.JsonOutput
1718
metadata {
1819
definition (name: "Ecobee Sensor", namespace: "smartthings", author: "SmartThings") {
1920
capability "Sensor"
@@ -25,7 +26,7 @@ metadata {
2526
tiles(scale: 2) {
2627
multiAttributeTile(name: "temperature", type: "generic", width: 6, height: 4, canChangeIcon: true) {
2728
tileAttribute ("device.temperature", key: "PRIMARY_CONTROL") {
28-
attributeState "temperature", label:'${currentValue}°',
29+
attributeState "temperature", label:'${currentValue}°', icon: "st.alarm.temperature.normal",
2930
backgroundColors:[
3031
// Celsius
3132
[value: 0, color: "#153591"],
@@ -61,13 +62,30 @@ metadata {
6162
}
6263
}
6364

64-
def refresh() {
65-
log.debug "refresh called"
66-
poll()
65+
def initialize() {
66+
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
67+
updateDataValue("EnrolledUTDH", "true")
68+
}
69+
70+
void installed() {
71+
initialize()
6772
}
6873

69-
void poll() {
70-
log.debug "Executing 'poll' using parent SmartApp"
71-
parent.pollChild()
74+
def updated() {
75+
log.debug "updated()"
76+
parent.setSensorName(device.label, device.deviceNetworkId)
77+
initialize()
78+
}
7279

80+
// Called when the DTH is uninstalled, is this true for cirrus/gadfly integrations?
81+
// Informs parent to purge its associated data
82+
def uninstalled() {
83+
log.debug "uninstalled() parent.purgeChildDevice($device.deviceNetworkId)"
84+
// purge DTH from parent
85+
parent?.purgeChildDevice(this)
86+
}
87+
88+
def refresh() {
89+
log.debug "refresh, calling parent poll"
90+
parent.poll()
7391
}

devicetypes/smartthings/ecobee-switch.src/ecobee-switch.groovy

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ metadata {
3232
attributeState "off", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
3333
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.Home.home30", backgroundColor:"#00a0dc", nextState:"turningOff"
3434
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.Home.home30", backgroundColor:"#ffffff", nextState:"turningOn"
35-
}
35+
}
3636
}
3737

3838
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
@@ -44,49 +44,52 @@ metadata {
4444
}
4545
standardTile("refresh", "device.switch", inactiveLabel: false, height: 2, width: 2, decoration: "flat") {
4646
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
47-
}
47+
}
4848
main(["switch"])
4949
details(["rich-control", "refresh"])
5050
}
5151
}
5252

5353
// parse events into attributes
5454
def parse(String description) {
55-
log.debug "Parsing '${description}'"
55+
log.debug "Parsing '${description}'"
56+
}
57+
58+
void initialize() {
59+
sendEvent(name: "DeviceWatch-Enroll", value: toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
5660
}
5761

5862
void installed() {
5963
log.trace "[DTH] Executing installed() for device=${this.device.displayName}"
60-
sendEvent(name: "DeviceWatch-Enroll", value: toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
64+
initialize()
65+
}
66+
67+
void updated() {
68+
log.trace "[DTH] Executing updated() for device=${this.device.displayName}"
69+
initialize()
6170
}
6271

6372
//remove from the selected devices list in SM
6473
void uninstalled() {
6574
log.trace "[DTH] Executing uninstalled() for device=${this.device.displayName}"
66-
parent?.removeChildDevice(this)
67-
}
68-
69-
// handle commands
70-
def poll() {
71-
log.trace "[DTH] Executing 'poll' for ${this.device.displayName}"
72-
parent.pollSwitches()
75+
parent?.purgeChildDevice(this)
7376
}
7477

7578
def refresh() {
76-
log.trace "[DTH] Executing 'refresh' for ${this.device.displayName}"
77-
poll()
79+
log.trace "[DTH] Executing 'refresh' for ${this.device.displayName}"
80+
parent?.poll()
7881
}
7982

8083
def on() {
81-
log.trace "[DTH] Executing 'on' for ${this.device.displayName}"
84+
log.trace "[DTH] Executing 'on' for ${this.device.displayName}"
8285
boolean desiredState = true
83-
parent.controlSwitch( this.device.deviceNetworkId, desiredState )
86+
parent.controlSwitch( this.device.deviceNetworkId, desiredState )
8487
}
8588

8689
def off() {
87-
log.trace "[DTH] Executing 'on' for ${this.device.displayName}"
90+
log.trace "[DTH] Executing 'off' for ${this.device.displayName}"
8891
boolean desiredState = false
89-
parent.controlSwitch( this.device.deviceNetworkId, desiredState )
92+
parent.controlSwitch( this.device.deviceNetworkId, desiredState )
9093
}
9194

9295
def toJson(Map m) {

devicetypes/smartthings/ecobee-thermostat.src/ecobee-thermostat.groovy

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* Author: SmartThings
1616
* Date: 2013-06-13
1717
*/
18+
import groovy.json.JsonOutput
1819
metadata {
1920
definition (name: "Ecobee Thermostat", namespace: "smartthings", author: "SmartThings") {
2021
capability "Actuator"
@@ -135,16 +136,29 @@ metadata {
135136
void installed() {
136137
// The device refreshes every 5 minutes by default so if we miss 2 refreshes we can consider it offline
137138
// Using 12 minutes because in testing, device health team found that there could be "jitter"
138-
sendEvent(name: "checkInterval", value: 60 * 12, data: [protocol: "cloud"], displayed: false)
139+
initialize()
140+
}
141+
def initialize() {
142+
sendEvent(name: "DeviceWatch-Enroll", value: JsonOutput.toJson([protocol: "cloud", scheme:"untracked"]), displayed: false)
143+
updateDataValue("EnrolledUTDH", "true")
144+
}
145+
146+
def updated() {
147+
log.debug "updated()"
148+
parent.setName(device.label, device.deviceNetworkId)
149+
initialize()
150+
}
151+
152+
// Called when the DTH is uninstalled, is this true for cirrus/gadfly integrations?
153+
// Informs parent to purge its associated data
154+
def uninstalled() {
155+
log.debug "uninstalled() parent.purgeChildDevice($device.deviceNetworkId)"
156+
// purge DTH from parent
157+
parent?.purgeChildDevice(this)
139158
}
140159

141-
// Device Watch will ping the device to proactively determine if the device has gone offline
142-
// If the device was online the last time we refreshed, trigger another refresh as part of the ping.
143160
def ping() {
144-
def isAlive = device.currentValue("deviceAlive") == "true" ? true : false
145-
if (isAlive) {
146-
refresh()
147-
}
161+
log.debug "ping() NOP"
148162
}
149163

150164
// parse events into attributes
@@ -153,13 +167,12 @@ def parse(String description) {
153167
}
154168

155169
def refresh() {
156-
log.debug "refresh"
157-
poll()
170+
log.debug "refresh, calling parent poll"
171+
parent.poll()
158172
}
159173

160174
void poll() {
161-
log.debug "Executing 'poll' using parent SmartApp"
162-
parent.pollChild()
175+
log.debug "poll not implemented as it is done by parent SmartApp every 5 minutes"
163176
}
164177

165178
def generateEvent(Map results) {
@@ -197,6 +210,8 @@ def generateEvent(Map results) {
197210
} else if (name == "thermostatMode") {
198211
thermostatMode = (value == "auxHeatOnly") ? "emergency heat" : value.toLowerCase()
199212
return // as we don't want to send this event here, proceed to next name/value pair
213+
} else if (name == "name") {
214+
return // as we don't want to send this event, proceed to next name/value pair
200215
} else {
201216
event << [value: value.toString()]
202217
}
@@ -502,9 +517,13 @@ def updateSetpoint(data) {
502517
def sendHoldType = holdType ? ((holdType=="Temporary") ? "nextTransition" : "indefinite") : "indefinite"
503518

504519
if (parent.setHold(data.targetHeatingSetpoint, data.targetCoolingSetpoint, deviceId, sendHoldType)) {
505-
log.debug "alterSetpoint succeed to change setpoints:${data}"
520+
log.debug "updateSetpoint succeed to change setpoints:${data}"
521+
sendEvent("name": "heatingSetpoint", "value": getTempInLocalScale(data.targetHeatingSetpoint, deviceScale),
522+
unit: getTemperatureScale(), eventType: "ENTITY_UPDATE", displayed: false)
523+
sendEvent("name": "coolingSetpoint", "value": getTempInLocalScale(data.targetCoolingSetpoint, deviceScale),
524+
unit: getTemperatureScale(), eventType: "ENTITY_UPDATE", displayed: false)
506525
} else {
507-
log.error "Error alterSetpoint"
526+
log.error "Error updateSetpoint"
508527
}
509528
runIn(5, "refresh", [overwrite: true])
510529
}

0 commit comments

Comments
 (0)