Advertisement
cjcharles

ST Test

Feb 26th, 2017
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.47 KB | None | 0 0
  1. /**
  2. * Copyright 2017 Chris Charles
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  5. * in compliance with the License. You may obtain a copy of the License at:
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  10. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  11. * for the specific language governing permissions and limitations under the License.
  12. *
  13. * Neo Hub Bridge (Parent Device of Neo Thermostat)
  14. *
  15. * Author: Chris Charles (cjcharles0)
  16. * Date: 2017-04-26
  17. */
  18.  
  19. import groovy.json.JsonSlurper
  20.  
  21. metadata {
  22. definition (name: "Neo Hub Bridge", namespace: "cjcharles0", author: "Chris Charles") {
  23. capability "Refresh"
  24. capability "Configuration"
  25. capability "Polling"
  26.  
  27. command "getthermostats"
  28. command "removethermostats"
  29. command "childRequestingRefresh"
  30.  
  31. command "updateThermostatInfo"
  32.  
  33. command "testcommand"
  34.  
  35. }
  36.  
  37. simulator {
  38. }
  39.  
  40. preferences {
  41.  
  42. input("password", "password", title:"Password", required:false, displayDuringSetup:false)
  43. input("bridgeip", "string", title:"Neo Bridge IP Address", description: "e.g. 192.168.1.10", required: true, displayDuringSetup: true)
  44. input("neohubip", "string", title:"NeoHub IP Address", description: "e.g. 192.168.1.11", required: true, displayDuringSetup: true)
  45. input("prestatname", "string", title:"Add before stat name", description: "e.g. 'Thermostat' would give 'Thermostat Kitchen'", required: false, displayDuringSetup: true)
  46. input("poststatname", "string", title:"Add after stat name", description: "e.g. 'Thermostat' would give 'Kitchen Thermostat'", required: false, displayDuringSetup: true)
  47. }
  48.  
  49. tiles (scale: 2){
  50.  
  51. valueTile("lastcommand", "lastcommand", decoration: "flat", width: 6, height: 2) {
  52. state "lastcommand", label:'${currentValue}', icon: "st.Home.home2"
  53. }
  54.  
  55. valueTile("stip", "stip", decoration: "flat", width: 2, height: 1) {
  56. state "stip", label:'ST IP Addr.\r\n${currentValue}'
  57. }
  58. valueTile("neoip", "neoip", decoration: "flat", width: 2, height: 1) {
  59. state "neoip", label:'Neohub IP Addr.\r\n${currentValue}'
  60. }
  61. valueTile("brip", "brip", decoration: "flat", width: 2, height: 1) {
  62. state "brip", label:'ESP Bridge IP Addr.\r\n${currentValue}'
  63. }
  64.  
  65. standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
  66. state "default", label:"Refresh Inf", action:"refresh", icon:"st.secondary.refresh"
  67. }
  68. standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
  69. state "configure", label:'Bridge', action:"configure", icon:"st.secondary.configure"
  70. }
  71. standardTile("getthermostats", "device.getthermostats", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
  72. state "getthermostats", label:'Create Thermostat Devices', action:"getthermostats", icon: "st.unknown.zwave.remote-controller"
  73. }
  74. standardTile("removethermostats", "device.removethermostats", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
  75. state "removethermostats", label:'Remove Thermostat Devices', action:"removethermostats", icon: "st.samsung.da.washer_ic_cancel"
  76. }
  77. standardTile("testcommand", "device.testcommand", inactiveLabel: false, decoration: "flat", width: 2, height: 1) {
  78. state "testcommand", label:'Send Test Neohub command', action:"testcommand"
  79. }
  80. }
  81.  
  82. main(["lastcommand"])
  83. details(["lastcommand",
  84. "stip", "neoip", "brip",
  85. "refresh", "configure", "getthermostats", "removethermostats",
  86. //"testcommand"
  87. ])
  88. }
  89.  
  90. def testcommand(){
  91. log.debug "Getting firmware version"
  92. childAwayOff("neostatDownstairs")
  93. }
  94.  
  95. def configure(){
  96. def cmds = []
  97. log.debug "Configuring NeoBridge"
  98. cmds << getAction("/config?ip_for_st=${device.hub.getDataValue("localIP")}&port_for_st=${device.hub.getDataValue("localSrvPortTCP")}&ip_for_neohub=${neohubip}&port_for_neohub=4242")
  99. return cmds
  100. }
  101.  
  102. def refresh() {
  103. log.debug "refresh()"
  104. //SendEvents should be before any getAction, otherwise getAction does nothing
  105. sendEvent(name: "stip", value: device.hub.getDataValue("localIP")+" Port:"+device.hub.getDataValue("localSrvPortTCP"), displayed: false)
  106. sendEvent(name: "neoip", value: neohubip + " Port:4242", displayed: false)
  107. sendEvent(name: "brip", value: bridgeip + " Port:80", displayed: false)
  108. //Also refresh thermostats with the same command
  109. childRequestingRefresh()
  110. }
  111.  
  112. def installed() {
  113. log.debug "installed()"
  114. //configure()
  115. }
  116.  
  117. def uninstalled() {
  118. removethermostats()
  119. }
  120.  
  121. def updated() {
  122. log.debug "updated()"
  123. configure()
  124. }
  125.  
  126. def ping() {
  127. log.debug "ping()"
  128. getAction("/ping")
  129. }
  130.  
  131. private getthermostats(){
  132. //Before sending request for thermostat list we should remove current thermostats
  133. def cmds = []
  134. removethermostats()
  135. log.debug "Requesting List of Thermostats"
  136. cmds << getAction("/neorelay?device=hubzonesetup&command={\"GET_ZONES\":0}")
  137. return cmds
  138. }
  139.  
  140. private removethermostats(){
  141. log.debug "Removing Child Thermostats"
  142. getChildDevices()?.each {
  143. deleteChildDevice(it.deviceNetworkId)
  144. }
  145. }
  146.  
  147. def childRequestingRefresh() {
  148. //Send Refresh command
  149. def cmds = []
  150. log.debug "Requesting refreshed info for all children"
  151. cmds << getAction("/neorelay?device=hubzonerefresh&command={\"INFO\":0}")
  152. return cmds
  153. }
  154.  
  155. def childSetTemp(int temp, String dni) {
  156. //Send Child Set Temp command
  157. def cmds = []
  158. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  159. log.debug "Requesting ${temp} degrees for child ${deviceid}"
  160. cmds << getAction("/neorelay?device=${dni}&command={\"SET_TEMP\":[\"${temp}\", \"${deviceid}\"]}")
  161. return cmds
  162. }
  163.  
  164. def childAwayOn(String dni) {
  165. //Send Child Away on command
  166. def cmds = []
  167. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  168. log.debug "Requesting away mode on for child ${deviceid}"
  169. cmds << getAction("/neorelay?device=${dni}&command={\"AWAY_ON\":\"${deviceid}\"}")
  170. return cmds
  171. }
  172.  
  173. def childAwayOff(String dni) {
  174. //Send Child Away off command
  175. def cmds = []
  176. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  177. log.debug "Requesting away mode off for child ${deviceid}"
  178. cmds << getAction("/neorelay?device=${dni}&command={\"AWAY_OFF\":\"${deviceid}\"}")
  179. return cmds
  180. }
  181.  
  182. def childHeat(String dni) {
  183. //Send Child Heat mode
  184. def cmds = []
  185. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  186. log.debug "Requesting heat mode for child ${deviceid}"
  187. cmds << getAction("/neorelay?device=${dni}&command={\"HEAT\":\"${deviceid}\"}")
  188. return cmds
  189. }
  190.  
  191. def childHold(int temp, String id, int hours, int minutes, String dni) {
  192. //Send Child Hold command
  193. def cmds = []
  194. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  195. log.debug "Requesting Hold at ${temp} degrees for ${hours}h:${mins}m for child ${deviceid}"
  196. cmds << getAction("/neorelay?device=${dni}&command={\"HOLD\":[{\"temp\":\"${temp}\",\"id\":\"${id}\",\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
  197. return cmds
  198. }
  199.  
  200. def childBoostOn(int hours, int minutes, String dni) {
  201. //Send Child Boost On command
  202. def cmds = []
  203. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  204. log.debug "Requesting boost on for child ${deviceid}"
  205. cmds << getAction("/neorelay?device=${dni}&command={\"BOOST_ON\":[{\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
  206. return cmds
  207. }
  208.  
  209. def childBoostOff(int hours, int minutes, String dni) {
  210. //Send Child Boost On command
  211. def cmds = []
  212. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  213. log.debug "Requesting boost off for child ${deviceid}"
  214. cmds << getAction("/neorelay?device=${dni}&command={\"BOOST_OFF\":[{\"hours\":\"${hours}\",\"minutes\":\"${minutes}\"}, \"${deviceid}\"]}")
  215. return cmds
  216. }
  217.  
  218. def childFrostOn(String dni) {
  219. //Send Child Frost On command
  220. def cmds = []
  221. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  222. log.debug "Requesting frost on for child ${deviceid}"
  223. cmds << getAction("/neorelay?device=${dni}&command={\"FROST_ON\":\"${deviceid}\"}")
  224. return cmds
  225. }
  226.  
  227. def childFrostOff(String dni) {
  228. //Send Child Frost On command
  229. def cmds = []
  230. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  231. log.debug "Requesting frost off for child ${deviceid}"
  232. cmds << getAction("/neorelay?device=${dni}&command={\"FROST_OFF\":\"${deviceid}\"}")
  233. return cmds
  234. }
  235.  
  236. def childSetFrost(int temp, String dni) {
  237. //Send Child Set Frost command
  238. def cmds = []
  239. def deviceid = dni.replaceAll("neostat", "").replaceAll("-", " ")
  240. log.debug "Requesting set frost at ${temp} degrees for child ${deviceid}"
  241. cmds << getAction("/neorelay?device=${dni}&command={\"SET_FROST\":[\"${temp}\", \"${deviceid}\"]}")
  242. return cmds
  243. }
  244.  
  245. def parse(description) {
  246. def map = [:]
  247. def events = []
  248. def cmds = []
  249.  
  250. //log.debug description
  251.  
  252. if (description == "updated") return
  253. def descMap = parseDescriptionAsMap(description)
  254.  
  255. def body = new String(descMap["body"].decodeBase64())
  256.  
  257. def slurper = new JsonSlurper()
  258. def result = slurper.parseText(body)
  259.  
  260. //log.debug result
  261. cmds << sendEvent(name: "lastcommand", value: "${result}", isStateChange: true)
  262.  
  263. if (result.containsKey("relaydevice")) {
  264. //Received a device key, hence process the command (null devices will be ignored to make it easier to avoid bugs)
  265. if (result.relaydevice == "hubzonesetup") {
  266. //Device is a fake device for setting up zones, so create new devices if they dont exist
  267. for (def currentthermostat in result.relayresult) {
  268. //Iterate through each of the items in the result to create a device
  269. for ( item in currentthermostat) {
  270. def thisthermostatname = ""
  271. if (prestatname != null) {thisthermostatname = thisthermostatname + prestatname + " "}
  272. thisthermostatname = thisthermostatname + item.key
  273. if (poststatname != null) {thisthermostatname = thisthermostatname + " " + poststatname}
  274. log.debug "Adding child Name: ${thisthermostatname}, ID: ${item.value} to ${device.hub.id}"
  275. addChildDevice("cjcharles0", "Neo Thermostat", "neostat${item.key.replaceAll(" ", "-")}", device.hub.id, [name: thisthermostatname])
  276. }
  277. }
  278. }
  279. if (result.relaydevice == "hubzonerefresh") {
  280. //Device is a fake device for refreshing all zone info, so process responses out to each thermostat device
  281. log.debug "Received a refresh command from NeoHub"
  282. for (deviceinfo in result.relayresult.devices) {
  283. //If we have a devices key then it is an INFO command so process the events to update the DH
  284. if (deviceinfo.DEVICE_TYPE < 10) {
  285. //Device type < 10 should exclude repeaters
  286. def curdevicename = deviceinfo.device.replaceAll(" ", "-")
  287. log.debug curdevicename
  288. def curdevice = getChildDevices().find { it.deviceNetworkId == "neostat"+curdevicename}
  289. curdevice?.processNeoResponse(deviceinfo)
  290. }
  291. }
  292. }
  293. if (result.relaydevice.contains("neostat")) {
  294. //We got a command/response for an individual thermostat so send data to thermostat
  295. def resultdevice = getChildDevices().find { it.deviceNetworkId == result.relaydevice}
  296. resultdevice?.processNeoResponse(result)
  297. }
  298. }
  299. return cmds
  300. }
  301.  
  302. private getAction(uri){
  303. log.debug "uri ${uri}"
  304. updateDNI()
  305.  
  306. def userpass
  307.  
  308. if(password != null && password != "")
  309. userpass = encodeCredentials("admin", password)
  310.  
  311. def headers = getHeader(userpass)
  312.  
  313. def hubAction = new physicalgraph.device.HubAction(
  314. method: "GET",
  315. path: uri,
  316. headers: headers
  317. )
  318. return hubAction
  319. }
  320.  
  321. def parseDescriptionAsMap(description) {
  322. description.split(",").inject([:]) { map, param ->
  323. def nameAndValue = param.split(":")
  324. map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
  325. }
  326. }
  327.  
  328. private getHeader(userpass = null){
  329. def headers = [:]
  330. headers.put("Host", getHostAddress())
  331. headers.put("Content-Type", "application/x-www-form-urlencoded")
  332. if (userpass != null)
  333. headers.put("Authorization", userpass)
  334. return headers
  335. }
  336.  
  337. private encodeCredentials(username, password){
  338. def userpassascii = "${username}:${password}"
  339. def userpass = "Basic " + userpassascii.encodeAsBase64().toString()
  340. return userpass
  341. }
  342.  
  343. private updateDNI() {
  344. if (state.dni != null && state.dni != "" && device.deviceNetworkId != state.dni) {
  345. device.deviceNetworkId = state.dni
  346. }
  347. }
  348.  
  349. private getHostAddress() {
  350. if(getDeviceDataByName("bridgeip") && getDeviceDataByName("port")){
  351. return "${getDeviceDataByName("bridgeip")}:${getDeviceDataByName("bridgeport")}"
  352. }
  353. else {
  354. return "${bridgeip}:80"
  355. }
  356. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement