]> git.basschouten.com Git - openhab-addons.git/commitdiff
[boschshc] Support smoke detector (#13760)
authorGerd Zanker <gerd.zanker@web.de>
Sat, 10 Dec 2022 10:18:13 +0000 (11:18 +0100)
committerGitHub <noreply@github.com>
Sat, 10 Dec 2022 10:18:13 +0000 (11:18 +0100)
* Add smoke detector service and add it to twinguard handler
* Add handler for smoke detector
* Support for smoke detector

added smoke detector device with SmokeDetectorCheckService
added SmokeDetectorCheckService to TwinguardHandler

added tests for smoke detector code
updated smoke detector code to latest boschshc version after cherry-picks of initial code from Christian Oeing

* re-generate i18n file, refactoring of smoke detector code to use abstract base classes
* Fix typos
* Add unit test for PlayPauseType commands
* Add unit test for SmokeDetectorCheckState
* Re-add null annotation
* Fix warning

Signed-off-by: Christian Oeing <christian.oeing@slashgames.org>
Signed-off-by: Gerd Zanker <gerd.zanker@web.de>
Signed-off-by: David Pace <dev@davidpace.de>
16 files changed:
bundles/org.openhab.binding.boschshc/README.md
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/AbstractBatteryPoweredDeviceHandler.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/twinguard/TwinguardHandler.java
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckService.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckState.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/dto/SmokeDetectorCheckServiceState.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties
bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandlerTest.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandlerTest.java [new file with mode: 0644]
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/twinguard/TwinguardHandlerTest.java
bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckStateTest.java [new file with mode: 0644]

index f93813689cf4334e2f7fb00e71b30b81941e4e1e..cd2fe0b83844e380ae892aeba76f6585f2dfe9a4 100644 (file)
@@ -17,6 +17,7 @@ Binding for the Bosch Smart Home.
     - [Security Camera Eyes](#security-camera-eyes)
     - [Intrusion Detection System](#intrusion-detection-system)
     - [Smart Bulb](#smart-bulb)
+    - [Smoke Detector](#smoke-detector)
   - [Limitations](#limitations)
   - [Discovery](#discovery)
   - [Bridge Configuration](#bridge-configuration)
@@ -68,6 +69,7 @@ The Twinguard smoke detector warns you in case of fire and constantly monitors t
 | combined-rating    | String               | &#9744;  | Combined rating of the air quality.                                                               |
 | battery-level      | Number               | &#9744;  | 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               | &#9744;  | Indicates whether the battery is low (`ON`) or OK (`OFF`). |
+| smoke-check        | String               | &#9745;  | State of the smoke check. Also used to request a new smoke check.                                 |
 
 ### Door/Window Contact
 
@@ -191,6 +193,17 @@ A smart bulb connected to the bridge via Zigbee such as a Ledvance Smart+ bulb.
 | brightness      | Dimmer    | &#9745;  | Regulates the brightness on a percentage scale from 0 to 100%. |
 | color           | Color     | &#9745;  | The color of the emitted light.                                |
 
+### Smoke detector
+
+The smoke detector warns you in case of fire.
+
+**Thing Type ID**: `smoke-detector`
+
+| Channel Type ID    | Item Type            | Writable | Description                                                                                       |
+| ------------------ | -------------------- | :------: | ------------------------------------------------------------------------------------------------- |
+| smoke-check        | String               | &#9745;  | State of the smoke check. Also used to request a new smoke check.                                 |
+
+
 ## Limitations
 
 - Discovery of Things
index 4e87b10844f93e1de8c6b0f48c749c58169825f9..56729066ca4f095c150afc24bc493a65d712f90b 100644 (file)
@@ -30,7 +30,7 @@ import org.openhab.core.thing.Thing;
  *
  */
 @NonNullByDefault
-public class AbstractBatteryPoweredDeviceHandler extends BoschSHCDeviceHandler {
+public abstract class AbstractBatteryPoweredDeviceHandler extends BoschSHCDeviceHandler {
 
     /**
      * Service to monitor the battery level of the device
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandler.java
new file mode 100644 (file)
index 0000000..e51067c
--- /dev/null
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2010-2022 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.devices;
+
+import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.SmokeDetectorCheckService;
+import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.dto.SmokeDetectorCheckServiceState;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
+import org.openhab.core.types.Command;
+
+/**
+ * Abstract handler implementation for devices with a smoke detector.
+ *
+ * @author Christian Oeing - Initial contribution
+ * @author Gerd Zanker - AbstractSmokeDetectorHandler refactoring for reuse
+ */
+@NonNullByDefault
+public abstract class AbstractSmokeDetectorHandler extends AbstractBatteryPoweredDeviceHandler {
+
+    private SmokeDetectorCheckService smokeDetectorCheckService;
+
+    public AbstractSmokeDetectorHandler(Thing thing) {
+        super(thing);
+        this.smokeDetectorCheckService = new SmokeDetectorCheckService();
+    }
+
+    @Override
+    protected void initializeServices() throws BoschSHCException {
+        super.initializeServices();
+
+        this.registerService(smokeDetectorCheckService, this::updateChannels, List.of(CHANNEL_SMOKE_CHECK));
+    }
+
+    @Override
+    public void handleCommand(ChannelUID channelUID, Command command) {
+        super.handleCommand(channelUID, command);
+
+        switch (channelUID.getId()) {
+            case CHANNEL_SMOKE_CHECK:
+                this.handleServiceCommand(this.smokeDetectorCheckService, command);
+                break;
+        }
+    }
+
+    private void updateChannels(SmokeDetectorCheckServiceState state) {
+        updateState(CHANNEL_SMOKE_CHECK, new StringType(state.value.toString()));
+    }
+}
index 4425b76909b7658db8701319d6a0f2bd32baa01f..9f62e8ccec6c46513fd002b99d57b4cf06a71839 100644 (file)
@@ -23,6 +23,7 @@ import org.openhab.core.thing.ThingTypeUID;
  * @author Christian Oeing - added Shutter Control, ThermostatHandler
  * @author Christian Oeing - Added WallThermostatHandler
  * @author David Pace - Added cameras, intrusion detection system, smart plugs, battery state support and smart bulbs
+ * @author Christian Oeing - Added smoke detector
  */
 @NonNullByDefault
 public class BoschSHCBindingConstants {
@@ -46,6 +47,7 @@ public class BoschSHCBindingConstants {
             "intrusion-detection-system");
     public static final ThingTypeUID THING_TYPE_SMART_PLUG_COMPACT = new ThingTypeUID(BINDING_ID, "smart-plug-compact");
     public static final ThingTypeUID THING_TYPE_SMART_BULB = new ThingTypeUID(BINDING_ID, "smart-bulb");
+    public static final ThingTypeUID THING_TYPE_SMOKE_DETECTOR = new ThingTypeUID(BINDING_ID, "smoke-detector");
 
     // List of all Channel IDs
     // Auto-generated from thing-types.xml via script, don't modify
@@ -79,6 +81,7 @@ public class BoschSHCBindingConstants {
     public static final String CHANNEL_LOW_BATTERY = "low-battery";
     public static final String CHANNEL_COLOR = "color";
     public static final String CHANNEL_BRIGHTNESS = "brightness";
+    public static final String CHANNEL_SMOKE_CHECK = "smoke-check";
 
     // static device/service names
     public static final String SERVICE_INTRUSION_DETECTION = "intrusionDetectionSystem";
index 1de7728829eb6cc971bb950be6e8c3d60439b8e4..01b75eab74fe1630a7f7e0470e61ffcd0824aaa9 100644 (file)
@@ -29,6 +29,7 @@ import org.openhab.binding.boschshc.internal.devices.motiondetector.MotionDetect
 import org.openhab.binding.boschshc.internal.devices.plug.PlugHandler;
 import org.openhab.binding.boschshc.internal.devices.shuttercontrol.ShutterControlHandler;
 import org.openhab.binding.boschshc.internal.devices.smartbulb.SmartBulbHandler;
+import org.openhab.binding.boschshc.internal.devices.smokedetector.SmokeDetectorHandler;
 import org.openhab.binding.boschshc.internal.devices.thermostat.ThermostatHandler;
 import org.openhab.binding.boschshc.internal.devices.twinguard.TwinguardHandler;
 import org.openhab.binding.boschshc.internal.devices.wallthermostat.WallThermostatHandler;
@@ -50,6 +51,7 @@ import org.osgi.service.component.annotations.Component;
  * @author Christian Oeing - Added Shutter Control and ThermostatHandler; refactored handler mapping
  * @author Christian Oeing - Added WallThermostatHandler
  * @author David Pace - Added cameras, intrusion detection system and smart plugs
+ * @author Christian Oeing - Added smoke detector
  */
 @NonNullByDefault
 @Component(configurationPid = "binding.boschshc", service = ThingHandlerFactory.class)
@@ -79,7 +81,8 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory {
             new ThingTypeHandlerMapping(THING_TYPE_CAMERA_EYES, CameraHandler::new),
             new ThingTypeHandlerMapping(THING_TYPE_INTRUSION_DETECTION_SYSTEM, IntrusionDetectionHandler::new),
             new ThingTypeHandlerMapping(THING_TYPE_SMART_PLUG_COMPACT, PlugHandler::new),
-            new ThingTypeHandlerMapping(THING_TYPE_SMART_BULB, SmartBulbHandler::new));
+            new ThingTypeHandlerMapping(THING_TYPE_SMART_BULB, SmartBulbHandler::new),
+            new ThingTypeHandlerMapping(THING_TYPE_SMOKE_DETECTOR, SmokeDetectorHandler::new));
 
     @Override
     public boolean supportsThingType(ThingTypeUID thingTypeUID) {
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandler.java
new file mode 100644 (file)
index 0000000..fc38527
--- /dev/null
@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2010-2022 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.devices.smokedetector;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandler;
+import org.openhab.core.thing.Thing;
+
+/**
+ * The smoke detector warns you in case of fire.
+ *
+ * @author Christian Oeing - Initial contribution
+ * @author Gerd Zanker - AbstractSmokeDetectorHandler refactoring for reuse
+ */
+@NonNullByDefault
+public class SmokeDetectorHandler extends AbstractSmokeDetectorHandler {
+
+    public SmokeDetectorHandler(Thing thing) {
+        super(thing);
+    }
+}
index a4b0f3ac8244d7bb3422943c279d6487cfa7fb16..bcb01292a69977e6e7fb7c57f3220f16db616bc9 100644 (file)
@@ -20,7 +20,7 @@ import javax.measure.quantity.Dimensionless;
 import javax.measure.quantity.Temperature;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandler;
+import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandler;
 import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
 import org.openhab.binding.boschshc.internal.services.airqualitylevel.AirQualityLevelService;
 import org.openhab.binding.boschshc.internal.services.airqualitylevel.dto.AirQualityLevelServiceState;
@@ -35,9 +35,11 @@ import org.openhab.core.thing.Thing;
  *
  * @author Stefan Kästle - Initial contribution
  * @author Christian Oeing - Use service instead of custom logic
+ * @author Christian Oeing - Add smoke detector service
+ * @author Gerd Zanker - AbstractSmokeDetectorHandler refactoring for reuse
  */
 @NonNullByDefault
-public class TwinguardHandler extends AbstractBatteryPoweredDeviceHandler {
+public class TwinguardHandler extends AbstractSmokeDetectorHandler {
 
     public TwinguardHandler(Thing thing) {
         super(thing);
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckService.java
new file mode 100644 (file)
index 0000000..8fa26d9
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2010-2022 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.smokedetectorcheck;
+
+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.smokedetectorcheck.dto.SmokeDetectorCheckServiceState;
+import org.openhab.core.library.types.PlayPauseType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.types.Command;
+
+/**
+ * Returns the result of the last smoke test and is used to request a new smoke test.
+ * 
+ * @author Christian Oeing - Initial contribution
+ */
+@NonNullByDefault
+public class SmokeDetectorCheckService extends BoschSHCService<SmokeDetectorCheckServiceState> {
+
+    public SmokeDetectorCheckService() {
+        super("SmokeDetectorCheck", SmokeDetectorCheckServiceState.class);
+    }
+
+    @Override
+    public SmokeDetectorCheckServiceState handleCommand(Command command) throws BoschSHCException {
+        if (command instanceof StringType) {
+            var stringCommand = (StringType) command;
+            var state = new SmokeDetectorCheckServiceState();
+            state.value = SmokeDetectorCheckState.from(stringCommand.toString());
+            return state;
+        }
+
+        if (command instanceof PlayPauseType) {
+            var playPauseCommand = (PlayPauseType) command;
+            if (playPauseCommand.equals(PlayPauseType.PLAY)) {
+                var state = new SmokeDetectorCheckServiceState();
+                state.value = SmokeDetectorCheckState.SMOKE_TEST_REQUESTED;
+                return state;
+            }
+        }
+
+        return super.handleCommand(command);
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckState.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckState.java
new file mode 100644 (file)
index 0000000..4b6fab5
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2010-2022 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.smokedetectorcheck;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * Possible states for a smoke detector.
+ * 
+ * @author Christian Oeing - Initial contribution
+ */
+@NonNullByDefault
+public enum SmokeDetectorCheckState {
+    NONE,
+    SMOKE_TEST_REQUESTED,
+    SMOKE_TEST_OK,
+    SMOKE_TEST_FAILED;
+
+    public static SmokeDetectorCheckState from(String stateString) {
+
+        try {
+            return SmokeDetectorCheckState.valueOf(stateString);
+        } catch (Exception a) {
+            return NONE;
+        }
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/dto/SmokeDetectorCheckServiceState.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/dto/SmokeDetectorCheckServiceState.java
new file mode 100644 (file)
index 0000000..6ae80cb
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2010-2022 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.smokedetectorcheck.dto;
+
+import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
+import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.SmokeDetectorCheckState;
+
+/**
+ * State for {@link org.openhab.binding.boschshc.internal.services.smokedetectorcheck.SmokeDetectorCheckService}
+ * to get the current smoke test state and request a new smoke test.
+ *
+ * @author Christian Oeing - Initial contribution
+ */
+public class SmokeDetectorCheckServiceState extends BoschSHCServiceState {
+
+    public SmokeDetectorCheckServiceState() {
+        super("smokeDetectorCheckState");
+    }
+
+    /**
+     * Current state.
+     */
+    public SmokeDetectorCheckState value;
+}
index a634c7e3e002055b9a514c322e9ba54d76a90272..b6d037df3f090cc5bf7c2894c3b234c4d308e6e8 100644 (file)
@@ -25,6 +25,8 @@ thing-type.boschshc.smart-bulb.label = Smart Bulb
 thing-type.boschshc.smart-bulb.description = A smart bulb connected via Zigbee.
 thing-type.boschshc.smart-plug-compact.label = Compact Smart Plug
 thing-type.boschshc.smart-plug-compact.description = A compact smart plug with energy monitoring capabilities.
+thing-type.boschshc.smoke-detector.label = Smoke Detector
+thing-type.boschshc.smoke-detector.description = The smoke detector warns you in case of fire.
 thing-type.boschshc.thermostat.label = Thermostat
 thing-type.boschshc.thermostat.description = Radiator thermostat
 thing-type.boschshc.twinguard.label = Twinguard
@@ -105,6 +107,12 @@ channel-type.boschshc.purity.label = Purity
 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.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-type.boschshc.smoke-check.state.option.SMOKE_TEST_REQUESTED = Test requested
+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-rating.label = Temperature Rating
index ab84a6fea0c3200c048befffa94aa9651dcc7f8d..17cd2baaffb4e7c77242090f3ab684fafc1f5350 100644 (file)
@@ -12,6 +12,8 @@
                <config-description-ref uri="thing-type:boschshc:bridge"/>
        </bridge-type>
 
+       <!-- Things -->
+
        <thing-type id="in-wall-switch">
                <supported-bridge-type-refs>
                        <bridge-type-ref id="shc"/>
@@ -67,6 +69,7 @@
                        <channel id="combined-rating" typeId="combined-rating"/>
                        <channel id="battery-level" typeId="system.battery-level"/>
                        <channel id="low-battery" typeId="system.low-battery"/>
+                       <channel id="smoke-check" typeId="smoke-check"/>
                </channels>
 
                <config-description-ref uri="thing-type:boschshc:device"/>
 
        </thing-type>
 
+       <thing-type id="smoke-detector">
+               <supported-bridge-type-refs>
+                       <bridge-type-ref id="shc"/>
+               </supported-bridge-type-refs>
+
+               <label>Smoke Detector</label>
+               <description>The smoke detector warns you in case of fire.</description>
+
+               <channels>
+                       <channel id="smoke-check" typeId="smoke-check"/>
+                       <channel id="battery-level" typeId="system.battery-level"/>
+                       <channel id="low-battery" typeId="system.low-battery"/>
+               </channels>
+
+               <config-description-ref uri="thing-type:boschshc:device"/>
+       </thing-type>
+
+       <!-- Channels -->
+
        <channel-type id="system-availability">
                <item-type>Switch</item-type>
                <label>System Availability</label>
                </state>
        </channel-type>
 
+       <channel-type id="smoke-check">
+               <item-type>String</item-type>
+               <label>Smoke Check State</label>
+               <description>State of last smoke detector check.</description>
+               <state readOnly="false">
+                       <options>
+                               <option value="NONE">None</option>
+                               <option value="SMOKE_TEST_REQUESTED">Test requested</option>
+                               <option value="SMOKE_TEST_OK">Test successful</option>
+                               <option value="SMOKE_TEST_FAILED">Test failed</option>
+                       </options>
+               </state>
+       </channel-type>
+
        <channel-type id="contact">
                <item-type>Contact</item-type>
                <label>Window/Door contact</label>
diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandlerTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/AbstractSmokeDetectorHandlerTest.java
new file mode 100644 (file)
index 0000000..9a6514a
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2010-2022 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.devices;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.openhab.binding.boschshc.internal.devices.smokedetector.SmokeDetectorHandler;
+import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
+import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.SmokeDetectorCheckState;
+import org.openhab.binding.boschshc.internal.services.smokedetectorcheck.dto.SmokeDetectorCheckServiceState;
+import org.openhab.core.library.types.PlayPauseType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.thing.ChannelUID;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+/**
+ * Unit Tests for {@link SmokeDetectorHandler}.
+ *
+ * @author Gerd Zanker - Initial contribution
+ *
+ */
+@NonNullByDefault
+public abstract class AbstractSmokeDetectorHandlerTest<T extends AbstractSmokeDetectorHandler>
+        extends AbstractBatteryPoweredDeviceHandlerTest<T> {
+
+    @Captor
+    private @NonNullByDefault({}) ArgumentCaptor<SmokeDetectorCheckServiceState> smokeDetectorCheckStateCaptor;
+
+    @Test
+    public void testHandleCommand()
+            throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+
+        // valid commands with valid thing & channel
+        getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType(SmokeDetectorCheckState.SMOKE_TEST_REQUESTED.toString()));
+        verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
+                smokeDetectorCheckStateCaptor.capture());
+        SmokeDetectorCheckServiceState state = smokeDetectorCheckStateCaptor.getValue();
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_REQUESTED, state.value);
+
+        getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType(SmokeDetectorCheckState.NONE.toString()));
+        verify(getBridgeHandler(), times(2)).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
+                smokeDetectorCheckStateCaptor.capture());
+        state = smokeDetectorCheckStateCaptor.getValue();
+        assertSame(SmokeDetectorCheckState.NONE, state.value);
+
+        getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType(SmokeDetectorCheckState.SMOKE_TEST_OK.toString()));
+        verify(getBridgeHandler(), times(3)).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
+                smokeDetectorCheckStateCaptor.capture());
+        state = smokeDetectorCheckStateCaptor.getValue();
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_OK, state.value);
+
+        getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType(SmokeDetectorCheckState.SMOKE_TEST_FAILED.toString()));
+        verify(getBridgeHandler(), times(4)).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
+                smokeDetectorCheckStateCaptor.capture());
+        state = smokeDetectorCheckStateCaptor.getValue();
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_FAILED, state.value);
+    }
+
+    @Test
+    public void testHandleCommand_PlayPauseType()
+            throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException {
+
+        getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                PlayPauseType.PLAY);
+        verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"),
+                smokeDetectorCheckStateCaptor.capture());
+        SmokeDetectorCheckServiceState state = smokeDetectorCheckStateCaptor.getValue();
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_REQUESTED, state.value);
+    }
+
+    @Test
+    public void testUpdateChannel_SmokeDetectorCheckServiceState_none() {
+        JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":NONE}");
+        getFixture().processUpdate("SmokeDetectorCheck", jsonObject);
+        verify(getCallback()).stateUpdated(
+                new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType("NONE"));
+    }
+
+    @Test
+    public void testUpdateChannel_SmokeDetectorCheckServiceState_Requests() {
+        JsonElement jsonObject = JsonParser
+                .parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":SMOKE_TEST_REQUESTED}");
+        getFixture().processUpdate("SmokeDetectorCheck", jsonObject);
+        verify(getCallback()).stateUpdated(
+                new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK),
+                new StringType("SMOKE_TEST_REQUESTED"));
+    }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandlerTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetectorHandlerTest.java
new file mode 100644 (file)
index 0000000..314a77f
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2010-2022 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.devices.smokedetector;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
+import org.openhab.core.thing.ThingTypeUID;
+
+/**
+ * Unit Tests for {@link SmokeDetectorHandler}.
+ *
+ * @author Gerd Zanker - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class SmokeDetectorHandlerTest extends AbstractSmokeDetectorHandlerTest<SmokeDetectorHandler> {
+
+    @Override
+    protected SmokeDetectorHandler createFixture() {
+        return new SmokeDetectorHandler(getThing());
+    }
+
+    @Override
+    protected String getDeviceID() {
+        return "hdm:HomeMaticIP:3014F711A00004DBB85C1234";
+    }
+
+    @Override
+    protected ThingTypeUID getThingTypeUID() {
+        return BoschSHCBindingConstants.THING_TYPE_SMOKE_DETECTOR;
+    }
+}
index 0b22f87c0b1d604d27c1dc58a96e13e64887cebb..49272f84f2f5bc6aa183eeb2de4358666fe1bde2 100644 (file)
@@ -13,7 +13,7 @@
 package org.openhab.binding.boschshc.internal.devices.twinguard;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.boschshc.internal.devices.AbstractBatteryPoweredDeviceHandlerTest;
+import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandlerTest;
 import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants;
 import org.openhab.core.thing.ThingTypeUID;
 
@@ -24,7 +24,7 @@ import org.openhab.core.thing.ThingTypeUID;
  *
  */
 @NonNullByDefault
-public class TwinguardHandlerTest extends AbstractBatteryPoweredDeviceHandlerTest<TwinguardHandler> {
+public class TwinguardHandlerTest extends AbstractSmokeDetectorHandlerTest<TwinguardHandler> {
 
     @Override
     protected TwinguardHandler createFixture() {
diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckStateTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/smokedetectorcheck/SmokeDetectorCheckStateTest.java
new file mode 100644 (file)
index 0000000..42a3a73
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2010-2022 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.smokedetectorcheck;
+
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link SmokeDetectorCheckState}.
+ * 
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class SmokeDetectorCheckStateTest {
+
+    @Test
+    void testFrom() {
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_OK, SmokeDetectorCheckState.from("SMOKE_TEST_OK"));
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_REQUESTED, SmokeDetectorCheckState.from("SMOKE_TEST_REQUESTED"));
+        assertSame(SmokeDetectorCheckState.SMOKE_TEST_FAILED, SmokeDetectorCheckState.from("SMOKE_TEST_FAILED"));
+        assertSame(SmokeDetectorCheckState.NONE, SmokeDetectorCheckState.from("NONE"));
+        assertSame(SmokeDetectorCheckState.NONE, SmokeDetectorCheckState.from("invalid string"));
+    }
+}