[DSL rule] Add time of day trigger to DSL file syntax (#5440)

* [DSL rule] Add time of day trigger to DSL file syntax

Closes #5435

Exampele of rule:
```
rule "Test time of day trigger"
when
  Time is 20:13
then
  logInfo("Rule","Test")
end
```

For backward compatibility, using "noon" and "midnight" is still supported.
"timer.TimeOfDayTrigger" is now used (instead of "timer.GenericCronTrigger").

Here is the log confirming the execution of the rule at the expected time:
```
20:13:00.531 [INFO ] [org.openhab.core.model.script.Rule  ] - Test
```

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo
2026-03-25 21:48:52 +01:00
committed by GitHub
parent 0edae941f1
commit e2aacb11a9
3 changed files with 58 additions and 51 deletions
@@ -375,23 +375,23 @@ public class DSLRuleProvider
return TriggerBuilder.create().withId(Integer.toString(triggerId++)) return TriggerBuilder.create().withId(Integer.toString(triggerId++))
.withTypeUID("core.GroupStateChangeTrigger").withConfiguration(cfg).build(); .withTypeUID("core.GroupStateChangeTrigger").withConfiguration(cfg).build();
} else if (t instanceof TimerTrigger tt) { } else if (t instanceof TimerTrigger tt) {
String triggerType;
Configuration cfg = new Configuration(); Configuration cfg = new Configuration();
String id;
if (tt.getCron() != null) { if (tt.getCron() != null) {
id = tt.getCron(); triggerType = "timer.GenericCronTrigger";
cfg.put("cronExpression", tt.getCron()); cfg.put("cronExpression", tt.getCron());
} else { } else {
id = tt.getTime(); triggerType = "timer.TimeOfDayTrigger";
String id = tt.getTime();
if ("noon".equals(id)) { if ("noon".equals(id)) {
cfg.put("cronExpression", "0 0 12 * * ?"); cfg.put("time", "12:00");
} else if ("midnight".equals(id)) { } else if ("midnight".equals(id)) {
cfg.put("cronExpression", "0 0 0 * * ?"); cfg.put("time", "00:00");
} else { } else {
logger.warn("Unrecognized time expression '{}' in rule trigger", tt.getTime()); cfg.put("time", id);
return null;
} }
} }
return TriggerBuilder.create().withId(Integer.toString(triggerId++)).withTypeUID("timer.GenericCronTrigger") return TriggerBuilder.create().withId(Integer.toString(triggerId++)).withTypeUID(triggerType)
.withConfiguration(cfg).build(); .withConfiguration(cfg).build();
} else if (t instanceof DateTimeTrigger tt) { } else if (t instanceof DateTimeTrigger tt) {
Configuration cfg = new Configuration(); Configuration cfg = new Configuration();
@@ -64,7 +64,7 @@ EventEmittedTrigger:
TimerTrigger: TimerTrigger:
'Time' 'cron' cron=STRING | 'Time' 'cron' cron=STRING |
'Time' 'is' time=('midnight' | 'noon') 'Time' 'is' time=('midnight' | 'noon' | TIME)
; ;
DateTimeTrigger: DateTimeTrigger:
@@ -162,6 +162,10 @@ ThingValidState:
'REMOVED' 'REMOVED'
; ;
terminal TIME:
(('0'..'1') ('0'..'9') ':' ('0'..'5') ('0'..'9')) | ('2' ('0'..'3') ':' ('0'..'5') ('0'..'9'))
;
SIGNED_INT: SIGNED_INT:
'-'? INT '-'? INT
; ;
@@ -39,6 +39,7 @@ import org.openhab.core.automation.internal.module.handler.ItemCommandTriggerHan
import org.openhab.core.automation.internal.module.handler.ItemStateTriggerHandler; import org.openhab.core.automation.internal.module.handler.ItemStateTriggerHandler;
import org.openhab.core.automation.internal.module.handler.SystemTriggerHandler; import org.openhab.core.automation.internal.module.handler.SystemTriggerHandler;
import org.openhab.core.automation.internal.module.handler.ThingStatusTriggerHandler; import org.openhab.core.automation.internal.module.handler.ThingStatusTriggerHandler;
import org.openhab.core.automation.internal.module.handler.TimeOfDayTriggerHandler;
import org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler; import org.openhab.core.automation.module.script.internal.handler.AbstractScriptModuleHandler;
import org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler; import org.openhab.core.automation.module.script.internal.handler.ScriptActionHandler;
import org.openhab.core.events.EventPublisher; import org.openhab.core.events.EventPublisher;
@@ -149,6 +150,7 @@ public class DSLRuleProviderTest extends JavaOSGiTest {
" System started or\n" + // " System started or\n" + //
" Time is noon or\n" + // " Time is noon or\n" + //
" Time is midnight or\n" + // " Time is midnight or\n" + //
" Time is 20:57 or\n" + //
" Time cron \"0 0/1 * * * ?\" or\n" + // " Time cron \"0 0/1 * * * ?\" or\n" + //
" Item X received command ON or\n" + // " Item X received command ON or\n" + //
" Item Y received update \"A\" or\n" + // " Item Y received update \"A\" or\n" + //
@@ -175,70 +177,71 @@ public class DSLRuleProviderTest extends JavaOSGiTest {
assertThat(rule.getUID(), is("dslruletest-1")); assertThat(rule.getUID(), is("dslruletest-1"));
assertThat(rule.getName(), is("RuleWithAllTriggers")); assertThat(rule.getName(), is("RuleWithAllTriggers"));
assertThat(rule.getTriggers().size(), is(13)); assertThat(rule.getTriggers().size(), is(14));
assertThat(rule.getTriggers().getFirst().getTypeUID(), is(SystemTriggerHandler.STARTLEVEL_MODULE_TYPE_ID)); assertThat(rule.getTriggers().getFirst().getTypeUID(), is(SystemTriggerHandler.STARTLEVEL_MODULE_TYPE_ID));
assertThat(rule.getTriggers().getFirst().getConfiguration().get(SystemTriggerHandler.CFG_STARTLEVEL), assertThat(rule.getTriggers().getFirst().getConfiguration().get(SystemTriggerHandler.CFG_STARTLEVEL),
is(new BigDecimal(40))); is(new BigDecimal(40)));
assertThat(rule.getTriggers().get(1).getTypeUID(), is(GenericCronTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(1).getTypeUID(), is(TimeOfDayTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(1).getConfiguration().get(GenericCronTriggerHandler.CFG_CRON_EXPRESSION), assertThat(rule.getTriggers().get(1).getConfiguration().get(TimeOfDayTriggerHandler.CFG_TIME), is("12:00"));
is("0 0 12 * * ?"));
assertThat(rule.getTriggers().get(2).getTypeUID(), is(GenericCronTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(2).getTypeUID(), is(TimeOfDayTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(2).getConfiguration().get(GenericCronTriggerHandler.CFG_CRON_EXPRESSION), assertThat(rule.getTriggers().get(2).getConfiguration().get(TimeOfDayTriggerHandler.CFG_TIME), is("00:00"));
is("0 0 0 * * ?"));
assertThat(rule.getTriggers().get(3).getTypeUID(), is(GenericCronTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(3).getTypeUID(), is(TimeOfDayTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(3).getConfiguration().get(GenericCronTriggerHandler.CFG_CRON_EXPRESSION), assertThat(rule.getTriggers().get(3).getConfiguration().get(TimeOfDayTriggerHandler.CFG_TIME), is("20:57"));
assertThat(rule.getTriggers().get(4).getTypeUID(), is(GenericCronTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(4).getConfiguration().get(GenericCronTriggerHandler.CFG_CRON_EXPRESSION),
is("0 0/1 * * * ?")); is("0 0/1 * * * ?"));
assertThat(rule.getTriggers().get(4).getTypeUID(), is(ItemCommandTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(5).getTypeUID(), is(ItemCommandTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(4).getConfiguration().get(ItemCommandTriggerHandler.CFG_ITEMNAME), is("X")); assertThat(rule.getTriggers().get(5).getConfiguration().get(ItemCommandTriggerHandler.CFG_ITEMNAME), is("X"));
assertThat(rule.getTriggers().get(4).getConfiguration().get(ItemCommandTriggerHandler.CFG_COMMAND), is("ON")); assertThat(rule.getTriggers().get(5).getConfiguration().get(ItemCommandTriggerHandler.CFG_COMMAND), is("ON"));
assertThat(rule.getTriggers().get(5).getTypeUID(), is(ItemStateTriggerHandler.UPDATE_MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(6).getTypeUID(), is(ItemStateTriggerHandler.UPDATE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(5).getConfiguration().get(ItemStateTriggerHandler.CFG_ITEMNAME), is("Y")); assertThat(rule.getTriggers().get(6).getConfiguration().get(ItemStateTriggerHandler.CFG_ITEMNAME), is("Y"));
assertThat(rule.getTriggers().get(5).getConfiguration().get(ItemStateTriggerHandler.CFG_STATE), is("A")); assertThat(rule.getTriggers().get(6).getConfiguration().get(ItemStateTriggerHandler.CFG_STATE), is("A"));
assertThat(rule.getTriggers().get(6).getTypeUID(), is(ItemStateTriggerHandler.CHANGE_MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(7).getTypeUID(), is(ItemStateTriggerHandler.CHANGE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(6).getConfiguration().get(ItemStateTriggerHandler.CFG_ITEMNAME), is("Z")); assertThat(rule.getTriggers().get(7).getConfiguration().get(ItemStateTriggerHandler.CFG_ITEMNAME), is("Z"));
assertThat(rule.getTriggers().get(6).getConfiguration().get(ItemStateTriggerHandler.CFG_PREVIOUS_STATE), assertThat(rule.getTriggers().get(7).getConfiguration().get(ItemStateTriggerHandler.CFG_PREVIOUS_STATE),
is("1")); is("1"));
assertThat(rule.getTriggers().get(6).getConfiguration().get(ItemStateTriggerHandler.CFG_STATE), is("2")); assertThat(rule.getTriggers().get(7).getConfiguration().get(ItemStateTriggerHandler.CFG_STATE), is("2"));
assertThat(rule.getTriggers().get(7).getTypeUID(), is(GroupCommandTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(8).getTypeUID(), is(GroupCommandTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(7).getConfiguration().get(GroupCommandTriggerHandler.CFG_GROUPNAME), assertThat(rule.getTriggers().get(8).getConfiguration().get(GroupCommandTriggerHandler.CFG_GROUPNAME),
is("G1")); is("G1"));
assertThat(rule.getTriggers().get(7).getConfiguration().get(GroupCommandTriggerHandler.CFG_COMMAND), is("UP")); assertThat(rule.getTriggers().get(8).getConfiguration().get(GroupCommandTriggerHandler.CFG_COMMAND), is("UP"));
assertThat(rule.getTriggers().get(8).getTypeUID(), is(GroupStateTriggerHandler.UPDATE_MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(9).getTypeUID(), is(GroupStateTriggerHandler.UPDATE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(8).getConfiguration().get(GroupStateTriggerHandler.CFG_GROUPNAME), is("G2")); assertThat(rule.getTriggers().get(9).getConfiguration().get(GroupStateTriggerHandler.CFG_GROUPNAME), is("G2"));
assertThat(rule.getTriggers().get(8).getConfiguration().get(GroupStateTriggerHandler.CFG_STATE), is("10|°C")); assertThat(rule.getTriggers().get(9).getConfiguration().get(GroupStateTriggerHandler.CFG_STATE), is("10|°C"));
assertThat(rule.getTriggers().get(9).getTypeUID(), is(GroupStateTriggerHandler.CHANGE_MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(10).getTypeUID(), is(GroupStateTriggerHandler.CHANGE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(9).getConfiguration().get(GroupStateTriggerHandler.CFG_GROUPNAME), is("G3")); assertThat(rule.getTriggers().get(10).getConfiguration().get(GroupStateTriggerHandler.CFG_GROUPNAME), is("G3"));
assertThat(rule.getTriggers().get(9).getConfiguration().get(GroupStateTriggerHandler.CFG_PREVIOUS_STATE), assertThat(rule.getTriggers().get(10).getConfiguration().get(GroupStateTriggerHandler.CFG_PREVIOUS_STATE),
is("PLAY")); is("PLAY"));
assertThat(rule.getTriggers().get(9).getConfiguration().get(GroupStateTriggerHandler.CFG_STATE), is("PAUSE")); assertThat(rule.getTriggers().get(10).getConfiguration().get(GroupStateTriggerHandler.CFG_STATE), is("PAUSE"));
assertThat(rule.getTriggers().get(10).getTypeUID(), is(ThingStatusTriggerHandler.UPDATE_MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(11).getTypeUID(), is(ThingStatusTriggerHandler.UPDATE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(10).getConfiguration().get(ThingStatusTriggerHandler.CFG_THING_UID),
is("T1"));
assertThat(rule.getTriggers().get(10).getConfiguration().get(ThingStatusTriggerHandler.CFG_STATUS),
is("OFFLINE"));
assertThat(rule.getTriggers().get(11).getTypeUID(), is(ThingStatusTriggerHandler.CHANGE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(11).getConfiguration().get(ThingStatusTriggerHandler.CFG_THING_UID), assertThat(rule.getTriggers().get(11).getConfiguration().get(ThingStatusTriggerHandler.CFG_THING_UID),
is("T2")); is("T1"));
assertThat(rule.getTriggers().get(11).getConfiguration().get(ThingStatusTriggerHandler.CFG_PREVIOUS_STATUS),
is("OFFLINE"));
assertThat(rule.getTriggers().get(11).getConfiguration().get(ThingStatusTriggerHandler.CFG_STATUS), assertThat(rule.getTriggers().get(11).getConfiguration().get(ThingStatusTriggerHandler.CFG_STATUS),
is("OFFLINE"));
assertThat(rule.getTriggers().get(12).getTypeUID(), is(ThingStatusTriggerHandler.CHANGE_MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(12).getConfiguration().get(ThingStatusTriggerHandler.CFG_THING_UID),
is("T2"));
assertThat(rule.getTriggers().get(12).getConfiguration().get(ThingStatusTriggerHandler.CFG_PREVIOUS_STATUS),
is("OFFLINE"));
assertThat(rule.getTriggers().get(12).getConfiguration().get(ThingStatusTriggerHandler.CFG_STATUS),
is("ONLINE")); is("ONLINE"));
assertThat(rule.getTriggers().get(12).getTypeUID(), is(ChannelEventTriggerHandler.MODULE_TYPE_ID)); assertThat(rule.getTriggers().get(13).getTypeUID(), is(ChannelEventTriggerHandler.MODULE_TYPE_ID));
assertThat(rule.getTriggers().get(12).getConfiguration().get(ChannelEventTriggerHandler.CFG_CHANNEL), assertThat(rule.getTriggers().get(13).getConfiguration().get(ChannelEventTriggerHandler.CFG_CHANNEL),
is("a:b:c:1")); is("a:b:c:1"));
assertThat(rule.getTriggers().get(12).getConfiguration().get(ChannelEventTriggerHandler.CFG_CHANNEL_EVENT), assertThat(rule.getTriggers().get(13).getConfiguration().get(ChannelEventTriggerHandler.CFG_CHANNEL_EVENT),
is("START")); is("START"));
} }