Advertisement
Guest User

Untitled

a guest
Dec 28th, 2020
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.77 KB | None | 0 0
  1. def setVersion() {
  2. state.name = "Auto Lock"
  3. state.version = "1.0.5"
  4. }
  5.  
  6. definition(
  7. name: "Auto Lock Child",
  8. namespace: "chris.sader",
  9. author: "Chris Sader",
  10. description: "Automatically locks a specific door after X minutes/seconds when closed and unlocks it when open after X seconds.",
  11. category: "Convenience",
  12. parent: "chris.sader:Auto Lock",
  13. iconUrl: "",
  14. iconX2Url: "",
  15. iconX3Url: "")
  16.  
  17. preferences {
  18. page(name: "mainPage")
  19. page(name: "timeIntervalInput", title: "Only during a certain time") {
  20. section {
  21. input "starting", "time", title: "Starting", required: false
  22. input "ending", "time", title: "Ending", required: false
  23. }
  24. }
  25. }
  26.  
  27. def mainPage() {
  28. ifTrace("mainPage")
  29. if (!isDebug) {
  30. app.updateSetting("isDebug", false)
  31. }
  32. if (isTrace == true) {
  33. runIn(1800, traceOff)
  34. }
  35. if (isDebug == true) {
  36. runIn(1800, debugOff)
  37. }
  38. if (isTrace == true) {
  39. runIn(1800, traceOff)
  40. }
  41.  
  42. dynamicPage(name: "mainPage", install: true, uninstall: true) {
  43. ifDebug("mainPage: [state.status = ${state?.status}] [state.paused = ${state?.paused}] [state.disabled = ${state.disabled}]")
  44. if (state?.disabled == "Disabled") {
  45. state.pauseButtonName = "Enable"
  46. unsubscribe()
  47. unschedule()
  48. subscribe(disabledSwitch, "switch", disabledHandler)
  49. } else if (state.paused == true) {
  50. state.pauseButtonName = "Resume"
  51. unsubscribe()
  52. unschedule()
  53. subscribe(disabledSwitch, "switch", disabledHandler)
  54. } else {
  55. state.pauseButtonName = "Pause"
  56. initialize()
  57. }
  58. section("") {
  59. input name: "Pause", type: "button", title: state.pauseButtonName, submitOnChange:true
  60. }
  61. section("") {
  62. String defaultName = "Enter a name for this child app"
  63. if (state.displayName) {
  64. defaultName = state.displayName
  65. app.updateLabel(defaultName)
  66. }
  67. label title: "Enter a name for this child app", required:false, defaultValue: defaultName, submitOnChange:true
  68. }
  69. section("When a door unlocks...") {
  70. input "lock1", "capability.lock", title: "Lock Location:", required: true
  71. }
  72. section() {
  73. input "duration", "number", title: "Lock it how many minutes/seconds later?"
  74. }
  75. section() {
  76. input type: "bool", name: "minSec", title: "Default is minutes. Use seconds instead?", required: true, defaultValue: false
  77. }
  78. section("Lock it only when this door is closed.") {
  79. input "openSensor", "capability.contactSensor", title: "Choose Door Contact Sensor"
  80. }
  81. section("Logging Options", hideable: true, hidden: hideLoggingSection()) {
  82. input "isInfo", "bool", title: "Enable Info logging for 30 minutes", submitOnChange: true, defaultValue: false
  83. input "isDebug", "bool", title: "Enable debug logging for 30 minutes", submitOnChange: true, defaultValue: false
  84. input "isTrace", "bool", title: "Enable Trace logging for 30 minutes", submitOnChange: true, defaultValue: false
  85. input "ifLevel","enum", title: "IDE logging level",required: true, options: getLogLevels(), defaultValue : "1"
  86. paragraph "NOTE: IDE logging level overrides the temporary logging selections."
  87. }
  88. section(title: "Only Run When:", hideable: true, hidden: hideOptionsSection()) {
  89. def timeLabel = timeIntervalLabel()
  90. href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : null
  91. input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
  92. options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
  93. input "modes", "mode", title: "Only when mode is", multiple: true, required: false
  94. input "disableSwitch", "capability.switch", title: "Switch to Enable and Disable this app", submitOnChange:true, required:false, multiple:true
  95. }
  96. }
  97. }
  98.  
  99. // Application settings and startup
  100. def installed() {
  101. ifDebug("Auto Lock Door installed.")
  102. state.installed = true
  103. initialize()
  104. }
  105.  
  106. def updated() {
  107. ifDebug("Auto Lock Door updated.")
  108. unsubscribe()
  109. unschedule()
  110. initialize()
  111. updateLabel()
  112. }
  113.  
  114. def initialize() {
  115. ifTrace("initialize")
  116. ifDebug("Settings: ${settings}")
  117. ifDebug("Settings: ${settings}")
  118. subscribe(lock1, "lock", doorHandler)
  119. subscribe(openSensor, "contact.closed", doorHandler)
  120. subscribe(openSensor, "contact.open", doorHandler)
  121. subscribe(disabledSwitch, "switch", disabledHandler)
  122. subscribe(deviceActivationSwitch, "switch", deviceActivationSwitchHandler)
  123. checkPausedOrDisabled()
  124. updateLabel
  125. }
  126.  
  127. // Device Handlers
  128.  
  129.  
  130. def doorHandler(evt) {
  131. ifTrace("doorHandler")
  132. checkPausedOrDisabled()
  133. if (state.pausedOrDisabled == false) {
  134. if (evt.value == "contact.closed") {ifDebug("Door Closed")}
  135. if (evt.value == "contact.opened") {
  136. ifDebug("Door Open")
  137. checkPausedOrDisabled()
  138. if (state.pausedOrDisabled == false) {
  139. ifDebug("Door open reset previous lock task...")
  140. unschedule(lockDoor)
  141. if (minSec) {
  142. def delay = duration
  143. runIn(delay, lockDoor)
  144. } else {
  145. def delay = duration * 60
  146. runIn(delay, lockDoor)
  147. }
  148. }
  149. }
  150. if (evt.value == "locked") { // If the human locks the door then...
  151. ifDebug("Cancelling previous lock task...")
  152. unschedule(lockDoor) // ...we don't need to lock it later.
  153. state.status = "(Locked)"
  154. } else { // If the door is unlocked then...
  155. state.status = "(Unlocked)"
  156. if (minSec) {
  157. def delay = duration
  158. ifDebug("Re-arming lock in in $duration second(s)")
  159. runIn( delay, lockDoor )
  160. } else {
  161. def delay = duration * 60
  162. ifDebug("Re-arming lock in in $duration minute(s)")
  163. runIn( delay, lockDoor )
  164. }
  165. }
  166. }
  167. updateLabel()
  168. }
  169.  
  170. def disabledHandler(evt) {
  171. ifTrace("disabledHandler")
  172. if(disabledSwitch) {
  173. disabledSwitch.each { it ->
  174. disabledSwitchState = it.currentValue("switch")
  175. if (disabledSwitchState == "on") {
  176. ifTrace("disabledHandler: disabledSwitchState = ${disabledSwitchState}")
  177. state.disabled = ""
  178. if (state?.paused) {
  179. state.status = "(Paused)"
  180. updateLabel()
  181. } else {
  182. state.status = "${lockStatus()}"
  183. updateLabel()
  184. }
  185. } else if (disabledSwitchState == "off") {
  186. state.pauseButtonName = "Enable"
  187. state.status = "(Disabled)"
  188. state.disabled = "Disabled"
  189. updateLabel()
  190. ifTrace("disabledHandler: Disabled")
  191. }
  192. }
  193. } else {
  194. state.disabledSwitchState = false
  195. state.disabledSwitch = false
  196. state.disabled = false
  197. if(!state.paused) {
  198. state.status = "${lockStatus()}"
  199. updateLabel()
  200. }
  201. }
  202. }
  203.  
  204. def deviceActivationSwitchHandler(evt) {
  205. ifTrace("deviceActivationSwitchHandler")
  206. ifTrace("DeviceActivationSwitchHandler: state.status = ${state.status} [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  207. checkPausedOrDisabled()
  208. if (state.pausedOrDisabled == false) {
  209. if(deviceActivationSwitch) {
  210. deviceActivationSwitch.each { it ->
  211. deviceActivationSwitchState = it.currentValue("switch")
  212. }
  213. if (deviceActivationSwitchState == "on") {
  214. ifDebug("deviceActivationSwitchHandler: Locking the door now")
  215. lockDoor()
  216. } else if (deviceActivationSwitchState == "off") {
  217. ifDebug("deviceActivationSwitchHandler: Unlocking the door now")
  218. unlockDoorSwitch()
  219. unschedule()
  220. updateLabel()
  221. }
  222. }
  223. } else {
  224. ifDebug("deviceActivationSwitchHandler: Application is paused or disabled.")
  225. }
  226. }
  227.  
  228. // Application Functions
  229. def lockDoor() {
  230. ifDebug("Locking Door if Closed")
  231. if((openSensor?.latestValue("contact") == "closed") || (!openSensor)) {
  232. ifDebug("Is bypass sensor triggering? openSensor == ${!openSensor}")
  233. ifDebug("Door Closed")
  234. lock1.lock()
  235. state.status = "(Locked)"
  236. updateLabel()
  237. } else {
  238. if ((openSensor?.latestValue("contact") == "open")) {
  239. if (minSec) {
  240. def delay = duration
  241. ifDebug("Door open will try again in $duration second(s)")
  242. runIn(delay, lockDoor)
  243. } else {
  244. def delay = duration * 60
  245. ifDebug("Door open will try again in $duration minute(s)")
  246. runIn(delay, lockDoor)
  247. }
  248. }
  249. }
  250. }
  251.  
  252. def unlockDoor() {
  253. ifTrace("unlockDoor")
  254. ifDebug("Unlocking Door")
  255. checkPausedOrDisabled()
  256. if (state.pausedOrDisabled == false) {
  257. if (lock1.currentValue("lock") == "locked") {
  258. ifInfo("unlockDoor: Unlocking the door now")
  259. lock1.unlock()
  260. state.status = "(Unlocked)"
  261. updateLabel()
  262. }
  263. }
  264. }
  265.  
  266. def lockStatus() {
  267. ifTrace("lockStatus")
  268. ifTrace("lockStatus: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  269. ifTrace("lockStatus: [lock1.currentValue(lock) = ${lock1?.currentValue("lock")}]")
  270. if (lock1?.currentValue("lock") == "locked") {
  271. ifTrace("lockStatus - lock1.CurrentValue locked: [state.paused = ${state?.paused}] [state.disabled = ${state?.disabled}] [state.disabled = ${state?.disabled == ""}])")
  272. if ((state?.paused == false) && ((state?.disabled == false) || (state?.disabled == ""))) {
  273. ifTrace("lockStatus: [state.paused = ${state?.paused}] [state.disabled = ${state?.disabled}] [state.disabled = ${state?.disabled == ""}])")
  274. state.status = "(Locked)"
  275. ifDebug("lockStatus - locked: state.status = ${state.status}")
  276. if (state.status == "(Locked)") return "(Locked)"
  277. } else {
  278. ifTrace("lockStatus - lock1.CurrentValue locked: [state.paused = ${state?.paused}] [state.disabled = ${state?.disabled}]")
  279. }
  280. }
  281. if (lock1?.currentValue("lock") == "unlocked") {
  282. ifTrace("lockStatus - lock1.CurrentValue unlocked: [state.paused = ${state?.paused}] [state.disabled = ${state?.disabled}] [state.disabled = ${state?.disabled == false}]")
  283. if ((state?.paused == false) && (state?.disabled == false)) {
  284. state.status = "(Unlocked)"
  285. ifDebug("lockStatus - Unlocked: state.status = ${state.status}")
  286. if (state.status == "(Unlocked)") return "(Unlocked)"
  287. } else {
  288. ifTrace("lockStatus - lock1.CurrentValue unlocked: [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  289. }
  290. }
  291. }
  292.  
  293. def checkPausedOrDisabled() {
  294. ifTrace("checkPausedOrDisabled")
  295. if (state.disabledSwitchState == true) {
  296. if (disabledSwitchState == "Enabled") {
  297. state.disabled = false
  298. state.status = "${lockStatus()}"
  299. } else if (disabledSwitchState == "Disabled") {
  300. state.disabled = "Disabled"
  301. state.status = "(Disabled)"
  302. }
  303. } else if (!disabledSwitchState) {
  304. state.disabled = false
  305. state.status = "${lockStatus()}"
  306. } else {
  307. state.disabled = false
  308. state.status = "${lockStatus()}"
  309. }
  310. lockStatus()
  311. if (state?.disabled || state?.paused) { state.pausedOrDisabled = true } else { state.pausedOrDisabled = false }
  312. ifTrace("checkPausedOrDisabled: [state.paused = ${state.paused}] [state.disabled = ${state.disabled}] [${state.pausedOrDisabled}]")
  313. }
  314.  
  315. def changeMode(mode) {
  316. ifTrace("changeMode")
  317. ifDebug("Changing Mode to: ${mode}")
  318. if (location.mode != mode && location.modes?.find { it.name == mode}) setLocationMode(mode)
  319. }
  320.  
  321.  
  322.  
  323. //Label Updates
  324. void updateLabel() {
  325. if (!app.label.contains("<span") && !app.label.contains("Paused") && !app.label.contains("Disabled") && state?.displayName != app.label) {
  326. state.displayName = app.label
  327. }
  328. if (state?.status || state?.paused || state?.enableSwitch || !state?.enableSwitch) {
  329. def status = state?.status
  330. String label = "${state.displayName} <span style=color:"
  331. if (state?.enableSwitch == true) {
  332. status = "(Disabled)"
  333. ifDebug("updateLabel: Status set to (Disabled)")
  334. label += "red"
  335. } else if (state?.paused) {
  336. status = "(Paused)"
  337. ifDebug("updateLabel: Status set to (Paused)")
  338. label += "red"
  339. } else if (state.status == "(Locked)") {
  340. status = "(Locked)"
  341. ifDebug("updateLabel: Status set to (Locked)")
  342. label += "green"
  343. } else if (state.status == "(Unlocked)") {
  344. status = "(Unlocked)"
  345. ifDebug("updateLabel: Status set to (Unlocked)")
  346. label += "orange"
  347. } else {
  348. status = ""
  349. label += "white"
  350. }
  351. label += ">${status}</span>"
  352. app.updateLabel(label)
  353. }
  354. }
  355.  
  356. //Enable, Resume, Pause button
  357. def appButtonHandler(btn) {
  358. ifTrace("appButtonHandler")
  359. ifTrace("appButtonHandler: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  360. if (btn == "Enable") {
  361. ifTrace("appButtonHandler - Enable button before updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  362. updateLabel()
  363. ifTrace("appButtonHandler - Enable button after updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  364. } else if (btn == "Resume") {
  365. state.disabled = false
  366. state.paused = false
  367. state.status = ""
  368. ifTrace("appButtonHandler - Resume button before updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  369. updateLabel()
  370. ifTrace("appButtonHandler - Resume after updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  371. } else if (btn == "Pause") {
  372. state.disabled = false
  373. state.paused = !state.paused
  374. if (state.paused) {
  375. unschedule()
  376. unsubscribe()
  377. ifTrace("appButtonHandler - Pause button before updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  378. updateLabel()
  379. ifTrace("appButtonHandler - Pause after updateLabel: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  380. } else {
  381. initialize()
  382. ifTrace("appButtonHandler: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  383. updateLabel()
  384. ifTrace("appButtonHandler: [state.status = ${state.status}] [state.paused = ${state.paused}] [state.disabled = ${state.disabled}]")
  385. }
  386. }
  387. }
  388.  
  389. // Application Page settings
  390. private hideLoggingSection() {
  391. (isInfo || isDebug || isTrace || ifLevel) ? true : true
  392. }
  393.  
  394. private hideOptionsSection() {
  395. (starting || ending || days || modes || manualCount) ? false : true
  396. }
  397.  
  398. private getAllOk() {
  399. modeOk && daysOk && timeOk
  400. }
  401.  
  402. private getModeOk() {
  403. def result = !modes || modes.contains(location.mode)
  404. ifDebug("modeOk = ${result}")
  405. result
  406. }
  407.  
  408. private getDaysOk() {
  409. def result = true
  410. if (days) {
  411. def df = new java.text.SimpleDateFormat("EEEE")
  412. if (location.timeZone) {
  413. df.setTimeZone(location.timeZone)
  414. }
  415. else {
  416. df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
  417. }
  418. def day = df.format(new Date())
  419. result = days.contains(day)
  420. }
  421. ifDebug("daysOk = ${result}")
  422. result
  423. }
  424.  
  425. private getTimeOk() {
  426. def result = true
  427. if (starting && ending) {
  428. def currTime = now()
  429. def start = timeToday(starting).time
  430. def stop = timeToday(ending).time
  431. result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
  432. }
  433. ifDebug{"timeOk = ${result}"}
  434. result
  435. }
  436.  
  437. private hhmm(time, fmt = "h:mm a") {
  438. def t = timeToday(time, location.timeZone)
  439. def f = new java.text.SimpleDateFormat(fmt)
  440. f.setTimeZone(location.timeZone ?: timeZone(time))
  441. f.format(t)
  442. }
  443.  
  444. private timeIntervalLabel() {
  445. (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
  446. }
  447.  
  448. // Logging functions
  449. def getLogLevels() {
  450. return [["0":"None"],["1":"Info"],["2":"Debug"],["3":"Trace"]]
  451. }
  452.  
  453. def infoOff() {
  454. app.updateSetting("isInfo", false)
  455. log.info "${state.displayName}: Info logging auto disabled."
  456. }
  457.  
  458. def debugOff() {
  459. app.updateSetting("isDebug", false)
  460. log.info "${state.displayName}: Debug logging auto disabled."
  461. }
  462.  
  463. def traceOff() {
  464. app.updateSetting("isTrace", false)
  465. log.trace "${state.displayName}: Trace logging auto disabled."
  466. }
  467.  
  468. def disableInfoIn30() {
  469. if (isInfo == true) {
  470. runIn(1800, infoOff)
  471. log.info "Info logging disabling in 30 minutes."
  472. }
  473. }
  474.  
  475. def disableDebugIn30() {
  476. if (isDebug == true) {
  477. runIn(1800, debugOff)
  478. log.debug "Debug logging disabling in 30 minutes."
  479. }
  480. }
  481.  
  482. def disableTraceIn30() {
  483. if (isTrace == true) {
  484. runIn(1800, traceOff)
  485. log.trace "Trace logging disabling in 30 minutes."
  486. }
  487. }
  488.  
  489. def ifWarn(msg) {
  490. log.warn "${state.displayName}: ${msg}"
  491. }
  492.  
  493. def ifInfo(msg) {
  494. def logL = 0
  495. if (ifLevel) logL = ifLevel.toInteger()
  496. if (logL == 1 && isInfo == false) {return}//bail
  497. else if (logL > 0) {
  498. log.info "${state.displayName}: ${msg}"
  499. }
  500. }
  501.  
  502. def ifDebug(msg) {
  503. def logL = 0
  504. if (ifLevel) logL = ifLevel.toInteger()
  505. if (logL < 2 && isDebug == false) {return}//bail
  506. else if (logL > 1) {
  507. log.debug "${state.displayName}: ${msg}"
  508. }
  509. }
  510.  
  511. def ifTrace(msg) {
  512. def logL = 0
  513. if (ifLevel) logL = ifLevel.toInteger()
  514. if (logL < 3 && isTrace == false) {return}//bail
  515. else if (logL > 2) {
  516. log.trace "${state.displayName}: ${msg}"
  517. }
  518. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement