I have a SmartApp …
… whose initialize method …
def initialize() {
if (clearState) {
// state.clear // this doesn’t work. why? this does:
(state.keySet() as String).each {state.remove it}
}
switches .each {name, title → logState settings.get(name)}
switchLevels.each {name, title → logState settings.get(name)}
[‘sunrise’, ‘sunset’].each {
subscribe location , it , respondToSun}
if (On && Off) [‘On’, ‘Off’].each {name →
schedule settings.get(name) , ‘respondToSchedule’ + name}
contactSensors.each {name, title →
subscribe settings.get(name) , ‘contact’ , respondToContact}
illuminanceMeasurements.each {name, title →
subscribe settings.get(name) , ‘illuminance’ , respondToIlluminance}
motionSensors.each {name, title →
subscribe settings.get(name) , ‘motion’ , respondToMotion}
respond()
}
… arranges to respondTo my location’s sunrise/sunset, my background lighting On/Off schedule, contact from contactSensors, illuminance from illuminanceMeasurements and motion from motionSensors. initialize then responds to the current state. Future events are all handled in the same manner …
def respondToSun(EventWrapper e) {
log.info indent + “$e.name $e.location”
respond()
}def respondToScheduleOn() {
log.info indent + “on schedule”
respond()
}def respondToScheduleOff() {
log.info indent + “off schedule”
respond()
}def respondToContact(EventWrapper e) {
log.info indent + “$e.value $e.name $e.device”
respond()
}def respondToIlluminance(EventWrapper e) {
log.info indent + “☼ $e.value $e.name $e.device”
respond()
}def respondToMotion(EventWrapper e) {
log.info indent + “$e.value $e.name $e.device”
respond()
}
… which is to log an informational message and respond to the new current state.
The execution time of respond …
// respond according to current state
def respond() {
Date now = new Date()
TimeZone timeZone = location.getTimeZone()// consider the sun if we should not ignore it and // now is within interval [sunrise, sunset) def sunriseAndSunset = getSunriseAndSunset() boolean sun = !ignoreSun && timeOfDayIsBetween( sunriseAndSunset.sunrise, new Date(sunriseAndSunset.sunset.getTime() - 1), now, timeZone) // consider retaining a background lighting level (as opposed to off) // if we are ignoring the on/off schedule, we don't have one or // now is within the [On, Off) interval boolean background = ignoreSchedule || !(On && Off) || timeOfDayIsBetween( nextOccurrence(On), new Date(nextOccurrence(Off).getTime() - 1), now, timeZone) setLevel DWSL, findValue( {valueIf 0 , {sun}}, {valueIf 0 , {findBrighter(64, DWLIM, DWRIM) && !ignoreIlluminance}}, {valueIf 100, {findMotion DWLMS, DWRMS}}, {valueIf 100, {findOpen GDCS}}, {valueIf 50 , {findMotion WWMS}}, {valueIf 25 , {findMotion FPMS}}, {valueIf 25 , {findOpen FDCS}}, {valueIf 5 , {background}}, ) // etc ...
}
… will vary depending on the state remembered from previous setLevel calls, the current state of the sun, the current timeOfDay in my background lighting On/Off schedule, and the current state of my sensors.
The problem is that respond execution time also seems to depend on whether it was invoked from respondToScheduleOn, respondToScheduleOff or not. When responding to exactly the same state, a respondToScheduleOn or respondToScheduleOff execution will fail (early, after setting the level of only one light) with a TimeoutException. When this execution is followed immediately by saving (unchanged) settings from the SmartThings mobile app, initialize is called to respond to exactly the same state and this works!