mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Add event information in rules for time, manual and RunRuleAction trigger (#2965)
* Add event information for time triggers Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
+10
-1
@@ -64,12 +64,14 @@ import org.openhab.core.automation.dto.RuleDTO;
|
||||
import org.openhab.core.automation.dto.RuleDTOMapper;
|
||||
import org.openhab.core.automation.dto.TriggerDTO;
|
||||
import org.openhab.core.automation.dto.TriggerDTOMapper;
|
||||
import org.openhab.core.automation.events.AutomationEventFactory;
|
||||
import org.openhab.core.automation.rest.internal.dto.EnrichedRuleDTO;
|
||||
import org.openhab.core.automation.rest.internal.dto.EnrichedRuleDTOMapper;
|
||||
import org.openhab.core.automation.util.ModuleBuilder;
|
||||
import org.openhab.core.automation.util.RuleBuilder;
|
||||
import org.openhab.core.config.core.ConfigUtil;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.io.rest.DTOMapper;
|
||||
import org.openhab.core.io.rest.JSONResponse;
|
||||
import org.openhab.core.io.rest.RESTConstants;
|
||||
@@ -331,7 +333,14 @@ public class RuleResource implements RESTResource {
|
||||
ruleUID);
|
||||
return Response.status(Status.NOT_FOUND).build();
|
||||
} else {
|
||||
ruleManager.runNow(ruleUID, false, context);
|
||||
if (context == null || context.isEmpty()) {
|
||||
// only add event to context if no context given, otherwise it might interfere with the intention of the
|
||||
// provided context
|
||||
Event event = AutomationEventFactory.createExecutionEvent(ruleUID, null, "manual");
|
||||
ruleManager.runNow(ruleUID, false, Map.of("event", event));
|
||||
} else {
|
||||
ruleManager.runNow(ruleUID, false, context);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.automation.events;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.AbstractEventFactory;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.openhab.core.events.EventFactory;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class is a factory that creates Timer and Execution Events.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = EventFactory.class, immediate = true)
|
||||
public class AutomationEventFactory extends AbstractEventFactory {
|
||||
private static final String MODULE_IDENTIFIER = "{moduleId}";
|
||||
private static final String TIMER_EVENT_TOPIC = "openhab/timer/" + MODULE_IDENTIFIER + "/triggered";
|
||||
private static final String EXECUTION_EVENT_TOPIC = "openhab/execution/" + MODULE_IDENTIFIER + "/triggered";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(AutomationEventFactory.class);
|
||||
|
||||
private static final Set<String> SUPPORTED_TYPES = Set.of(TimerEvent.TYPE, ExecutionEvent.TYPE);
|
||||
|
||||
public AutomationEventFactory() {
|
||||
super(SUPPORTED_TYPES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Event createEventByType(String eventType, String topic, String payload, @Nullable String source)
|
||||
throws Exception {
|
||||
logger.trace("creating ruleEvent of type: {}", eventType);
|
||||
if (TimerEvent.TYPE.equals(eventType)) {
|
||||
return createTimerEvent(topic, payload, Objects.requireNonNullElse(source, "<unknown>"));
|
||||
} else if (ExecutionEvent.TYPE.equals(eventType)) {
|
||||
if (source == null) {
|
||||
throw new IllegalArgumentException("'source' must not be null for execution events");
|
||||
}
|
||||
return createExecutionEvent(topic, payload, source);
|
||||
}
|
||||
throw new IllegalArgumentException("The event type '" + eventType + "' is not supported by this factory.");
|
||||
}
|
||||
|
||||
private Event createTimerEvent(String topic, String payload, String source) {
|
||||
return new TimerEvent(topic, payload, source);
|
||||
}
|
||||
|
||||
private Event createExecutionEvent(String topic, String payload, String source) {
|
||||
return new ExecutionEvent(topic, payload, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TimerEvent}
|
||||
*
|
||||
* @param moduleId the module type id of this event
|
||||
* @param label The label (or id) of this object
|
||||
* @param configuration the configuration of the trigger
|
||||
* @return the created event
|
||||
*/
|
||||
public static TimerEvent createTimerEvent(String moduleId, @Nullable String label,
|
||||
Map<String, Object> configuration) {
|
||||
String topic = TIMER_EVENT_TOPIC.replace(MODULE_IDENTIFIER, moduleId);
|
||||
String payload = serializePayload(configuration);
|
||||
return new TimerEvent(topic, payload, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link ExecutionEvent}
|
||||
*
|
||||
* @param moduleId the module type id of this event
|
||||
* @param payload A map with additional information like preceding events when rules are called from other rules
|
||||
* (optional)
|
||||
* @param source The source of this event (e.g. "script" or "manual")
|
||||
* @return the created event
|
||||
*/
|
||||
public static ExecutionEvent createExecutionEvent(String moduleId, @Nullable Map<String, Object> payload,
|
||||
String source) {
|
||||
String topic = EXECUTION_EVENT_TOPIC.replace(MODULE_IDENTIFIER, moduleId);
|
||||
String serializedPayload = serializePayload(Objects.requireNonNullElse(payload, Map.of()));
|
||||
return new ExecutionEvent(topic, serializedPayload, source);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.automation.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.events.AbstractEvent;
|
||||
|
||||
/**
|
||||
* An {@link ExecutionEvent} is only used to notify rules when a script or the REST API trigger the run.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ExecutionEvent extends AbstractEvent {
|
||||
|
||||
public static final String TYPE = ExecutionEvent.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Constructs a new rule execution event
|
||||
*
|
||||
* @param topic the topic of the event
|
||||
* @param payload the payload of the event
|
||||
* @param source the source of the event
|
||||
*/
|
||||
public ExecutionEvent(String topic, String payload, String source) {
|
||||
super(topic, payload, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Execution triggered by " + getSource();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.core.automation.events;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.events.AbstractEvent;
|
||||
|
||||
/**
|
||||
* An {@link TimerEvent} is only used to notify rules when timer triggers fire.
|
||||
*
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TimerEvent extends AbstractEvent {
|
||||
|
||||
public static final String TYPE = TimerEvent.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* Constructs a new timer event
|
||||
*
|
||||
* @param topic the topic of the event
|
||||
* @param payload the payload of the event (contains trigger configuration)
|
||||
* @param source the source of the event
|
||||
*/
|
||||
public TimerEvent(String topic, String payload, @Nullable String source) {
|
||||
super(topic, payload, source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Timer " + getSource() + " triggered.";
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -14,12 +14,16 @@ package org.openhab.core.automation.internal.module.handler;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.ModuleHandlerCallback;
|
||||
import org.openhab.core.automation.Trigger;
|
||||
import org.openhab.core.automation.events.AutomationEventFactory;
|
||||
import org.openhab.core.automation.events.TimerEvent;
|
||||
import org.openhab.core.automation.handler.BaseTriggerModuleHandler;
|
||||
import org.openhab.core.automation.handler.TimeBasedTriggerHandler;
|
||||
import org.openhab.core.automation.handler.TriggerHandlerCallback;
|
||||
@@ -114,7 +118,9 @@ public class DateTimeTriggerHandler extends BaseTriggerModuleHandler
|
||||
public void run() {
|
||||
ModuleHandlerCallback callback = this.callback;
|
||||
if (callback instanceof TriggerHandlerCallback triggerHandlerCallback) {
|
||||
triggerHandlerCallback.triggered(module);
|
||||
TimerEvent event = AutomationEventFactory.createTimerEvent(module.getTypeUID(),
|
||||
Objects.requireNonNullElse(module.getLabel(), module.getId()), Map.of(CONFIG_ITEM_NAME, itemName));
|
||||
triggerHandlerCallback.triggered(module, Map.of("event", event));
|
||||
} else {
|
||||
logger.debug("Tried to trigger, but callback isn't available!");
|
||||
}
|
||||
|
||||
+9
-1
@@ -12,10 +12,15 @@
|
||||
*/
|
||||
package org.openhab.core.automation.internal.module.handler;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.ModuleHandlerCallback;
|
||||
import org.openhab.core.automation.Trigger;
|
||||
import org.openhab.core.automation.events.AutomationEventFactory;
|
||||
import org.openhab.core.automation.events.TimerEvent;
|
||||
import org.openhab.core.automation.handler.BaseTriggerModuleHandler;
|
||||
import org.openhab.core.automation.handler.TimeBasedTriggerHandler;
|
||||
import org.openhab.core.automation.handler.TriggerHandlerCallback;
|
||||
@@ -80,7 +85,10 @@ public class GenericCronTriggerHandler extends BaseTriggerModuleHandler
|
||||
@Override
|
||||
public void run() {
|
||||
if (callback != null) {
|
||||
((TriggerHandlerCallback) callback).triggered(module);
|
||||
TimerEvent event = AutomationEventFactory.createTimerEvent(module.getTypeUID(),
|
||||
Objects.requireNonNullElse(module.getLabel(), module.getId()),
|
||||
Map.of(CFG_CRON_EXPRESSION, expression));
|
||||
((TriggerHandlerCallback) callback).triggered(module, Map.of("event", event));
|
||||
} else {
|
||||
logger.debug("Tried to trigger, but callback isn't available!");
|
||||
}
|
||||
|
||||
+12
-2
@@ -12,14 +12,17 @@
|
||||
*/
|
||||
package org.openhab.core.automation.internal.module.handler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.Action;
|
||||
import org.openhab.core.automation.events.AutomationEventFactory;
|
||||
import org.openhab.core.automation.handler.BaseActionModuleHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.events.Event;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -64,6 +67,7 @@ public class RunRuleActionHandler extends BaseActionModuleHandler {
|
||||
* the UIDs of the rules to be executed.
|
||||
*/
|
||||
private final List<String> ruleUIDs;
|
||||
private final String moduleId;
|
||||
|
||||
/**
|
||||
* boolean to express if the conditions should be considered, defaults to
|
||||
@@ -84,16 +88,22 @@ public class RunRuleActionHandler extends BaseActionModuleHandler {
|
||||
throw new IllegalArgumentException("'ruleUIDs' property must not be null.");
|
||||
}
|
||||
if (config.get(CONSIDER_CONDITIONS_KEY) != null && config.get(CONSIDER_CONDITIONS_KEY) instanceof Boolean) {
|
||||
this.considerConditions = ((Boolean) config.get(CONSIDER_CONDITIONS_KEY)).booleanValue();
|
||||
this.considerConditions = (Boolean) config.get(CONSIDER_CONDITIONS_KEY);
|
||||
}
|
||||
this.moduleId = module.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map<String, Object> execute(Map<String, Object> context) {
|
||||
// execute each rule after the other; at the moment synchronously
|
||||
Object previousEvent = context.get("event");
|
||||
Event event = AutomationEventFactory.createExecutionEvent(moduleId,
|
||||
previousEvent instanceof Event ? Map.of("previous", previousEvent) : null, "runRuleAction");
|
||||
Map<String, Object> newContext = new HashMap<>(context);
|
||||
newContext.put("event", event);
|
||||
for (String uid : ruleUIDs) {
|
||||
if (callback != null) {
|
||||
callback.runNow(uid, considerConditions, context);
|
||||
callback.runNow(uid, considerConditions, newContext);
|
||||
} else {
|
||||
logger.warn("Action is not applied to {} because rule engine is not available.", uid);
|
||||
}
|
||||
|
||||
+9
-2
@@ -13,11 +13,15 @@
|
||||
package org.openhab.core.automation.internal.module.handler;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.automation.ModuleHandlerCallback;
|
||||
import org.openhab.core.automation.Trigger;
|
||||
import org.openhab.core.automation.events.AutomationEventFactory;
|
||||
import org.openhab.core.automation.events.TimerEvent;
|
||||
import org.openhab.core.automation.handler.BaseTriggerModuleHandler;
|
||||
import org.openhab.core.automation.handler.TimeBasedTriggerHandler;
|
||||
import org.openhab.core.automation.handler.TriggerHandlerCallback;
|
||||
@@ -46,13 +50,14 @@ public class TimeOfDayTriggerHandler extends BaseTriggerModuleHandler
|
||||
public static final String CFG_TIME = "time";
|
||||
|
||||
private final CronScheduler scheduler;
|
||||
private final String time;
|
||||
private final String expression;
|
||||
private @Nullable ScheduledCompletableFuture<?> schedule;
|
||||
|
||||
public TimeOfDayTriggerHandler(Trigger module, CronScheduler scheduler) {
|
||||
super(module);
|
||||
this.scheduler = scheduler;
|
||||
String time = module.getConfiguration().get(CFG_TIME).toString();
|
||||
this.time = module.getConfiguration().get(CFG_TIME).toString();
|
||||
this.expression = buildExpressionFromConfigurationTime(time);
|
||||
}
|
||||
|
||||
@@ -83,7 +88,9 @@ public class TimeOfDayTriggerHandler extends BaseTriggerModuleHandler
|
||||
@Override
|
||||
public void run() {
|
||||
if (callback != null) {
|
||||
((TriggerHandlerCallback) callback).triggered(module);
|
||||
TimerEvent event = AutomationEventFactory.createTimerEvent(module.getTypeUID(),
|
||||
Objects.requireNonNullElse(module.getLabel(), module.getId()), Map.of(CFG_TIME, time));
|
||||
((TriggerHandlerCallback) callback).triggered(module, Map.of("event", event));
|
||||
} else {
|
||||
logger.debug("Tried to trigger, but callback isn't available!");
|
||||
}
|
||||
|
||||
+1
-2
@@ -22,8 +22,7 @@ import com.google.gson.Gson;
|
||||
/**
|
||||
* The {@link AbstractEventFactory} defines an abstract implementation of the {@link EventFactory} interface. Subclasses
|
||||
* must implement the abstract method {@link #createEventByType(String, String, String, String)} in order to create
|
||||
* event
|
||||
* instances based on the event type.
|
||||
* event instances based on the event type.
|
||||
*
|
||||
* @author Stefan Bußweiler - Initial contribution
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user