Add ItemStateUpdatedEvent and enable group channel-links (#3141)

* Add (Group)ItemStateUpdatedEvent

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2023-03-31 23:01:40 +02:00 committed by GitHub
parent 4d0dba1abc
commit 4182980ec8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 374 additions and 48 deletions

View File

@ -31,7 +31,7 @@ import org.openhab.core.items.events.GroupItemStateChangedEvent;
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;
@ -77,7 +77,7 @@ public class ItemStateTriggerHandler extends BaseTriggerModuleHandler implements
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);
@ -122,9 +122,9 @@ public class ItemStateTriggerHandler extends BaseTriggerModuleHandler implements
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);
}

View File

@ -41,8 +41,10 @@ import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.ItemStateConverter;
import org.openhab.core.items.ItemUtil;
import org.openhab.core.items.events.AbstractItemRegistryEvent;
import org.openhab.core.items.events.GroupStateUpdatedEvent;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemStateEvent;
import org.openhab.core.items.events.ItemStateUpdatedEvent;
import org.openhab.core.library.items.NumberItem;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
@ -115,7 +117,7 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
public static final long THINGHANDLER_EVENT_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
private static final Set<String> SUBSCRIBED_EVENT_TYPES = Set.of(ItemStateEvent.TYPE, ItemCommandEvent.TYPE,
ChannelTriggeredEvent.TYPE);
GroupStateUpdatedEvent.TYPE, ChannelTriggeredEvent.TYPE);
private final Logger logger = LoggerFactory.getLogger(CommunicationManager.class);
@ -179,8 +181,8 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
@Override
public void receive(Event event) {
if (event instanceof ItemStateEvent) {
receiveUpdate((ItemStateEvent) event);
if (event instanceof ItemStateUpdatedEvent) {
receiveUpdate((ItemStateUpdatedEvent) event);
} else if (event instanceof ItemCommandEvent) {
receiveCommand((ItemCommandEvent) event);
} else if (event instanceof ChannelTriggeredEvent) {
@ -358,7 +360,7 @@ public class CommunicationManager implements EventSubscriber, RegistryChangeList
});
}
private void receiveUpdate(ItemStateEvent updateEvent) {
private void receiveUpdate(ItemStateUpdatedEvent updateEvent) {
final String itemName = updateEvent.getItemName();
final State newState = updateEvent.getItemState();
handleEvent(itemName, newState, updateEvent.getSource(), s -> acceptedStateTypeMap.get(s),

View File

@ -231,14 +231,23 @@ public abstract class GenericItem implements ActiveItem {
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));
}
}

View File

@ -25,6 +25,7 @@ import java.util.stream.Collectors;
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;
@ -371,6 +372,7 @@ public class GroupItem extends GenericItem implements StateChangeListener {
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);
@ -413,9 +415,17 @@ public class GroupItem extends GenericItem implements StateChangeListener {
}
}
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));
}
}

View File

@ -17,7 +17,8 @@ import org.openhab.core.types.State;
/**
* {@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

View File

@ -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);
}
}

View File

@ -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";
@ -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
@ -80,6 +84,8 @@ public class ItemEventFactory extends AbstractEventFactory {
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)) {
@ -88,12 +94,22 @@ public class ItemEventFactory extends AbstractEventFactory {
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);
@ -124,6 +140,13 @@ public class ItemEventFactory extends AbstractEventFactory {
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);
@ -268,6 +291,54 @@ public class ItemEventFactory extends AbstractEventFactory {
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.
*

View File

@ -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.
@ -62,6 +62,6 @@ public class ItemStateEvent extends ItemEvent {
@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);
}
}

View File

@ -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);
}
}

View File

@ -27,7 +27,9 @@ import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.items.events.ItemEvent;
import org.openhab.core.items.events.ItemStateChangedEvent;
import org.openhab.core.items.events.ItemStateUpdatedEvent;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.library.types.RawType;
@ -58,24 +60,51 @@ public class GenericItemTest {
item.setEventPublisher(publisher);
State oldState = item.getState();
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
item.setState(new RawType(new byte[0], RawType.DEFAULT_MIME_TYPE));
ArgumentCaptor<ItemStateChangedEvent> captor = ArgumentCaptor.forClass(ItemStateChangedEvent.class);
ArgumentCaptor<ItemEvent> captor = ArgumentCaptor.forClass(ItemEvent.class);
verify(publisher, times(1)).post(captor.capture());
verify(publisher, times(2)).post(captor.capture());
ItemStateChangedEvent change = captor.getValue();
List<ItemEvent> events = captor.getAllValues();
assertEquals(2, events.size());
// first event should be updated event
assertInstanceOf(ItemStateUpdatedEvent.class, events.get(0));
ItemStateUpdatedEvent updated = (ItemStateUpdatedEvent) events.get(0);
assertEquals(item.getName(), updated.getItemName());
assertEquals("openhab/items/member1/stateupdated", updated.getTopic());
assertEquals(item.getState(), updated.getItemState());
assertEquals(ItemStateUpdatedEvent.TYPE, updated.getType());
// second event should be changed event
assertInstanceOf(ItemStateChangedEvent.class, events.get(1));
ItemStateChangedEvent change = (ItemStateChangedEvent) events.get(1);
assertEquals(item.getName(), change.getItemName());
assertEquals("openhab/items/member1/statechanged", change.getTopic());
assertEquals(oldState, change.getOldItemState());
assertEquals(item.getState(), change.getItemState());
assertEquals(ItemStateChangedEvent.TYPE, change.getType());
// State doesn't change -> no event is fired
// reset invocations and captor
clearInvocations(publisher);
captor = ArgumentCaptor.forClass(ItemEvent.class);
// State doesn't change -> only update event is fired
item.setState(item.getState());
verifyNoMoreInteractions(publisher);
verify(publisher).post(captor.capture());
events = captor.getAllValues();
assertEquals(1, events.size()); // two before and one additional
// event should be updated event
assertInstanceOf(ItemStateUpdatedEvent.class, events.get(0));
updated = (ItemStateUpdatedEvent) events.get(0);
assertEquals(item.getName(), updated.getItemName());
assertEquals("openhab/items/member1/stateupdated", updated.getTopic());
assertEquals(item.getState(), updated.getItemState());
assertEquals(ItemStateUpdatedEvent.TYPE, updated.getType());
}
@Test

View File

@ -14,13 +14,18 @@ package org.openhab.core.library.items;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
import java.util.List;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Temperature;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -29,9 +34,11 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.openhab.core.events.Event;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.i18n.UnitProvider;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemStateUpdatedEvent;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.library.types.PercentType;
@ -57,12 +64,15 @@ public class NumberItemTest {
private static final String ITEM_NAME = "test";
private @Mock @NonNullByDefault({}) StateDescriptionService stateDescriptionServiceMock;
private @Mock @NonNullByDefault({}) UnitProvider unitProviderMock;
private @Mock @NonNullByDefault({}) EventPublisher eventPublisherMock;
@BeforeEach
public void setup() {
when(stateDescriptionServiceMock.getStateDescription(ITEM_NAME, null))
.thenReturn(StateDescriptionFragmentBuilder.create().withPattern("%.1f " + UnitUtils.UNIT_PLACEHOLDER)
.build().toStateDescription());
when(unitProviderMock.getUnit(Temperature.class)).thenReturn(SIUnits.CELSIUS);
}
@Test
@ -286,4 +296,47 @@ public class NumberItemTest {
assertThat(item.getState(), is(new QuantityType<>("329 kWh")));
assertThat(item.getUnit(), is(nullValue()));
}
public void quantityTypeCorrectlySetWithDifferentUnit() {
NumberItem numberItem = new NumberItem("Number:Temperature", ITEM_NAME);
numberItem.setUnitProvider(unitProviderMock);
numberItem.setEventPublisher(eventPublisherMock);
numberItem.setState(new QuantityType<>("140 °F"));
assertThat(numberItem.getState(), Matchers.is(new QuantityType<>("60 °C")));
ArgumentCaptor<Event> captor = ArgumentCaptor.forClass(Event.class);
verify(eventPublisherMock, times(2)).post(captor.capture());
List<Event> events = captor.getAllValues();
assertThat(events, hasSize(2));
assertThat(events.get(0), Matchers.is(instanceOf(ItemStateUpdatedEvent.class)));
ItemStateUpdatedEvent updatedEvent = (ItemStateUpdatedEvent) events.get(0);
assertThat(updatedEvent.getItemName(), Matchers.is(ITEM_NAME));
assertThat(updatedEvent.getItemState(), Matchers.is(new QuantityType<>("60°C")));
}
@Test
public void decimalTypeCorrectlySetWithUnit() {
NumberItem numberItem = new NumberItem("Number:Temperature", ITEM_NAME);
numberItem.setUnitProvider(unitProviderMock);
numberItem.setEventPublisher(eventPublisherMock);
numberItem.setState(new DecimalType(10));
assertThat(numberItem.getState(), Matchers.is(new QuantityType<>("10 °C")));
ArgumentCaptor<Event> captor = ArgumentCaptor.forClass(Event.class);
verify(eventPublisherMock, times(2)).post(captor.capture());
List<Event> events = captor.getAllValues();
assertThat(events, hasSize(2));
assertThat(events.get(0), Matchers.is(instanceOf(ItemStateUpdatedEvent.class)));
ItemStateUpdatedEvent updatedEvent = (ItemStateUpdatedEvent) events.get(0);
assertThat(updatedEvent.getItemName(), Matchers.is(ITEM_NAME));
assertThat(updatedEvent.getItemState(), Matchers.is(new QuantityType<>("10°C")));
}
}

View File

@ -179,7 +179,7 @@ public abstract class BasicConditionHandlerTest extends JavaOSGiTest {
logger.info("Rule is enabled and idle");
logger.info("Send and wait for item state is ON");
eventPublisher.post(ItemEventFactory.createStateEvent(testItemName1, OnOffType.ON));
eventPublisher.post(ItemEventFactory.createStateUpdatedEvent(testItemName1, OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(notNullValue()));
@ -194,7 +194,7 @@ public abstract class BasicConditionHandlerTest extends JavaOSGiTest {
// prepare the execution
itemEvent = null;
eventPublisher.post(ItemEventFactory.createStateEvent(testItemName1, OnOffType.ON));
eventPublisher.post(ItemEventFactory.createStateUpdatedEvent(testItemName1, OnOffType.ON));
waitForAssert(() -> {
assertThat(itemEvent, is(nullValue()));
});

View File

@ -46,7 +46,9 @@ import org.openhab.core.internal.items.GroupFunctionHelper;
import org.openhab.core.internal.items.ItemStateConverterImpl;
import org.openhab.core.items.dto.GroupFunctionDTO;
import org.openhab.core.items.events.GroupItemStateChangedEvent;
import org.openhab.core.items.events.GroupStateUpdatedEvent;
import org.openhab.core.items.events.ItemCommandEvent;
import org.openhab.core.items.events.ItemStateUpdatedEvent;
import org.openhab.core.items.events.ItemUpdatedEvent;
import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.library.items.ColorItem;
@ -422,6 +424,7 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
public void assertThatGroupItemPostsEventsForChangesCorrectly() {
// from ItemEventFactory.GROUPITEM_STATE_CHANGED_EVENT_TOPIC
String groupitemStateChangedEventTopic = "openhab/items/{itemName}/{memberName}/statechanged";
String groupitemStateUpdatedEventTopic = "openhab/items/{itemName}/{memberName}/stateupdated";
events.clear();
GroupItem groupItem = new GroupItem("root", new SwitchItem("mySwitch"), new GroupFunction.Equality());
@ -432,10 +435,21 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
groupItem.setEventPublisher(publisher);
State oldGroupState = groupItem.getState();
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
member.setState(OnOffType.ON);
waitForAssert(() -> assertThat(events.size(), is(1)));
waitForAssert(() -> assertThat(events.size(), is(2)));
List<Event> updates = events.stream().filter(it -> it instanceof GroupStateUpdatedEvent)
.collect(Collectors.toList());
assertThat(updates.size(), is(1));
GroupStateUpdatedEvent update = (GroupStateUpdatedEvent) updates.get(0);
assertThat(update.getItemName(), is(groupItem.getName()));
assertThat(update.getMemberName(), is(member.getName()));
assertThat(update.getTopic(), is(groupitemStateUpdatedEventTopic.replace("{memberName}", member.getName())
.replace("{itemName}", groupItem.getName())));
assertThat(update.getItemState(), is(groupItem.getState()));
List<Event> changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent)
.collect(Collectors.toList());
@ -451,9 +465,10 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
events.clear();
// State doesn't change -> no events are fired
// State doesn't change -> only update event is posted
member.setState(member.getState());
assertThat(events.size(), is(0));
waitForAssert(() -> assertThat(events.size(), is(1)));
assertThat(events.get(0), is(instanceOf(ItemStateUpdatedEvent.class)));
}
@Test
@ -470,10 +485,10 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
groupItem.setEventPublisher(publisher);
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
sw1.setState(OnOffType.ON);
waitForAssert(() -> assertThat(events, hasSize(1)));
waitForAssert(() -> assertThat(events, hasSize(2)));
List<Event> groupItemStateChangedEvents = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent)
.collect(Collectors.toList());
@ -490,13 +505,13 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
events.clear();
// State does not change -> no change event is fired
// State does not change -> only update event is fired
sw2.setState(OnOffType.ON);
// wait to see that the event doesn't fire
Thread.sleep(WAIT_EVENT_TO_BE_HANDLED);
waitForAssert(() -> assertThat(events, hasSize(0)));
waitForAssert(() -> assertThat(events, hasSize(1)));
}
@Test
@ -543,15 +558,19 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
groupItem.setEventPublisher(publisher);
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
sw1.setState(OnOffType.ON);
waitForAssert(() -> assertThat(events, hasSize(1)));
waitForAssert(() -> assertThat(events, hasSize(2)));
List<Event> changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent)
.collect(Collectors.toList());
assertThat(changes, hasSize(1));
List<Event> updates = events.stream().filter(it -> it instanceof GroupStateUpdatedEvent)
.collect(Collectors.toList());
assertThat(updates, hasSize(1));
GroupItemStateChangedEvent change = (GroupItemStateChangedEvent) changes.get(0);
assertThat(change.getItemName(), is(groupItem.getName()));
@ -563,15 +582,21 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
events.clear();
// State does not change -> no change event is fired
// State does not change -> only update event is fired
sw2.setState(OnOffType.ON);
sw2.setState(UnDefType.UNDEF);
// wait to see that the event doesn't fire
// wait to see that only state updated events are fired
Thread.sleep(WAIT_EVENT_TO_BE_HANDLED);
assertThat(events, hasSize(0));
assertThat(events, hasSize(2));
changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent).collect(Collectors.toList());
assertThat(changes, hasSize(0));
updates = events.stream().filter(it -> it instanceof GroupStateUpdatedEvent).collect(Collectors.toList());
assertThat(updates, hasSize(2));
assertThat(groupItem.getState(), is(OnOffType.ON));
}
@ -590,10 +615,10 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
groupItem.setEventPublisher(publisher);
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
sw1.setState(OnOffType.ON);
waitForAssert(() -> assertThat(events, hasSize(1)));
waitForAssert(() -> assertThat(events, hasSize(2)));
List<Event> changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent)
.collect(Collectors.toList());
@ -610,10 +635,10 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
events.clear();
// State changes -> one change event is fired
// State changes -> one update and one change event is fired
sw2.setState(OnOffType.ON);
waitForAssert(() -> assertThat(events, hasSize(1)));
waitForAssert(() -> assertThat(events, hasSize(2)));
changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent).collect(Collectors.toList());
assertThat(changes, hasSize(1));
@ -727,7 +752,7 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
member1.setState(new PercentType(50));
waitForAssert(() -> assertThat(events.size(), is(1)));
waitForAssert(() -> assertThat(events.size(), is(2)));
List<Event> changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent)
.collect(Collectors.toList());
@ -746,7 +771,7 @@ public class GroupItemOSGiTest extends JavaOSGiTest {
member2.setState(new PercentType(10));
waitForAssert(() -> assertThat(events.size(), is(1)));
waitForAssert(() -> assertThat(events.size(), is(2)));
changes = events.stream().filter(it -> it instanceof GroupItemStateChangedEvent).collect(Collectors.toList());
assertThat(changes.size(), is(1));

View File

@ -351,7 +351,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
@Test
public void testItemStateEventSingleLink() {
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, OnOffType.ON));
manager.receive(ItemEventFactory.createStateUpdatedEvent(ITEM_NAME_2, OnOffType.ON));
waitForAssert(() -> {
verify(stateProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
@ -362,7 +362,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
@Test
public void testItemStateEventMultiLink() {
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON));
manager.receive(ItemEventFactory.createStateUpdatedEvent(ITEM_NAME_1, OnOffType.ON));
waitForAssert(() -> {
verify(stateProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
@ -374,7 +374,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
@Test
public void testItemStateEventNotToSource() {
manager.receive(
ItemEventFactory.createStateEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString()));
ItemEventFactory.createStateUpdatedEvent(ITEM_NAME_1, OnOffType.ON, STATE_CHANNEL_UID_2.getAsString()));
waitForAssert(() -> {
verify(stateProfileMock).onStateUpdateFromItem(eq(OnOffType.ON));
verify(triggerProfileMock, times(2)).onStateUpdateFromItem(eq(OnOffType.ON));
@ -596,7 +596,7 @@ public class CommunicationManagerOSGiTest extends JavaOSGiTest {
thing.setHandler(thingHandlerMock);
when(thingRegistryMock.get(eq(THING_UID))).thenReturn(thing);
manager.receive(ItemEventFactory.createStateEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128)));
manager.receive(ItemEventFactory.createStateUpdatedEvent(ITEM_NAME_2, HSBType.fromRGB(128, 128, 128)));
waitForAssert(() -> {
ArgumentCaptor<State> stateCaptor = ArgumentCaptor.forClass(State.class);
verify(stateProfileMock).onStateUpdateFromItem(stateCaptor.capture());