Advertisement
Guest User

SmartThings Infintude Bryant/Carrier SmartApp

a guest
Apr 19th, 2020
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.97 KB | None | 0 0
  1. /**
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  4. * in compliance with the License. You may obtain a copy of the License at:
  5. *
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  9. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  10. * for the specific language governing permissions and limitations under the License.
  11. *
  12. */
  13. definition(
  14. name: "Infinitude Integration",
  15. namespace: "Infinitude",
  16. author: "zraken, swerb73",
  17. description: "Infinitude Integration for Carrier/Bryant Thermostats",
  18. category: "SmartThings Labs",
  19. iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch.png",
  20. iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch@2x.png",
  21. )
  22.  
  23.  
  24. preferences {
  25. page(name: "prefLogIn", title: "Infinitude Server")
  26. page(name: "pausePage", title: "Infinitude retrieving...")
  27. page(name: "prefListDevice", title: "Infinitude Zones")
  28. }
  29.  
  30. /* Preferences */
  31. def prefLogIn() {
  32. def showUninstall = configURL != null
  33. return dynamicPage(name: "prefLogIn", title: "Click next to proceed...", nextPage:"pausePage", uninstall:showUninstall, install: false) {
  34. section("Server URL"){
  35. input(name: "configURL", type: "text", title: "Local network ip_address:port", defaultValue: "192.168.15.3:3000", description: "Infinitude LAN Server Address")
  36. }
  37. }
  38. }
  39.  
  40. def pausePage() {
  41. state.SystemRunning = 0
  42. state.thermostatList = syncSystem()
  43. log.debug "Query complete"
  44.  
  45. return dynamicPage(name: "pausePage", title: "Configure", nextPage:"prefListDevice", uninstall:false, install: false) {
  46. section("Advanced Options"){
  47. input(name: "polling", title: "Server Polling (in Minutes)", type: "number", description: "in minutes", defaultValue: "5", range: "1..120" )
  48. }
  49. }
  50. }
  51. def prefListDevice() {
  52. if (state.thermostatList) {
  53. log.debug "Got a list"
  54. return dynamicPage(name: "prefListDevice", title: "Thermostats", install:true, uninstall:true) {
  55. section("Select which thermostat/zones to use"){
  56. input(name: "selectedThermostats", type: "enum", required:false, multiple:true, metadata:[values:state.thermostatList])
  57. }
  58. }
  59. } else {
  60. log.debug "Empty list returned"
  61. return dynamicPage(name: "prefListDevice", title: "Error!", install:false, uninstall:true) {
  62. section(""){ paragraph "Could not find any devices " }
  63. }
  64. }
  65. }
  66.  
  67. /* Initialization */
  68. def installed() { initialize() }
  69. def updated() {
  70. unschedule()
  71. unsubscribe()
  72. initialize()
  73. }
  74. def uninstalled() {
  75. unschedule()
  76. unsubscribe()
  77. getAllChildDevices().each { deleteChildDevice(it.deviceNetworkId) }
  78. }
  79.  
  80. def initialize() {
  81. // Set initial states
  82. state.data = [:]
  83. state.setData = [:]
  84. state.SystemRunning = 1
  85.  
  86. //selectedThermostats.each { dni, val ->
  87. def devices = selectedThermostats.collect { dni ->
  88. log.debug "Processing DNI: ${dni} with Value: {val}"
  89. def d = getChildDevice(dni)
  90. if(!d) {
  91. d = addChildDevice("SmartThingsMod", "Infinitude Thermostat", dni, null, ["label" : "Stat: " + dni.split("\\|")[3]])
  92. log.debug "----->created ${d.displayName} with id $dni"
  93. } else {
  94. log.debug "found ${d.displayName} with id $dni already exists"
  95. }
  96. return d
  97. }
  98. log.debug "Completed creating devices"
  99.  
  100. pollTask()
  101. }
  102.  
  103.  
  104. import groovy.json.JsonSlurper
  105. def httpCallback(physicalgraph.device.HubResponse hubResponseX) {
  106. setLookupInfo()
  107.  
  108. //log.debug "httpCallback - Status: {$hubResponseX.status}"
  109. //log.debug "httpCallback - Body: {$hubResponseX.json}"
  110.  
  111. def object = new groovy.json.JsonSlurper().parseText(hubResponseX.body)
  112. state.thermostatList = [:]
  113. state.data = [:]
  114. state.outsideairtemp = 0
  115.  
  116. def systemName = "Thermostat"
  117.  
  118. if (hubResponseX.status == 200) {
  119. log.debug "-----APIRESP(systems/id/status) 3"
  120. state.outsideAirTemp = object.oat[0]
  121. object.zones[0].zone.each { zone ->
  122. if (zone.enabled[0] == "on") {
  123. def dni = [ app.id, systemName, zone.id[0], zone.name[0] ].join('|')
  124. log.debug "DNI: " + dni
  125. state.thermostatList[dni] = systemName + ":" + zone.name[0]
  126.  
  127. //Get the current status of each device
  128. state.data[dni] = [
  129. temperature: zone.rt[0],
  130. humidity: zone.rh[0],
  131. coolingSetpoint: zone.clsp[0],
  132. heatingSetpoint: zone.htsp[0],
  133. //thermostatFanMode: lookupInfo( "thermostatFanMode", zone.fan[0], true ),
  134. thermostatFanMode: zone.fan[0],
  135. //thermostatOperatingState: lookupInfo( "thermostatOperatingState", response.data.mode.text().toString(), true ),
  136. thermostatOperatingState: zone.zoneconditioning[0],
  137. thermostatActivityState: zone.currentActivity[0],
  138. thermostatHoldStatus: zone.hold[0],
  139. thermostatHoldUntil: zone.otmr[0],
  140. thermostatDamper: zone.damperposition[0],
  141. thermostatZoneId: zone.id[0]
  142. ]
  143. if(state.SystemRunning) {
  144. refreshChild(dni)
  145. }
  146. log.debug "===== " + zone.name[0] + " =====" /*
  147. log.debug "Temperature: " + state.data[dni].temperature
  148. log.debug "Humidity: " + state.data[dni].humidity
  149. log.debug "Heat set point: " + state.data[dni].heatingSetpoint
  150. log.debug "Cooling set point: " + state.data[dni].coolingSetpoint
  151. log.debug "Fan: " + state.data[dni].thermostatFanMode
  152. log.debug "Operating state: " + state.data[dni].thermostatOperatingState
  153. log.debug "Current schedule mode: " + state.data[dni].thermostatActivityState
  154. log.debug "Current Hold Status: " + state.data[dni].thermostatHoldStatus
  155. log.debug "Hold Until: " + state.data[dni].thermostatHoldUntil
  156. log.debug "Current Damper Position: " + state.data[dni].thermostatDamper
  157. log.debug "Current Outside Temp: " + state.outsideAirTemp
  158. log.debug "Zone ID: " + state.data[dni].thermostatZoneId
  159. log.debug "=====Done=====" */
  160. }
  161. }
  162. }
  163. else {
  164. log.debug "API request failed"
  165. }
  166.  
  167. log.debug state.thermostatList
  168. //xxxxx return thermostatList
  169. }
  170.  
  171. private syncSystem() {
  172. def result = new physicalgraph.device.HubAction(
  173. method: "GET",
  174. path: "/api/status",
  175. headers: [
  176. "HOST" : configURL
  177. ],
  178. null,
  179. [callback: httpCallback]
  180. )
  181. log.debug "apiGet called with apiPath: " + apiPath
  182. try {
  183. sendHubCommand(result)
  184. } catch (all) {
  185. log.error "Error executing internal web request: $all"
  186. }
  187. }
  188.  
  189. private changeHtsp(zoneId, heatingSetPoint) {
  190.  
  191. //First Adjust the Manual Comfort Profile
  192. def result = new physicalgraph.device.HubAction(
  193. method: "GET",
  194. path: "/api/" + zoneId + "/activity/manual",
  195. headers: [
  196. "HOST" : configURL
  197. ],
  198. query: [htsp: heatingSetPoint]
  199. )
  200. log.debug "HTTP GET Parameters: " + result
  201. try {
  202. sendHubCommand(result)
  203. } catch (all) {
  204. log.error "Error executing internal web request: $all"
  205. }
  206.  
  207. //Now tell the zone to use the Manual Comfort Profile
  208. def NowDate = new Date(now())
  209. log.debug "Now = ${NowDate.format('dd-MM-yy HH:mm',location.timeZone)}"
  210. NowDate.set(minute:NowDate.minutes+15)
  211. def HoldTime = NowDate.format('HH:mm',location.timeZone)
  212. log.debug "Later = " + HoldTime
  213.  
  214. result = new physicalgraph.device.HubAction(
  215. method: "GET",
  216. path: "/api/" + zoneId + "/hold",
  217. headers: [
  218. "HOST" : configURL
  219. ],
  220. query: [activity: "manual", until: "24:00" ]
  221. )
  222. log.debug "HTTP GET Parameters: " + result
  223. try {
  224. sendHubCommand(result)
  225. } catch (all) {
  226. log.error "Error executing internal web request: $all"
  227. }
  228. }
  229.  
  230. private changeClsp(zoneId, coolingSetpoint) {
  231.  
  232. //First Adjust the Manual Comfort Profile
  233. def result = new physicalgraph.device.HubAction(
  234. method: "GET",
  235. path: "/api/" + zoneId + "/activity/manual",
  236. headers: [
  237. "HOST" : configURL
  238. ],
  239. query: [clsp: coolingSetpoint]
  240. )
  241. log.debug "HTTP GET Parameters: " + result
  242. try {
  243. sendHubCommand(result)
  244. } catch (all) {
  245. log.error "Error executing internal web request: $all"
  246. }
  247.  
  248. //Now tell the zone to use the Manual Comfort Profile
  249. def NowDate = new Date(now())
  250. log.debug "Now = ${NowDate.format('dd-MM-yy HH:mm',location.timeZone)}"
  251. NowDate.set(minute:NowDate.minutes+15)
  252. def HoldTime = NowDate.format('HH:mm',location.timeZone)
  253. log.debug "Later = " + HoldTime
  254.  
  255. result = new physicalgraph.device.HubAction(
  256. method: "GET",
  257. path: "/api/" + zoneId + "/hold",
  258. headers: [
  259. "HOST" : configURL
  260. ],
  261. query: [activity: "manual", until: "24:00" ]
  262. )
  263. log.debug "HTTP GET Parameters: " + result
  264. try {
  265. sendHubCommand(result)
  266. } catch (all) {
  267. log.error "Error executing internal web request: $all"
  268. }
  269. }
  270.  
  271. private changeProfile(zoneId, nextProfile) {
  272. //Now tell the zone to use the nextProfile Comfort Profile
  273. log.debug "Changing Profile for Zone " + zoneId + " to " + nextProfile
  274.  
  275. def result = new physicalgraph.device.HubAction(
  276. method: "GET",
  277. path: "/api/" + zoneId + "/hold",
  278. headers: [
  279. "HOST" : configURL
  280. ],
  281. query: [activity: nextProfile, until: "24:00" ]
  282. )
  283. log.debug "HTTP GET Parameters: " + result
  284. try {
  285. sendHubCommand(result)
  286. } catch (all) {
  287. log.error "Error executing internal web request: $all"
  288. }
  289. }
  290.  
  291. def setLookupInfo() {
  292. state.lookup = [
  293. thermostatOperatingState: [:],
  294. thermostatFanMode: [:],
  295. thermostatMode: [:],
  296. activity: [:],
  297. coolingSetPointHigh: [:],
  298. coolingSetPointLow: [:],
  299. heatingSetPointHigh: [:],
  300. heatingSetPointLow: [:],
  301. differenceSetPoint: [:],
  302. temperatureRangeF: [:]
  303. ]
  304. state.lookup.thermostatMode["off"] = "off"
  305. state.lookup.thermostatMode["cool"] = "cool"
  306. state.lookup.thermostatMode["heat"] = "heat"
  307. state.lookup.thermostatMode["fanonly"] = "off"
  308. state.lookup.thermostatMode["auto"] = "auto"
  309. state.lookup.thermostatOperatingState["heat"] = "heating"
  310. state.lookup.thermostatOperatingState["hpheat"] = "heating"
  311. state.lookup.thermostatOperatingState["cool"] = "cooling"
  312. state.lookup.thermostatOperatingState["off"] = "idle"
  313. state.lookup.thermostatOperatingState["fanonly"] = "fan only"
  314. state.lookup.thermostatFanMode["off"] = "auto"
  315. state.lookup.thermostatFanMode["low"] = "circulate"
  316. state.lookup.thermostatFanMode["med"] = "on"
  317. state.lookup.thermostatFanMode["high"] = "on"
  318. }
  319.  
  320. // lookup value translation
  321. def lookupInfo( lookupName, lookupValue, lookupMode ) {
  322. if (lookupName == "thermostatFanMode") {
  323. if (lookupMode) {
  324. return state.lookup.thermostatFanMode.getAt(lookupValue.toString())
  325. } else {
  326. return state.lookup.thermostatFanMode.find{it.value==lookupValue.toString()}?.key
  327. }
  328. }
  329. if (lookupName == "thermostatMode") {
  330. if (lookupMode) {
  331. return state.lookup.thermostatMode.getAt(lookupValue.toString())
  332. } else {
  333. return state.lookup.thermostatMode.find{it.value==lookupValue.toString()}?.key
  334. }
  335. }
  336. if (lookupName == "thermostatOperatingState") {
  337. if (lookupMode) {
  338. return state.lookup.thermostatOperatingState.getAt(lookupValue.toString())
  339. } else {
  340. return state.lookup.thermostatOperatingState.find{it.value==lookupValue.toString()}?.key
  341. }
  342. }
  343. }
  344. def pollTask() {
  345. syncSystem()
  346. runIn(60*settings.polling, pollTask)
  347. }
  348. def refreshChild(dni) {
  349. log.debug "Refreshing for child " + dni
  350. //def dni = [ app.id, systemID, zone.'@id'.text().toString() ].join('|')
  351. def d = getChildDevice(dni)
  352. if(d) {
  353. log.debug "--Refreshing Child Zone ID: " + state.data[dni].thermostatZoneId
  354. d.zUpdate(state.data[dni].temperature,
  355. state.data[dni].thermostatOperatingState,
  356. state.data[dni].humidity,
  357. state.data[dni].heatingSetpoint,
  358. state.data[dni].coolingSetpoint,
  359. state.data[dni].thermostatFanMode,
  360. state.data[dni].thermostatActivityState,
  361. state.outsideAirTemp,
  362. state.data[dni].thermostatHoldStatus,
  363. state.data[dni].thermostatHoldUntil,
  364. state.data[dni].thermostatDamper,
  365. state.data[dni].thermostatZoneId)
  366. log.debug "Data sent to DH"
  367. }
  368. else {
  369. log.debug "Skipping refresh for unused thermostat"
  370. }
  371. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement