Sorry - another question.
I have many of the day state transitions working fine.
Twilight came at sunset (4:18PM), my outdoor lights came on. Then evening (8PM) happened a few hours later and many lights turned on, and night (11PM) happened and the remaining outdoor lights turned off.
- this was all exactly as intended.
Then:
Just after midnight, it appears my state was changed to twilight (and as such my outdoor lights all came on). This was not intended. After
From event.log, searching for midnight (grep “2023-12-03 00:00:” events.log):
2023-12-03 00:00:00.136 [INFO ] [openhab.event.RuleStatusInfoEvent ] - MoveToToday updated: RUNNING
2023-12-03 00:00:00.221 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultNight' changed from 2023-12-02T23:00:00.000-0800 to 2023-12-03T23:00:00.000-0800
2023-12-03 00:00:00.223 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.228 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayNight' changed from 2023-12-02T23:00:00.000-0800 to 2023-12-03T23:00:00.000-0800
2023-12-03 00:00:00.230 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.233 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayNight' changed from 2023-12-02T23:00:00.000-0800 to 2023-12-03T23:00:00.000-0800
2023-12-03 00:00:00.235 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayEvening' changed from 2023-12-02T20:00:00.000-0800 to 2023-12-03T20:00:00.000-0800
2023-12-03 00:00:00.239 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.240 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendMorning' changed from 2023-12-02T09:00:00.000-0800 to 2023-12-03T09:00:00.000-0800
2023-12-03 00:00:00.242 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendEvening' changed from 2023-12-02T20:00:00.000-0800 to 2023-12-03T20:00:00.000-0800
2023-12-03 00:00:00.244 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.245 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.248 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.249 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.250 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.252 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.253 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayMorning' changed from 2023-12-02T06:55:00.000-0800 to 2023-12-03T06:55:00.000-0800
2023-12-03 00:00:00.255 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayEvening' changed from 2023-12-02T20:00:00.000-0800 to 2023-12-03T20:00:00.000-0800
2023-12-03 00:00:00.256 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultEvening' changed from 2023-12-02T20:00:00.000-0800 to 2023-12-03T20:00:00.000-0800
2023-12-03 00:00:00.258 [INFO ] [openhab.event.RuleStatusInfoEvent ] - MoveToToday updated: IDLE
2023-12-03 00:00:00.260 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendNight' changed from 2023-12-02T23:00:00.000-0800 to 2023-12-03T23:00:00.000-0800
2023-12-03 00:00:00.262 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultMorning' changed from 2023-12-02T07:00:00.000-0800 to 2023-12-03T07:00:00.000-0800
2023-12-03 00:00:00.264 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayMorning' changed from 2023-12-02T09:00:00.000-0800 to 2023-12-03T09:00:00.000-0800
2023-12-03 00:00:00.265 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.267 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.268 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.269 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.271 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.272 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.273 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.275 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.276 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.278 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.279 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.280 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.281 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:00.282 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:00.283 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:28.201 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command TWILIGHT
2023-12-03 00:00:28.203 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TimeOfDay' changed from NIGHT to TWILIGHT
2023-12-03 00:00:28.206 [INFO ] [openhab.event.RuleStatusInfoEvent ] - lights-15 updated: RUNNING
2023-12-03 00:00:28.218 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'FF_FrontPorch_Light' received command ON
2023-12-03 00:00:28.227 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'CH_Outdoor_Yard_Light' received command ON
2023-12-03 00:00:28.230 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'FF_FrontPorch_Light' predicted to become ON
2023-12-03 00:00:28.246 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'FF_Front_Porch_Accessory_Outlet' received command ON
2023-12-03 00:00:28.248 [INFO ] [openhab.event.RuleStatusInfoEvent ] - lights-15 updated: IDLE
2023-12-03 00:00:28.249 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'CH_Outdoor_Yard_Light' predicted to become ON
2023-12-03 00:00:28.256 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'FF_FrontPorch_Light' changed from OFF to ON
2023-12-03 00:00:28.257 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'Outdoor_Lights' changed from OFF to ON through FF_FrontPorch_Light
2023-12-03 00:00:28.258 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'FF_Front_Porch_Accessory_Outlet' predicted to become ON
2023-12-03 00:00:28.264 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'CH_Outdoor_Yard_Light' changed from OFF to ON
2023-12-03 00:00:28.265 [INFO ] [hab.event.GroupItemStateChangedEvent] - Item 'CH_Outdoor_Lights' changed from OFF to ON through CH_Outdoor_Yard_Light
2023-12-03 00:00:28.266 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'FF_Front_Porch_Accessory_Outlet' changed from OFF to ON
2023-12-03 00:00:30.485 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultDay' changed from 2023-12-02T07:58:00.000-0800 to 2023-12-03T07:55:00.000-0800
2023-12-03 00:00:30.490 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayDay' changed from 2023-12-02T07:58:00.000-0800 to 2023-12-03T07:55:00.000-0800
2023-12-03 00:00:30.498 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.499 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendDay' changed from 2023-12-02T07:58:00.000-0800 to 2023-12-03T07:55:00.000-0800
2023-12-03 00:00:30.502 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayDay' changed from 2023-12-02T07:58:00.000-0800 to 2023-12-03T07:55:00.000-0800
2023-12-03 00:00:30.506 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultDay' changed from 2023-12-03T07:55:00.000-0800 to 2023-12-03T07:59:00.000-0800
2023-12-03 00:00:30.507 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayDay' changed from 2023-12-03T07:55:00.000-0800 to 2023-12-03T07:59:00.000-0800
2023-12-03 00:00:30.509 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendDay' changed from 2023-12-03T07:55:00.000-0800 to 2023-12-03T07:59:00.000-0800
2023-12-03 00:00:30.511 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayDay' changed from 2023-12-03T07:55:00.000-0800 to 2023-12-03T07:59:00.000-0800
2023-12-03 00:00:30.514 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'DefaultTwilight' changed from 2023-12-02T16:19:00.000-0800 to 2023-12-03T16:18:00.000-0800
2023-12-03 00:00:30.515 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekdayTwilight' changed from 2023-12-02T16:19:00.000-0800 to 2023-12-03T16:18:00.000-0800
2023-12-03 00:00:30.518 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'WeekendTwilight' changed from 2023-12-02T16:19:00.000-0800 to 2023-12-03T16:18:00.000-0800
2023-12-03 00:00:30.519 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'HolidayTwilight' changed from 2023-12-02T16:19:00.000-0800 to 2023-12-03T16:18:00.000-0800
2023-12-03 00:00:30.537 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.539 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.543 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.545 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.549 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.550 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.553 [INFO ] [openhab.event.ChannelTriggeredEvent ] - astro:sun:local:morningNight#event triggered START
2023-12-03 00:00:30.556 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.558 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.562 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.564 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.567 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.568 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.569 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.571 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.572 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.574 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.575 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.577 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.578 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.580 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.581 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
2023-12-03 00:00:30.582 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: RUNNING
2023-12-03 00:00:30.584 [INFO ] [openhab.event.RuleStatusInfoEvent ] - TODStateMachine updated: IDLE
rule in question (light-15):
rule "Porch light on at dusk"
when
Item TimeOfDay changed to "TWILIGHT"
then
if (FrontPorchSuppressLights.state == OFF) {
FF_FrontPorch_Light.sendCommand(ON)
CH_Outdoor_Yard_Light.sendCommand(ON) // CH parking lights
logInfo("lights.rules", "TWILIGHT started, entry lights turned on")
}
else {
logInfo("lights.rules", "Was going to turn porch lights on due to dusk, but already too late or was suppressed")
}
FF_Front_Porch_Accessory_Outlet.sendCommand(ON)
end
relevant TOD items:
DateTime WeekendMorning "Weekend Morning" <time> (TimesOfDay) ["DTUpdate"] { tod_sm="MORNING" [type="weekend"] }
DateTime WeekendDay "Weekend Day" <sunrise> (TimesOfDay) { channel="astro:sun:local:rise#end", tod_sm="DAY" [type="weekend"] }
DateTime WeekendTwilight "Weekend Twilight" <sunset> (TimesOfDay) { channel="astro:sun:local:set#start", tod_sm="TWILIGHT" [type="weekend"] }
DateTime WeekendEvening "Weekend Evening" <time> (TimesOfDay) ["DTUpdate"] { tod_sm="EVENING"[type="weekend"] }
DateTime WeekendNight "Weekend Night" <moon> (TimesOfDay) ["DTUpdate"] { tod_sm="NIGHT"[type="weekend"] }
My (unmodified/noncustomized from template implementation) TOD State Machine rule code:
configuration:
namespace: tod_sm
timesOfDayGrp: TimesOfDay
timeOfDay: TimeOfDay
triggers:
- id: "1"
configuration:
groupName: TimesOfDay
type: core.GroupStateChangeTrigger
- id: "2"
configuration:
startlevel: 20
type: core.SystemStartlevelTrigger
conditions: []
actions:
- inputs: {}
id: "3"
label: Determine current time of day
configuration:
type: application/javascript
script: >
// Imports
if(typeof(require) === "function") Object.assign(this, require('@runtime'));
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.rules_tools.Time_SM");
this.Ephemeris = (this.Ephemeris === undefined) ? Java.type("org.openhab.core.model.script.actions.Ephemeris") : this.Ephemeris;
this.ZonedDateTime = (this.ZonedDateTime === undefined) ? Java.type("java.time.ZonedDateTime") : this.ZonedDateTime;
// Get Metadata query stuff
this.FrameworkUtil = (this.FrameworkUtil === undefined) ? Java.type("org.osgi.framework.FrameworkUtil") : this.FrameworkUtil;
this.ScriptHandler = Java.type("org.openhab.core.automation.module.script.rulesupport.shared.ScriptedHandler");
this._bundle = (this._bundle === undefined) ? FrameworkUtil.getBundle(ScriptHandler.class) : this._bundle;
this.bundle_context = (this.bundle_context === undefined) ? this._bundle.getBundleContext() : this.bundle_context;
this.MetadataRegistry_Ref = (this.MetadataRegistry_Ref === undefined) ? bundle_context.getServiceReference("org.openhab.core.items.MetadataRegistry") : this.MetadataRegistry_Ref;
this.MetadataRegistry = (this.MetadataRegistry === undefined) ? bundle_context.getService(MetadataRegistry_Ref) : this.MetadataRegistry;
this.Metadata = (this.Metadata === undefined) ? Java.type("org.openhab.core.items.Metadata") : this.Metadata;
this.MetadataKey = (this.MetadataKey === undefined) ? Java.type("org.openhab.core.items.MetadataKey") : this.MetadataKey;
// Constants
var ETOD_ITEM = "TimeOfDay";
var ETOD_GROUP = "TimesOfDay";
var DAY_TYPES = ["default", "weekday", "weekend", "dayset", "holiday", "custom"];
var EXPECTED = "Invalid metadata for Item! "
+ "Expected metadata in the form of tod_sm=\"STATE\"[type=\"daytype\", set=\"dayset\", file=\"uri\"] "
+ "where set is required if type is dayset and file is required if type is custom.";
var ETOD_NAMESPACE = "tod_sm";
// TODO Load timer manager from a library
// Load TimerMgr
//this.OPENHAB_CONF = (this.OPENHAB_CONF === undefined) ? java.lang.System.getenv("OPENHAB_CONF") : this.OPENHAB_CONF;
//load(OPENHAB_CONF+'/automation/lib/javascript/community/timerMgr.js');
//load(OPENHAB_CONF+'/automation/lib/javascript/community/timeUtils.js');
var TimerMgr = function() {
var OPENHAB_CONF = java.lang.System.getenv("OPENHAB_CONF");
this.log = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Rules.rules_tools.rules_tools.TimerMgr");
this.log.debug("Building timerMgr instance.");
this.timers = {};
// this.log.debug("Loading timeUtils");
// load(OPENHAB_CONF+'/automation/lib/javascript/community/timeUtils.js');
this.ScriptExecution = Java.type("org.openhab.core.model.script.actions.ScriptExecution");
this.log.debug("Timer Mgr is ready to operate");
}
TimerMgr.prototype._notFlapping = function(key) {
this.log.debug("Timer expired for " + key);
if (key in this.timers && "notFlapping" in this.timers[key]) {
this.log.debug("Calling expired function " + this.timers[key]["notFlapping"]);
this.timers[key]["notFlapping"]();
}
if (key in this.timers){
this.log.debug("Deleting the expired timer");
delete this.timers[key];
}
},
TimerMgr.prototype._noop = function() { },
TimerMgr.prototype.check = function(key, when, func, reschedule, flappingFunc) {
this.log.debug("Timer manager check called");
if (reschedule === undefined) reschedule = false;
// var timeout = this.toDateTime(when); We will assume it's already a ZonedDateTime
var timeout = when;
this.log.debug("Timer to be set for " + timeout.toString());
// Timer exists
if (key in this.timers){
if (reschedule){
this.log.debug("Rescheduling timer " + key + " for " + timeout.toString());
this.timers[key]["timer"].reschedule(timeout);
}
else {
this.log.debug("Cancelling timer " + key);
this.cancel(key);
}
if (flappingFunc !== undefined){
this.log.debug("Running flapping function for " + key);
flappingFunc();
}
}
// Timer doesn't already exist, create one
else {
this.log.debug("Creating timer for " + key);
var timer = this.ScriptExecution.createTimerWithArgument(timeout, this, function(context) { context._notFlapping(key); });
this.timers[key] = { "timer": timer,
"flapping": flappingFunc,
"notFlapping": (func !== undefined) ? func : this._noop }
this.log.debug("Timer created for " + key);
}
},
TimerMgr.prototype.hasTimer = function(key) {
return key in this.timers;
},
TimerMgr.prototype.cancel = function(key) {
if (key in this.timers) {
this.timers[key]["timer"].cancel();
delete this.timers[key];
}
},
TimerMgr.prototype.cancelAll = function() {
for (var key in this.timers) {
if (!this.timers[key]["timer"].hasTerminated() && !this.timers[key]["timer"].isRunning()) {
this.log.debug("Timer has not terminated, cancelling timer " + key);
this.cancel(key);
}
delete this.timers[key];
this.log.debug("Timer entry has been deleted for " + key);
}
}
// END TODO
/**
* Return the value or a key value from the Item's metadata
* @param {string} item name of the item
* @param {string} namespace metadata namespace to pull
* @param {string} key index into the configuration dict for the value
* @return {string} value assocaited with key or null if it doesn't exist.
*/
var getValue = function(item, namespace, key) {
var md = MetadataRegistry.get(new MetadataKey(namespace, item));
if(md === null || md === undefined) {
return null;
}
else if(key === undefined) {
return md.value;
}
else {
return md.configuration[key];
}
}
/**
* Verify Item and Item metadata
* @param {string} item name of the Item
* return {string} error string or null if the metadata checks out
*/
var verifyMetadata = function(item) {
// if(items[item].class == UnDefType.class) {
// return item +"'s state is " + items[items];
// }
if(getValue(item, ETOD_NAMESPACE) === null) {
return item + " lacks metadata or metadata value.";
}
var type = getValue(item, ETOD_NAMESPACE, "type");
if(type === null) {
return item + " lacks a type key."
}
if(DAY_TYPES.indexOf(type) < 0) {
return item + " has " + type + " which is not a valid day type, expected one of " + DAY_TYPES + ".";
}
if(type == "dayset" && getValue(item, ETOD_NAMESPACE, "set") === null) {
return item + " has type " + type + " which requires a 'set' value to be defined.";
}
if(type == "custom" && getValue(item, ETOD_NAMESPACE, "file") === null ) {
return item + " has type " + type + " which requires a 'file' value to be defined.";
}
return null;
}
/**
* Get a list of all the Items that have ephem metadata with type
* @param {java.util.List} etodItems collection of all the ETOD Items
* @param {string} type the type of day
* @return {java.util.List} those Items with a type metadata matching type
*/
var getType = function(etodItems, type){
return etodItems.stream()
.filter(function(item){
return getValue(item.name, ETOD_NAMESPACE, "type") == type;
})
.toArray();
}
/**
* Pull the set of Items for today based on Ephemeris
* @param {java.util.List} etodItems collection of all ETOD Items
* @return {java.util.List} only those Items defined for today's daytype
*/
var getTodayItems = function(etodItems) {
/**
Get the Items for today. Hierarchy is:
- custom
- holiday
- dayset
- weekend
- weekday
- default
*/
var startTimes = {"default": getType(etodItems, "default"),
"weekday": (!Ephemeris.isWeekend()) ? getType(etodItems, "weekday") : [],
"weekend": (Ephemeris.isWeekend()) ? getType(etodItems, "weekend") : [],
"dayset": etodItems.stream()
.filter(function(item) {
return getValue(item.name, ETOD_NAMESPACE, "type") == "dayset"
&& Ephemeris.isInDayset(getValue(item.name, ETOD_NAMESPACE, "set"));
})
.toArray(),
"holiday": (Ephemeris.isBankHoliday()) ? getType(etodItems, "holiday") : [],
"custom": etodItems.stream()
.filter(function(item) {
return getValue(item.name, ETOD_NAMESPACE, "type") == "custom"
&& Ephemeris.isBankHoliday(0, getValue(item.name, ETOD_NAMESPACE, "file"));
})
.toArray()
};
var dayType = null;
if(startTimes["custom"].length > 0) {
dayType = "custom";
}
else if(startTimes["holiday"].length > 0) {
dayType = "holiday";
}
else if(startTimes["dayset"].length > 0) {
dayType = "dayset";
}
else if(startTimes["weekend"].length > 0) {
dayType = "weekend";
}
else if(startTimes["weekday"].length > 0) {
dayType = "weekday";
}
else if(startTimes["default"].length > 0) {
dayType = "default";
}
logger.info("Today is a " + dayType + " day.");
return (dayType === null) ? null : startTimes[dayType];
}
/**
* Update Items to today
* @param {java.util.List} times list of all the ETOD Items for today
*/
/** Use To Today rule template
var moveTimes = function(times) {
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var now = ZonedDateTime.now();
for each(var time in times) {
if(time.state.zonedDateTime.isBefore(now.withHour(0).withMinute(0).withSecond(0))) {
events.postUpdate(time.name, toToday(items[time.name]).toString());
logger.info("Moved " + time.name + " to today.");
}
}
} */
/**
* Create timers for all Items with a time in the future
* @param {java.util.List} times list of all the ETOD Items for todayu
*/
var createTimersGenerator = function(times, timers) {
return function() {
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
var now = ZonedDateTime.now();
var mostRecentTime = now.minusDays(1);
var mostRecentState = items[ETOD_ITEM];
logger.debug("Cancelling any existing timers");
timers.cancelAll();
logger.debug("Existing timers have been cancelled");
for each (var time in times) {
var name = time.name;
if(time.state.class === UnDefType.class) {
logger.warn("Time State Machine Item " + name + " is NULL or UNDEF, ignoring");
}
else {
var dt = time.state.zonedDateTime
var state = getValue(name, ETOD_NAMESPACE);
if(dt.isBefore(now) && dt.isAfter(mostRecentTime)) {
logger.debug("NOW: " + state + " start time " + dt + " is in the past "
+ " after " + mostRecentTime);
mostRecentTime = dt;
mostRecentState = state;
}
else if(dt.isAfter(now)) {
logger.debug("FUTURE: " + state + " scheduleing timer for " + dt);
timers.check(state, dt, etodTransitionGenerator(state));
}
else {
logger.debug("PAST : " + state + " start time of " + dt + " is before "
+ now + " and before " + mostRecentState + " " + mostRecentTime);
}
}
}
logger.debug("Created " + (Object.keys(timers.timers).length - 1) + " time of day timers");
logger.info("The current time of day is " + mostRecentState);
if(items[ETOD_ITEM] != mostRecentState) {
events.sendCommand(ETOD_ITEM, mostRecentState);
}
}
}
/**
* Transition to a new Time of Day
* @TODO look into moving this to another rule we can call so it shows up in schedule
* @param {string} state the new time of day state
*/
var etodTransitionGenerator = function(state) {
return function() {
logger.info("Transitioning Time of Day from " + items[ETOD_ITEM] + " to " + state);
events.sendCommand(ETOD_ITEM, state);
}
}
//--------------------------------------------
// Main body of rule
if(this.timers === undefined){
logger.debug("Creating timer manager");
}
this.timers = (this.timers === undefined) ? new TimerMgr() : this.timers;
// Skip if we have a flapping timer set
if(!this.timers.hasTimer("ephem_tod_rule")) {
// Check that all the required Items and Groups exist
if(items[ETOD_ITEM] === undefined) {
throw "The " + ETOD_ITEM + " Item is not defined!";
}
if(items[ETOD_GROUP] === undefined) {
throw "The " + ETOD_GROUP + " Group is not defined!";
}
var etodItems = ir.getItem(ETOD_GROUP).getMembers();
if(etodItems.size() == 0) {
throw ETOD_GROUP + " has no members!";
}
// Check the metadata for all the relevant Items
for each (var item in etodItems) {
var verify = verifyMetadata(item.name);
if(verify !== null) {
throw verify + "\n" + EXPECTED;
}
}
// Get the time Items for today
var times = getTodayItems(etodItems);
if(times === null){
throw "No set of date times were found for today! Do you have a default set of date times?";
}
// Update the Items to today
//moveTimes(times);
// The times will often be updated all at once, schedule a timer to wait for all the Items to update before creating the Timers.
var ZonedDateTime = Java.type("java.time.ZonedDateTime");
this.timers.check("ephem_tod_rule",
ZonedDateTime.now().plusSeconds(60),
createTimersGenerator(times, this.timers),
true,
function() { logger.info("Flapping timer, waiting before creating timers for time of day"); });
}
type: script.ScriptAction
Searching my log for all the TimeofDay updates:
grep “Item ‘TimeOfDay’ received command” events.log
2023-12-02 16:50:31.361 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command TWILIGHT
2023-12-02 20:00:00.043 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command EVENING
2023-12-02 23:00:00.018 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command NIGHT
2023-12-03 00:00:28.201 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command TWILIGHT
2023-12-03 07:59:00.007 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command DAY
2023-12-03 09:00:00.009 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'TimeOfDay' received command MORNING
It looks like it triggers Twilight, Evening, and Night as expected.
It then triggered twilight for some reason at midnight…
and then went on to trigger day (sunrise) and morning (late start as weekend) as expected.
A quick few searches of the forum do not reveal similar problems with others.
Is there something I need to do to look into this further?
Thanks again!