mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 21:31:53 +01:00
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:
parent
4d0dba1abc
commit
4182980ec8
@ -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);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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")));
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
});
|
||||
|
@ -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));
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user