Skip to content

Commit

Permalink
Add ItemStateUpdatedEvent and enable group channel-links (openhab#3141)
Browse files Browse the repository at this point in the history
* Add (Group)ItemStateUpdatedEvent

Signed-off-by: Jan N. Klug <[email protected]>
GitOrigin-RevId: 4182980
  • Loading branch information
J-N-K authored and splatch committed Jul 12, 2023
1 parent b4bf208 commit af2ddfe
Show file tree
Hide file tree
Showing 14 changed files with 374 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.openhab.core.items.events.ItemAddedEvent;
import org.openhab.core.items.events.ItemRemovedEvent;
import org.openhab.core.items.events.ItemStateChangedEvent;
import org.openhab.core.items.events.ItemStateEvent;
import org.openhab.core.items.events.ItemStateUpdatedEvent;
import org.openhab.core.types.State;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
Expand Down Expand Up @@ -77,7 +77,7 @@ public ItemStateTriggerHandler(Trigger module, String ruleUID, BundleContext bun
this.previousState = (String) module.getConfiguration().get(CFG_PREVIOUS_STATE);
this.ruleUID = ruleUID;
if (UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) {
this.types = Set.of(ItemStateEvent.TYPE, ItemAddedEvent.TYPE, ItemRemovedEvent.TYPE);
this.types = Set.of(ItemStateUpdatedEvent.TYPE, ItemAddedEvent.TYPE, ItemRemovedEvent.TYPE);
} else {
this.types = Set.of(ItemStateChangedEvent.TYPE, GroupItemStateChangedEvent.TYPE, ItemAddedEvent.TYPE,
ItemRemovedEvent.TYPE);
Expand Down Expand Up @@ -122,9 +122,9 @@ public void receive(Event event) {
logger.trace("Received Event: Source: {} Topic: {} Type: {} Payload: {}", event.getSource(),
event.getTopic(), event.getType(), event.getPayload());
Map<String, Object> values = new HashMap<>();
if (event instanceof ItemStateEvent && UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) {
if (event instanceof ItemStateUpdatedEvent && UPDATE_MODULE_TYPE_ID.equals(module.getTypeUID())) {
String state = this.state;
State itemState = ((ItemStateEvent) event).getItemState();
State itemState = ((ItemStateUpdatedEvent) event).getItemState();
if ((state == null || state.equals(itemState.toFullString()))) {
values.put("state", itemState);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,23 @@ protected final void applyState(State state) {
State oldState = this.state;
this.state = state;
notifyListeners(oldState, state);
sendStateUpdatedEvent(state);
if (!oldState.equals(state)) {
sendStateChangedEvent(state, oldState);
}
}

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.items.events.ItemEventFactory;
import org.openhab.core.service.CommandDescriptionService;
Expand Down Expand Up @@ -371,6 +372,7 @@ public void stateUpdated(Item item, State state) {
State calculatedState = function.calculate(getStateMembers(getMembers()));
newState = itemStateConverter.convertToAcceptedState(calculatedState, baseItem);
setState(newState);
sendGroupStateUpdatedEvent(item.getName(), newState);
}
if (!oldState.equals(newState)) {
sendGroupStateChangedEvent(item.getName(), newState, oldState);
Expand Down Expand Up @@ -413,9 +415,17 @@ public void setUnitProvider(@Nullable UnitProvider unitProvider) {
}
}

private void sendGroupStateUpdatedEvent(String memberName, State state) {
EventPublisher eventPublisher1 = this.eventPublisher;
if (eventPublisher1 != null) {
eventPublisher1.post(ItemEventFactory.createGroupStateEvent(getName(), memberName, state, null));
}
}

private void sendGroupStateChangedEvent(String memberName, State newState, State oldState) {
if (eventPublisher != null) {
eventPublisher
EventPublisher eventPublisher1 = this.eventPublisher;
if (eventPublisher1 != null) {
eventPublisher1
.post(ItemEventFactory.createGroupStateChangedEvent(getName(), memberName, newState, oldState));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

/**
* {@link GroupItemStateChangedEvent}s can be used to deliver group item state changes through the openHAB event bus. In
* contrast to the {@link GroupItemStateEvent} the {@link GroupItemStateChangedEvent} is only sent if the state changed.
* contrast to the {@link GroupStateUpdatedEvent} the {@link GroupItemStateChangedEvent} is only sent if the state
* changed.
* State events must be created with the {@link ItemEventFactory}.
*
* @author Christoph Knauf - Initial contribution
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* 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.items.events;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.types.State;

/**
* {@link GroupStateUpdatedEvent}s can be used to deliver group item state updates through the openHAB event bus.
* In contrast to the {@link GroupItemStateChangedEvent} it is always sent.
* State events must be created with the {@link ItemEventFactory}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class GroupStateUpdatedEvent extends ItemStateUpdatedEvent {

/**
* The group item state changed event type.
*/
public static final String TYPE = GroupStateUpdatedEvent.class.getSimpleName();

private final String memberName;

protected GroupStateUpdatedEvent(String topic, String payload, String itemName, String memberName,
State newItemState, @Nullable String source) {
super(topic, payload, itemName, newItemState, source);
this.memberName = memberName;
}

/**
* @return the name of the changed group member
*/
public String getMemberName() {
return this.memberName;
}

@Override
public String getType() {
return TYPE;
}

@Override
public String toString() {
return String.format("Group '%s' updated to %s through %s", itemName, itemState, memberName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ public class ItemEventFactory extends AbstractEventFactory {

private static final String ITEM_STATE_EVENT_TOPIC = "openhab/items/{itemName}/state";

private static final String ITEM_STATE_UPDATED_EVENT_TOPIC = "openhab/items/{itemName}/stateupdated";

private static final String ITEM_STATE_PREDICTED_EVENT_TOPIC = "openhab/items/{itemName}/statepredicted";

private static final String ITEM_STATE_CHANGED_EVENT_TOPIC = "openhab/items/{itemName}/statechanged";

private static final String GROUP_STATE_EVENT_TOPIC = "openhab/items/{itemName}/{memberName}/stateupdated";

private static final String GROUPITEM_STATE_CHANGED_EVENT_TOPIC = "openhab/items/{itemName}/{memberName}/statechanged";

private static final String ITEM_ADDED_EVENT_TOPIC = "openhab/items/{itemName}/added";
Expand All @@ -67,8 +71,8 @@ public class ItemEventFactory extends AbstractEventFactory {
*/
public ItemEventFactory() {
super(Set.of(ItemCommandEvent.TYPE, ItemStateEvent.TYPE, ItemStatePredictedEvent.TYPE,
ItemStateChangedEvent.TYPE, ItemAddedEvent.TYPE, ItemUpdatedEvent.TYPE, ItemRemovedEvent.TYPE,
GroupItemStateChangedEvent.TYPE));
ItemStateUpdatedEvent.TYPE, ItemStateChangedEvent.TYPE, ItemAddedEvent.TYPE, ItemUpdatedEvent.TYPE,
ItemRemovedEvent.TYPE, GroupStateUpdatedEvent.TYPE, GroupItemStateChangedEvent.TYPE));
}

@Override
Expand All @@ -80,6 +84,8 @@ protected Event createEventByType(String eventType, String topic, String payload
return createStateEvent(topic, payload, source);
} else if (ItemStatePredictedEvent.TYPE.equals(eventType)) {
return createStatePredictedEvent(topic, payload);
} else if (ItemStateUpdatedEvent.TYPE.equals(eventType)) {
return createStateUpdatedEvent(topic, payload);
} else if (ItemStateChangedEvent.TYPE.equals(eventType)) {
return createStateChangedEvent(topic, payload);
} else if (ItemAddedEvent.TYPE.equals(eventType)) {
Expand All @@ -88,12 +94,22 @@ protected Event createEventByType(String eventType, String topic, String payload
return createUpdatedEvent(topic, payload);
} else if (ItemRemovedEvent.TYPE.equals(eventType)) {
return createRemovedEvent(topic, payload);
} else if (GroupStateUpdatedEvent.TYPE.equals(eventType)) {
return createGroupStateEvent(topic, payload);
} else if (GroupItemStateChangedEvent.TYPE.equals(eventType)) {
return createGroupStateChangedEvent(topic, payload);
}
throw new IllegalArgumentException("The event type '" + eventType + "' is not supported by this factory.");
}

private Event createGroupStateEvent(String topic, String payload) {
String itemName = getItemName(topic);
String memberName = getMemberName(topic);
ItemEventPayloadBean bean = deserializePayload(payload, ItemEventPayloadBean.class);
State state = getState(bean.getType(), bean.getValue());
return new GroupStateUpdatedEvent(topic, payload, itemName, memberName, state, null);
}

private Event createGroupStateChangedEvent(String topic, String payload) {
String itemName = getItemName(topic);
String memberName = getMemberName(topic);
Expand Down Expand Up @@ -124,6 +140,13 @@ private Event createStatePredictedEvent(String topic, String payload) {
return new ItemStatePredictedEvent(topic, payload, itemName, state, bean.isConfirmation());
}

private Event createStateUpdatedEvent(String topic, String payload) {
String itemName = getItemName(topic);
ItemEventPayloadBean bean = deserializePayload(payload, ItemEventPayloadBean.class);
State state = getState(bean.getType(), bean.getValue());
return new ItemStateUpdatedEvent(topic, payload, itemName, state, null);
}

private Event createStateChangedEvent(String topic, String payload) {
String itemName = getItemName(topic);
ItemStateChangedEventPayloadBean bean = deserializePayload(payload, ItemStateChangedEventPayloadBean.class);
Expand Down Expand Up @@ -268,6 +291,54 @@ public static ItemEvent createStateEvent(String itemName, State state) {
return createStateEvent(itemName, state, null);
}

/**
* Creates an item state updated event.
*
* @param itemName the name of the item to report the state update for
* @param state the new state
* @return the created item state update event
* @throws IllegalArgumentException if itemName or state is null
*/
public static ItemStateUpdatedEvent createStateUpdatedEvent(String itemName, State state) {
return createStateUpdatedEvent(itemName, state, null);
}

/**
* Creates an item state updated event.
*
* @param itemName the name of the item to report the state update for
* @param state the new state
* @param source the name of the source identifying the sender (can be null)
* @return the created item state update event
* @throws IllegalArgumentException if itemName or state is null
*/
public static ItemStateUpdatedEvent createStateUpdatedEvent(String itemName, State state, @Nullable String source) {
assertValidArguments(itemName, state, "state");
String topic = buildTopic(ITEM_STATE_UPDATED_EVENT_TOPIC, itemName);
ItemEventPayloadBean bean = new ItemEventPayloadBean(getStateType(state), state.toFullString());
String payload = serializePayload(bean);
return new ItemStateUpdatedEvent(topic, payload, itemName, state, source);
}

/**
* Creates an group item state updated event.
*
* @param groupName the name of the group to report the state update for
* @param member the name of the item that updated the group state
* @param state the new state
* @param source the name of the source identifying the sender (can be null)
* @return the created group item state update event
* @throws IllegalArgumentException if groupName or state is null
*/
public static GroupStateUpdatedEvent createGroupStateEvent(String groupName, String member, State state,
@Nullable String source) {
assertValidArguments(groupName, member, state, "state");
String topic = buildGroupTopic(GROUP_STATE_EVENT_TOPIC, groupName, member);
ItemEventPayloadBean bean = new ItemEventPayloadBean(getStateType(state), state.toFullString());
String payload = serializePayload(bean);
return new GroupStateUpdatedEvent(topic, payload, groupName, member, state, source);
}

/**
* Creates an item state predicted event.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ItemStateEvent extends ItemEvent {
*/
public static final String TYPE = ItemStateEvent.class.getSimpleName();

private final State itemState;
protected final State itemState;

/**
* Constructs a new item state event.
Expand Down Expand Up @@ -62,6 +62,6 @@ public State getItemState() {

@Override
public String toString() {
return String.format("Item '%s' updated to %s", itemName, itemState);
return String.format("Item '%s' shall update to %s", itemName, itemState);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* 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.items.events;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.types.State;

/**
* {@link ItemStateUpdatedEvent}s can be used to report item status updates through the openHAB event bus.
* State update events must be created with the {@link ItemEventFactory}.
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ItemStateUpdatedEvent extends ItemEvent {

/**
* The item state event type.
*/
public static final String TYPE = ItemStateUpdatedEvent.class.getSimpleName();

protected final State itemState;

/**
* Constructs a new item state event.
*
* @param topic the topic
* @param payload the payload
* @param itemName the item name
* @param itemState the item state
* @param source the source, can be null
*/
protected ItemStateUpdatedEvent(String topic, String payload, String itemName, State itemState,
@Nullable String source) {
super(topic, payload, itemName, source);
this.itemState = itemState;
}

@Override
public String getType() {
return TYPE;
}

/**
* Gets the item state.
*
* @return the item state
*/
public State getItemState() {
return itemState;
}

@Override
public String toString() {
return String.format("Item '%s' updated to %s", itemName, itemState);
}
}
Loading

0 comments on commit af2ddfe

Please sign in to comment.