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 getLastChange, getLastUpdate, and getPreviousState to GenericItem #4351

Open
wants to merge 1 commit 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 @@ -25,8 +25,10 @@
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);
String previousState, Long lastUpdate, Long lastChange, String transformedState,
StateDescription stateDescription, String unitSymbol) {
super(itemDTO, link, state, previousState, lastUpdate, lastChange, 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 previousState;
public Long lastUpdate;
public Long lastChange;
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 previousState, Long lastUpdate,
Long lastChange, 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.previousState = previousState;
this.lastUpdate = lastUpdate;
this.lastChange = lastChange;
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 previousState = Optional.ofNullable(item.getPreviousState()).map(State::toFullString).orElse(null);
Long lastUpdate = Optional.ofNullable(item.getLastUpdate()).map(zdt -> zdt.toInstant().toEpochMilli())
.orElse(null);
Long lastChange = Optional.ofNullable(item.getLastChange()).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, previousState, lastUpdate,
lastChange, transformedState, stateDescription, unitSymbol);
} else {
enrichedItemDTO = new EnrichedItemDTO(itemDTO, link, state, transformedState, stateDescription,
item.getCommandDescription(locale), unitSymbol);
enrichedItemDTO = new EnrichedItemDTO(itemDTO, link, state, previousState, lastUpdate, lastChange,
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 previousState;

protected @Nullable ZonedDateTime lastUpdate;
protected @Nullable ZonedDateTime lastChange;

protected @Nullable String label;

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

@Override
public @Nullable State getPreviousState() {
return previousState;
}

@Override
public @Nullable ZonedDateTime getLastUpdate() {
return lastUpdate;
}

@Override
public @Nullable ZonedDateTime getLastChange() {
return lastChange;
}

@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) {
previousState = oldState; // update before we notify listeners
}
notifyListeners(oldState, state);
sendStateUpdatedEvent(state);
if (!oldState.equals(state)) {
if (stateChanged) {
sendStateChangedEvent(state, oldState);
lastChange = now; // update after we've notified listeners
}
lastUpdate = 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 getPreviousState();

/**
* 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 getLastUpdate();

/**
* 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 getLastChange();

/**
* 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 testGetLastUpdate() {
TestItem item = new TestItem("member1");
assertNull(item.getLastUpdate());
item.setState(PercentType.HUNDRED);
assertThat(item.getLastUpdate().toInstant().toEpochMilli() * 1.0,
is(closeTo(ZonedDateTime.now().toInstant().toEpochMilli(), 5)));
}

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

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

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

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

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