- [In-Wall Switch](#in-wall-switch)
- [Compact Smart Plug](#compact-smart-plug)
- [Twinguard Smoke Detector](#twinguard-smoke-detector)
- - [Door/Window Contact](#doorwindow-contact)
+ - [Door/Window Contact](#door-window-contact)
- [Motion Detector](#motion-detector)
- [Shutter Control](#shutter-control)
- [Thermostat](#thermostat)
| temperature | Number:Temperature | ☐ | Current measured temperature. |
| valve-tappet-position | Number:Dimensionless | ☐ | Current open ratio of valve tappet (0 to 100). |
| child-lock | Switch | ☑ | Indicates if child lock is active. |
+| silent-mode | Switch | ☑ | Enables or disables silent mode on thermostats. When enabled, the battery usage is higher. |
| battery-level | Number | ☐ | 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 | ☐ | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
| brightness | Dimmer | ☑ | Regulates the brightness on a percentage scale from 0 to 100%. |
| color | Color | ☑ | The color of the emitted light. |
-### Smoke detector
+### Smoke Detector
The smoke detector warns you in case of fire.
public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_BRIGHTNESS = "brightness";
public static final String CHANNEL_SMOKE_CHECK = "smoke-check";
+ public static final String CHANNEL_SILENT_MODE = "silent-mode";
// static device/service names
public static final String SERVICE_INTRUSION_DETECTION = "intrusionDetectionSystem";
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
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.silentmode.SilentModeService;
+import org.openhab.binding.boschshc.internal.services.silentmode.dto.SilentModeServiceState;
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.valvetappet.ValveTappetService;
* Handler for a thermostat device.
*
* @author Christian Oeing - Initial contribution
+ * @author David Pace - Added silent mode service
*/
@NonNullByDefault
public final class ThermostatHandler extends AbstractBatteryPoweredDeviceHandler {
private ChildLockService childLockService;
+ private SilentModeService silentModeService;
public ThermostatHandler(Thing thing) {
super(thing);
this.childLockService = new ChildLockService();
+ this.silentModeService = new SilentModeService();
}
@Override
this.createService(TemperatureLevelService::new, this::updateChannels, List.of(CHANNEL_TEMPERATURE));
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.silentModeService, this::updateChannels, List.of(CHANNEL_SILENT_MODE));
}
@Override
case CHANNEL_CHILD_LOCK:
this.handleServiceCommand(this.childLockService, command);
break;
+ case CHANNEL_SILENT_MODE:
+ this.handleServiceCommand(this.silentModeService, command);
+ break;
}
}
private void updateChannels(ChildLockServiceState state) {
super.updateState(CHANNEL_CHILD_LOCK, state.getActiveState());
}
+
+ /**
+ * Updates the channels which are linked to the {@link SilentModeService} of the device.
+ *
+ * @param state current state of {@link SilentModeService}
+ */
+ private void updateChannels(SilentModeServiceState state) {
+ super.updateState(CHANNEL_SILENT_MODE, state.toOnOffType());
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2023 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.silentmode;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.BoschSHCService;
+import org.openhab.binding.boschshc.internal.services.silentmode.dto.SilentModeServiceState;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.types.Command;
+
+/**
+ * Service to get and set the silent mode of thermostats.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class SilentModeService extends BoschSHCService<SilentModeServiceState> {
+
+ public SilentModeService() {
+ super("SilentMode", SilentModeServiceState.class);
+ }
+
+ @Override
+ public SilentModeServiceState handleCommand(Command command) throws BoschSHCException {
+ if (command instanceof OnOffType onOffCommand) {
+ SilentModeServiceState serviceState = new SilentModeServiceState();
+ serviceState.mode = SilentModeState.fromOnOffType(onOffCommand);
+ return serviceState;
+ }
+ return super.handleCommand(command);
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2023 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.silentmode;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.OnOffType;
+
+/**
+ * Enum for possible silent mode states.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public enum SilentModeState {
+ MODE_NORMAL,
+ MODE_SILENT;
+
+ public static SilentModeState fromOnOffType(OnOffType onOffType) {
+ return onOffType == OnOffType.ON ? SilentModeState.MODE_SILENT : SilentModeState.MODE_NORMAL;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2010-2023 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.silentmode.dto;
+
+import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
+import org.openhab.binding.boschshc.internal.services.silentmode.SilentModeState;
+import org.openhab.core.library.types.OnOffType;
+
+/**
+ * Represents the state of the silent mode for thermostats.
+ * <p>
+ * Example JSON for normal mode:
+ *
+ * <pre>
+ * {
+ * "@type": "silentModeState",
+ * "mode": "MODE_NORMAL"
+ * }
+ * </pre>
+ *
+ * Example JSON for silent mode:
+ *
+ * <pre>
+ * {
+ * "@type": "silentModeState",
+ * "mode": "MODE_SILENT"
+ * }
+ * </pre>
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+public class SilentModeServiceState extends BoschSHCServiceState {
+
+ public SilentModeServiceState() {
+ super("silentModeState");
+ }
+
+ public SilentModeState mode;
+
+ public OnOffType toOnOffType() {
+ return mode == SilentModeState.MODE_SILENT ? OnOffType.ON : OnOffType.OFF;
+ }
+}
channel-type.boschshc.camera-notification.state.option.ENABLED = Enable notifications
channel-type.boschshc.camera-notification.state.option.DISABLED = Disable notifications
channel-type.boschshc.child-lock.label = Child Lock
-channel-type.boschshc.child-lock.description = Indicates if it is possible to set the desired temperature on the device.
+channel-type.boschshc.child-lock.description = Enables or disables the child lock on the device.
channel-type.boschshc.combined-rating.label = Combined Rating
channel-type.boschshc.combined-rating.description = Combined rating of the air quality.
channel-type.boschshc.combined-rating.state.option.GOOD = Good Quality
channel-type.boschshc.purity.description = Purity of the air. A higher value indicates a higher pollution.
channel-type.boschshc.setpoint-temperature.label = Setpoint Temperature
channel-type.boschshc.setpoint-temperature.description = Desired temperature.
+channel-type.boschshc.silent-mode.label = Silent Mode
+channel-type.boschshc.silent-mode.description = Enables or disables silent mode on thermostats. When enabled, the battery usage is higher.
+channel-type.boschshc.silent-mode.state.option.MODE_NORMAL = Silent mode disabled (lower battery usage)
+channel-type.boschshc.silent-mode.state.option.MODE_SILENT = Silent mode enabled (higher battery usage)
channel-type.boschshc.smoke-check.label = Smoke Check State
channel-type.boschshc.smoke-check.description = State of last smoke detector check.
channel-type.boschshc.smoke-check.state.option.NONE = None
<channel id="temperature" typeId="temperature"/>
<channel id="valve-tappet-position" typeId="valve-tappet-position"/>
<channel id="child-lock" typeId="child-lock"/>
+ <channel id="silent-mode" typeId="silent-mode"/>
<channel id="battery-level" typeId="system.battery-level"/>
<channel id="low-battery" typeId="system.low-battery"/>
</channels>
<channel-type id="child-lock">
<item-type>Switch</item-type>
<label>Child Lock</label>
- <description>Indicates if it is possible to set the desired temperature on the device.</description>
+ <description>Enables or disables the child lock on the device.</description>
+ </channel-type>
+
+ <channel-type id="silent-mode">
+ <item-type>Switch</item-type>
+ <label>Silent Mode</label>
+ <description>Enables or disables silent mode on thermostats. When enabled, the battery usage is higher.</description>
+ <state>
+ <options>
+ <option value="MODE_NORMAL">Silent mode disabled (lower battery usage)</option>
+ <option value="MODE_SILENT">Silent mode enabled (higher battery usage)</option>
+ </options>
+ </state>
</channel-type>
</thing:thing-descriptions>
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
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.silentmode.SilentModeState;
+import org.openhab.binding.boschshc.internal.services.silentmode.dto.SilentModeServiceState;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
*
*/
@NonNullByDefault
-public class ThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<ThermostatHandler> {
+class ThermostatHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<ThermostatHandler> {
private @Captor @NonNullByDefault({}) ArgumentCaptor<ChildLockServiceState> childLockServiceStateCaptor;
+ private @Captor @NonNullByDefault({}) ArgumentCaptor<SilentModeServiceState> silentModeServiceStateCaptor;
+
@Override
protected ThermostatHandler createFixture() {
return new ThermostatHandler(getThing());
}
@Test
- public void testHandleCommand()
+ void testHandleCommandChildLockService()
throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK),
OnOffType.ON);
}
@Test
- public void testHandleCommandUnknownCommand() {
+ void testHandleCommandSilentModeService()
+ throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SILENT_MODE),
+ OnOffType.ON);
+ verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("SilentMode"),
+ silentModeServiceStateCaptor.capture());
+ SilentModeServiceState state = silentModeServiceStateCaptor.getValue();
+ assertSame(SilentModeState.MODE_SILENT, state.mode);
+ }
+
+ @Test
+ void testHandleCommandUnknownCommandChildLockService() {
getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK),
new DecimalType(42));
ThingStatusInfo expectedThingStatusInfo = ThingStatusInfoBuilder
}
@Test
- public void testUpdateChannelsTemperatureLevelService() {
+ void testHandleCommandUnknownCommandSilentModeService() {
+ getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SILENT_MODE),
+ new DecimalType(42));
+ ThingStatusInfo expectedThingStatusInfo = ThingStatusInfoBuilder
+ .create(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR)
+ .withDescription(
+ "Error when service SilentMode should handle command org.openhab.core.library.types.DecimalType: SilentMode: Can not handle command org.openhab.core.library.types.DecimalType")
+ .build();
+ verify(getCallback()).statusUpdated(getThing(), expectedThingStatusInfo);
+ }
+
+ @Test
+ void testUpdateChannelsTemperatureLevelService() {
JsonElement jsonObject = JsonParser.parseString(
"{\n" + " \"@type\": \"temperatureLevelState\",\n" + " \"temperature\": 21.5\n" + " }");
getFixture().processUpdate("TemperatureLevel", jsonObject);
}
@Test
- public void testUpdateChannelsValveTappetService() {
+ void testUpdateChannelsValveTappetService() {
JsonElement jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"valveTappetState\",\n" + " \"position\": 42\n" + " }");
getFixture().processUpdate("ValveTappet", jsonObject);
}
@Test
- public void testUpdateChannelsChildLockService() {
+ void testUpdateChannelsChildLockService() {
JsonElement jsonObject = JsonParser
.parseString("{\n" + " \"@type\": \"childLockState\",\n" + " \"childLock\": \"ON\"\n" + " }");
getFixture().processUpdate("Thermostat", jsonObject);
verify(getCallback()).stateUpdated(
new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_CHILD_LOCK), OnOffType.ON);
}
+
+ @Test
+ void testUpdateChannelsSilentModeService() {
+ JsonElement jsonObject = JsonParser.parseString("{\"@type\": \"silentModeState\", \"mode\": \"MODE_SILENT\"}");
+ getFixture().processUpdate("SilentMode", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SILENT_MODE), OnOffType.ON);
+ }
+
+ @Test
+ void testUpdateChannelsSilentModeServiceNormal() {
+ JsonElement jsonObject = JsonParser.parseString("{\"@type\": \"silentModeState\", \"mode\": \"MODE_NORMAL\"}");
+ getFixture().processUpdate("SilentMode", jsonObject);
+ verify(getCallback()).stateUpdated(
+ new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SILENT_MODE), OnOffType.OFF);
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2023 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.silentmode;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.core.library.types.OnOffType;
+
+/**
+ * Unit tests for {@link SilentModeState}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+class SilentModeStateTest {
+
+ @Test
+ void fromOnOffType() {
+ assertSame(SilentModeState.MODE_NORMAL, SilentModeState.fromOnOffType(OnOffType.OFF));
+ assertSame(SilentModeState.MODE_SILENT, SilentModeState.fromOnOffType(OnOffType.ON));
+ }
+}