mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-08 05:31:56 +00:00
Fix Ecobee access_token doesn't get refresh after it's expired
This commit is contained in:
@@ -64,3 +64,8 @@ void poll() {
|
||||
log.debug "Executing 'poll' using parent SmartApp"
|
||||
parent.pollChildren(this)
|
||||
}
|
||||
|
||||
//generate custom mobile activity feeds event
|
||||
def generateActivityFeedsEvent(notificationMessage) {
|
||||
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
|
||||
}
|
||||
|
||||
@@ -676,3 +676,8 @@ def generateStatusEvent() {
|
||||
log.debug "Generate Status Event = ${statusText}"
|
||||
sendEvent("name":"thermostatStatus", "value":statusText, "description":statusText, displayed: true)
|
||||
}
|
||||
|
||||
//generate custom mobile activity feeds event
|
||||
def generateActivityFeedsEvent(notificationMessage) {
|
||||
sendEvent(name: "notificationMessage", value: "$device.displayName $notificationMessage", descriptionText: "$device.displayName $notificationMessage", displayed: true)
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
* 10-28-2015 DVCSMP-604 - accessory sensor, DVCSMP-1174, DVCSMP-1111 - not respond to routines
|
||||
*/
|
||||
definition(
|
||||
name: "Ecobee (Connect)",
|
||||
namespace: "smartthings",
|
||||
author: "SmartThings",
|
||||
description: "Connect your Ecobee thermostat to SmartThings.",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee@2x.png",
|
||||
singleInstance: true
|
||||
name: "Ecobee (Connect)",
|
||||
namespace: "smartthings",
|
||||
author: "SmartThings",
|
||||
description: "Connect your Ecobee thermostat to SmartThings.",
|
||||
category: "SmartThings Labs",
|
||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee.png",
|
||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/ecobee@2x.png",
|
||||
singleInstance: true
|
||||
) {
|
||||
appSetting "clientId"
|
||||
}
|
||||
@@ -236,27 +236,32 @@ def getEcobeeThermostats() {
|
||||
]
|
||||
|
||||
def stats = [:]
|
||||
httpGet(deviceListParams) { resp ->
|
||||
try {
|
||||
httpGet(deviceListParams) { resp ->
|
||||
|
||||
if(resp.status == 200) {
|
||||
resp.data.thermostatList.each { stat ->
|
||||
atomicState.remoteSensors = stat.remoteSensors
|
||||
def dni = [ app.id, stat.identifier ].join('.')
|
||||
stats[dni] = getThermostatDisplayName(stat)
|
||||
}
|
||||
} else {
|
||||
log.debug "http status: ${resp.status}"
|
||||
//refresh the auth token
|
||||
if (resp.status == 500 && resp.data.status.code == 14) {
|
||||
log.debug "Storing the failed action to try later"
|
||||
atomicState.action = "getEcobeeThermostats"
|
||||
log.debug "Refreshing your auth_token!"
|
||||
refreshAuthToken()
|
||||
} else {
|
||||
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
|
||||
}
|
||||
}
|
||||
}
|
||||
if (resp.status == 200) {
|
||||
resp.data.thermostatList.each { stat ->
|
||||
atomicState.remoteSensors = stat.remoteSensors
|
||||
def dni = [app.id, stat.identifier].join('.')
|
||||
stats[dni] = getThermostatDisplayName(stat)
|
||||
}
|
||||
} else {
|
||||
log.debug "http status: ${resp.status}"
|
||||
//refresh the auth token
|
||||
if (resp.status == 500 && resp.data.status.code == 14) {
|
||||
log.debug "Storing the failed action to try later"
|
||||
atomicState.action = "getEcobeeThermostats"
|
||||
log.debug "Refreshing your auth_token!"
|
||||
refreshAuthToken()
|
||||
} else {
|
||||
log.error "Authentication error, invalid authentication method, lack of credentials, etc."
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.debug "___exception getEcobeeThermostats(): " + e
|
||||
refreshAuthToken()
|
||||
}
|
||||
atomicState.thermostats = stats
|
||||
return stats
|
||||
}
|
||||
@@ -338,22 +343,19 @@ def initialize() {
|
||||
|
||||
atomicState.thermostatData = [:] //reset Map to store thermostat data
|
||||
|
||||
//send activity feeds to tell that device is connected
|
||||
def notificationMessage = "is connected to SmartThings"
|
||||
sendActivityFeeds(notificationMessage)
|
||||
state.timeSendPush = null
|
||||
|
||||
pollHandler() //first time polling data data from thermostat
|
||||
|
||||
//automatically update devices status every 5 mins
|
||||
runEvery5Minutes("poll")
|
||||
|
||||
}
|
||||
//since access_token expires every 2 hours
|
||||
runEvery1Hour("refreshAuthToken")
|
||||
|
||||
def uninstalled() {
|
||||
log.info("Uninstalling, removing child devices...")
|
||||
removeChildDevices(getChildDevices())
|
||||
}
|
||||
|
||||
private removeChildDevices(delete) {
|
||||
delete.each {
|
||||
deleteChildDevice(it.deviceNetworkId)
|
||||
}
|
||||
}
|
||||
|
||||
def pollHandler() {
|
||||
@@ -579,65 +581,69 @@ def toQueryString(Map m) {
|
||||
}
|
||||
|
||||
private refreshAuthToken() {
|
||||
log.debug "refreshing auth token"
|
||||
log.debug "refreshing auth token"
|
||||
|
||||
if(!atomicState.refreshToken) {
|
||||
log.warn "Can not refresh OAuth token since there is no refreshToken stored"
|
||||
} else {
|
||||
if(!atomicState.refreshToken) {
|
||||
log.warn "Can not refresh OAuth token since there is no refreshToken stored"
|
||||
} else {
|
||||
|
||||
def refreshParams = [
|
||||
method: 'POST',
|
||||
uri : apiEndpoint,
|
||||
path : "/token",
|
||||
query : [grant_type: 'refresh_token', code: "${atomicState.refreshToken}", client_id: smartThingsClientId],
|
||||
]
|
||||
def refreshParams = [
|
||||
method: 'POST',
|
||||
uri : apiEndpoint,
|
||||
path : "/token",
|
||||
query : [grant_type: 'refresh_token', code: "${atomicState.refreshToken}", client_id: smartThingsClientId],
|
||||
]
|
||||
|
||||
log.debug refreshParams
|
||||
log.debug refreshParams
|
||||
|
||||
//changed to httpPost
|
||||
try {
|
||||
def jsonMap
|
||||
httpPost(refreshParams) { resp ->
|
||||
def notificationMessage = "is disconnected from SmartThings, because the access credential changed or was lost. Please go to the Ecobee (Connect) SmartApp and re-enter your account login credentials."
|
||||
//changed to httpPost
|
||||
try {
|
||||
def jsonMap
|
||||
httpPost(refreshParams) { resp ->
|
||||
|
||||
if(resp.status == 200) {
|
||||
log.debug "Token refreshed...calling saved RestAction now!"
|
||||
if(resp.status == 200) {
|
||||
log.debug "Token refreshed...calling saved RestAction now!"
|
||||
|
||||
debugEvent("Token refreshed ... calling saved RestAction now!")
|
||||
debugEvent("Token refreshed ... calling saved RestAction now!")
|
||||
|
||||
log.debug resp
|
||||
log.debug resp
|
||||
|
||||
jsonMap = resp.data
|
||||
jsonMap = resp.data
|
||||
|
||||
if(resp.data) {
|
||||
if(resp.data) {
|
||||
|
||||
log.debug resp.data
|
||||
debugEvent("Response = ${resp.data}")
|
||||
log.debug resp.data
|
||||
debugEvent("Response = ${resp.data}")
|
||||
|
||||
atomicState.refreshToken = resp?.data?.refresh_token
|
||||
atomicState.authToken = resp?.data?.access_token
|
||||
atomicState.refreshToken = resp?.data?.refresh_token
|
||||
atomicState.authToken = resp?.data?.access_token
|
||||
|
||||
debugEvent("Refresh Token = ${atomicState.refreshToken}")
|
||||
debugEvent("OAUTH Token = ${atomicState.authToken}")
|
||||
debugEvent("Refresh Token = ${atomicState.refreshToken}")
|
||||
debugEvent("OAUTH Token = ${atomicState.authToken}")
|
||||
|
||||
if(atomicState.action && atomicState.action != "") {
|
||||
log.debug "Executing next action: ${atomicState.action}"
|
||||
if(atomicState.action && atomicState.action != "") {
|
||||
log.debug "Executing next action: ${atomicState.action}"
|
||||
|
||||
"${atomicState.action}"()
|
||||
"${atomicState.action}"()
|
||||
|
||||
//remove saved action
|
||||
atomicState.action = ""
|
||||
}
|
||||
//remove saved action
|
||||
atomicState.action = ""
|
||||
}
|
||||
|
||||
}
|
||||
atomicState.action = ""
|
||||
} else {
|
||||
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.debug "caught exception refreshing auth token: " + e
|
||||
}
|
||||
}
|
||||
}
|
||||
atomicState.action = ""
|
||||
} else {
|
||||
log.debug "refresh failed ${resp.status} : ${resp.status.code}"
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
log.error "refreshAuthToken() >> Error: e.statusCode ${e.statusCode}"
|
||||
if (e.statusCode == 401) {
|
||||
sendPushAndFeeds(notificationMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def resumeProgram(child, deviceId) {
|
||||
@@ -727,7 +733,7 @@ def sendJson(child = null, String jsonBody) {
|
||||
} catch(Exception e) {
|
||||
log.debug "Exception Sending Json: " + e
|
||||
debugEvent ("Exception Sending JSON: " + e)
|
||||
// debugEventFromParent(child, "Exception Sending JSON: " + e)
|
||||
refreshAuthToken()
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -761,3 +767,28 @@ def debugEvent(message, displayEvent = false) {
|
||||
def debugEventFromParent(child, message) {
|
||||
if (child != null) { child.sendEvent("name":"debugEventFromParent", "value":message, "description":message, displayed: true, isStateChange: true)}
|
||||
}
|
||||
|
||||
//send both push notification and mobile activity feeds
|
||||
def sendPushAndFeeds(notificationMessage){
|
||||
log.warn "sendPushAndFeeds >> notificationMessage: ${notificationMessage}"
|
||||
log.warn "sendPushAndFeeds >> atomicState.timeSendPush: ${atomicState.timeSendPush}"
|
||||
if (atomicState.timeSendPush){
|
||||
if (now() - atomicState.timeSendPush > 86400000){ // notification is sent to remind user once a day
|
||||
sendPush("Your Ecobee thermostat " + notificationMessage)
|
||||
sendActivityFeeds(notificationMessage)
|
||||
atomicState.timeSendPush = now()
|
||||
}
|
||||
} else {
|
||||
sendPush("Your Ecobee thermostat " + notificationMessage)
|
||||
sendActivityFeeds(notificationMessage)
|
||||
atomicState.timeSendPush = now()
|
||||
}
|
||||
atomicState.authToken = null
|
||||
}
|
||||
|
||||
def sendActivityFeeds(notificationMessage) {
|
||||
def devices = getChildDevices()
|
||||
devices.each { child ->
|
||||
child.generateActivityFeedsEvent(notificationMessage) //parse received message from parent
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user