mirror of
https://github.com/danieldemus/openhab-addons
synced 2026-07-29 12:34:21 +02:00
[boschshc] Support TemperatureOffset service for thermostats (#20139)
* [boschshc] Support TemperatureOffset service for thermostats - add new channel definition - re-generate i18n properties - add migration metadata - add new service implementation - register service in command extension - add new service to abstract handler implementation - add unit tests Signed-off-by: David Pace <dev@davidpace.de>
This commit is contained in:
@@ -236,14 +236,15 @@ First generation radiator thermostat.
|
||||
|
||||
**Thing Type ID**: `thermostat`
|
||||
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| silent-mode | Switch | yes | Enables or disables silent mode on thermostats. When enabled, the battery usage is higher. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| temperature-offset | Number:Temperature | yes | Temperature offset to be added or subtracted from the measured temperature. Value range for Celsius and Kelvin quantities: minimum -5°C / -5 K, maximum +5°C / +5 K. Value range for Fahrenheit quantities: minimum -9°F, maximum +9°F. Step size: 0.1°C. Non-Celsius temperature offsets will be converted to Celsius deltas automatically and rounded to the first decimal digit. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| silent-mode | Switch | yes | Enables or disables silent mode on thermostats. When enabled, the battery usage is higher. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
|
||||
### Radiator Thermostat II
|
||||
|
||||
@@ -251,15 +252,16 @@ Second generation radiator thermostat.
|
||||
|
||||
**Thing Type ID**: `thermostat-2`
|
||||
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
| display-direction | Switch | yes | Configures the display direction. `OFF` corresponds to `NORMAL` and `ON` corresponds to `REVERSED`. |
|
||||
| displayed-temperature | Switch | yes | Configures whether the measured temperature or the setpoint temperature is displayed. `OFF` corresponds to `MEASURED` and `ON` corresponds to `SETPOINT`. |
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| temperature-offset | Number:Temperature | yes | Temperature offset to be added or subtracted from the measured temperature. Value range for Celsius and Kelvin quantities: minimum -5°C / -5 K, maximum +5°C / +5 K. Value range for Fahrenheit quantities: minimum -9°F, maximum +9°F. Step size: 0.1°C. Non-Celsius temperature offsets will be converted to Celsius deltas automatically and rounded to the first decimal digit. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
| display-direction | Switch | yes | Configures the display direction. `OFF` corresponds to `NORMAL` and `ON` corresponds to `REVERSED`. |
|
||||
| displayed-temperature | Switch | yes | Configures whether the measured temperature or the setpoint temperature is displayed. `OFF` corresponds to `MEASURED` and `ON` corresponds to `SETPOINT`. |
|
||||
|
||||
### Radiator Thermostat II [+M]<a id="radiator-thermostat-ii-m"></a>
|
||||
|
||||
@@ -267,15 +269,16 @@ Second generation radiator thermostat with Matter support.
|
||||
|
||||
**Thing Type ID**: `thermostat-2-matter`
|
||||
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
| display-direction | Switch | yes | Configures the display direction. `OFF` corresponds to `NORMAL` and `ON` corresponds to `REVERSED`. |
|
||||
| displayed-temperature | Switch | yes | Configures whether the measured temperature or the setpoint temperature is displayed. `OFF` corresponds to `MEASURED` and `ON` corresponds to `SETPOINT`. |
|
||||
| Channel ID | Item Type | Writable | Description |
|
||||
| --------------------- | -------------------- | :------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| temperature | Number:Temperature | no | Current measured temperature. |
|
||||
| temperature-offset | Number:Temperature | yes | Temperature offset to be added or subtracted from the measured temperature. Value range for Celsius and Kelvin quantities: minimum -5°C / -5 K, maximum +5°C / +5 K. Value range for Fahrenheit quantities: minimum -9°F, maximum +9°F. Step size: 0.1°C. Non-Celsius temperature offsets will be converted to Celsius deltas automatically and rounded to the first decimal digit. |
|
||||
| valve-tappet-position | Number:Dimensionless | no | Current open ratio of valve tappet (0 to 100). |
|
||||
| child-lock | Switch | yes | Indicates if child lock is active. |
|
||||
| battery-level | Number | no | Current battery level percentage as integer number. Bosch-specific battery levels are mapped to numbers as follows: `OK`: 100, `LOW_BATTERY`: 10, `CRITICAL_LOW`: 1, `CRITICALLY_LOW_BATTERY`: 1, `NOT_AVAILABLE`: `UNDEF`. |
|
||||
| low-battery | Switch | no | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
|
||||
| display-direction | Switch | yes | Configures the display direction. `OFF` corresponds to `NORMAL` and `ON` corresponds to `REVERSED`. |
|
||||
| displayed-temperature | Switch | yes | Configures whether the measured temperature or the setpoint temperature is displayed. `OFF` corresponds to `MEASURED` and `ON` corresponds to `SETPOINT`. |
|
||||
|
||||
### Climate Control
|
||||
|
||||
|
||||
+2
-2
@@ -86,8 +86,8 @@ public class BoschShcCommandExtension extends AbstractConsoleCommandExtension im
|
||||
"displayedtemperatureconfiguration", "hsbcoloractuator", "humiditylevel", "illuminance",
|
||||
"impulseswitch", "intrusion", "keypad", "latestmotion", "multilevelswitch", "powermeter", "powerswitch",
|
||||
"presence", "privacymode", "roomclimatecontrol", "shuttercontact", "shuttercontrol", "silentmode",
|
||||
"smokedetectorcheck", "temperaturelevel", "userstate", "valvetappet", "vibrationsensor",
|
||||
"waterleakagesensor", "waterleakagesensorcheck", "waterleakagesensortilt");
|
||||
"smokedetectorcheck", "temperaturelevel", "temperatureoffset", "userstate", "valvetappet",
|
||||
"vibrationsensor", "waterleakagesensor", "waterleakagesensorcheck", "waterleakagesensortilt");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
@@ -79,6 +79,7 @@ public class BoschSHCBindingConstants {
|
||||
public static final String CHANNEL_TRIGGER_SCENARIO = "trigger-scenario";
|
||||
public static final String CHANNEL_POWER_SWITCH = "power-switch";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_TEMPERATURE_OFFSET = "temperature-offset";
|
||||
public static final String CHANNEL_TEMPERATURE_RATING = "temperature-rating";
|
||||
public static final String CHANNEL_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_HUMIDITY_RATING = "humidity-rating";
|
||||
|
||||
+1
-1
@@ -402,7 +402,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
|
||||
TService service, TState state) {
|
||||
try {
|
||||
service.setState(state);
|
||||
} catch (TimeoutException | ExecutionException e) {
|
||||
} catch (TimeoutException | ExecutionException | BoschSHCException e) {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String.format(
|
||||
"Error while trying to update state for service %s: %s", service.getServiceName(), e.getMessage()));
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
+6
-6
@@ -943,8 +943,8 @@ public class BridgeHandler extends BaseBridgeHandler {
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
*/
|
||||
public <T extends BoschSHCServiceState> @Nullable Response putState(String deviceId, String serviceName, T state)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
public <T extends BoschSHCServiceState> @Nullable ContentResponse putState(String deviceId, String serviceName,
|
||||
T state) throws InterruptedException, TimeoutException, ExecutionException {
|
||||
return sendState(deviceId, serviceName, state, PUT);
|
||||
}
|
||||
|
||||
@@ -963,13 +963,13 @@ public class BridgeHandler extends BaseBridgeHandler {
|
||||
* @throws TimeoutException
|
||||
* @throws ExecutionException
|
||||
*/
|
||||
public <T extends BoschSHCServiceState> @Nullable Response postState(String deviceId, String serviceName, T state)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
public <T extends BoschSHCServiceState> @Nullable ContentResponse postState(String deviceId, String serviceName,
|
||||
T state) throws InterruptedException, TimeoutException, ExecutionException {
|
||||
return sendState(deviceId, serviceName, state, POST);
|
||||
}
|
||||
|
||||
private <T extends BoschSHCServiceState> @Nullable Response sendState(String deviceId, String serviceName, T state,
|
||||
HttpMethod method) throws InterruptedException, TimeoutException, ExecutionException {
|
||||
private <T extends BoschSHCServiceState> @Nullable ContentResponse sendState(String deviceId, String serviceName,
|
||||
T state, HttpMethod method) throws InterruptedException, TimeoutException, ExecutionException {
|
||||
@Nullable
|
||||
BoschHttpClient localHttpClient = this.httpClient;
|
||||
if (localHttpClient == null) {
|
||||
|
||||
+24
-3
@@ -23,6 +23,8 @@ import org.openhab.binding.boschshc.internal.services.childlock.ChildLockService
|
||||
import org.openhab.binding.boschshc.internal.services.childlock.dto.ChildLockServiceState;
|
||||
import org.openhab.binding.boschshc.internal.services.temperaturelevel.TemperatureLevelService;
|
||||
import org.openhab.binding.boschshc.internal.services.temperaturelevel.dto.TemperatureLevelServiceState;
|
||||
import org.openhab.binding.boschshc.internal.services.temperatureoffset.TemperatureOffsetService;
|
||||
import org.openhab.binding.boschshc.internal.services.temperatureoffset.dto.TemperatureOffsetServiceState;
|
||||
import org.openhab.binding.boschshc.internal.services.valvetappet.ValveTappetService;
|
||||
import org.openhab.binding.boschshc.internal.services.valvetappet.dto.ValveTappetServiceState;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
@@ -46,10 +48,12 @@ import org.openhab.core.types.Command;
|
||||
public abstract class AbstractThermostatHandler extends AbstractBatteryPoweredDeviceHandler {
|
||||
|
||||
private ChildLockService childLockService;
|
||||
private TemperatureOffsetService temperatureOffsetService;
|
||||
|
||||
protected AbstractThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
this.childLockService = new ChildLockService();
|
||||
this.temperatureOffsetService = new TemperatureOffsetService();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,6 +64,7 @@ public abstract class AbstractThermostatHandler extends AbstractBatteryPoweredDe
|
||||
this.createService(ValveTappetService::new, this::updateChannels, List.of(CHANNEL_VALVE_TAPPET_POSITION));
|
||||
|
||||
this.registerService(this.childLockService, this::updateChannels, List.of(CHANNEL_CHILD_LOCK));
|
||||
this.registerService(this.temperatureOffsetService, this::updateChannels, List.of(CHANNEL_TEMPERATURE_OFFSET));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,6 +73,8 @@ public abstract class AbstractThermostatHandler extends AbstractBatteryPoweredDe
|
||||
|
||||
if (CHANNEL_CHILD_LOCK.equals(channelUID.getId())) {
|
||||
this.handleServiceCommand(this.childLockService, command);
|
||||
} else if (CHANNEL_TEMPERATURE_OFFSET.equals(channelUID.getId())) {
|
||||
this.handleServiceCommand(this.temperatureOffsetService, command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,17 +82,30 @@ public abstract class AbstractThermostatHandler extends AbstractBatteryPoweredDe
|
||||
* Updates the channels which are linked to the {@link TemperatureLevelService}
|
||||
* of the device.
|
||||
*
|
||||
* @param state Current state of {@link TemperatureLevelService}.
|
||||
* @param state current {@link TemperatureLevelServiceState} received from the
|
||||
* Smart Home Controller
|
||||
*/
|
||||
private void updateChannels(TemperatureLevelServiceState state) {
|
||||
super.updateState(CHANNEL_TEMPERATURE, state.getTemperatureState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channels which are linked to the {@link TemperatureOffsetService}
|
||||
* of the device.
|
||||
*
|
||||
* @param state current {@link TemperatureOffsetServiceState} received from the Smart
|
||||
* Home Controller
|
||||
*/
|
||||
private void updateChannels(TemperatureOffsetServiceState state) {
|
||||
super.updateState(CHANNEL_TEMPERATURE_OFFSET, state.getOffsetState());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the channels which are linked to the {@link ValveTappetService} of
|
||||
* the device.
|
||||
*
|
||||
* @param state Current state of {@link ValveTappetService}.
|
||||
* @param state current {@link ValveTappetServiceState} received from the Smart
|
||||
* Home Controller
|
||||
*/
|
||||
private void updateChannels(ValveTappetServiceState state) {
|
||||
super.updateState(CHANNEL_VALVE_TAPPET_POSITION, state.getPositionState());
|
||||
@@ -95,7 +115,8 @@ public abstract class AbstractThermostatHandler extends AbstractBatteryPoweredDe
|
||||
* Updates the channels which are linked to the {@link ChildLockService} of the
|
||||
* device.
|
||||
*
|
||||
* @param state Current state of {@link ChildLockService}.
|
||||
* @param state current {@link ChildLockServiceState} received from the Smart
|
||||
* Home Controller
|
||||
*/
|
||||
private void updateChannels(ChildLockServiceState state) {
|
||||
super.updateState(CHANNEL_CHILD_LOCK, state.getActiveState());
|
||||
|
||||
+17
-3
@@ -18,6 +18,7 @@ import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler;
|
||||
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
|
||||
import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
|
||||
@@ -49,7 +50,7 @@ import com.google.gson.JsonElement;
|
||||
@NonNullByDefault
|
||||
public abstract class BoschSHCService<TState extends BoschSHCServiceState> extends AbstractBoschSHCService {
|
||||
|
||||
protected final Logger logger = LoggerFactory.getLogger(BoschSHCService.class);
|
||||
private final Logger logger = LoggerFactory.getLogger(BoschSHCService.class);
|
||||
|
||||
/**
|
||||
* Class of service state
|
||||
@@ -141,8 +142,10 @@ public abstract class BoschSHCService<TState extends BoschSHCServiceState> exten
|
||||
* @throws InterruptedException
|
||||
* @throws ExecutionException
|
||||
* @throws TimeoutException
|
||||
* @throws BoschSHCException
|
||||
*/
|
||||
public void setState(TState state) throws InterruptedException, TimeoutException, ExecutionException {
|
||||
public void setState(TState state)
|
||||
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
|
||||
String deviceId = getDeviceId();
|
||||
if (deviceId == null) {
|
||||
return;
|
||||
@@ -151,7 +154,18 @@ public abstract class BoschSHCService<TState extends BoschSHCServiceState> exten
|
||||
if (bridgeHandler == null) {
|
||||
return;
|
||||
}
|
||||
bridgeHandler.putState(deviceId, getServiceName(), state);
|
||||
|
||||
@Nullable
|
||||
ContentResponse response = bridgeHandler.putState(deviceId, getServiceName(), state);
|
||||
if (response != null) {
|
||||
int status = response.getStatus();
|
||||
if (status >= 400) {
|
||||
String responseBody = response.getContentAsString();
|
||||
throw new BoschSHCException(String.format(
|
||||
"Error while updating state for service %s. SHC returned status code %d with response %s",
|
||||
getServiceName(), status, responseBody));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 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.openhab.binding.boschshc.internal.services.temperatureoffset;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
|
||||
import org.openhab.binding.boschshc.internal.services.BoschSHCService;
|
||||
import org.openhab.binding.boschshc.internal.services.temperatureoffset.dto.TemperatureOffsetServiceState;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service to configure temperature offsets for thermostats.
|
||||
*
|
||||
* @author David Pace - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TemperatureOffsetService extends BoschSHCService<TemperatureOffsetServiceState> {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(TemperatureOffsetService.class);
|
||||
|
||||
public static final String TEMPERATURE_OFFSET_SERVICE_NAME = "TemperatureOffset";
|
||||
|
||||
public static final BigDecimal MINIMUM_OFFSET = BigDecimal.valueOf(-5);
|
||||
public static final BigDecimal MAXIMUM_OFFSET = BigDecimal.valueOf(5);
|
||||
|
||||
public TemperatureOffsetService() {
|
||||
super(TEMPERATURE_OFFSET_SERVICE_NAME, TemperatureOffsetServiceState.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemperatureOffsetServiceState handleCommand(Command command) throws BoschSHCException {
|
||||
if (command instanceof DecimalType numberCommand) {
|
||||
return createNewTemperatureOffsetState(numberCommand.toBigDecimal());
|
||||
} else if (command instanceof QuantityType<?> quantityCommand) {
|
||||
@Nullable
|
||||
QuantityType<Temperature> relativeValue = getRelativeTemperatureValue(quantityCommand);
|
||||
if (relativeValue != null) {
|
||||
return createNewTemperatureOffsetState(relativeValue.toBigDecimal());
|
||||
}
|
||||
}
|
||||
return super.handleCommand(command);
|
||||
}
|
||||
|
||||
private @Nullable QuantityType<Temperature> getRelativeTemperatureValue(QuantityType<?> quantityCommand) {
|
||||
// check if the given quantity has a temperature unit
|
||||
if (!quantityCommand.getUnit().isCompatible(SIUnits.CELSIUS)) {
|
||||
logger.warn("Received a command that has no temperature quantity: {}", quantityCommand);
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
QuantityType<Temperature> temperatureCommand = (QuantityType<Temperature>) quantityCommand;
|
||||
return temperatureCommand.toUnitRelative(SIUnits.CELSIUS);
|
||||
}
|
||||
|
||||
private TemperatureOffsetServiceState createNewTemperatureOffsetState(BigDecimal offset) {
|
||||
TemperatureOffsetServiceState state = new TemperatureOffsetServiceState();
|
||||
double sanitizedOffset = sanitizeOffsetValue(offset);
|
||||
logger.debug("Temperature offset value {} was sanitized to {}.", offset, sanitizedOffset);
|
||||
state.offset = sanitizedOffset;
|
||||
return state;
|
||||
}
|
||||
|
||||
static double sanitizeOffsetValue(BigDecimal bigDecimal) {
|
||||
if (bigDecimal.compareTo(MINIMUM_OFFSET) < 0) {
|
||||
return MINIMUM_OFFSET.doubleValue();
|
||||
} else if (bigDecimal.compareTo(MAXIMUM_OFFSET) > 0) {
|
||||
return MAXIMUM_OFFSET.doubleValue();
|
||||
}
|
||||
|
||||
// accept at most one decimal digit
|
||||
if (bigDecimal.scale() > 1) {
|
||||
// round the value in case more than one decimal digits are provided
|
||||
return bigDecimal.setScale(1, RoundingMode.HALF_UP).doubleValue();
|
||||
}
|
||||
|
||||
return bigDecimal.doubleValue();
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 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.openhab.binding.boschshc.internal.services.temperatureoffset.dto;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
|
||||
/**
|
||||
* DTO for temperature offset states.
|
||||
*
|
||||
* @author David Pace - Initial contribution
|
||||
*
|
||||
*/
|
||||
public class TemperatureOffsetServiceState extends BoschSHCServiceState {
|
||||
|
||||
public TemperatureOffsetServiceState() {
|
||||
super("temperatureOffsetState");
|
||||
}
|
||||
|
||||
public double offset;
|
||||
|
||||
// Note: the following members are Double objects intentionally in order to make them nullable.
|
||||
// Those members must NOT be serialized for outgoing status updates, otherwise they will be rejected
|
||||
// by the Smart Home Controller, but they are needed for incoming service state updates
|
||||
public Double stepSize;
|
||||
public Double minOffset;
|
||||
public Double maxOffset;
|
||||
|
||||
public QuantityType<Temperature> getOffsetState() {
|
||||
return new QuantityType<>(offset, SIUnits.CELSIUS);
|
||||
}
|
||||
}
|
||||
+2
@@ -214,6 +214,8 @@ channel-type.boschshc.smoke-check.state.option.SMOKE_TEST_OK = Test successful
|
||||
channel-type.boschshc.smoke-check.state.option.SMOKE_TEST_FAILED = Test failed
|
||||
channel-type.boschshc.system-availability.label = System Availability
|
||||
channel-type.boschshc.system-availability.description = Indicates whether the intrusion detection system is available.
|
||||
channel-type.boschshc.temperature-offset.label = Temperature Offset
|
||||
channel-type.boschshc.temperature-offset.description = Temperature offset to be added or subtracted from the measured temperature.
|
||||
channel-type.boschshc.temperature-rating.label = Temperature Rating
|
||||
channel-type.boschshc.temperature-rating.description = Rating of the currently measured temperature.
|
||||
channel-type.boschshc.temperature-rating.state.option.GOOD = Good Temperature
|
||||
|
||||
@@ -275,6 +275,7 @@
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="temperature-offset" typeId="temperature-offset"/>
|
||||
<channel id="valve-tappet-position" typeId="valve-tappet-position"/>
|
||||
<channel id="child-lock" typeId="child-lock"/>
|
||||
<channel id="silent-mode" typeId="silent-mode"/>
|
||||
@@ -282,6 +283,10 @@
|
||||
<channel id="low-battery" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description-ref uri="thing-type:boschshc:device"/>
|
||||
|
||||
</thing-type>
|
||||
@@ -297,6 +302,7 @@
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="temperature-offset" typeId="temperature-offset"/>
|
||||
<channel id="valve-tappet-position" typeId="valve-tappet-position"/>
|
||||
<channel id="child-lock" typeId="child-lock"/>
|
||||
<channel id="battery-level" typeId="system.battery-level"/>
|
||||
@@ -305,6 +311,10 @@
|
||||
<channel id="displayed-temperature" typeId="displayed-temperature"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description-ref uri="thing-type:boschshc:device"/>
|
||||
|
||||
</thing-type>
|
||||
@@ -320,6 +330,7 @@
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="temperature-offset" typeId="temperature-offset"/>
|
||||
<channel id="valve-tappet-position" typeId="valve-tappet-position"/>
|
||||
<channel id="child-lock" typeId="child-lock"/>
|
||||
<channel id="battery-level" typeId="system.battery-level"/>
|
||||
@@ -328,6 +339,10 @@
|
||||
<channel id="displayed-temperature" typeId="displayed-temperature"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description-ref uri="thing-type:boschshc:device"/>
|
||||
|
||||
</thing-type>
|
||||
@@ -730,6 +745,16 @@
|
||||
<state min="0" max="40" step="0.5" pattern="%.1f %unit%" readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperature-offset">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature Offset</label>
|
||||
<description>Temperature offset to be added or subtracted from the measured temperature.</description>
|
||||
<tags>
|
||||
<tag>Temperature</tag>
|
||||
</tags>
|
||||
<state min="-9" max="9" step="0.1" pattern="%.1f %unit%" readOnly="false"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="temperature-rating">
|
||||
<item-type>String</item-type>
|
||||
<label>Temperature Rating</label>
|
||||
|
||||
@@ -38,4 +38,28 @@
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
<thing-type uid="boschshc:thermostat">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="temperature-offset">
|
||||
<type>boschshc:temperature-offset</type>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
<thing-type uid="boschshc:thermostat-2">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="temperature-offset">
|
||||
<type>boschshc:temperature-offset</type>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
<thing-type uid="boschshc:thermostat-2-matter">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="temperature-offset">
|
||||
<type>boschshc:temperature-offset</type>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
||||
|
||||
+134
-3
@@ -12,9 +12,9 @@
|
||||
*/
|
||||
package org.openhab.binding.boschshc.internal.devices.thermostat;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@@ -27,10 +27,14 @@ import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDevic
|
||||
import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
|
||||
import org.openhab.binding.boschshc.internal.services.childlock.dto.ChildLockServiceState;
|
||||
import org.openhab.binding.boschshc.internal.services.childlock.dto.ChildLockState;
|
||||
import org.openhab.binding.boschshc.internal.services.temperatureoffset.TemperatureOffsetService;
|
||||
import org.openhab.binding.boschshc.internal.services.temperatureoffset.dto.TemperatureOffsetServiceState;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
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.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
@@ -51,6 +55,7 @@ public abstract class AbstractThermostatHandlerTest<T extends AbstractThermostat
|
||||
extends AbstractBatteryPoweredDeviceHandlerTest<T> {
|
||||
|
||||
private @Captor @NonNullByDefault({}) ArgumentCaptor<ChildLockServiceState> childLockServiceStateCaptor;
|
||||
private @Captor @NonNullByDefault({}) ArgumentCaptor<TemperatureOffsetServiceState> temperatureOffsetCaptor;
|
||||
|
||||
@Test
|
||||
void testHandleCommandChildLockService() throws InterruptedException, TimeoutException, ExecutionException {
|
||||
@@ -113,4 +118,130 @@ public abstract class AbstractThermostatHandlerTest<T extends AbstractThermostat
|
||||
verify(getCallback()).stateUpdated(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK), OnOffType.ON);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdateChannelsTemperatureOffsetService() {
|
||||
JsonElement jsonObject = JsonParser.parseString("""
|
||||
{
|
||||
"@type": "temperatureOffsetState",
|
||||
"offset": 1.3,
|
||||
"stepSize": 0.1,
|
||||
"minOffset": -5.0,
|
||||
"maxOffset": 5.0
|
||||
}\
|
||||
""");
|
||||
getFixture().processUpdate(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME, jsonObject);
|
||||
verify(getCallback()).stateUpdated(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(1.3d, SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeCelsius()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(-1.3d, SIUnits.CELSIUS));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(-1.3d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeCelsiusExceedMaxOffset()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(6d, SIUnits.CELSIUS));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(5d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeFahrenheit()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(-1.3d, ImperialUnits.FAHRENHEIT));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(-0.7d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeFahrenheitExceedMaxOffset()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(10d, ImperialUnits.FAHRENHEIT));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(5d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeKelvin()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(-1.3d, Units.KELVIN));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(-1.3d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceQuantityTypeDimensionless()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new QuantityType<>(-1.3d, Units.ONE));
|
||||
verify(getBridgeHandler(), times(0)).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceDecimalType()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET),
|
||||
new DecimalType(-1.3d));
|
||||
verify(getBridgeHandler()).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), temperatureOffsetCaptor.capture());
|
||||
TemperatureOffsetServiceState state = temperatureOffsetCaptor.getValue();
|
||||
assertNull(state.minOffset);
|
||||
assertNull(state.maxOffset);
|
||||
assertNull(state.stepSize);
|
||||
assertEquals(-1.3d, state.offset, 0.001d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHandleCommandTemperatureOffsetServiceInvalidCommand()
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
getFixture().handleCommand(
|
||||
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_TEMPERATURE_OFFSET), OnOffType.ON);
|
||||
verify(getBridgeHandler(), times(0)).putState(eq(getDeviceID()),
|
||||
eq(TemperatureOffsetService.TEMPERATURE_OFFSET_SERVICE_NAME), any());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ class IntrusionDetectionControlStateServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void setState() throws InterruptedException, TimeoutException, ExecutionException {
|
||||
void setState() throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
|
||||
fixture.setState(testState);
|
||||
verify(bridgeHandler).putState(BoschSHCBindingConstants.SERVICE_INTRUSION_DETECTION,
|
||||
"IntrusionDetectionControl", testState);
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 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.openhab.binding.boschshc.internal.services.temperatureoffset;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TemperatureOffsetService}.
|
||||
*
|
||||
* @author David Pace - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class TemperatureOffsetServiceTest {
|
||||
|
||||
@Test
|
||||
void sanitizeOffsetValue() {
|
||||
assertEquals(-5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(-6)), 0.001d);
|
||||
assertEquals(-5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(-5.1)), 0.001d);
|
||||
|
||||
assertEquals(5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(6)), 0.001d);
|
||||
assertEquals(5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(5.1)), 0.001d);
|
||||
|
||||
assertEquals(-5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(-5)), 0.001d);
|
||||
assertEquals(-5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(-5d)), 0.001d);
|
||||
|
||||
assertEquals(5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(5)), 0.001d);
|
||||
assertEquals(5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(5d)), 0.001d);
|
||||
|
||||
assertEquals(0.6d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(0.56d)), 0.001d);
|
||||
assertEquals(0.5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(0.54)), 0.001d);
|
||||
assertEquals(0.5d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(0.548)), 0.001d);
|
||||
|
||||
assertEquals(-1.9d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(-1.9d)), 0.001d);
|
||||
assertEquals(1.9d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(1.9d)), 0.001d);
|
||||
assertEquals(0d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(0)), 0.001d);
|
||||
assertEquals(0d, TemperatureOffsetService.sanitizeOffsetValue(BigDecimal.valueOf(0d)), 0.001d);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2026 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.openhab.binding.boschshc.internal.services.temperatureoffset.dto;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.boschshc.internal.serialization.GsonUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TemperatureOffsetServiceState}.
|
||||
*
|
||||
* @author David Pace - Initial contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class TemperatureOffsetServiceStateTest {
|
||||
@Test
|
||||
void testSerialization() {
|
||||
TemperatureOffsetServiceState state = new TemperatureOffsetServiceState();
|
||||
String json = GsonUtils.DEFAULT_GSON_INSTANCE.toJson(state);
|
||||
assertTrue(json.contains("offset"));
|
||||
assertTrue(json.contains("0.0"));
|
||||
|
||||
// make sure the nullable Double objects are not serialized
|
||||
assertFalse(json.contains("stepSize"));
|
||||
assertFalse(json.contains("minOffset"));
|
||||
assertFalse(json.contains("maxOffset"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user