Added change and update timestamp profiles (#732)

* Added change and update timestamp profiles

Signed-off-by: Gaël L'hopital <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital 2019-04-18 12:59:15 +02:00 committed by Christoph Weitkamp
parent f4348cd6e8
commit 20ee4b8fe0
5 changed files with 250 additions and 10 deletions

View File

@ -55,15 +55,17 @@ public class SystemProfileFactory implements ProfileFactory, ProfileAdvisor, Pro
@NonNullByDefault({})
private ChannelTypeRegistry channelTypeRegistry;
private static final Set<ProfileType> SUPPORTED_PROFILE_TYPES = Stream.of(SystemProfiles.DEFAULT_TYPE,
SystemProfiles.FOLLOW_TYPE, SystemProfiles.RAWBUTTON_TOGGLE_SWITCH_TYPE,
SystemProfiles.RAWROCKER_ON_OFF_TYPE, SystemProfiles.RAWROCKER_DIMMER_TYPE, SystemProfiles.OFFSET_TYPE, SystemProfiles.RAWROCKER_PLAY_PAUSE_TYPE)
private static final Set<ProfileType> SUPPORTED_PROFILE_TYPES = Stream
.of(SystemProfiles.DEFAULT_TYPE, SystemProfiles.FOLLOW_TYPE, SystemProfiles.RAWBUTTON_TOGGLE_SWITCH_TYPE,
SystemProfiles.RAWROCKER_ON_OFF_TYPE, SystemProfiles.RAWROCKER_DIMMER_TYPE,
SystemProfiles.OFFSET_TYPE, SystemProfiles.RAWROCKER_PLAY_PAUSE_TYPE,
SystemProfiles.TIMESTAMP_UPDATE_TYPE, SystemProfiles.TIMESTAMP_CHANGE_TYPE)
.collect(Collectors.toSet());
private static final Set<ProfileTypeUID> SUPPORTED_PROFILE_TYPE_UIDS = Stream
.of(SystemProfiles.DEFAULT, SystemProfiles.FOLLOW, SystemProfiles.RAWBUTTON_TOGGLE_SWITCH,
SystemProfiles.RAWROCKER_ON_OFF, SystemProfiles.RAWROCKER_DIMMER, SystemProfiles.OFFSET, SystemProfiles.RAWROCKER_PLAY_PAUSE)
.collect(Collectors.toSet());
private static final Set<ProfileTypeUID> SUPPORTED_PROFILE_TYPE_UIDS = Stream.of(SystemProfiles.DEFAULT,
SystemProfiles.FOLLOW, SystemProfiles.RAWBUTTON_TOGGLE_SWITCH, SystemProfiles.RAWROCKER_ON_OFF,
SystemProfiles.RAWROCKER_DIMMER, SystemProfiles.OFFSET, SystemProfiles.RAWROCKER_PLAY_PAUSE,
SystemProfiles.TIMESTAMP_UPDATE, SystemProfiles.TIMESTAMP_CHANGE).collect(Collectors.toSet());
@Nullable
@Override
@ -82,6 +84,10 @@ public class SystemProfileFactory implements ProfileFactory, ProfileAdvisor, Pro
return new RawRockerPlayPauseProfile(callback);
} else if (SystemProfiles.OFFSET.equals(profileTypeUID)) {
return new SystemOffsetProfile(callback, context);
} else if (SystemProfiles.TIMESTAMP_UPDATE.equals(profileTypeUID)) {
return new TimestampUpdateProfile(callback);
} else if (SystemProfiles.TIMESTAMP_CHANGE.equals(profileTypeUID)) {
return new TimestampChangeProfile(callback);
} else {
return null;
}

View File

@ -0,0 +1,75 @@
/**
* Copyright (c) 2010-2019 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.eclipse.smarthome.core.thing.internal.profiles;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.DateTimeType;
import org.eclipse.smarthome.core.thing.profiles.ProfileCallback;
import org.eclipse.smarthome.core.thing.profiles.ProfileTypeUID;
import org.eclipse.smarthome.core.thing.profiles.StateProfile;
import org.eclipse.smarthome.core.thing.profiles.SystemProfiles;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
/**
* This is the default implementation for a change timestamp profile.
* The timestamp updates to now each time the channel or item state changes.
*
* @author Gaël L'hopital - initial contribution
*
*/
@NonNullByDefault
public class TimestampChangeProfile implements StateProfile {
private final ProfileCallback callback;
private @Nullable State previousState;
public TimestampChangeProfile(ProfileCallback callback) {
this.callback = callback;
}
@Override
public ProfileTypeUID getProfileTypeUID() {
return SystemProfiles.TIMESTAMP_CHANGE;
}
@SuppressWarnings("null")
@Override
public void onStateUpdateFromItem(State state) {
if (previousState == null || !state.equals(previousState.as(state.getClass()))) {
previousState = state;
callback.sendUpdate(new DateTimeType());
}
}
@SuppressWarnings("null")
@Override
public void onStateUpdateFromHandler(State state) {
if (previousState == null || !state.equals(previousState.as(state.getClass()))) {
previousState = state;
callback.sendUpdate(new DateTimeType());
}
}
@Override
public void onCommandFromItem(Command command) {
// no-op
}
@Override
public void onCommandFromHandler(Command command) {
// no-op
}
}

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2019 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.eclipse.smarthome.core.thing.internal.profiles;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.library.types.DateTimeType;
import org.eclipse.smarthome.core.thing.profiles.ProfileCallback;
import org.eclipse.smarthome.core.thing.profiles.ProfileTypeUID;
import org.eclipse.smarthome.core.thing.profiles.StateProfile;
import org.eclipse.smarthome.core.thing.profiles.SystemProfiles;
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.State;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is the default implementation for a state update timestamp profile.
* The timestamp updates to now each time the channel or item state is updated.
*
* @author Gaël L'hopital - initial contribution
*
*/
@NonNullByDefault
public class TimestampUpdateProfile implements StateProfile {
private final Logger logger = LoggerFactory.getLogger(TimestampUpdateProfile.class);
private final ProfileCallback callback;
public TimestampUpdateProfile(ProfileCallback callback) {
this.callback = callback;
}
@Override
public ProfileTypeUID getProfileTypeUID() {
return SystemProfiles.TIMESTAMP_UPDATE;
}
@Override
public void onStateUpdateFromItem(State state) {
logger.debug("Received state update from Item, sending timestamp to callback");
callback.sendUpdate(new DateTimeType());
}
@Override
public void onStateUpdateFromHandler(State state) {
logger.debug("Received state update from Handler, sending timestamp to callback");
callback.sendUpdate(new DateTimeType());
}
@Override
public void onCommandFromItem(Command command) {
// no-op
}
@Override
public void onCommandFromHandler(Command command) {
// no-op
}
}

View File

@ -32,6 +32,8 @@ public interface SystemProfiles {
ProfileTypeUID RAWROCKER_ON_OFF = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "rawrocker-to-on-off");
ProfileTypeUID RAWROCKER_DIMMER = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "rawrocker-to-dimmer");
ProfileTypeUID RAWROCKER_PLAY_PAUSE = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "rawrocker-to-play-pause");
ProfileTypeUID TIMESTAMP_UPDATE = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "timestamp-update");
ProfileTypeUID TIMESTAMP_CHANGE = new ProfileTypeUID(ProfileTypeUID.SYSTEM_SCOPE, "timestamp-change");
StateProfileType DEFAULT_TYPE = ProfileTypeBuilder.newState(DEFAULT, "Default").build();
@ -53,8 +55,15 @@ public interface SystemProfiles {
TriggerProfileType RAWROCKER_DIMMER_TYPE = ProfileTypeBuilder.newTrigger(RAWROCKER_DIMMER, "Raw Rocker To Dimmer")
.withSupportedItemTypes(CoreItemFactory.DIMMER)
.withSupportedChannelTypeUIDs(DefaultSystemChannelTypeProvider.SYSTEM_RAWROCKER.getUID()).build();
TriggerProfileType RAWROCKER_PLAY_PAUSE_TYPE = ProfileTypeBuilder.newTrigger(RAWROCKER_PLAY_PAUSE, "Raw Rocker To Play/Pause")
.withSupportedItemTypes(CoreItemFactory.PLAYER)
TriggerProfileType RAWROCKER_PLAY_PAUSE_TYPE = ProfileTypeBuilder
.newTrigger(RAWROCKER_PLAY_PAUSE, "Raw Rocker To Play/Pause").withSupportedItemTypes(CoreItemFactory.PLAYER)
.withSupportedChannelTypeUIDs(DefaultSystemChannelTypeProvider.SYSTEM_RAWROCKER.getUID()).build();
StateProfileType TIMESTAMP_UPDATE_TYPE = ProfileTypeBuilder.newState(TIMESTAMP_UPDATE, "Timestamp on update")
.withSupportedItemTypesOfChannel(CoreItemFactory.DATETIME).build();
StateProfileType TIMESTAMP_CHANGE_TYPE = ProfileTypeBuilder.newState(TIMESTAMP_CHANGE, "Timestamp on change")
.withSupportedItemTypesOfChannel(CoreItemFactory.DATETIME).build();
}

View File

@ -0,0 +1,79 @@
/**
* Copyright (c) 2010-2019 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.eclipse.smarthome.core.thing.internal.profiles;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import org.eclipse.smarthome.core.library.types.DateTimeType;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.thing.profiles.ProfileCallback;
import org.eclipse.smarthome.core.types.State;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
/**
* Tests for the system:timestamp-update profile
*
* @author Gaël L'hopital - initial contribution
*
*/
public class TimestampProfileTest {
@Test
public void testTimestampOnUpdate() {
ProfileCallback callback = mock(ProfileCallback.class);
TimestampUpdateProfile timestampProfile = new TimestampUpdateProfile(callback);
State state = new DecimalType(23);
ZonedDateTime now = ZonedDateTime.now();
timestampProfile.onStateUpdateFromItem(state);
ArgumentCaptor<State> capture = ArgumentCaptor.forClass(State.class);
verify(callback, times(1)).sendUpdate(capture.capture());
State result = capture.getValue();
DateTimeType updateResult = (DateTimeType) result;
ZonedDateTime timestamp = updateResult.getZonedDateTime();
long difference = ChronoUnit.MINUTES.between(now, timestamp);
assertTrue(difference < 1);
}
@Test
public void testTimestampOnChange() {
ProfileCallback callback = mock(ProfileCallback.class);
ArgumentCaptor<State> capture = ArgumentCaptor.forClass(State.class);
TimestampChangeProfile timestampProfile = new TimestampChangeProfile(callback);
timestampProfile.onStateUpdateFromItem(new DecimalType(23));
verify(callback, atLeastOnce()).sendUpdate(capture.capture());
State result = capture.getValue();
DateTimeType changeResult = (DateTimeType) result;
timestampProfile.onStateUpdateFromItem(new DecimalType(23));
verify(callback, atLeastOnce()).sendUpdate(capture.capture());
result = capture.getValue();
DateTimeType newChangeResult = (DateTimeType) result;
assertEquals(changeResult, newChangeResult);
timestampProfile.onStateUpdateFromItem(new DecimalType(24));
verify(callback, atLeastOnce()).sendUpdate(capture.capture());
result = capture.getValue();
DateTimeType updatedResult = (DateTimeType) result;
assertTrue(updatedResult.getZonedDateTime().isAfter(newChangeResult.getZonedDateTime()));
}
}