Advertisement
Guest User

Untitled

a guest
Aug 1st, 2018
211
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.62 KB | None | 0 0
  1. preferences {
  2. input("TCusername", "text", title: "Username", description: "Your TC username")
  3. input("TCpassword", "password", title: "Password", description: "Your TC password")
  4. input("TClocation", "text", title: "Location", description: "Your TC location")
  5. }
  6.  
  7.  
  8. // for the UI
  9. metadata {
  10. definition (name: "TotalConnect 2.0", author: "minollo@minollo.com", namespace: "minollo") {
  11. capability "Polling"
  12. capability "Alarm"
  13.  
  14. attribute "alarmStatus", "string"
  15. attribute "bypassStatus", "string"
  16. attribute "enabled", "string"
  17.  
  18. command "alarmOn"
  19. command "alarmStay"
  20. command "alarmOff"
  21. command "toggleAlarm"
  22. command "toggleEnable"
  23. command "poll"
  24. }
  25.  
  26. tiles {
  27. standardTile("alarmStatus", "device.alarmStatus", width: 2, height: 2, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
  28. state "off", label: "off", action: "toggleAlarm", icon: "", backgroundColor: "#79b821"
  29. state "away", label: "away", action: "toggleAlarm", icon: "", backgroundColor: "#F70000"
  30. state "stay", label: "stay", action: "toggleAlarm", icon: "", backgroundColor: "#F7B900"
  31. state "arming", label: "arming", icon: "", backgroundColor: "#C09FA6"
  32. state "disarming", label: "disarming", icon: "", backgroundColor: "#A4C09F"
  33. state "unknown", label: "unknown", icon: "", backgroundColor: "#FFFFFF"
  34. }
  35.  
  36. standardTile("refresh", "device.alarmStatus", inactiveLabel: false, decoration: "flat") {
  37. state "default", action:"polling.poll", icon:"st.secondary.refresh"
  38. }
  39.  
  40. standardTile("enable", "device.enabled", canChangeIcon: false, inactiveLabel: true) {
  41. state "default", label: "enabled", action: "toggleEnable", icon: "", backgroundColor: "#79b821"
  42. state "false", label: "disabled", action: "toggleEnable", icon: "", backgroundColor: "#F70000"
  43. }
  44.  
  45. standardTile("bypass", "device.bypassStatus", canChangeIcon: false, inactiveLabel: true) {
  46. state "default", label: "no bypass", icon: "", backgroundColor: "#A4C09F"
  47. state "true", label: "bypassed", icon: "", backgroundColor: "#C09FA6"
  48. }
  49.  
  50. main "alarmStatus"
  51. details(["alarmStatus", "enable", "bypass", "refresh"])
  52. }
  53. }
  54.  
  55.  
  56.  
  57. def toggleEnable() {
  58. def currentStatus = device.currentValue("enabled")
  59. log.debug "toggleEnable() from ${currentStatus}"
  60. if (currentStatus == "false") {
  61. sendEvent(name: "enabled", value: "true")
  62. } else {
  63. alarmOff()
  64. sendEvent(name: "enabled", value: "false")
  65. }
  66. }
  67.  
  68. def toggleAlarm() {
  69. state.sessionID = null //use as a way to force a new session
  70. def currentStatus = device.currentValue("alarmStatus")
  71. log.debug "toggleAlarm() from ${currentStatus}"
  72. if (currentStatus == "away" || currentStatus == "stay") {
  73. alarmOff()
  74. } else if (currentStatus == "off") {
  75. alarmOn()
  76. }
  77. }
  78.  
  79.  
  80. def alarmOn() {
  81. def enabled = device.currentValue("enabled")
  82. log.debug "alarmOn() - enabled == ${enabled}"
  83. def currentStatus = device.currentValue("alarmStatus")
  84. if (enabled == "true") {
  85. state.latestRequestedStatus = "away"
  86. if (currentStatus == "off") {
  87. def sessionID = getSession(TCusername, TCpassword)
  88. if (sessionID) {
  89. def sessionDetails = getSessionDetails(sessionID, TClocation)
  90. def locationID = sessionDetails[0]
  91. def deviceID = sessionDetails[1]
  92. def userID = sessionDetails[2]
  93. if (locationID && deviceID) {
  94. def status = getArmedStatus(sessionID, locationID)
  95. if (status && status[0] && status[0] == "off") {
  96. def userPIN = getUserPIN(sessionID, locationID, deviceID, userID)
  97. armAlarm(sessionID, locationID, deviceID, userPIN, "away")
  98. runIn(20, poll)
  99. }
  100. }
  101. }
  102. } else {
  103. log.warn "Alarm is not off; ignoring alarmOn()"
  104. }
  105. } else {
  106. log.debug "Ignoring command"
  107. }
  108. }
  109.  
  110. def alarmStay() {
  111. def enabled = device.currentValue("enabled")
  112. log.debug "alarmOn() - enabled == ${enabled}"
  113. if (enabled == "true") {
  114. state.latestRequestedStatus = "stay"
  115. def currentStatus = device.currentValue("alarmStatus")
  116. if (currentStatus == "off") {
  117. def sessionID = getSession(TCusername, TCpassword)
  118. if (sessionID) {
  119. def sessionDetails = getSessionDetails(sessionID, TClocation)
  120. def locationID = sessionDetails[0]
  121. def deviceID = sessionDetails[1]
  122. def userID = sessionDetails[2]
  123. if (locationID && deviceID) {
  124. def status = getArmedStatus(sessionID, locationID)
  125. if (status && status[0] && status[0] == "off") {
  126. def userPIN = getUserPIN(sessionID, locationID, deviceID, userID)
  127. armAlarm(sessionID, locationID, deviceID, userPIN, "stay")
  128. runIn(20, poll)
  129. }
  130. }
  131. }
  132. } else {
  133. log.warn "Alarm is not off; ignoring alarmStay()"
  134. }
  135. } else {
  136. log.debug "Ignoring command"
  137. }
  138. }
  139.  
  140. def alarmOff() {
  141. log.debug "alarmOff()"
  142. state.latestRequestedStatus = "off"
  143. def sessionID = getSession(TCusername, TCpassword)
  144. if (sessionID) {
  145. def sessionDetails = getSessionDetails(sessionID, TClocation)
  146. def locationID = sessionDetails[0]
  147. def deviceID = sessionDetails[1]
  148. def userID = sessionDetails[2]
  149. if (locationID && deviceID) {
  150. def status = getArmedStatus(sessionID, locationID)
  151. if (status && status[0] && (status[0] == "away" || status[0] == "stay")) {
  152. def userPIN = getUserPIN(sessionID, locationID, deviceID, userID)
  153. disarmAlarm(sessionID, locationID, deviceID, userPIN)
  154. runIn(20, poll)
  155. }
  156. }
  157. }
  158. }
  159.  
  160.  
  161.  
  162.  
  163. def api(method, args, success) {
  164. def baseURL = "https://rs.alarmnet.com/tc21api/tc2.asmx"
  165.  
  166. def methods = [
  167. "getSession": [uri: "${baseURL}/AuthenticateUserLogin?${args}"],
  168. "getSessionDetails": [uri: "${baseURL}/GetSessionDetails?${args}"],
  169. "getPanelStatus": [uri: "${baseURL}/GetPanelMetaDataAndFullStatus?${args}"],
  170. "getUserDetails": [uri: "${baseURL}/GetUserDetails?${args}"],
  171. "armAlarm": [uri: "${baseURL}/ArmSecuritySystem?${args}"],
  172. "disarmAlarm": [uri: "${baseURL}/DisarmSecuritySystem?${args}"],
  173. "keepAlive": [uri: "${baseURL}/KeepAlive?${args}"],
  174. "logOut": [uri: "${baseURL}/Logout?${args}"]
  175. ]
  176.  
  177. def request = methods.getAt(method)
  178. // log.debug "httpGet: ${request}"
  179. httpGet([uri: request.uri], success)
  180. }
  181.  
  182.  
  183.  
  184. private getSession(username, password) {
  185. def sessionID
  186. def nowTime = new Date().time
  187. if (state.sessionTime && nowTime - state.sessionTime < (3 * 60 * 1000 + 20000)) {
  188. sessionID = state.sessionID
  189. }
  190. def result = {
  191. response ->
  192. if (response.data && response.data.name() == "AuthenticateLoginResults") {
  193. def resultCode = response.data.ResultCode.text()
  194. log.debug "getSession().resultCode == ${resultCode}"
  195. if (resultCode != "0") {
  196. log.error "getSession(): ${response.data.ResultData.text()}"
  197. } else {
  198. sessionID = response.data.SessionID.text()
  199. log.info "getSession(): ${sessionID}"
  200. }
  201. } else {
  202. log.error "getSession(): catastrophic failure"
  203. }
  204. }
  205. if (keepAlive(sessionID) != "0") {
  206. log.debug "Creating new session"
  207. api("getSession", "userName=${username}&password=${password}&ApplicationID=34857971&ApplicationVersion=2.2.0", result)
  208. state.sessionID = sessionID
  209. } else {
  210. log.debug "Using existing session: ${sessionID}"
  211. }
  212. state.sessionTime = nowTime
  213. sessionID
  214. }
  215.  
  216. private keepAlive(sessionID) {
  217. if (sessionID == null) return null
  218. log.debug "KeepAlive(); sessionID == ${sessionID}"
  219. def resultCode
  220. def result = {
  221. response ->
  222. if (response.data && response.data.name() == "WebMethodResults") {
  223. resultCode = response.data.ResultCode.text()
  224. log.debug "keepAlive().resultCode == ${resultCode}"
  225. } else {
  226. log.error "keepAlive(): catastrophic failure"
  227. }
  228. }
  229. api("keepAlive", "SessionID=${sessionID}", result)
  230. resultCode
  231. }
  232.  
  233. private getSessionDetails(sessionID, location) {
  234. def locationID
  235. def deviceID
  236. def userID
  237. def result = {
  238. response ->
  239. if (response.data && response.data.name() == "SessionDetailResults") {
  240. def resultCode = response.data.ResultCode.text()
  241. log.debug "getSessionDetails().resultCode == ${resultCode}"
  242. if (resultCode != "0") {
  243. log.error "getSessionDetails(): ${response.data.ResultData.text()}"
  244. } else {
  245. userID = response.data.UserInfo.UserID.text()
  246. response.data.Locations.LocationInfoBasic.each {
  247. log.debug "locationName = ${it.LocationName.text()} (looking for '${location}')"
  248. if (it.LocationName.text() == location) {
  249. locationID = it.LocationID.text()
  250. deviceID = it.DeviceList.DeviceInfoBasic[0].DeviceID.text()
  251. }
  252. }
  253. log.info "getSessionDetails(): ${locationID}, ${deviceID}, ${userID}"
  254. }
  255. } else {
  256. log.error "getSessionDetails(): catastrophic failure"
  257. }
  258. }
  259. api("getSessionDetails", "SessionID=${sessionID}&ApplicationID=34857971&ApplicationVersion=2.2.0", result)
  260. [locationID, deviceID, userID]
  261. }
  262.  
  263. private getArmedStatus(sessionID, locationID) {
  264. def armedStatus
  265. def bypassStatus
  266. def result = {
  267. response ->
  268. if (response.data && response.data.name() == "PanelMetadataAndStatusResults") {
  269. def resultCode = response.data.ResultCode.text()
  270. log.debug "getArmedStatus().resultCode == ${resultCode}"
  271. if (resultCode != "0") {
  272. log.error "getArmedStatus(): ${response.data.ResultData.text()}"
  273. } else {
  274. def armedCode = response.data.PanelMetadataAndStatus.Partitions.PartitionInfo.ArmingState.text()
  275. if (armedCode == "10200") {
  276. armedStatus = "off"
  277. bypassStatus = "false"
  278. } else if (armedCode == "10201") {
  279. armedStatus = "away"
  280. bypassStatus = "false"
  281. } else if (armedCode == "10202") {
  282. armedStatus = "away"
  283. bypassStatus = "true"
  284. } else if (armedCode == "10203") {
  285. armedStatus = "stay"
  286. bypassStatus = "false"
  287. } else if (armedCode == "10204") {
  288. armedStatus = "stay"
  289. bypassStatus = "false"
  290. } else if (armedCode == "10211") {
  291. armedStatus = "off"
  292. bypassStatus = "true"
  293. } else if (armedCode == "10307") {
  294. armedStatus = "arming"
  295. bypassStatus = "false"
  296. } else if (armedCode == "10308") {
  297. armedStatus = "disarming"
  298. bypassStatus = "false"
  299. } else {
  300. armedStatus = "unknown"
  301. bypassStatus = "false"
  302. }
  303. log.info "getArmedStatus(): ${armedCode}, ${armedStatus}, ${bypassStatus}"
  304. }
  305. } else {
  306. log.error "getArmedStatus(): catastrophic failure"
  307. }
  308. }
  309. api("getPanelStatus", "SessionID=${sessionID}&LocationID=${locationID}&LastSequenceNumber=0&LastUpdatedTimestampTicks=0&PartitionID=0", result)
  310. // log.trace "SessionID=${sessionID}&LocationID=${locationID}&LastSequenceNumber=0&LastUpdatedTimestampTicks=0&PartitionID=0"
  311. [armedStatus, bypassStatus]
  312. }
  313.  
  314. private getUserPIN(sessionID, locationID, deviceID, userID) {
  315. def userPIN
  316. def result = {
  317. response ->
  318. if (response.data && response.data.name() == "UserDetailResults") {
  319. def resultCode = response.data.ResultCode.text()
  320. log.debug "getUserPIN().resultCode == ${resultCode}"
  321. if (resultCode != "0") {
  322. log.error "getUserPIN(): ${response.data.ResultData.text()}"
  323. } else {
  324. response.data.UserDetails.LocationList.LocationUserAuthorization.each {
  325. log.debug "Location ID: ${it.LocationID}"
  326. if (it.LocationID == locationID) {
  327. it.DeviceList.DeviceUserAuthorization.each {
  328. log.debug "Device ID: ${it.DeviceID}"
  329. if (it.DeviceID == deviceID) {
  330. it.DeviceAuthorizationAttributes.DeviceAttribute.each {
  331. log.debug "Attribute name: ${it.Name.text()}"
  332. if (it.Name.text() == "PanelUserCode") {
  333. userPIN = it.Value.text()
  334. }
  335. }
  336. }
  337. }
  338. }
  339. }
  340. log.info "getUserPIN().length: ${userPIN.length()}"
  341. }
  342. } else {
  343. log.error "getUserPIN(): catastrophic failure"
  344. }
  345. }
  346. api("getUserDetails", "SessionID=${sessionID}&ManageUserId=${userID}&UserTypeId=${userID}&AdditionalInput=", result)
  347. userPIN
  348. }
  349.  
  350. private armAlarm(sessionID, locationID, deviceID, userPIN, stayOrAway) {
  351. def resultCode
  352. def result = {
  353. response ->
  354. if (response.data && response.data.name() == "ArmSecuritySystemResults") {
  355. resultCode = response.data.ResultCode.text()
  356. log.debug "armAlarm().resultCode == ${resultCode}"
  357. } else {
  358. log.error "armAlarm(): catastrophic failure"
  359. }
  360. }
  361. if (stayOrAway == "away") {
  362. api("armAlarm", "SessionID=${sessionID}&LocationID=${locationID}&DeviceID=${deviceID}&ArmType=0&UserCode=${userPIN}", result)
  363. } else {
  364. api("armAlarm", "SessionID=${sessionID}&LocationID=${locationID}&DeviceID=${deviceID}&ArmType=1&UserCode=${userPIN}", result)
  365. }
  366. resultCode
  367. }
  368.  
  369. private disarmAlarm(sessionID, locationID, deviceID, userPIN) {
  370. def resultCode
  371. def result = {
  372. response ->
  373. if (response.data && response.data.name() == "DisarmSecuritySystemResults") {
  374. resultCode = response.data.ResultCode.text()
  375. log.debug "disarmAlarm().resultCode == ${resultCode}"
  376. } else {
  377. log.error "disarmAlarm(): catastrophic failure"
  378. }
  379. }
  380. api("disarmAlarm", "SessionID=${sessionID}&LocationID=${locationID}&DeviceID=${deviceID}&UserCode=${userPIN}", result)
  381. resultCode
  382. }
  383.  
  384. private logOut(sessionID) {
  385. def result = {
  386. response ->
  387. if (response.data && response.data.name() == "WebMethodResults") {
  388. def resultCode = response.data.ResultCode.text()
  389. log.debug "logOut().resultCode == ${resultCode}"
  390. if (resultCode != "0") {
  391. log.error "logOut(): ${response.data.ResultData.text()}"
  392. } else {
  393. log.info "logOut(): success"
  394. }
  395. } else {
  396. log.error "logOut(): catastrophic failure"
  397. }
  398. }
  399. api("logOut", "SessionID=${sessionID}", result)
  400. }
  401.  
  402. def poll() {
  403. log.debug "Poll: latestRequestedStatus == ${state.latestRequestedStatus}"
  404. def sessionID = getSession(TCusername, TCpassword)
  405. if (sessionID) {
  406. def sessionDetails = getSessionDetails(sessionID, TClocation)
  407. def locationID = sessionDetails[0]
  408. def deviceID = sessionDetails[1]
  409. def userID = sessionDetails[2]
  410. if (locationID && deviceID) {
  411. def status = getArmedStatus(sessionID, locationID)
  412. sendEvent(name: "alarmStatus", value: status[0])
  413. sendEvent(name: "bypassStatus", value: status[1])
  414. log.debug "Current alarmStatus == ${status[0]}"
  415. if(status[0] != "arming" && status[0] != "disarming") { // if in transition state, just wait for the next poll
  416. if(state.latestRequestedStatus != null && state.latestRequestedStatus != status[0]) {
  417. state.sessionID = null
  418. if(state.latestRequestedStatus == "away") {
  419. log.warn "Requesting state change to away again..."
  420. alarmOn()
  421. } else if (state.latestRequestedStatus == "stay") {
  422. log.warn "Requesting state change to stay again..."
  423. alarmStay()
  424. } else if (state.latestRequestedStatus == "off") {
  425. log.warn "Requesting state change to off again..."
  426. alarmOff()
  427. } else {
  428. log.error "Unknown state.latestRequestedStatus value"
  429. }
  430. } else {
  431. if (state.latestRequestedStatus != null) {
  432. log.debug "Resetting state.latestRequestedStatus"
  433. state.latestRequestedStatus = null
  434. }
  435. }
  436. }
  437. } else {
  438. state.sessionID = null
  439. }
  440. }
  441. }
  442.  
  443. def configure() {
  444. log.debug "Configuring"
  445. poll()
  446. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement