From 9e83cf764ba821a99df244c2039dbaa6d9a8c033 Mon Sep 17 00:00:00 2001 From: Tonesto7 Date: Sat, 14 Oct 2017 22:27:18 -0400 Subject: [PATCH 01/46] Update appData.json --- Data/appData.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Data/appData.json b/Data/appData.json index be3dfded4..d371fa339 100644 --- a/Data/appData.json +++ b/Data/appData.json @@ -59,6 +59,9 @@ "newexceptionPath": "newexceptionData", "remoteDiagPath": "remoteDiagLogs" }, + "appSettings": { + "pullFromFB": false + }, "aaPrefs": { "enAaMsgQueue": true, "enMultiQueue": false From 969e6ecda52988359833aaee1fda2f50c20eeb1a Mon Sep 17 00:00:00 2001 From: tonesto7 Date: Sat, 14 Oct 2017 23:32:34 -0400 Subject: [PATCH 02/46] v5.2.1 Added support for requiring your own nest id and secret for creating tokens --- Data/appData.json | 5 +- Data/changelog.txt | 5 ++ .../nest-manager.src/nest-manager.groovy | 50 ++++++++++--------- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Data/appData.json b/Data/appData.json index be3dfded4..4951f4023 100644 --- a/Data/appData.json +++ b/Data/appData.json @@ -24,7 +24,7 @@ "setupVersion": 2, "versions": { "app": { - "ver": "5.2.0" + "ver": "5.2.1" }, "autoapp": { "ver": "5.1.7" @@ -59,6 +59,9 @@ "newexceptionPath": "newexceptionData", "remoteDiagPath": "remoteDiagLogs" }, + "appSettings": { + "pullFromFB": false + }, "aaPrefs": { "enAaMsgQueue": true, "enMultiQueue": false diff --git a/Data/changelog.txt b/Data/changelog.txt index 354c71e3e..4d1f37720 100644 --- a/Data/changelog.txt +++ b/Data/changelog.txt @@ -1,3 +1,8 @@ +V5.2.1 (October 14th, 2017): +▔▔▔▔▔▔▔▔▔▔▔ +Manager App: + • UPDATED: I have changed the app to no longer use our tokens and it will tell you when you are missing the required id and secret. + V5.2.0 (July 22nd, 2017): ▔▔▔▔▔▔▔▔▔▔▔ Manager App: diff --git a/smartapps/tonesto7/nest-manager.src/nest-manager.groovy b/smartapps/tonesto7/nest-manager.src/nest-manager.groovy index 8e3296f2b..c010d9350 100644 --- a/smartapps/tonesto7/nest-manager.src/nest-manager.groovy +++ b/smartapps/tonesto7/nest-manager.src/nest-manager.groovy @@ -32,12 +32,11 @@ definition( { appSetting "clientId" appSetting "clientSecret" - appSetting "clientToken" appSetting "devOpt" } -def appVersion() { "5.2.0" } -def appVerDate() { "8-12-2017" } +def appVersion() { "5.2.1" } +def appVerDate() { "10-15-2017" } def minVersions() { return [ "automation":["val":517, "desc":"5.1.7"], @@ -145,13 +144,18 @@ def authPage() { def stateSz = getStateSizePerc() if(!atomicState?.devHandlersTested) { deviceHandlerTest() } - if(!atomicState?.accessToken || (!atomicState?.isInstalled && (!atomicState?.devHandlersTested || !preReqOk)) || (stateSz > 80)) { + if(!atomicState?.accessToken || !nestDevAccountCheckOk() || (!atomicState?.isInstalled && (!atomicState?.devHandlersTested || !preReqOk)) || (stateSz > 80)) { return dynamicPage(name: "authPage", title: "Status Page", nextPage: "", install: false, uninstall: false) { section ("Status Page:") { def desc = "" + def showWiki = false if(!atomicState?.accessToken) { desc = "OAuth is not Enabled for ${appName()} application. Please click remove and review the installation directions again" } + else if(!nestDevAccountCheckOk()) { + desc = "You are missing the Client ID and Secret.\n\nWe can no longer provide you with a built-in Nest Client ID and Secret. Please check the Wiki for Detailed instructions on creating your own Nest Dev ID and Secret." + showWiki = true + } else if(!atomicState?.devHandlersTested) { desc = "Device Handlers are Missing or Not Published. Please verify the installation instructions and device handlers are present before continuing." } @@ -166,6 +170,9 @@ def authPage() { } LogAction("Status Message: $desc", "warn", true) paragraph "$desc", required: true, state: null + if(showWiki) { + href url: getWikiPageUrl(), style:"embedded", required:false, title:"View the Projects Wiki", description:"Tap to open in browser", state: "complete", image: getAppImg("web_icon.png") + } } devPageFooter("authErrLoadCnt", execTime) } @@ -5883,7 +5890,9 @@ def webResponse(resp, data) { if(atomicState?.appData && !appDevType() && atomicState?.clientBlacklisted) { appUpdateNotify() } - getFbAppSettings(data?.type == "async" ? false : true ) + if(atomicState?.appData?.appSettings?.pullFromFB == true) { + getFbAppSettings(data?.type == "async" ? false : true ) + } atomicState?.lastWebUpdDt = getDtNow() result = true } else { @@ -7002,7 +7011,7 @@ def callback() { if(atomicState?.authToken) { atomicState?.authTokenCreatedDt = getDtNow() atomicState.authTokenExpires = resp?.data.expires_in - atomicState.authTokenNum = clientToken() + // atomicState.authTokenNum = clientToken() atomicState.oauthInitState = UUID?.randomUUID().toString() } } @@ -7192,33 +7201,26 @@ def toQueryString(Map m) { } def clientId() { - if(appSettings.clientId) { - return appSettings.clientId + if(appSettings?.clientId) { + return appSettings?.clientId } else { - if(atomicState?.appData?.token?.id) { - return atomicState?.appData?.token?.id - } else { LogAction("clientId is missing and is required to generate your Nest Auth token. Please verify you are running the latest software version", "error", true) } + LogAction("clientId is missing and is required to generate your Nest Auth token. Please verify you are running the latest software version", "error", true) + return null } } def clientSecret() { - if(appSettings.clientSecret) { - return appSettings.clientSecret + if(appSettings?.clientSecret) { + return appSettings?.clientSecret } else { - if(atomicState?.appData?.token?.secret) { - return atomicState?.appData?.token?.secret - } else { LogAction("clientSecret is missing and is required to generate your Nest Auth token. Please verify you are running the latest software version", "error", true) } + LogAction("clientSecret is missing and is required to generate your Nest Auth token. Please verify you are running the latest software version", "error", true) + return null } } -def clientToken() { - if(appSettings.clientToken) { - return appSettings.clientToken - } else { - if(atomicState?.appData?.token?.tokenNum) { - return atomicState?.appData?.token?.tokenNum - } else { LogAction("clientToken is missing and is required to generate your Nest Auth token. Please verify you are running the latest software version", "error", true) } - } +def nestDevAccountCheckOk() { + if(atomicState?.authToken == null && (clientId() == null || clientSecret() == null) ) { return false } + else { return true } } /************************************************************************************************ From 6e5b0a7e90bde6e1713ae0182ccc577ab9c36b4b Mon Sep 17 00:00:00 2001 From: tonesto7 Date: Mon, 6 Nov 2017 18:02:42 -0500 Subject: [PATCH 03/46] Tweaks i'm experimenting with --- .../nest-thermostat.groovy | 25 +- .../nest-manager.src/nest-manager.groovy | 435 ++++++++---------- .../nst-automations.groovy | 75 +-- 3 files changed, 237 insertions(+), 298 deletions(-) diff --git a/devicetypes/tonesto7/nest-thermostat.src/nest-thermostat.groovy b/devicetypes/tonesto7/nest-thermostat.src/nest-thermostat.groovy index 3d7304f99..3bcf65fb5 100644 --- a/devicetypes/tonesto7/nest-thermostat.src/nest-thermostat.groovy +++ b/devicetypes/tonesto7/nest-thermostat.src/nest-thermostat.groovy @@ -13,7 +13,7 @@ import java.text.SimpleDateFormat import groovy.time.* -def devVer() { return "5.1.5" } +def devVer() { return "5.1.6" } // for the UI metadata { @@ -480,7 +480,7 @@ void processEvent(data) { if(eventData?.data?.is_locked != null) { tempLockOnEvent(eventData?.data?.is_locked.toString() == "true" ? true : false) } canHeatCool(eventData?.data?.can_heat, eventData?.data?.can_cool) hasFan(eventData?.data?.has_fan.toString()) - presenceEvent(eventData?.pres.toString()) + presenceEvent(eventData?.pres) def curMode = device?.currentState("nestThermostatMode")?.stringValue hvacModeEvent(eventData?.data?.hvac_mode.toString()) @@ -967,19 +967,24 @@ def humidityEvent(humidity) { } else { LogAction("Humidity is (${humidity}) | Original State: (${hum})") } } -def presenceEvent(presence) { +def presenceEvent(String presence) { + // log.trace "presenceEvent($presence)" def val = getPresence() - def pres = (presence == "home") ? "present" : "not present" + def pres = (presence == "away" || presence == "auto-away") ? "not present" : "present" def nestPres = state?.nestPresence - def newNestPres = (presence == "home") ? "home" : ((presence == "auto-away") ? "auto-away" : "away") - def statePres = state?.present - state?.present = (pres == "present") ? true : false + def newNestPres = (pres == "present") ? "home" : ((presence == "auto-away") ? "auto-away" : "away") + def statePres = state?.isPresent + state?.isPresent = (pres == "not present") ? false : true state?.nestPresence = newNestPres - if(!val.equals(pres) || !nestPres.equals(newNestPres) || !nestPres) { - Logger("UPDATED | Presence: ${pres.toString().capitalize()} | Original State: ${val.toString().capitalize()} | State Variable: ${statePres}") + if(isStateChange(device, "presence", pres.toString()) || isStateChange(device, "nestPresence", newNestPres.toString()) || nestPres == null) { + def chgType = "" + chgType += isStateChange(device, "presence", pres.toString()) ? "ST " : "" + chgType += isStateChange(device, "presence", pres.toString()) && isStateChange(device, "nestPresence", newNestPres.toString()) ? "| " : "" + chgType += isStateChange(device, "nestPresence", newNestPres.toString()) ? "Nest " : "" + Logger("UPDATED | ${chgType} Presence: ${pres.toString().capitalize()} | Original State: ${val.toString().capitalize()} | State Variable: ${statePres}") sendEvent(name: 'presence', value: pres, descriptionText: "Device is: ${pres}", displayed: false, isStateChange: true, state: pres ) sendEvent(name: 'nestPresence', value: newNestPres, descriptionText: "Nest Presence is: ${newNestPres}", displayed: true, isStateChange: true ) - } else { LogAction("Presence - Present: (${pres}) | Original State: (${val}) | State Variable: ${state?.present}") } + } else { LogAction("Presence - Present: (${pres}) | Original State: (${val}) | State Variable: ${state?.isPresent}") } } void whoMadeChanges(autoType, desc, dt) { diff --git a/smartapps/tonesto7/nest-manager.src/nest-manager.groovy b/smartapps/tonesto7/nest-manager.src/nest-manager.groovy index c010d9350..f564cd893 100644 --- a/smartapps/tonesto7/nest-manager.src/nest-manager.groovy +++ b/smartapps/tonesto7/nest-manager.src/nest-manager.groovy @@ -572,7 +572,10 @@ def reviewSetupPage() { //getDevChgDesc() showVoiceRprtPrefs() - + // section("App Mode: (Full or Lite)") { + // paragraph "Lite Mode will remove alot of the advanced features and allow for a very basic install. This will basically integrate Nest into ST without the bells and whistles." + // input ("liteAppMode", "bool", title: "Install the App in Lite Mode?", required: false, defaultValue: false, submitOnChange: true, image: getAppImg("app_analytics_icon.png")) + // } section("Notifications:") { def t1 = getAppNotifConfDesc() href "notifPrefPage", title: "Notifications", description: (t1 ? "${t1}\n\nTap to modify" : "Tap to configure"), state: (t1 ? "complete" : null), image: getAppImg("notification_icon2.png") @@ -603,6 +606,9 @@ def showDevSharePrefs() { if(settings?.optInAppAnalytics != false) { input(name: "mobileClientType", title:"Primary Mobile Device?", type: "enum", required: true, submitOnChange: true, metadata: [values:["android":"Android", "ios":"iOS", "winphone":"Windows Phone"]], image: getAppImg("${(settings?.mobileClientType && settings?.mobileClientType != "decline") ? "${settings?.mobileClientType}_icon" : "mobile_device_icon"}.png")) + // if(mobileClientType == "android") { + // input ("showHtmlOnAndroid", "bool", title: "Show HTML Content in Android Device Handlers?", required: false, defaultValue: true, submitOnChange: true, image: getAppImg("app_analytics_icon.png")) + // } href url: getAppEndpointUrl("renderInstallData"), style:"embedded", title:"View the Data shared with Developer", description: "Tap to view Data", required:false, image: getAppImg("view_icon.png") } } @@ -1936,8 +1942,8 @@ def getDevicesDesc(startNewLine=true) { str += vDev ? "${pDev ? "\n" : ""}\nVirtual Devices:" : "" str += atomicState?.vThermostats ? "\n • [${atomicState?.vThermostats?.size()}] Virtual Thermostat${(atomicState?.vThermostats?.size() > 1) ? "s" : ""}" : "" - str += settings?.presDevice ? "\n • [1] Presence Device" : "" - str += settings?.weatherDevice ? "\n • [1] Weather Device" : "" + str += settings?.presDevice ? "\n • Presence Device" : "" + str += settings?.weatherDevice ? "\n • Weather Device" : "" str += (!settings?.thermostats && !settings?.protects && !settings?.cameras && !settings?.presDevice && !settings?.weatherDevice) ? "\n • No Devices Selected" : "" return (str != "") ? str : null } @@ -2141,8 +2147,8 @@ def initManagerApp() { atomicState?.swVer = sData if(settings?.structures && atomicState?.structures && !atomicState.structName) { def structs = getNestStructures() - if(structs && structs?."${atomicState?.structures}") { - atomicState.structName = "${structs[atomicState?.structures]}" + if(structs && structs["${atomicState?.structures}"]) { + atomicState.structName = structs[atomicState?.structures]?.toString() } } if(!addRemoveDevices()) { // if we changed any devices or had an error trying, reset queues and polling @@ -2168,19 +2174,13 @@ def finishInitManagerApp() { createSavedNest() if(app.label == "Nest Manager") { app.updateLabel("NST Manager") } - def cApps = getChildApps() - if(cApps) { - cApps?.sort()?.each { chld -> - chld?.update() - } - } + getChildApps()?.sort()?.each { chld -> chld?.update() } def tstatAutoApp = getChildApps()?.find { try { def aa = it?.getAutomationType() def bb = it?.getCurrentSchedule() def ai = it?.getAutomationsInstalled() - } - catch (Exception e) { + } catch (Exception e) { LogAction("BAD Automation file ${it?.label?.toString()}, please INSTALL proper automation file", "error", true) appUpdateNotify(true) } @@ -2205,52 +2205,52 @@ def createSavedNest() { def dData = atomicState?.deviceData def t0 = [:] - t0 = dData?.thermostats?.findAll { it.key.toString() in settings?.thermostats } - LogAction("${str}: ${settings?.thermostats} ${t0?.size()}", "info", true) + t0 = dData?.thermostats?.findAll { it?.key?.toString() in settings?.thermostats } + LogAction("${str} | Thermostats(${t0?.size()}): ${settings?.thermostats}", "info", false) def t1 = [:] - t0.each { devItem -> - LogAction("${str}: found ${devItem?.value?.name}", "info", false) + t0?.each { devItem -> + LogAction("${str}: Found (${devItem?.value?.name})", "info", false) if(devItem?.key && devItem?.value?.name) { - t1."${devItem.key.toString()}" = devItem.value.name + t1?."${devItem.key.toString()}" = devItem?.value?.name } } def t3 = settings?.thermostats?.size() ?: 0 - if(t1.size() != t3) { LogAction("thermostat sizes wrong ${t1.size()} ${t3}", "error", true); bad = true } - bbb.b_thermostats_as = settings?.thermostats && dData && atomicState?.thermostats ? t1 : [:] - bbb.b_thermostats_setting = settings?.thermostats ?: [] + if(t1?.size() != t3) { LogAction("Thermostat Counts Wrong! | Current: (${t1?.size()}) | Expected: (${t3})", "error", true); bad = true } + bbb?.b_thermostats_as = settings?.thermostats && dData && atomicState?.thermostats ? t1 : [:] + bbb?.b_thermostats_setting = settings?.thermostats ?: [] dData = atomicState?.deviceData t0 = [:] - t0 = dData?.smoke_co_alarms?.findAll { it.key.toString() in settings?.protects } - LogAction("${str}: ${settings?.protects} ${t0?.size()}", "info", true) + t0 = dData?.smoke_co_alarms?.findAll { it?.key?.toString() in settings?.protects } + LogAction("${str} | Protects(${t0?.size()}): ${settings?.protects}", "info", true) t1 = [:] - t0.each { devItem -> - LogAction("${str}: found ${devItem?.value?.name}", "info", false) + t0?.each { devItem -> + LogAction("${str}: Found (${devItem?.value?.name})", "info", false) if(devItem?.key && devItem?.value?.name) { - t1."${devItem.key}" = devItem.value.name + t1."${devItem.key}" = devItem?.value?.name } } t3 = settings?.protects?.size() ?: 0 - if(t1.size() != t3) { LogAction("protects sizes wrong ${t1.size()} ${t3}", "error", true); bad = true } + if(t1?.size() != t3) { LogAction("Protect Counts Wrong! | Current: (${t1?.size()}) | Expected: (${t3})", "error", true); bad = true } bbb.c_protects_as = settings?.protects && dData && atomicState?.protects ? t1 : [:] bbb.c_protects_settings = settings?.protects ?: [] dData = atomicState?.deviceData t0 = [:] - t0 = dData?.cameras?.findAll { it.key.toString() in settings?.cameras } - LogAction("${str}: ${settings?.cameras} ${t0?.size()}", "info", true) + t0 = dData?.cameras?.findAll { it?.key?.toString() in settings?.cameras } + LogAction("${str} | Cameras(${t0?.size()}): ${settings?.cameras}", "info", true) t1 = [:] - t0.each { devItem -> - LogAction("${str}: found ${devItem?.value?.name}", "info", false) + t0?.each { devItem -> + LogAction("${str}: Found (${devItem?.value?.name})", "info", false) if(devItem?.key && devItem?.value?.name) { - t1."${devItem.key}" = devItem.value.name + t1."${devItem?.key}" = devItem?.value?.name } } t3 = settings?.cameras?.size() ?: 0 - if(t1.size() != t3) { LogAction("cameras sizes wrong ${t1.size()} ${t3}", "error", true); bad = true } + if(t1?.size() != t3) { LogAction("Camera Counts Wrong! | Current: (${t1?.size()}) | Expected: (${t3})", "error", true); bad = true } bbb.d_cameras_as = settings?.cameras && dData && atomicState?.cameras ? t1 : [:] bbb.d_cameras_setting = settings?.cameras ?: [] - } else { LogAction("${str}: no structs", "warn", true) } + } else { LogAction("${str}: No Structures Found!!!", "warn", true) } def t0 = atomicState?.savedNestSettings ?: null def t1 = t0 ? new groovy.json.JsonOutput().toJson(t0) : null @@ -2261,8 +2261,8 @@ def createSavedNest() { atomicState.savedNestSettings = bbb return true } - } else { LogAction("${str}: no structures settings", "warn", true) } - } else { LogAction("${str}: not installed", "warn", true) } + } else { LogAction("${str}: No Structure Settings", "warn", true) } + } else { LogAction("${str}: NOT Installed!!!", "warn", true) } return false } //ERSERS @@ -2311,32 +2311,32 @@ def checkRemapping() { sData?.each { strucId -> def t0 = strucId.key def t1 = strucId.value - if(t1?.name && t1?.name == savedNest.a_structure_name_as) { - newStructures_settings = [t1.structure_id].join('.') + if(t1?.name && t1?.name == savedNest?.a_structure_name_as) { + newStructures_settings = [t1?.structure_id]?.join('.') } } if(settings?.structures && newStructures_settings) { if(settings.structures != newStructures_settings) { atomicState.ReallyChanged = true - myRC = atomicState.ReallyChanged + myRC = atomicState?.ReallyChanged astr += ", STRUCTURE CHANGED" } else { - astr += ", NOTHING REALLY CHANGED DEVELOPER MODE" + astr += ", NOTHING REALLY CHANGED (DEVELOPER MODE)" } } else { astr += ", no new structure found" } LogAction(astr, "warn", true) astr = "" if(myRC || (newStructures_setting && getDevOpt())) { mySettingUpdate("structures", newStructures_settings) - if(myRC) { atomicState.structures = newStructures_settings } + if(myRC) { atomicState?.structures = newStructures_settings } def newStrucName = newStructures_settings ? atomicState?.structData[newStructures_settings]?.name : null astr = "${str}: newStructures ${newStructures_settings} | name: ${newStrucName} | to settings & as structures: ${settings?.structures}" astr += ", as.thermostats: ${atomicState?.thermostats} | saveNest: ${savedNest?.b_thermostats_as}" LogAction(astr, "info", true) savedNest?.b_thermostats_as.each { dni -> - def t0 = dni.key + def t0 = dni?.key def dev = getChildDevice(t0) if(dev) { //LogAction("${str}: found dev oldId: ${t0}", "info", true) @@ -2988,7 +2988,9 @@ def setPollingState() { schedule("${random_int} ${random_dint}/${timgcd} * * * ?", poll) // this runs every timgcd minutes def timChk = atomicState?.streamPolling ? 1200 : 240 if(!atomicState?.lastDevDataUpd || getLastDevicePollSec() > timChk) { - poll(true) + if(atomicState.streamPolling) { + poll() + } else { poll(true) } } else { runIn(30, "pollFollow", [overwrite: true]) } @@ -3012,25 +3014,10 @@ private gcd(input = []) { } def onAppTouch(event) { -/* - if(createSavedNest()) { - checkRemapping() - } - return -*/ stateCleanup() createSavedNest() fixStuckMigration() poll(true) - /* - NOTE: - This runin is used strictly for testing as it calls the cleanRestAutomationTest() method - which will remove any New migrated automations and restore the originals back to active - and clear the flags that marked the migration complete. - FYI: If allowMigration() is set to true it will attempt to run a migration - - runIn(3, "cleanRestAutomationTest",[overwrite: true]) - */ } def refresh(child = null) { @@ -3193,8 +3180,8 @@ def createAutoBackupJson() { def getIds4These = ["phone", "contact"] def setObj = null if(itemType?.contains("capability") || itemType in getIds4These) { - if(itemVal instanceof List) { setObj = settings[item?.key].collect { it?.getId() } } - else { setObj = settings[item?.key].getId() } + if(itemVal instanceof List) { setObj = settings[item?.key]?.collect { it?.id } } + else { setObj = settings[item?.key]?.id } } else { if(itemType == "mode" || itemVal instanceof Integer || itemVal instanceof Double || itemVal instanceof Boolean || itemVal instanceof Float || itemVal instanceof Long || itemVal instanceof BigDecimal) { @@ -3203,7 +3190,7 @@ def createAutoBackupJson() { else { setObj = itemVal.toString() } } //log.debug "setting item ${item?.key}: ${getObjType(itemVal)} | result: $setObj" - setData[item?.key].value = setObj + setData[item?.key]?.value = setObj } setData["automationTypeFlag"] = getAutoType().toString() //setData["backedUpData"] = true @@ -3410,7 +3397,7 @@ def postChildRestore(childId) { cApp?.each { ca -> atomicState?.migrationState3A = "Step 3A postChildRestore Checking Automation (${ca?.label})..." LogAction("postChildRestore Checking Automation (${ca?.label})...", "info", true) - if(ca?.getId() == childId) { + if(ca?.id.toString() == childId) { if(keepBackups() == false) { atomicState?.migrationState3A = "Step 3A postChildRestore Removing Old Automation (${ca?.label})..." LogAction("postChildRestore Removing Old Automation (${ca?.label})...", "warn", true) @@ -3463,9 +3450,11 @@ void finishMigrationProcess(result=true) { def poll(force = false, type = null) { if(isPollAllowed()) { if(checkIfSwupdated()) { return } - - if(force == true) { forcedPoll(type); finishPoll(); return } - + if(force == true) { + forcedPoll(type) + finishPoll() + return + } def pollTime = !settings?.pollValue ? 180 : settings?.pollValue.toInteger() if(settings?.restStreaming && atomicState?.restStreamingOn) { pollTime = 60*5 @@ -3519,14 +3508,12 @@ def poll(force = false, type = null) { } else { def sstr = "" - def allowAsync = false def metstr = "sync" if(atomicState?.appData && atomicState?.appData?.pollMethod?.allowAsync) { allowAsync = true metstr = "async" } - if(okStruct) { sstr += "Updating Structure Data (Last Updated: ${getLastStructPollSec()} seconds ago)" if(allowAsync) { @@ -3584,25 +3571,9 @@ def resetPolling() { setPollingState() // will call poll } -/* -def finishPollHandler(data) { - def dev = data?.dev - finishPoll(false, dev) -} -*/ - def schedFinishPoll(devChg) { - //def curNow = now() - //atomicState?.lastFinishedPoll = curNow finishPoll(false, devChg) return -/* - if(!atomicState?.lastFinishedPoll || curNow >= atomicState?.lastFinishedPoll + 3400) { - def devFlg = [dev:devChg] - runIn(4, "finishPollHandler", [overwrite: true, data: devFlg]) - atomicState?.lastFinishedPoll = curNow - } -*/ } def forcedPoll(type = null) { @@ -3675,7 +3646,6 @@ def getApiData(type = null) { apiIssueEvent(false) atomicState?.apiRateLimited = false atomicState?.apiCmdFailData = null - if(type == "str") { def t0 = resp?.data //LogTrace("API Structure Resp.Data: ${t0}") @@ -3870,11 +3840,6 @@ def receiveEventData() { def devChgd = false def gotSomething = false if(evtData?.data && settings?.restStreaming) { - //def t0 = atomicState?.aaOldStreamData - //whatChanged(t0, evtData, "/") - //atomicState.aaOldStreamData = evtData - //state.remove("aaOldStreamData") - if(evtData?.data?.devices) { //LogTrace("API Device Resp.Data: ${evtData?.data?.devices}") gotSomething = true @@ -3941,6 +3906,7 @@ def didChange(old, newer, type, src) { if(type == "str") { atomicState?.lastStrucDataUpd = getDtNow() atomicState.needStrPoll = false + log.debug "NestAPI AWAY Debug | Current: (${newer[atomicState?.structures]?.away})${(newer[atomicState?.structures]?.away != old[atomicState?.structures]?.away) ? " | Previous: (${old[atomicState?.structures]?.away})" : ""}" } if(type == "dev") { atomicState?.lastDevDataUpd = getDtNow() @@ -4706,7 +4672,7 @@ def setStructureAway(child, value, virtual=false) { def t0 = atomicState?.structData t0[atomicState?.structures].away = "away" atomicState?.structData = t0 - locationPresNotify(getLocationPresence()) + // locationPresNotify(getLocationPresence()) } return ret } @@ -4716,7 +4682,7 @@ def setStructureAway(child, value, virtual=false) { def t0 = atomicState?.structData t0[atomicState?.structures].away = "home" atomicState?.structData = t0 - locationPresNotify(getLocationPresence()) + // locationPresNotify(getLocationPresence()) } return ret } @@ -4963,6 +4929,11 @@ def sendNestApiCmd(cmdTypeId, cmdType, cmdObj, cmdObjVal, childId) { } else { tempQueue << cmdData } + // tempQueue?.each { qi-> + // if(qi[2]?.cmdObj?.away) { + // tempQueue + // } + // } atomicState."cmdQ${qnum}" = tempQueue def str = "Adding" @@ -5110,7 +5081,6 @@ def storeLastCmdData(cmd, qnum) { void workQueue() { LogTrace("workQueue") //def cmdDelay = getChildWaitVal() - if(!atomicState?.cmdQlist) { atomicState?.cmdQlist = [] } def cmdQueueList = atomicState?.cmdQlist @@ -5126,18 +5096,21 @@ void workQueue() { if(!atomicState?."cmdQ${qnum}") { atomicState."cmdQ${qnum}" = [] } def cmdQueue = atomicState?."cmdQ${qnum}" + log.debug "cmdQueue: $cmdQueue" try { if(cmdQueue?.size() > 0) { LogAction("workQueue │ Run Queue: ${qnum} | ($metstr)", "trace", true) runIn(60, "workQueue", [overwrite: true]) // lost schedule catchall - if(!cmdIsProc()) { cmdProcState(true) atomicState?.pollBlocked = true atomicState?.pollBlockedReason = "Processing Queue" cmdQueue = atomicState?."cmdQ${qnum}" + log.trace "cmdQueue(workqueue): $cmdQueue" def cmd = cmdQueue?.remove(0) + log.trace "cmdQueue(workqueue-after): $cmdQueue" + log.debug "cmd: $cmd" atomicState?."cmdQ${qnum}" = cmdQueue def cmdres @@ -5160,7 +5133,6 @@ void workQueue() { } finishWorkQ(cmd, cmdres) } else { LogAction("workQueue: busy processing command", "warn", true) } - } else { atomicState.pollBlocked = false; atomicState?.pollBlockedReason = null; cmdProcState(false); } } catch (ex) { @@ -5502,19 +5474,20 @@ def deviceHealthNotify(child, Boolean isHealthy) { } def getLocationPresence() { - def away = atomicState?.structData && atomicState?.structures ? atomicState?.structData[atomicState?.structures]?.away : null - return (away != null) ? away.toString() : null + def away = atomicState?.structData && atomicState?.structures && atomicState?.structData[atomicState?.structures] && atomicState?.structData[atomicState?.structures]?.away ? atomicState?.structData[atomicState?.structures]?.away : null + return (away != null) ? away as String : null } def locationPresNotify(pres) { - if(!pres) { return } + log.trace "locationPresNotify($pres)" + if(pres == null) { return } if(atomicState?.notificationPrefs?.locationChg == true) { - def lastStatus = atomicState?.nestLocStatus - if(lastStatus && lastStatus != pres) { + def lastStatus = atomicState?.curNestLocStatus + if(lastStatus != null && lastStatus?.toString() != pres?.toString()) { sendMsg("${app?.label} Nest Location Info", "\nNest (${atomicState?.structName}) Location has been changed to [${pres.toString().capitalize()}]") } } - atomicState?.nestLocStatus = pres + atomicState?.curNestLocStatus = pres } def apiIssueNotify(msgOn, rateOn, wait) { @@ -7987,7 +7960,7 @@ def buildDevInputMap() { def buildChildAppInputMap() { def appMap = [:] getAllChildApps()?.each { - appMap[[it?.getId()].join('.')] = it?.getLabel() + appMap[[it?.id]?.join('.')] = it?.getLabel() } return appMap } @@ -8233,161 +8206,159 @@ def renderDiagHome() { //def newHtml = getWebData([uri: "https://raw.githubusercontent.com/${gitPath()}/Documents/html/diagHome.html", contentType: "text/plain; charset=UTF-8"], "newHtml").toString() //log.debug "newHtml: $newHtml" def html = """ - - - - - - - NST Diagnostics ${atomicState?.structName} - - - - - - - - - - - - - - - - - - - - -
-