Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getLastStateChange, getLastStateUpdate, and getLastState to GenericItem #4351

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
*/
public class EnrichedGroupItemDTO extends EnrichedItemDTO {

public EnrichedGroupItemDTO(ItemDTO itemDTO, EnrichedItemDTO[] members, String link, String state,
String transformedState, StateDescription stateDescription, String unitSymbol) {
super(itemDTO, link, state, transformedState, stateDescription, null, unitSymbol);
public EnrichedGroupItemDTO(ItemDTO itemDTO, EnrichedItemDTO[] members, String link, String state, String lastState,
Long lastStateUpdate, Long lastStateChange, String transformedState, StateDescription stateDescription,
String unitSymbol) {
super(itemDTO, link, state, lastState, lastStateUpdate, lastStateChange, transformedState, stateDescription,
null, unitSymbol);
this.members = members;
this.groupType = ((GroupItemDTO) itemDTO).groupType;
this.function = ((GroupItemDTO) itemDTO).function;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ public class EnrichedItemDTO extends ItemDTO {
public String state;
public String transformedState;
public StateDescription stateDescription;
public String unitSymbol;
public CommandDescription commandDescription;
public String lastState;
public Long lastStateUpdate;
public Long lastStateChange;
public String unitSymbol;
public Map<String, Object> metadata;
public Boolean editable;

public EnrichedItemDTO(ItemDTO itemDTO, String link, String state, String transformedState,
StateDescription stateDescription, CommandDescription commandDescription, String unitSymbol) {
public EnrichedItemDTO(ItemDTO itemDTO, String link, String state, String lastState, Long lastStateUpdate,
Long lastStateChange, String transformedState, StateDescription stateDescription,
CommandDescription commandDescription, String unitSymbol) {
this.type = itemDTO.type;
this.name = itemDTO.name;
this.label = itemDTO.label;
Expand All @@ -50,6 +54,9 @@ public EnrichedItemDTO(ItemDTO itemDTO, String link, String state, String transf
this.transformedState = transformedState;
this.stateDescription = stateDescription;
this.commandDescription = commandDescription;
this.lastState = lastState;
this.lastStateUpdate = lastStateUpdate;
this.lastStateChange = lastStateChange;
this.unitSymbol = unitSymbol;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -91,6 +92,12 @@ private static EnrichedItemDTO map(Item item, ItemDTO itemDTO, boolean drillDown
}
StateDescription stateDescription = considerTransformation(item.getStateDescription(locale));

String lastState = Optional.ofNullable(item.getLastState()).map(State::toFullString).orElse(null);
Long lastStateUpdate = Optional.ofNullable(item.getLastStateUpdate()).map(zdt -> zdt.toInstant().toEpochMilli())
.orElse(null);
Long lastStateChange = Optional.ofNullable(item.getLastStateChange()).map(zdt -> zdt.toInstant().toEpochMilli())
.orElse(null);

final String link;
if (uriBuilder != null) {
link = uriBuilder.build(itemDTO.name).toASCIIString();
Expand Down Expand Up @@ -124,11 +131,11 @@ private static EnrichedItemDTO map(Item item, ItemDTO itemDTO, boolean drillDown
} else {
memberDTOs = new EnrichedItemDTO[0];
}
enrichedItemDTO = new EnrichedGroupItemDTO(itemDTO, memberDTOs, link, state, transformedState,
stateDescription, unitSymbol);
enrichedItemDTO = new EnrichedGroupItemDTO(itemDTO, memberDTOs, link, state, lastState, lastStateUpdate,
lastStateChange, transformedState, stateDescription, unitSymbol);
} else {
enrichedItemDTO = new EnrichedItemDTO(itemDTO, link, state, transformedState, stateDescription,
item.getCommandDescription(locale), unitSymbol);
enrichedItemDTO = new EnrichedItemDTO(itemDTO, link, state, lastState, lastStateUpdate, lastStateChange,
transformedState, stateDescription, item.getCommandDescription(locale), unitSymbol);
}

return enrichedItemDTO;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.core.items;

import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -77,6 +78,10 @@ public abstract class GenericItem implements ActiveItem {
protected final String type;

protected State state = UnDefType.NULL;
protected @Nullable State lastState;

protected @Nullable ZonedDateTime lastStateUpdate;
protected @Nullable ZonedDateTime lastStateChange;

protected @Nullable String label;

Expand All @@ -103,6 +108,21 @@ public State getState() {
return state.as(typeClass);
}

@Override
public @Nullable State getLastState() {
return lastState;
}

@Override
public @Nullable ZonedDateTime getLastStateUpdate() {
return lastStateUpdate;
}

@Override
public @Nullable ZonedDateTime getLastStateChange() {
return lastStateChange;
}

@Override
public String getUID() {
return getName();
Expand Down Expand Up @@ -218,13 +238,20 @@ public void setState(State state) {
* @param state new state of this item
*/
protected final void applyState(State state) {
ZonedDateTime now = ZonedDateTime.now();
State oldState = this.state;
boolean stateChanged = !oldState.equals(state);
this.state = state;
if (stateChanged) {
lastState = oldState; // update before we notify listeners
}
notifyListeners(oldState, state);
sendStateUpdatedEvent(state);
if (!oldState.equals(state)) {
if (stateChanged) {
sendStateChangedEvent(state, oldState);
lastStateChange = now; // update after we've notified listeners
}
lastStateUpdate = now;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.core.items;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Locale;
import java.util.Set;
Expand Down Expand Up @@ -56,6 +57,30 @@ public interface Item extends Identifiable<String> {
*/
<T extends State> @Nullable T getStateAs(Class<T> typeClass);

/**
* Returns the previous state of the item.
*
* @return the previous state of the item, or null if the item has never been changed.
*/
@Nullable
State getLastState();

/**
* Returns the time the item was last updated.
*
* @return the time the item was last updated, or null if the item has never been updated.
*/
@Nullable
ZonedDateTime getLastStateUpdate();

/**
* Returns the time the item was last changed.
*
* @return the time the item was last changed, or null if the item has never been changed.
*/
@Nullable
ZonedDateTime getLastStateChange();

/**
* returns the name of the item
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
package org.openhab.core.items;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Locale;

Expand All @@ -39,6 +42,7 @@
import org.openhab.core.types.State;
import org.openhab.core.types.StateDescriptionFragmentBuilder;
import org.openhab.core.types.StateOption;
import org.openhab.core.types.UnDefType;

/**
* The GenericItemTest tests functionality of the GenericItem.
Expand Down Expand Up @@ -133,6 +137,47 @@ public void testGetStateAsWithNull() {
assertNull(item.getStateAs(toNull()));
}

@Test
public void testGetLastStateUpdate() {
TestItem item = new TestItem("member1");
assertNull(item.getLastStateUpdate());
item.setState(PercentType.HUNDRED);
assertThat(item.getLastStateUpdate().toInstant().toEpochMilli() * 1.0,
is(closeTo(ZonedDateTime.now().toInstant().toEpochMilli(), 5)));
}

@Test
public void testGetLastStateChange() throws InterruptedException {
TestItem item = new TestItem("member1");
assertNull(item.getLastStateChange());
item.setState(PercentType.HUNDRED);
ZonedDateTime initialChangeTime = ZonedDateTime.now();
assertThat(item.getLastStateChange().toInstant().toEpochMilli() * 1.0,
is(closeTo(initialChangeTime.toInstant().toEpochMilli(), 5)));

Thread.sleep(50);
item.setState(PercentType.HUNDRED);
assertThat(item.getLastStateChange().toInstant().toEpochMilli() * 1.0,
is(closeTo(initialChangeTime.toInstant().toEpochMilli(), 5)));

Thread.sleep(50);
ZonedDateTime secondChangeTime = ZonedDateTime.now();
item.setState(PercentType.ZERO);
assertThat(item.getLastStateChange().toInstant().toEpochMilli() * 1.0,
is(closeTo(secondChangeTime.toInstant().toEpochMilli(), 5)));
}

@Test
public void testGetLastState() {
TestItem item = new TestItem("member1");
assertEquals(UnDefType.NULL, item.getState());
assertNull(item.getLastState());
item.setState(PercentType.HUNDRED);
assertEquals(UnDefType.NULL, item.getLastState());
item.setState(PercentType.ZERO);
assertEquals(PercentType.HUNDRED, item.getLastState());
}

@Test
public void testDispose() {
TestItem item = new TestItem("test");
Expand Down