[siemensrds] Binding no longer fails if thermostat does not use optional features (#13888)

* [siemensrds] fix charset; ansi => utf-8
* [siemensrds] refactor class so CI build runs tests w/o errors
* [siemensrds] add missing UoM; fix compiler error
* [siemensrds] fix issue #13887

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
Andrew Fiddian-Green 2022-12-10 08:02:11 +00:00 committed by GitHub
parent b9f092fdb2
commit 8e31d8f0ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 67 deletions

View File

@ -83,8 +83,7 @@ public class RdsDataPoints {
* execute an HTTP GET command on the remote cloud server to retrieve the JSON
* response from the given urlString
*/
protected static String httpGenericGetJson(String apiKey, String token, String urlString)
throws RdsCloudException, IOException {
protected static String httpGenericGetJson(String apiKey, String token, String urlString) throws IOException {
/*
* NOTE: this class uses JAVAX HttpsURLConnection library instead of the
* preferred JETTY library; the reason is that JETTY does not allow sending the
@ -196,7 +195,7 @@ public class RdsDataPoints {
}
@Nullable
String pointId = indexClassToId.get(pointClass);
if (pointId != null) {
if (pointId != null && !pointId.isEmpty()) {
return pointId;
}
throw new RdsCloudException(String.format("no pointId to match pointClass \"%s\"", pointClass));
@ -250,10 +249,12 @@ public class RdsDataPoints {
Set<String> set = new HashSet<>();
String pointId;
for (ChannelMap chan : CHAN_MAP) {
pointId = pointClassToId(chan.clazz);
if (!pointId.isEmpty()) {
for (ChannelMap channel : CHAN_MAP) {
try {
pointId = pointClassToId(channel.clazz);
set.add(String.format("\"%s\"", pointId));
} catch (RdsCloudException e) {
logger.debug("{} \"{}\" not implemented; don't include in request", channel.id, channel.clazz);
}
}

View File

@ -38,6 +38,7 @@ import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,9 +47,9 @@ import com.google.gson.JsonParseException;
/**
* The {@link RdsHandler} is the OpenHab Handler for Siemens RDS smart
* thermostats
*
*
* @author Andrew Fiddian-Green - Initial contribution
*
*
*/
@NonNullByDefault
public class RdsHandler extends BaseThingHandler {
@ -229,7 +230,15 @@ public class RdsHandler extends BaseThingHandler {
continue;
}
BasePoint point = points.getPointByClass(channel.clazz);
BasePoint point;
try {
point = points.getPointByClass(channel.clazz);
} catch (RdsCloudException e) {
logger.debug("{} \"{}\" not implemented; set state to UNDEF", channel.id, channel.clazz);
updateState(channel.id, UnDefType.UNDEF);
continue;
}
State state = null;
switch (channel.id) {

View File

@ -12,6 +12,7 @@
*/
package org.openhab.binding.siemensrds.points;
import javax.measure.MetricPrefix;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -43,6 +44,12 @@ public abstract class BasePoint {
public static final String DEGREES_KELVIN = "K";
public static final String PERCENT_RELATIVE_HUMIDITY = "%r.H.";
private static final String PARTS_PER_MILLION = "ppm";
private static final String MILLI_SECOND = "ms";
private static final String MINUTE = "min";
private static final String HOUR = "h";
private static final String AMPERE = "A";
public static final int UNDEFINED_VALUE = -1;
@SerializedName("rep")
@ -68,7 +75,7 @@ public abstract class BasePoint {
@SerializedName("presentPriority")
protected int presentPriority;
private String @Nullable [] enumVals;
private String[] enumVals = {};
private boolean enumParsed = false;
protected boolean isEnum = false;
@ -79,7 +86,8 @@ public abstract class BasePoint {
if (!enumParsed) {
String descr = this.descr;
if (descr != null && descr.contains("*")) {
enumVals = descr.split("\\*");
String[] values = descr.split("\\*");
enumVals = values;
isEnum = true;
}
}
@ -107,8 +115,7 @@ public abstract class BasePoint {
public State getEnum() {
if (isEnum()) {
int index = asInt();
String[] enumVals = this.enumVals;
if (index >= 0 && enumVals != null && index < enumVals.length) {
if (index >= 0 && index < enumVals.length) {
return new StringType(enumVals[index]);
}
}
@ -127,8 +134,7 @@ public abstract class BasePoint {
*/
public Unit<?> getUnit() {
/*
* determine the Units of Measure if available; note that other possible units
* (Ampere, hours, milliseconds, minutes) are currently not implemented
* determine the Units of Measure if available
*/
String descr = this.descr;
if (descr != null) {
@ -145,6 +151,21 @@ public abstract class BasePoint {
case PERCENT_RELATIVE_HUMIDITY: {
return Units.PERCENT;
}
case AMPERE: {
return Units.AMPERE;
}
case HOUR: {
return Units.HOUR;
}
case MINUTE: {
return Units.MINUTE;
}
case MILLI_SECOND: {
return MetricPrefix.MILLI(Units.SECOND);
}
case PARTS_PER_MILLION: {
return Units.PARTS_PER_MILLION;
}
}
}
return Units.ONE;
@ -155,12 +176,9 @@ public abstract class BasePoint {
*/
public String commandJson(String newVal) {
if (isEnum()) {
String[] enumVals = this.enumVals;
if (enumVals != null) {
for (int index = 0; index < enumVals.length; index++) {
if (enumVals[index].equals(newVal)) {
return String.format("{\"value\":%d}", index);
}
for (int index = 0; index < enumVals.length; index++) {
if (enumVals[index].equals(newVal)) {
return String.format("{\"value\":%d}", index);
}
}
}

View File

@ -18,10 +18,13 @@ import static org.openhab.binding.siemensrds.internal.RdsBindingConstants.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.measure.quantity.ElectricCurrent;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.jupiter.api.Test;
@ -38,6 +41,7 @@ import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.library.unit.Units;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* test suite
@ -46,11 +50,11 @@ import org.openhab.core.types.State;
*
*/
@NonNullByDefault
public class RdsTestData {
public class TestRdsData {
private String load(String fileName) {
try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName));
BufferedReader reader = new BufferedReader(file)) {
try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName),
StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(file)) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
@ -259,14 +263,14 @@ public class RdsTestData {
State state;
QuantityType<?> celsius;
state = dataPoints.getPointByClass("'TOa").getState();
assertTrue(state instanceof QuantityType<?>);
celsius = ((QuantityType<?>) state).toUnit(SIUnits.CELSIUS);
assertNotNull(celsius);
assertEquals(18.55, celsius.floatValue(), 0.01);
assertEquals("0.0", dataPoints.getPointByClass("'HDevElLd").getState().toString());
assertEquals(new QuantityType<ElectricCurrent>(0, Units.AMPERE),
dataPoints.getPointByClass("'HDevElLd").getState());
state = dataPoints.getPointByClass("'SpHPcf").getState();
assertTrue(state instanceof QuantityType<?>);
@ -316,7 +320,7 @@ public class RdsTestData {
assertNotNull(celsius);
assertEquals(35.00, celsius.floatValue(), 0.01);
assertEquals("30.0", dataPoints.getPointByClass("'WarmUpGrdnt").getState().toString());
assertEquals(new QuantityType<>(30, Units.ONE), dataPoints.getPointByClass("'WarmUpGrdnt").getState());
state = dataPoints.getPointByClass("'TRBltnMsvAdj").getState();
assertTrue(state instanceof QuantityType<?>);
@ -324,30 +328,35 @@ public class RdsTestData {
assertNotNull(kelvin);
assertEquals(35.0, celsius.floatValue(), 0.01);
assertEquals("0.0", dataPoints.getPointByClass("'Q22Q24ElLd").getState().toString());
assertEquals("713.0", dataPoints.getPointByClass("'RAQual").getState().toString());
assertEquals("0.0", dataPoints.getPointByClass("'TmpCmfBtn").getState().toString());
assertEquals("0.0", dataPoints.getPointByClass("'CmfBtn").getState().toString());
assertEquals("0.0", dataPoints.getPointByClass("'RPscDet").getState().toString());
assertEquals("1.0", dataPoints.getPointByClass("'EnHCtl").getState().toString());
assertEquals("0.0", dataPoints.getPointByClass("'EnRPscDet").getState().toString());
assertEquals("2.0", dataPoints.getPointByClass("'OffPrtCnf").getState().toString());
assertEquals("3.0", dataPoints.getPointByClass("'OccMod").getState().toString());
assertEquals("5.0", dataPoints.getPointByClass("'REei").getState().toString());
assertEquals("2.0", dataPoints.getPointByClass("'DhwMod").getState().toString());
assertEquals("2.0", dataPoints.getPointByClass("'HCSta").getState().toString());
assertEquals("4.0", dataPoints.getPointByClass("'PrOpModRsn").getState().toString());
assertEquals("6.0", dataPoints.getPointByClass("'HCtrSet").getState().toString());
assertEquals("2.0", dataPoints.getPointByClass("'OsscSet").getState().toString());
assertEquals("4.0", dataPoints.getPointByClass("'RAQualInd").getState().toString());
assertEquals("500.0", dataPoints.getPointByClass("'KickCyc").getState().toString());
assertEquals("180000.0", dataPoints.getPointByClass("'BoDhwTiOnMin").getState().toString());
assertEquals("180000.0", dataPoints.getPointByClass("'BoDhwTiOffMin").getState().toString());
assertEquals("UNDEF", dataPoints.getPointByClass("'ROpModSched").getState().toString());
assertEquals("UNDEF", dataPoints.getPointByClass("'DhwSched").getState().toString());
assertEquals("UNDEF", dataPoints.getPointByClass("'ROpModSched").getState().toString());
assertEquals("UNDEF", dataPoints.getPointByClass("'DhwSched").getState().toString());
assertEquals("253140.0", dataPoints.getPointByClass("'OphH").getState().toString());
assertEquals(new QuantityType<>(0, Units.AMPERE), dataPoints.getPointByClass("'Q22Q24ElLd").getState());
assertEquals(new QuantityType<>(713, Units.PARTS_PER_MILLION),
dataPoints.getPointByClass("'RAQual").getState());
assertEquals(new QuantityType<>(0, Units.ONE), dataPoints.getPointByClass("'TmpCmfBtn").getState());
assertEquals(new QuantityType<>(0, Units.ONE), dataPoints.getPointByClass("'CmfBtn").getState());
assertEquals(new QuantityType<>(0, Units.ONE), dataPoints.getPointByClass("'RPscDet").getState());
assertEquals(new QuantityType<>(1, Units.ONE), dataPoints.getPointByClass("'EnHCtl").getState());
assertEquals(new QuantityType<>(0, Units.ONE), dataPoints.getPointByClass("'EnRPscDet").getState());
assertEquals(new QuantityType<>(2, Units.ONE), dataPoints.getPointByClass("'OffPrtCnf").getState());
assertEquals(new QuantityType<>(3, Units.ONE), dataPoints.getPointByClass("'OccMod").getState());
assertEquals(new QuantityType<>(5, Units.ONE), dataPoints.getPointByClass("'REei").getState());
assertEquals(new QuantityType<>(2, Units.ONE), dataPoints.getPointByClass("'DhwMod").getState());
assertEquals(new QuantityType<>(2, Units.ONE), dataPoints.getPointByClass("'HCSta").getState());
assertEquals(new QuantityType<>(4, Units.ONE), dataPoints.getPointByClass("'PrOpModRsn").getState());
assertEquals(new QuantityType<>(6, Units.ONE), dataPoints.getPointByClass("'HCtrSet").getState());
assertEquals(new QuantityType<>(2, Units.ONE), dataPoints.getPointByClass("'OsscSet").getState());
assertEquals(new QuantityType<>(4, Units.ONE), dataPoints.getPointByClass("'RAQualInd").getState());
assertEquals(new QuantityType<>(500, Units.HOUR), dataPoints.getPointByClass("'KickCyc").getState());
assertEquals(new QuantityType<>(3, Units.MINUTE), dataPoints.getPointByClass("'BoDhwTiOnMin").getState());
assertEquals(new QuantityType<>(3, Units.MINUTE), dataPoints.getPointByClass("'BoDhwTiOffMin").getState());
assertEquals(UnDefType.UNDEF, dataPoints.getPointByClass("'ROpModSched").getState());
assertEquals(UnDefType.UNDEF, dataPoints.getPointByClass("'DhwSched").getState());
assertEquals(UnDefType.UNDEF, dataPoints.getPointByClass("'ROpModSched").getState());
assertEquals(UnDefType.UNDEF, dataPoints.getPointByClass("'DhwSched").getState());
assertEquals(new QuantityType<>(253140, Units.MINUTE), dataPoints.getPointByClass("'OphH").getState());
} catch (RdsCloudException e) {
fail(e.getMessage());
}

View File

@ -371,7 +371,7 @@
-50,
80
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Outside air temperature",
"objectName": "R(1)'TOa",
"memberName": "PresentValue",
@ -420,7 +420,7 @@
0,
50
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Comfort heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHCmf",
"memberName": "PresentValue",
@ -444,7 +444,7 @@
0,
50
],
"descr": "°F",
"descr": "°F",
"descriptionName": "Pre-comfort heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHPcf",
"memberName": "PresentValue",
@ -468,7 +468,7 @@
0,
50
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Economy heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHEco",
"memberName": "PresentValue",
@ -492,7 +492,7 @@
0,
50
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Protection heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHPrt",
"memberName": "PresentValue",
@ -517,7 +517,7 @@
12,
35
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Room temperature setpoint",
"objectName": "R(1)'RHvacCoo'SpTRDtr'SpTR",
"memberName": "PresentValue",
@ -590,7 +590,7 @@
0,
50
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Room temperature",
"objectName": "R(1)'RHvacCoo'RTemp",
"memberName": "PresentValue",
@ -614,7 +614,7 @@
0,
50
],
"descr": "°C",
"descr": "°C",
"descriptionName": "Max. heating setpoint",
"objectName": "R(1)'SpTRMaxHCmf",
"memberName": "PresentValue",

View File

@ -470,7 +470,7 @@
-50,
80
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Outside air temperature",
"objectName": "R(1)'TOa",
"memberName": "PresentValue",
@ -497,7 +497,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Comfort heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHCmf",
"memberName": "PresentValue",
@ -523,7 +523,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Economy heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHPcf",
"memberName": "PresentValue",
@ -549,7 +549,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Unoccupied heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHEco",
"memberName": "PresentValue",
@ -575,7 +575,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Protection heating setpoint",
"objectName": "R(1)'RHvacCoo'TCtlH'SpHPrt",
"memberName": "PresentValue",
@ -602,7 +602,7 @@
6,
35
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Room temperature setpoint",
"objectName": "R(1)'RHvacCoo'SpTRDtr'SpTR",
"memberName": "PresentValue",
@ -681,7 +681,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Room temperature",
"objectName": "R(1)'RHvacCoo'RTemp",
"memberName": "PresentValue",
@ -707,7 +707,7 @@
0,
50
],
"descr": "<EFBFBD>C",
"descr": "°C",
"descriptionName": "Max. heating setpoint",
"objectName": "R(1)'SpTRMaxHCmf",
"memberName": "PresentValue",