From ea978fe953b960dc3afd0ef8e23969b3f12c169d Mon Sep 17 00:00:00 2001 From: David Pace Date: Thu, 6 Feb 2025 22:46:53 +0100 Subject: [PATCH] [boschshc] Provide alarm channel for smoke detectors (#18194) Signed-off-by: David Pace --- .../org.openhab.binding.boschshc/README.md | 34 ++++---- .../console/BoschShcCommandExtension.java | 8 +- .../devices/AbstractSmokeDetectorHandler.java | 6 +- .../devices/BoschSHCBindingConstants.java | 1 + ...tSmokeDetectorHandlerWithAlarmService.java | 66 +++++++++++++++ .../smokedetector/SmokeDetector2Handler.java | 3 +- .../smokedetector/SmokeDetectorHandler.java | 3 +- .../internal/services/alarm/AlarmService.java | 44 ++++++++++ .../services/alarm/dto/AlarmServiceState.java | 29 +++++++ .../services/alarm/dto/AlarmState.java | 42 ++++++++++ .../resources/OH-INF/i18n/boschshc.properties | 8 ++ .../resources/OH-INF/thing/thing-types.xml | 27 +++++++ .../main/resources/OH-INF/update/binding.xml | 16 ++++ .../AbstractSmokeDetectorHandlerTest.java | 34 ++++---- ...keDetectorHandlerWithAlarmServiceTest.java | 81 +++++++++++++++++++ .../SmokeDetector2HandlerTest.java | 3 +- .../SmokeDetectorHandlerTest.java | 3 +- .../services/alarm/AlarmServiceTest.java | 54 +++++++++++++ .../services/alarm/dto/AlarmStateTest.java | 37 +++++++++ 19 files changed, 448 insertions(+), 51 deletions(-) create mode 100644 bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmService.java create mode 100644 bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmService.java create mode 100644 bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmServiceState.java create mode 100644 bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmState.java create mode 100644 bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmServiceTest.java create mode 100644 bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmServiceTest.java create mode 100644 bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmStateTest.java diff --git a/bundles/org.openhab.binding.boschshc/README.md b/bundles/org.openhab.binding.boschshc/README.md index 9ebf88009e39c..c20608b9e6415 100644 --- a/bundles/org.openhab.binding.boschshc/README.md +++ b/bundles/org.openhab.binding.boschshc/README.md @@ -284,11 +284,11 @@ A smart bulb connected to the bridge via Zigbee such as a Ledvance Smart+ bulb. **Thing Type ID**: `smart-bulb` -| Channel Type ID | Item Type | Writable | Description | -| ----------------| --------- | :------: | -------------------------------------------------------------- | -| power-switch | Switch | ☑ | Switches the light on or off. | -| brightness | Dimmer | ☑ | Regulates the brightness on a percentage scale from 0 to 100%. | -| color | Color | ☑ | The color of the emitted light. | +| Channel Type ID | Item Type | Writable | Description | +| ---------------- | --------- | :------: | -------------------------------------------------------------- | +| power-switch | Switch | ☑ | Switches the light on or off. | +| brightness | Dimmer | ☑ | Regulates the brightness on a percentage scale from 0 to 100%. | +| color | Color | ☑ | The color of the emitted light. | ### Smoke Detector @@ -296,22 +296,26 @@ The smoke detector warns you in case of fire. **Thing Type ID**: `smoke-detector` -| Channel Type ID | Item Type | Writable | Description | -| ------------------ | -------------------- | :------: | ------------------------------------------------------------------------------------------------- | -| smoke-check | String | ☑ | State of the smoke check. Also used to request a new smoke check. | +| Channel Type ID | Item Type | Writable | Description | +| ---------------- | --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| alarm | String | ☑ | Alarm state of the smoke detector. Possible values to read are: `IDLE_OFF`, `PRIMARY_ALARM`, `SECONDARY_ALARM` and `INTRUSION_ALARM`. Possible values to write are: `INTRUSION_ALARM_ON_REQUESTED` and `INTRUSION_ALARM_OFF_REQUESTED`. | +| smoke-check | String | ☑ | State of the smoke check. Also used to request a new smoke check. | +| 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`). | ### Smoke Detector II The smoke detector warns you in case of fire. -**Thing Type ID**: `smoke-detector` +**Thing Type ID**: `smoke-detector-2` -| Channel Type ID | Item Type | Writable | Description | -|-------------------|-------------| :------: |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| smoke-check | String | ☑ | State of the smoke check. Also used to request a new smoke check. | -| 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`). | -| signal-strength | Number | ☐ | Communication quality between the device and the Smart Home Controller. Possible values range between 0 (unknown) and 4 (best signal strength). | +| Channel Type ID | Item Type | Writable | Description | +| --------------- | --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| alarm | String | ☑ | Alarm state of the smoke detector. Possible values to read are: `IDLE_OFF`, `PRIMARY_ALARM`, `SECONDARY_ALARM` and `INTRUSION_ALARM`. Possible values to write are: `INTRUSION_ALARM_ON_REQUESTED` and `INTRUSION_ALARM_OFF_REQUESTED`. | +| smoke-check | String | ☑ | State of the smoke check. Also used to request a new smoke check. | +| 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`). | +| signal-strength | Number | ☐ | Communication quality between the device and the Smart Home Controller. Possible values range between 0 (unknown) and 4 (best signal strength). | ### User-defined States diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/console/BoschShcCommandExtension.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/console/BoschShcCommandExtension.java index 9bbc9e4310709..9916f45e5ea46 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/console/BoschShcCommandExtension.java +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/console/BoschShcCommandExtension.java @@ -81,10 +81,10 @@ public BoschShcCommandExtension(final @Reference ThingRegistry thingRegistry) { * src/main/java/org/openhab/binding/boschshc/internal/services. */ List getAllBoschShcServices() { - return List.of("airqualitylevel", "batterylevel", "binaryswitch", "bypass", "cameranotification", "childlock", - "childprotection", "communicationquality", "hsbcoloractuator", "humiditylevel", "illuminance", - "impulseswitch", "intrusion", "keypad", "latestmotion", "multilevelswitch", "powermeter", "powerswitch", - "privacymode", "roomclimatecontrol", "shuttercontact", "shuttercontrol", "silentmode", + return List.of("airqualitylevel", "alarm", "batterylevel", "binaryswitch", "bypass", "cameranotification", + "childlock", "childprotection", "communicationquality", "hsbcoloractuator", "humiditylevel", + "illuminance", "impulseswitch", "intrusion", "keypad", "latestmotion", "multilevelswitch", "powermeter", + "powerswitch", "privacymode", "roomclimatecontrol", "shuttercontact", "shuttercontrol", "silentmode", "smokedetectorcheck", "temperaturelevel", "userstate", "valvetappet", "waterleakagesensor", "waterleakagesensorcheck", "waterleakagesensortilt"); } 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 index 75ee078ad042b..a880b51d1e1e5 100644 --- 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 @@ -52,10 +52,8 @@ protected void initializeServices() throws BoschSHCException { public void handleCommand(ChannelUID channelUID, Command command) { super.handleCommand(channelUID, command); - switch (channelUID.getId()) { - case CHANNEL_SMOKE_CHECK: - this.handleServiceCommand(this.smokeDetectorCheckService, command); - break; + if (CHANNEL_SMOKE_CHECK.equals(channelUID.getId())) { + this.handleServiceCommand(this.smokeDetectorCheckService, command); } } diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java index 1f157431d6094..4a01184b7cd06 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCBindingConstants.java @@ -116,6 +116,7 @@ private BoschSHCBindingConstants() { public static final String CHANNEL_IMPULSE_SWITCH = "impulse-switch"; public static final String CHANNEL_IMPULSE_LENGTH = "impulse-length"; public static final String CHANNEL_INSTANT_OF_LAST_IMPULSE = "instant-of-last-impulse"; + public static final String CHANNEL_ALARM = "alarm"; // numbered channels // the rationale for introducing numbered channels was discussed in // https://github.com/openhab/openhab-addons/pull/16400 diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmService.java new file mode 100644 index 0000000000000..180ed66eed60c --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmService.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010-2025 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 static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_ALARM; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandler; +import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException; +import org.openhab.binding.boschshc.internal.services.alarm.AlarmService; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmServiceState; +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 for smoke detectors that have an Alarm service. + *

+ * Note that this includes Smoke Detector and Smoke Detector II, but not Twinguard. + * + * @author David Pace - Initial contribution + * + */ +@NonNullByDefault +public abstract class AbstractSmokeDetectorHandlerWithAlarmService extends AbstractSmokeDetectorHandler { + + private AlarmService alarmService; + + protected AbstractSmokeDetectorHandlerWithAlarmService(Thing thing) { + super(thing); + this.alarmService = new AlarmService(); + } + + @Override + protected void initializeServices() throws BoschSHCException { + super.initializeServices(); + + this.registerService(alarmService, this::updateChannels, List.of(CHANNEL_ALARM)); + } + + private void updateChannels(AlarmServiceState state) { + updateState(CHANNEL_ALARM, new StringType(state.value.toString())); + } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + super.handleCommand(channelUID, command); + + if (CHANNEL_ALARM.equals(channelUID.getId())) { + this.handleServiceCommand(this.alarmService, command); + } + } +} diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2Handler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2Handler.java index e8c0b5eab686d..c240c3032cb8f 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2Handler.java +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2Handler.java @@ -17,7 +17,6 @@ import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; -import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandler; import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException; import org.openhab.binding.boschshc.internal.services.communicationquality.CommunicationQualityService; import org.openhab.binding.boschshc.internal.services.communicationquality.dto.CommunicationQualityServiceState; @@ -29,7 +28,7 @@ * @author Patrick Gell - Initial contribution */ @NonNullByDefault -public class SmokeDetector2Handler extends AbstractSmokeDetectorHandler { +public class SmokeDetector2Handler extends AbstractSmokeDetectorHandlerWithAlarmService { public SmokeDetector2Handler(Thing thing) { super(thing); 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 index bb111e8efeeef..be52ba139739d 100644 --- 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 @@ -13,7 +13,6 @@ 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; /** @@ -23,7 +22,7 @@ * @author Gerd Zanker - AbstractSmokeDetectorHandler refactoring for reuse */ @NonNullByDefault -public class SmokeDetectorHandler extends AbstractSmokeDetectorHandler { +public class SmokeDetectorHandler extends AbstractSmokeDetectorHandlerWithAlarmService { public SmokeDetectorHandler(Thing thing) { super(thing); diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmService.java new file mode 100644 index 0000000000000..02ac03048b43d --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmService.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2025 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.alarm; + +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.alarm.dto.AlarmServiceState; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmState; +import org.openhab.core.library.types.StringType; +import org.openhab.core.types.Command; + +/** + * Alarm service for smoke detectors. + * + * @author David Pace - Initial contribution + * + */ +@NonNullByDefault +public class AlarmService extends BoschSHCService { + public AlarmService() { + super("Alarm", AlarmServiceState.class); + } + + @Override + public AlarmServiceState handleCommand(Command command) throws BoschSHCException { + if (command instanceof StringType stringCommand) { + AlarmServiceState state = new AlarmServiceState(); + state.value = AlarmState.from(stringCommand.toFullString()); + return state; + } + return super.handleCommand(command); + } +} diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmServiceState.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmServiceState.java new file mode 100644 index 0000000000000..fe462c638f6a7 --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmServiceState.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010-2025 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.alarm.dto; + +import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState; + +/** + * State for alarm services of smoke detectors. + * + * @author David Pace - Initial contribution + * + */ +public class AlarmServiceState extends BoschSHCServiceState { + public AlarmServiceState() { + super("alarmState"); + } + + public AlarmState value; +} diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmState.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmState.java new file mode 100644 index 0000000000000..be1d140cfa03b --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmState.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010-2025 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.alarm.dto; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Possible states of smoke detector alarms. + * + * @author David Pace - Initial contribution + * + */ +public enum AlarmState { + IDLE_OFF, + PRIMARY_ALARM, + SECONDARY_ALARM, + INTRUSION_ALARM, + INTRUSION_ALARM_ON_REQUESTED, + INTRUSION_ALARM_OFF_REQUESTED; + + private static final Logger LOGGER = LoggerFactory.getLogger(AlarmState.class); + + public static AlarmState from(String identifier) { + try { + return valueOf(identifier); + } catch (IllegalArgumentException e) { + LOGGER.warn("Unsupported alarm state: {}", identifier); + return IDLE_OFF; + } + } +} diff --git a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties index d66c4e8de47f5..51fa34f936e0b 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties +++ b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/i18n/boschshc.properties @@ -84,6 +84,14 @@ channel-type.boschshc.alarm-state.state.option.PRE_ALARM = Alarm is about to go channel-type.boschshc.alarm-state.state.option.ALARM_ON = Alarm was triggered channel-type.boschshc.alarm-state.state.option.ALARM_MUTED = Alarm is muted channel-type.boschshc.alarm-state.state.option.UNKNOWN = Alarm status is unknown +channel-type.boschshc.alarm.label = Alarm +channel-type.boschshc.alarm.description = Alarm state of the smoke detector. +channel-type.boschshc.alarm.state.option.IDLE_OFF = Alarm off +channel-type.boschshc.alarm.state.option.PRIMARY_ALARM = Primary alarm +channel-type.boschshc.alarm.state.option.SECONDARY_ALARM = Secondary alarm +channel-type.boschshc.alarm.state.option.INTRUSION_ALARM = Intrusion alarm +channel-type.boschshc.alarm.state.option.INTRUSION_ALARM_ON_REQUESTED = Intrusion alarm on requested +channel-type.boschshc.alarm.state.option.INTRUSION_ALARM_OFF_REQUESTED = Intrusion alarm off requested channel-type.boschshc.arm-action.label = Arm Action channel-type.boschshc.arm-action.description = Arms the intrusion detection system using the given profile ID. channel-type.boschshc.arming-state.label = Arming State diff --git a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml index 1bb020940eb8b..7aef9df110091 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/thing/thing-types.xml @@ -344,11 +344,16 @@ The smoke detector warns you in case of fire. + + + 1 + + @@ -412,12 +417,17 @@ The smoke detector warns you in case of fire. + + + 1 + + @@ -887,4 +897,21 @@ + + String + + Alarm state of the smoke detector. + Alarm + + + + + + + + + + + + diff --git a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/update/binding.xml b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/update/binding.xml index 78bdc3fac3b1a..5d440641c3377 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/update/binding.xml +++ b/bundles/org.openhab.binding.boschshc/src/main/resources/OH-INF/update/binding.xml @@ -22,4 +22,20 @@ + + + + boschshc:alarm + + + + + + + + boschshc:alarm + + + + 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 index 935626f6bdeb2..7025e802196e7 100644 --- 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 @@ -14,7 +14,9 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -24,7 +26,6 @@ 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.OnOffType; @@ -53,31 +54,30 @@ public abstract class AbstractSmokeDetectorHandlerTest smokeDetectorCheckStateCaptor; @Test - public void testHandleCommand() - throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException { + public void testHandleCommandSmokeTest() throws InterruptedException, TimeoutException, ExecutionException { // valid commands with valid thing & channel - getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK), + getFixture().handleCommand(new ChannelUID(getThing().getUID(), 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), + getFixture().handleCommand(new ChannelUID(getThing().getUID(), 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), + getFixture().handleCommand(new ChannelUID(getThing().getUID(), 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), + getFixture().handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_SMOKE_CHECK), new StringType(SmokeDetectorCheckState.SMOKE_TEST_FAILED.toString())); verify(getBridgeHandler(), times(4)).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"), smokeDetectorCheckStateCaptor.capture()); @@ -86,10 +86,8 @@ public void testHandleCommand() } @Test - public void testHandleCommandPlayPauseType() - throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException { - getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK), - PlayPauseType.PLAY); + public void testHandleCommandPlayPauseType() throws InterruptedException, TimeoutException, ExecutionException { + getFixture().handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_SMOKE_CHECK), PlayPauseType.PLAY); verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("SmokeDetectorCheck"), smokeDetectorCheckStateCaptor.capture()); SmokeDetectorCheckServiceState state = smokeDetectorCheckStateCaptor.getValue(); @@ -97,10 +95,8 @@ public void testHandleCommandPlayPauseType() } @Test - public void testHandleCommandUnknownCommand() - throws InterruptedException, TimeoutException, ExecutionException, BoschSHCException { - getFixture().handleCommand(new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK), - OnOffType.ON); + public void testHandleCommandUnknownCommand() { + getFixture().handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_SMOKE_CHECK), OnOffType.ON); ThingStatusInfo expectedThingStatusInfo = ThingStatusInfoBuilder .create(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR) .withDescription( @@ -113,8 +109,7 @@ public void testHandleCommandUnknownCommand() public void testUpdateChannelSmokeDetectorCheckServiceStateNone() { JsonElement jsonObject = JsonParser.parseString("{\"@type\":\"smokeDetectorCheckState\",\"value\":NONE}"); getFixture().processUpdate("SmokeDetectorCheck", jsonObject); - verify(getCallback()).stateUpdated( - new ChannelUID(getThing().getUID(), BoschSHCBindingConstants.CHANNEL_SMOKE_CHECK), + verify(getCallback()).stateUpdated(new ChannelUID(getThing().getUID(), CHANNEL_SMOKE_CHECK), new StringType("NONE")); } @@ -123,8 +118,7 @@ public void testUpdateChannelSmokeDetectorCheckServiceStateRequests() { 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), + verify(getCallback()).stateUpdated(new ChannelUID(getThing().getUID(), 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/AbstractSmokeDetectorHandlerWithAlarmServiceTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmServiceTest.java new file mode 100644 index 0000000000000..7e156435f16d5 --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/AbstractSmokeDetectorHandlerWithAlarmServiceTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2010-2025 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 static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_ALARM; + +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.AbstractSmokeDetectorHandlerTest; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmServiceState; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmState; +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 AbstractSmokeDetectorHandlerWithAlarmService}. + * + * @author David Pace - Initial contribution + * + * @param type of the smoke detector + */ +@NonNullByDefault +public abstract class AbstractSmokeDetectorHandlerWithAlarmServiceTest + extends AbstractSmokeDetectorHandlerTest { + + @Captor + private @NonNullByDefault({}) ArgumentCaptor alarmStateCaptor; + + @Test + public void testUpdateChannelsAlarm() { + String json = """ + { + "@type": "alarmState", + "value": IDLE_OFF + } + """; + JsonElement jsonObject = JsonParser.parseString(json); + getFixture().processUpdate("Alarm", jsonObject); + verify(getCallback()).stateUpdated(new ChannelUID(getThing().getUID(), CHANNEL_ALARM), + new StringType("IDLE_OFF")); + } + + @Test + public void testHandleCommandAlarm() throws InterruptedException, TimeoutException, ExecutionException { + getFixture().handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_ALARM), + new StringType("INTRUSION_ALARM_ON_REQUESTED")); + verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("Alarm"), alarmStateCaptor.capture()); + AlarmServiceState state = alarmStateCaptor.getValue(); + assertSame(AlarmState.INTRUSION_ALARM_ON_REQUESTED, state.value); + } + + @Test + public void testHandleCommandAlarmUnknownAlarmState() + throws InterruptedException, TimeoutException, ExecutionException { + getFixture().handleCommand(new ChannelUID(getThing().getUID(), CHANNEL_ALARM), new StringType("INVALID")); + verify(getBridgeHandler()).putState(eq(getDeviceID()), eq("Alarm"), alarmStateCaptor.capture()); + AlarmServiceState state = alarmStateCaptor.getValue(); + assertSame(AlarmState.IDLE_OFF, state.value); + } +} diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2HandlerTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2HandlerTest.java index eb26d36c05bf8..59c6bc918b09e 100644 --- a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2HandlerTest.java +++ b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/devices/smokedetector/SmokeDetector2HandlerTest.java @@ -16,7 +16,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; -import org.openhab.binding.boschshc.internal.devices.AbstractSmokeDetectorHandlerTest; import org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants; import org.openhab.core.library.types.DecimalType; import org.openhab.core.thing.ChannelUID; @@ -32,7 +31,7 @@ * */ @NonNullByDefault -public class SmokeDetector2HandlerTest extends AbstractSmokeDetectorHandlerTest { +class SmokeDetector2HandlerTest extends AbstractSmokeDetectorHandlerWithAlarmServiceTest { @Override protected SmokeDetector2Handler createFixture() { 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 index c9dfc4f77c782..5830af7359f09 100644 --- 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 @@ -13,7 +13,6 @@ 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; @@ -24,7 +23,7 @@ * */ @NonNullByDefault -public class SmokeDetectorHandlerTest extends AbstractSmokeDetectorHandlerTest { +public class SmokeDetectorHandlerTest extends AbstractSmokeDetectorHandlerWithAlarmServiceTest { @Override protected SmokeDetectorHandler createFixture() { diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmServiceTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmServiceTest.java new file mode 100644 index 0000000000000..7475215a64815 --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/AlarmServiceTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2025 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.alarm; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmServiceState; +import org.openhab.binding.boschshc.internal.services.alarm.dto.AlarmState; +import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.StringType; + +/** + * Unit tests for {@link AlarmService}. + * + * @author David Pace - Initial contribution + */ +@NonNullByDefault +class AlarmServiceTest { + + private @NonNullByDefault({}) AlarmService fixture; + + @BeforeEach + public void beforeEach() { + fixture = new AlarmService(); + } + + @Test + void testHandleCommandValidCommand() throws BoschSHCException { + AlarmServiceState state = fixture.handleCommand(new StringType("IDLE_OFF")); + assertNotNull(state); + assertSame(AlarmState.IDLE_OFF, state.value); + } + + @Test + void testHandleCommandInvalidCommand() { + assertThrows(BoschSHCException.class, () -> fixture.handleCommand(new DecimalType(0))); + } +} diff --git a/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmStateTest.java b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmStateTest.java new file mode 100644 index 0000000000000..a272984e43b2d --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/test/java/org/openhab/binding/boschshc/internal/services/alarm/dto/AlarmStateTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2025 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.alarm.dto; + +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link AlarmState}. + * + * @author David Pace - Initial contribution + * + */ +@NonNullByDefault +class AlarmStateTest { + @Test + void testFromValidIdentifier() { + assertSame(AlarmState.PRIMARY_ALARM, AlarmState.from("PRIMARY_ALARM")); + } + + @Test + void testFromInvalidIdentifier() { + assertSame(AlarmState.IDLE_OFF, AlarmState.from("INVALID")); + } +}