/**
* **************** Reset ES1 Presence ****************
*
* Usage:To fix the issue with Linptech/MOES ES1 mm-wave presence sensors that require them to be power cycled after a hub reboot or some elapsed time being online
* This app requires all sensors to be on power switches so they can be remotely power cycled.
A power-cycle for all sensors will take place after the reboot delay setting after a hub reboot.
* A scheduled Job is set for a timed reboot to avoid the sensors going unresponsive.
**/
definition (
name: "Reset ES1 Presence",
namespace: "Hubitat",
author: "ChrisB",
description: "",
category: "My Apps",
iconUrl: "",
iconX2Url: ""
)
preferences {
page name: "mainPage", title: "", install: true, uninstall: true
}
def mainPage() {
dynamicPage(name: "mainPage") {
section("App Name") {
label title: "Optionally assign a custom name for this app", required: false
}
section("USB Switch Devices to Reset Sensors") {
input (
name: "switches",
type: "capability.switch",
title: "Select All Sensor USB Switch Devices",
required: true,
multiple: true
)
}
section("USB Switch Devices to Reset Sensors") {
input (
name: "resetSwitch",
type: "capability.switch",
title: "Select a Virtual Switch to Reset Sensors Manually. Switch will turn off when reset is complete (optional)",
required: false,
multiple: false
)
}
section("Days are: SUN MON TUE WED THU FRI SAT. Use Ranges (MON-FRI) or comma separated Individual Days (TUE,THU)
Enter NONE to not schedule any days"){}
section("Back Hall") {
input (
name: "resetTime",
type: "time",
title: "Reset Schedule",
width: 2,
required: true,
defaultValue: '2024-04-06T14:00:00.000-0400'
)
input (
name: "resetDays",
type: "string",
title: "Reset Days",
width: 2,
required: true,
defaultValue: "SUN"
)
}
section("") {
input (
name: "rebootDelay",
type: "number",
title: "Seconds after Reboot to Reset Sensors ",
required: true,
defaultValue: 300
)
}
section("") {
input (
name: "resetDelay",
type: "number",
title: "Seconds to keep sensor Off before turning back on",
required: true,
defaultValue: 5
)
}
section("") {
input (
name: "executeDelay",
type: "number",
title: "Milliseconds between switch commands",
required: true,
defaultValue: 100
)
}
section("") {
input (
name: "debugMode",
type: "bool",
title: "Enable logging",
required: true,
defaultValue: false
)
}
}
}
def installed() {
updated()
}
def updated() {
if (logEnable) runIn(1800,logsOff)
state.action = "idle"
unschedule()
unsubscribe()
initialize()
}
def initialize() {
subscribe(location, "systemStart", "hubRestartHandler")
// subscribe to turn USB switch back on if it gets turned off (using resetDelay)
subscribe(switches, "switch", switchEventHandler)
if (resetSwitch) {subscribe(resetSwitch, "switch", switchHandler)}
// Set the schedule
def timeStr = settings?.resetTime.toString()
time = timeStr.substring(11,16) // get time from date
def values = time.split(":")
def hour = values[0]
def min = values[1]
String scheduled = "0 "+min+" "+hour+" ? * "+settings?.resetDays // create cron schedule
schedule(scheduled, scheduleHandler)
}
// optional switch to reset all sensors
def switchHandler(evt) {
if (evt.value == "on") {restartSensors()}
}
// Turn a switch back on if it gets turned off accidentially - but ignore this when they are turned off by this app dong the action
def switchEventHandler(evt) {
logDebug("${evt.descriptionText}")
if (evt.value == "off" && state?.action == "idle") {
logDebug("${evt.displayName} turned off")
runIn(resetDelay, turnOnSwitches)
}
}
def scheduleHandler() {
restartSensors()
runIn(resetDelay+10, resetAction)
}
def hubRestartHandler(evt) {
runIn(rebootDelay, restartSensors)
runIn(rebootDelay+10,resetAction)
}
// Restart Sensors
def restartSensors() {
state.action = "restart"
turnOffSwitches()
runIn(resetDelay,turnOnSwitches)
}
def turnOnSwitches() {
resetSwitch.off()
state.numSwitches = switches.size()
state.switchCount = 0
pauseOn()
}
def pauseOn() {
logDebug("pauseOn called with ${state?.switchCount}")
switches[state?.switchCount].on()
if (state?.switchCount < state?.numSwitches - 1) {
state.switchCount = state?.switchCount + 1
runInMillis(executeDelay.toInteger(), 'pauseOn')
} else {state.action = "idle"}
}
def turnOffSwitches() {
state.numSwitches = switches.size()
state.switchCount = 0
pauseOff()
}
def pauseOff() {
logDebug("pauseOff called with ${state?.switchCount}")
switches[state?.switchCount].off()
if (state?.switchCount < state?.numSwitches - 1) {
state.switchCount = state?.switchCount + 1
runInMillis(executeDelay.toInteger(), 'pauseOff')
}
}
def logDebug(txt){
try {
if (settings.debugMode) { log.debug("${app.label} - ${txt}") }
} catch(ex) {
log.error("bad debug message")
}
}
def logsOff(){
log.warn "debug logging disabled..."
device.updateSetting("logEnable",[value:"false",type:"bool"])
}