mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Add time series support for script profile (#4365)
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
+29
-13
@@ -13,6 +13,7 @@
|
||||
package org.openhab.core.automation.module.script.profile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
@@ -22,11 +23,12 @@ import org.openhab.core.config.core.ConfigParser;
|
||||
import org.openhab.core.thing.profiles.ProfileCallback;
|
||||
import org.openhab.core.thing.profiles.ProfileContext;
|
||||
import org.openhab.core.thing.profiles.ProfileTypeUID;
|
||||
import org.openhab.core.thing.profiles.StateProfile;
|
||||
import org.openhab.core.thing.profiles.TimeSeriesProfile;
|
||||
import org.openhab.core.transform.TransformationException;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.TimeSeries;
|
||||
import org.openhab.core.types.Type;
|
||||
import org.openhab.core.types.TypeParser;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
@@ -39,7 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||
* @author Jan N. Klug - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ScriptProfile implements StateProfile {
|
||||
public class ScriptProfile implements TimeSeriesProfile {
|
||||
|
||||
public static final String CONFIG_TO_ITEM_SCRIPT = "toItemScript";
|
||||
public static final String CONFIG_TO_HANDLER_SCRIPT = "toHandlerScript";
|
||||
@@ -148,21 +150,35 @@ public class ScriptProfile implements StateProfile {
|
||||
@Override
|
||||
public void onStateUpdateFromHandler(State state) {
|
||||
if (isConfigured) {
|
||||
String returnValue = executeScript(toItemScript, state);
|
||||
// special handling for UnDefType, it's not available in the TypeParser
|
||||
if ("UNDEF".equals(returnValue)) {
|
||||
callback.sendUpdate(UnDefType.UNDEF);
|
||||
} else if ("NULL".equals(returnValue)) {
|
||||
callback.sendUpdate(UnDefType.NULL);
|
||||
} else if (returnValue != null) {
|
||||
State newState = TypeParser.parseState(acceptedDataTypes, returnValue);
|
||||
if (newState != null) {
|
||||
callback.sendUpdate(newState);
|
||||
}
|
||||
transformState(state).ifPresent(callback::sendUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeSeriesFromHandler(TimeSeries timeSeries) {
|
||||
if (isConfigured) {
|
||||
TimeSeries transformedTimeSeries = new TimeSeries(timeSeries.getPolicy());
|
||||
timeSeries.getStates().forEach(entry -> {
|
||||
transformState(entry.state()).ifPresent(transformedState -> {
|
||||
transformedTimeSeries.add(entry.timestamp(), transformedState);
|
||||
});
|
||||
});
|
||||
if (transformedTimeSeries.size() > 0) {
|
||||
callback.sendTimeSeries(transformedTimeSeries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<State> transformState(State state) {
|
||||
return Optional.ofNullable(executeScript(toItemScript, state)).map(output -> {
|
||||
return switch (output) {
|
||||
case "UNDEF" -> UnDefType.UNDEF;
|
||||
case "NULL" -> UnDefType.NULL;
|
||||
default -> TypeParser.parseState(acceptedDataTypes, output);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private @Nullable String executeScript(String script, Type input) {
|
||||
if (!script.isBlank()) {
|
||||
try {
|
||||
|
||||
+71
-5
@@ -12,7 +12,9 @@
|
||||
*/
|
||||
package org.openhab.core.automation.module.script.profile;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -23,6 +25,7 @@ import static org.openhab.core.automation.module.script.profile.ScriptProfile.CO
|
||||
import static org.openhab.core.automation.module.script.profile.ScriptProfile.CONFIG_TO_HANDLER_SCRIPT;
|
||||
import static org.openhab.core.automation.module.script.profile.ScriptProfile.CONFIG_TO_ITEM_SCRIPT;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -51,6 +54,7 @@ import org.openhab.core.transform.TransformationException;
|
||||
import org.openhab.core.transform.TransformationService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.TimeSeries;
|
||||
|
||||
/**
|
||||
* The {@link ScriptProfileTest} contains tests for the {@link ScriptProfile}
|
||||
@@ -84,10 +88,12 @@ public class ScriptProfileTest extends JavaTest {
|
||||
|
||||
scriptProfile.onCommandFromHandler(OnOffType.ON);
|
||||
scriptProfile.onStateUpdateFromHandler(OnOffType.ON);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(OnOffType.ON));
|
||||
scriptProfile.onCommandFromItem(OnOffType.ON);
|
||||
|
||||
verify(transformationServiceMock, never()).transform(any(), any());
|
||||
verify(profileCallback, never()).handleCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
|
||||
@@ -142,11 +148,13 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(OnOffType.ON);
|
||||
scriptProfile.onCommandFromItem(OnOffType.ON);
|
||||
scriptProfile.onStateUpdateFromItem(OnOffType.ON);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(OnOffType.ON));
|
||||
|
||||
verify(transformationServiceMock, times(4)).transform(any(), any());
|
||||
verify(transformationServiceMock, times(5)).transform(any(), any());
|
||||
verify(profileCallback, never()).handleCommand(any());
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -163,11 +171,13 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(OnOffType.ON);
|
||||
scriptProfile.onCommandFromItem(OnOffType.ON);
|
||||
scriptProfile.onStateUpdateFromItem(OnOffType.ON);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(OnOffType.ON));
|
||||
|
||||
verify(transformationServiceMock, times(4)).transform(any(), any());
|
||||
verify(transformationServiceMock, times(5)).transform(any(), any());
|
||||
verify(profileCallback, never()).handleCommand(any());
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -187,10 +197,14 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
|
||||
verify(transformationServiceMock, times(4)).transform(any(), any());
|
||||
TimeSeries timeSeries = createTimeSeries(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(timeSeries);
|
||||
|
||||
verify(transformationServiceMock, times(5)).transform(any(), any());
|
||||
verify(profileCallback, times(2)).handleCommand(OnOffType.OFF);
|
||||
verify(profileCallback).sendUpdate(OnOffType.OFF);
|
||||
verify(profileCallback).sendCommand(OnOffType.OFF);
|
||||
verify(profileCallback).sendTimeSeries(replaceTimeSeries(timeSeries, OnOffType.OFF));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -209,10 +223,14 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
|
||||
verify(transformationServiceMock, times(2)).transform(any(), any());
|
||||
TimeSeries timeSeries = createTimeSeries(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(timeSeries);
|
||||
|
||||
verify(transformationServiceMock, times(3)).transform(any(), any());
|
||||
verify(profileCallback, never()).handleCommand(any());
|
||||
verify(profileCallback).sendUpdate(OnOffType.OFF);
|
||||
verify(profileCallback).sendCommand(OnOffType.OFF);
|
||||
verify(profileCallback).sendTimeSeries(replaceTimeSeries(timeSeries, OnOffType.OFF));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -230,11 +248,13 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(DecimalType.ZERO);
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(DecimalType.ZERO));
|
||||
|
||||
verify(transformationServiceMock, times(1)).transform(any(), any());
|
||||
verify(profileCallback, times(1)).handleCommand(OnOffType.OFF);
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -252,11 +272,13 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(DecimalType.ZERO);
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(DecimalType.ZERO));
|
||||
|
||||
verify(transformationServiceMock, times(1)).transform(any(), any());
|
||||
verify(profileCallback, times(1)).handleCommand(OnOffType.OFF);
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -275,11 +297,13 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(DecimalType.ZERO);
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(DecimalType.ZERO));
|
||||
|
||||
verify(transformationServiceMock, times(4)).transform(any(), any());
|
||||
verify(transformationServiceMock, times(5)).transform(any(), any());
|
||||
verify(profileCallback, never()).handleCommand(any());
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -297,11 +321,53 @@ public class ScriptProfileTest extends JavaTest {
|
||||
scriptProfile.onStateUpdateFromHandler(DecimalType.ZERO);
|
||||
scriptProfile.onCommandFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onStateUpdateFromItem(DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(createTimeSeries(DecimalType.ZERO));
|
||||
|
||||
verify(transformationServiceMock, times(1)).transform(any(), any());
|
||||
verify(profileCallback, times(1)).handleCommand(OnOffType.OFF);
|
||||
verify(profileCallback, never()).sendUpdate(any());
|
||||
verify(profileCallback, never()).sendCommand(any());
|
||||
verify(profileCallback, never()).sendTimeSeries(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filteredTimeSeriesTest() throws TransformationException {
|
||||
ProfileContext profileContext = ProfileContextBuilder.create().withToItemScript("inScript")
|
||||
.withAcceptedCommandTypes(List.of(OnOffType.class)).withAcceptedDataTypes(List.of(OnOffType.class))
|
||||
.withHandlerAcceptedCommandTypes(List.of(DecimalType.class)).build();
|
||||
|
||||
when(transformationServiceMock.transform(any(), eq("0"))).thenReturn(OnOffType.OFF.toString());
|
||||
when(transformationServiceMock.transform(any(), eq("1"))).thenReturn(null);
|
||||
|
||||
ScriptProfile scriptProfile = new ScriptProfile(mock(ProfileTypeUID.class), profileCallback, profileContext,
|
||||
transformationServiceMock);
|
||||
|
||||
TimeSeries timeSeries = createTimeSeries(DecimalType.ZERO, DecimalType.valueOf("1"), DecimalType.ZERO);
|
||||
scriptProfile.onTimeSeriesFromHandler(timeSeries);
|
||||
|
||||
verify(transformationServiceMock, times(3)).transform(any(), any());
|
||||
|
||||
TimeSeries transformedTimeSeries = new TimeSeries(timeSeries.getPolicy());
|
||||
timeSeries.getStates().forEach(entry -> {
|
||||
if (entry.state().equals(DecimalType.ZERO)) {
|
||||
transformedTimeSeries.add(entry.timestamp(), OnOffType.OFF);
|
||||
}
|
||||
});
|
||||
verify(profileCallback).sendTimeSeries(transformedTimeSeries);
|
||||
}
|
||||
|
||||
private TimeSeries createTimeSeries(State... states) {
|
||||
TimeSeries timeSeries = new TimeSeries(TimeSeries.Policy.ADD);
|
||||
for (State state : states) {
|
||||
timeSeries.add(Instant.now(), state);
|
||||
}
|
||||
return timeSeries;
|
||||
}
|
||||
|
||||
private TimeSeries replaceTimeSeries(TimeSeries timeSeries, State state) {
|
||||
TimeSeries newTimeSeries = new TimeSeries(timeSeries.getPolicy());
|
||||
timeSeries.getStates().forEach(entry -> newTimeSeries.add(entry.timestamp(), state));
|
||||
return newTimeSeries;
|
||||
}
|
||||
|
||||
private static class ProfileContextBuilder {
|
||||
|
||||
Reference in New Issue
Block a user