Skip to content

Commit

Permalink
Add lastStateUpdate, lastStateChange to ItemStateUpdatedEvent/`…
Browse files Browse the repository at this point in the history
…ItemStateChangedEvent`

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
  • Loading branch information
jimtng committed Feb 17, 2025
1 parent a94908c commit 1346a0b
Show file tree
Hide file tree
Showing 21 changed files with 334 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,13 @@ public void receive(Event event) {
if (item != null && item.getGroupNames().contains(groupName)) {
State state = isEvent.getItemState();
if ((this.state == null || state.toFullString().equals(this.state))) {
Map<String, Object> values = new HashMap<>();
Map<String, @Nullable Object> values = new HashMap<>();
if (group != null) {
values.put("triggeringGroup", group);
}
values.put("triggeringItem", item);
values.put("state", state);
values.put("lastStateUpdate", isEvent.getLastStateUpdate());
values.put("event", event);
cb.triggered(this.module, values);
}
Expand All @@ -142,13 +143,15 @@ public void receive(Event event) {
State oldState = iscEvent.getOldItemState();

if (stateMatches(this.state, state) && stateMatches(this.previousState, oldState)) {
Map<String, Object> values = new HashMap<>();
Map<String, @Nullable Object> values = new HashMap<>();
if (group != null) {
values.put("triggeringGroup", group);
}
values.put("triggeringItem", item);
values.put("oldState", oldState);
values.put("newState", state);
values.put("lastStateUpdate", iscEvent.getLastStateUpdate());
values.put("lastStateChange", iscEvent.getLastStateChange());
values.put("event", event);
cb.triggered(this.module, values);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,15 @@ public void receive(Event event) {
if (callback != null) {
logger.trace("Received Event: Source: {} Topic: {} Type: {} Payload: {}", event.getSource(),
event.getTopic(), event.getType(), event.getPayload());
Map<String, Object> values = new HashMap<>();
Map<String, @Nullable Object> values = new HashMap<>();
if (event instanceof ItemStateUpdatedEvent updatedEvent
&& UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) {
String state = this.state;
State itemState = updatedEvent.getItemState();
if ((state == null || state.equals(itemState.toFullString()))) {
values.put("state", itemState);
}
values.put("lastStateUpdate", updatedEvent.getLastStateUpdate());
} else if (event instanceof ItemStateChangedEvent changedEvent
&& CHANGE_MODULE_TYPE_ID.equals(module.getTypeUID())) {
State itemState = changedEvent.getItemState();
Expand All @@ -140,6 +141,8 @@ public void receive(Event event) {
values.put("oldState", oldItemState);
values.put("newState", itemState);
}
values.put("lastStateUpdate", changedEvent.getLastStateUpdate());
values.put("lastStateChange", changedEvent.getLastStateChange());
}
if (!values.isEmpty()) {
values.put("event", event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@
"state"
]
},
{
"name": "lastStateUpdate",
"type": "java.time.ZonedDateTime",
"description": "the time of the previous state update",
"label": "Last State Update"
},
{
"name": "event",
"type": "org.openhab.core.events.Event",
Expand Down Expand Up @@ -220,17 +226,29 @@
{
"name": "newState",
"type": "state",
"description": "the new item state",
"label": "New State",
"description": "the new item state",
"tags": [
"state"
]
},
{
"name": "oldState",
"type": "state",
"description": "the old item state",
"label": "Old State"
"label": "Old State",
"description": "the old item state"
},
{
"name": "lastStateUpdate",
"type": "java.time.ZonedDateTime",
"label": "Last State Update",
"description": "the time of the previous state update"
},
{
"name": "lastStateChange",
"type": "java.time.ZonedDateTime",
"label": "Last State Change",
"description": "the time of the previous state change"
},
{
"name": "event",
Expand Down Expand Up @@ -402,6 +420,12 @@
"state"
]
},
{
"name": "lastStateUpdate",
"type": "java.time.ZonedDateTime",
"description": "the time of the previous state update",
"label": "Last State Update"
},
{
"name": "event",
"type": "org.openhab.core.events.Event",
Expand Down Expand Up @@ -518,6 +542,18 @@
"description": "the old item state",
"label": "Old State"
},
{
"name": "lastStateUpdate",
"type": "java.time.ZonedDateTime",
"label": "Last State Update",
"description": "the time of the previous state update"
},
{
"name": "lastStateChange",
"type": "java.time.ZonedDateTime",
"label": "Last State Change",
"description": "the time of the previous state change"
},
{
"name": "event",
"type": "org.openhab.core.events.Event",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ public void eventFromBusFilterIncludeTopic() throws IOException {
eventWebSocket.processEvent(event);
verify(remoteEndpoint).sendString(gson.toJson(new EventDTO(event)));

event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO);
event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO, null,
null);
eventWebSocket.processEvent(event);
verify(remoteEndpoint).sendString(gson.toJson(new EventDTO(event)));

Expand All @@ -285,7 +286,8 @@ public void eventFromBusFilterExcludeTopic() throws IOException {
verify(remoteEndpoint, times(0)).sendString(any());

// not excluded topics are sent
event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO);
event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO, null,
null);
eventWebSocket.processEvent(event);
verify(remoteEndpoint).sendString(gson.toJson(new EventDTO(event)));

Expand All @@ -309,7 +311,8 @@ public void eventFromBusFilterIncludeAndExcludeTopic() throws IOException {
clearInvocations(remoteEndpoint);

// included topics are sent
Event event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO);
Event event = ItemEventFactory.createStateChangedEvent(TEST_ITEM_NAME, DecimalType.ZERO, DecimalType.ZERO, null,
null);
eventWebSocket.processEvent(event);
verify(remoteEndpoint).sendString(gson.toJson(new EventDTO(event)));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.core.model.rule.jvmmodel

import com.google.inject.Inject
import java.time.ZonedDateTime
import java.util.Set
import org.openhab.core.items.Item
import org.openhab.core.items.ItemRegistry
Expand Down Expand Up @@ -145,10 +146,22 @@ class RulesJvmModelInferrer extends ScriptJvmModelInferrer {
val commandTypeRef = ruleModel.newTypeRef(Command)
parameters += rule.toParameter(VAR_RECEIVED_COMMAND, commandTypeRef)
}
if ((containsStateChangeTrigger(rule) || containsStateUpdateTrigger(rule)) && !containsParam(parameters, VAR_NEW_STATE)) {
val stateTypeRef = ruleModel.newTypeRef(State)
parameters += rule.toParameter(VAR_NEW_STATE, stateTypeRef)
}
if (containsStateChangeTrigger(rule) && !containsParam(parameters, VAR_PREVIOUS_STATE)) {
val stateTypeRef = ruleModel.newTypeRef(State)
parameters += rule.toParameter(VAR_PREVIOUS_STATE, stateTypeRef)
}
if (containsStateChangeTrigger(rule) || containsStateUpdateTrigger(rule)) {
val lastStateUpdateTypeRef = ruleModel.newTypeRef(ZonedDateTime)
parameters += rule.toParameter(VAR_LAST_STATE_UPDATE, lastStateUpdateTypeRef)
}
if (containsStateChangeTrigger(rule)) {
val lastStateChangeTypeRef = ruleModel.newTypeRef(ZonedDateTime)
parameters += rule.toParameter(VAR_LAST_STATE_CHANGE, lastStateChangeTypeRef)
}
if (containsEventTrigger(rule)) {
val eventTypeRef = ruleModel.newTypeRef(String)
parameters += rule.toParameter(VAR_RECEIVED_EVENT, eventTypeRef)
Expand All @@ -163,10 +176,6 @@ class RulesJvmModelInferrer extends ScriptJvmModelInferrer {
val newStatusRef = ruleModel.newTypeRef(String)
parameters += rule.toParameter(VAR_NEW_STATUS, newStatusRef)
}
if ((containsStateChangeTrigger(rule) || containsStateUpdateTrigger(rule)) && !containsParam(parameters, VAR_NEW_STATE)) {
val stateTypeRef = ruleModel.newTypeRef(State)
parameters += rule.toParameter(VAR_NEW_STATE, stateTypeRef)
}

body = rule.script
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,16 @@ public class DSLScriptEngine implements javax.script.ScriptEngine {

public static final String MIMETYPE_OPENHAB_DSL_RULE = "application/vnd.openhab.dsl.rule";

private static final Map<String, String> IMPLICIT_VARS = Map.of("command",
ScriptJvmModelInferrer.VAR_RECEIVED_COMMAND, "state", ScriptJvmModelInferrer.VAR_NEW_STATE, "newState",
ScriptJvmModelInferrer.VAR_NEW_STATE, "oldState", ScriptJvmModelInferrer.VAR_PREVIOUS_STATE,
"triggeringItem", ScriptJvmModelInferrer.VAR_TRIGGERING_ITEM, "triggeringGroup",
ScriptJvmModelInferrer.VAR_TRIGGERING_GROUP, "input", ScriptJvmModelInferrer.VAR_INPUT);
private static final Map<String, String> IMPLICIT_VARS = Map.of( //
"command", ScriptJvmModelInferrer.VAR_RECEIVED_COMMAND, //
"state", ScriptJvmModelInferrer.VAR_NEW_STATE, //
"newState", ScriptJvmModelInferrer.VAR_NEW_STATE, //
"oldState", ScriptJvmModelInferrer.VAR_PREVIOUS_STATE, //
"lastStateUpdate", ScriptJvmModelInferrer.VAR_LAST_STATE_UPDATE, //
"lastStateChange", ScriptJvmModelInferrer.VAR_LAST_STATE_CHANGE, //
"triggeringItem", ScriptJvmModelInferrer.VAR_TRIGGERING_ITEM, //
"triggeringGroup", ScriptJvmModelInferrer.VAR_TRIGGERING_GROUP, //
"input", ScriptJvmModelInferrer.VAR_INPUT);

private final Logger logger = LoggerFactory.getLogger(DSLScriptEngine.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.core.model.script.jvmmodel

import com.google.inject.Inject
import java.time.ZonedDateTime
import java.util.Set
import org.openhab.core.items.ItemRegistry
import org.openhab.core.model.script.scoping.StateAndCommandProvider
Expand Down Expand Up @@ -61,6 +62,12 @@ class ScriptJvmModelInferrer extends AbstractModelInferrer {
/** Variable name for the new state of an item in a "changed state triggered" or "updated state triggered" rule */
public static final String VAR_NEW_STATE = "newState";

/** Variable name for the last update time of an item in a "changed state triggered" or "updated state triggered" rule */
public static final String VAR_LAST_STATE_UPDATE = "lastStateUpdate";

/** Variable name for the last change time of an item in a "changed state triggered" rule */
public static final String VAR_LAST_STATE_CHANGE = "lastStateChange";

/** Variable name for the received command in a "command triggered" rule */
public static final String VAR_RECEIVED_COMMAND = "receivedCommand";

Expand Down Expand Up @@ -160,6 +167,10 @@ class ScriptJvmModelInferrer extends AbstractModelInferrer {
parameters += script.toParameter(VAR_NEW_STATUS, newThingStatusRef)
val stateTypeRef2 = script.newTypeRef(State)
parameters += script.toParameter(VAR_NEW_STATE, stateTypeRef2)
val lastStateUpdateTypeRef = script.newTypeRef(ZonedDateTime)
parameters += script.toParameter(VAR_LAST_STATE_UPDATE, lastStateUpdateTypeRef)
val lastStateChangeTypeRef = script.newTypeRef(ZonedDateTime)
parameters += script.toParameter(VAR_LAST_STATE_CHANGE, lastStateChangeTypeRef)
val privateCacheTypeRef = script.newTypeRef(ValueCache)
parameters += script.toParameter(VAR_PRIVATE_CACHE, privateCacheTypeRef)
val sharedCacheTypeRef = script.newTypeRef(ValueCache)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@
*/
package org.openhab.core.events;

import java.io.IOException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

/**
* The {@link AbstractEventFactory} defines an abstract implementation of the {@link EventFactory} interface. Subclasses
Expand All @@ -31,7 +39,8 @@ public abstract class AbstractEventFactory implements EventFactory {

private final Set<String> supportedEventTypes;

private static final Gson JSONCONVERTER = new Gson();
private static final Gson JSONCONVERTER = new GsonBuilder()
.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeAdapter()).create();

/**
* Must be called in subclass constructor to define the supported event types.
Expand Down Expand Up @@ -120,4 +129,25 @@ protected static void checkNotNullOrEmpty(@Nullable String string, String argume
throw new IllegalArgumentException("The argument '" + argumentName + "' must not be null or empty.");
}
}

public static class ZonedDateTimeAdapter extends TypeAdapter<ZonedDateTime> {

@Override
public void write(JsonWriter out, @Nullable ZonedDateTime value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
}

@Override
public @Nullable ZonedDateTime read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return ZonedDateTime.parse(in.nextString(), DateTimeFormatter.ISO_ZONED_DATE_TIME);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,9 @@ public void setState(State state, @Nullable State lastState, @Nullable ZonedDate
if (oldStateUpdate != null && lastStateUpdate != null && !oldStateUpdate.equals(lastStateUpdate)) {
notifyListeners(oldState, state);
}
sendStateUpdatedEvent(state);
sendStateUpdatedEvent(state, lastStateUpdate);
if (!oldState.equals(state)) {
sendStateChangedEvent(state, oldState);
sendStateChangedEvent(state, oldState, lastStateUpdate, lastStateChange);
}
}

Expand All @@ -273,9 +273,9 @@ protected final void applyState(State state) {
lastState = oldState; // update before we notify listeners
}
notifyListeners(oldState, state);
sendStateUpdatedEvent(state);
sendStateUpdatedEvent(state, lastStateUpdate);
if (stateChanged) {
sendStateChangedEvent(state, oldState);
sendStateChangedEvent(state, oldState, lastStateUpdate, lastStateChange);
lastStateChange = now; // update after we've notified listeners
}
lastStateUpdate = now;
Expand Down Expand Up @@ -325,17 +325,19 @@ protected final void applyTimeSeries(TimeSeries timeSeries) {
}
}

private void sendStateUpdatedEvent(State newState) {
private void sendStateUpdatedEvent(State newState, @Nullable ZonedDateTime lastStateUpdate) {
EventPublisher eventPublisher1 = this.eventPublisher;
if (eventPublisher1 != null) {
eventPublisher1.post(ItemEventFactory.createStateUpdatedEvent(this.name, newState, null));
eventPublisher1.post(ItemEventFactory.createStateUpdatedEvent(this.name, newState, lastStateUpdate, null));
}
}

private void sendStateChangedEvent(State newState, State oldState) {
private void sendStateChangedEvent(State newState, State oldState, @Nullable ZonedDateTime lastStateUpdate,
@Nullable ZonedDateTime lastStateChange) {
EventPublisher eventPublisher1 = this.eventPublisher;
if (eventPublisher1 != null) {
eventPublisher1.post(ItemEventFactory.createStateChangedEvent(this.name, newState, oldState));
eventPublisher1.post(ItemEventFactory.createStateChangedEvent(this.name, newState, oldState,
lastStateUpdate, lastStateChange));
}
}

Expand Down
Loading

0 comments on commit 1346a0b

Please sign in to comment.