diff --git a/bundles/org.openhab.binding.boschshc/README.md b/bundles/org.openhab.binding.boschshc/README.md index 28b791ba7..d8dbbe840 100644 --- a/bundles/org.openhab.binding.boschshc/README.md +++ b/bundles/org.openhab.binding.boschshc/README.md @@ -3,16 +3,17 @@ Binding for the Bosch Smart Home. - [Bosch Smart Home Binding](#bosch-smart-home-binding) - - [Changelog](#changelog) - [Supported Things](#supported-things) - - [In-Wall switches & Smart Plugs](#in-wall-switches--smart-plugs) + - [In-Wall switches & Smart Plugs](#in-wall-switches-smart-plugs) - [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) - [Climate Control](#climate-control) - [Wall Thermostat](#wall-thermostat) + - [Security Camera 360](#security-camera-360) + - [Security Camera Eyes](#security-camera-eyes) - [Limitations](#limitations) - [Discovery](#discovery) - [Bridge Configuration](#bridge-configuration) @@ -115,6 +116,28 @@ Display of the current room temperature as well as the relative humidity in the | temperature | Number:Temperature | ☐ | Current measured temperature. | | humidity | Number:Dimensionless | ☐ | Current measured humidity (0 to 100). | +### Security Camera 360 + +Indoor security camera with 360° view and motion detection. + +**Thing Type ID**: `security-camera-360` + +| Channel Type ID | Item Type | Writable | Description | +| --------------------- | -------------------- | :------: | ------------------------------------------------------------------ | +| privacy-mode | Switch | ☑ | If privacy mode is enabled, the camera is disabled and vice versa. | +| camera-notification | Switch | ☑ | Enables or disables notifications for the camera. | + +### Security Camera Eyes + +Outdoor security camera with motion detection and light. + +**Thing Type ID**: `security-camera-eyes` + +| Channel Type ID | Item Type | Writable | Description | +| --------------------- | -------------------- | :------: | ------------------------------------------------------------------ | +| privacy-mode | Switch | ☑ | If privacy mode is enabled, the camera is disabled and vice versa. | +| camera-notification | Switch | ☑ | Enables or disables notifications for the camera. | + ## Limitations - Discovery of Things 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 675f10f1d..a942c5205 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 @@ -39,6 +39,8 @@ public class BoschSHCBindingConstants { public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat"); public static final ThingTypeUID THING_TYPE_CLIMATE_CONTROL = new ThingTypeUID(BINDING_ID, "climate-control"); public static final ThingTypeUID THING_TYPE_WALL_THERMOSTAT = new ThingTypeUID(BINDING_ID, "wall-thermostat"); + public static final ThingTypeUID THING_TYPE_CAMERA_360 = new ThingTypeUID(BINDING_ID, "security-camera-360"); + public static final ThingTypeUID THING_TYPE_CAMERA_EYES = new ThingTypeUID(BINDING_ID, "security-camera-eyes"); // List of all Channel IDs // Auto-generated from thing-types.xml via script, don't modify @@ -59,4 +61,6 @@ public class BoschSHCBindingConstants { public static final String CHANNEL_VALVE_TAPPET_POSITION = "valve-tappet-position"; public static final String CHANNEL_SETPOINT_TEMPERATURE = "setpoint-temperature"; public static final String CHANNEL_CHILD_LOCK = "child-lock"; + public static final String CHANNEL_PRIVACY_MODE = "privacy-mode"; + public static final String CHANNEL_CAMERA_NOTIFICATION = "camera-notification"; } diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java index 1a05585ec..0bfb53c6e 100644 --- a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/BoschSHCHandlerFactory.java @@ -21,6 +21,7 @@ import java.util.function.Function; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.boschshc.internal.devices.bridge.BridgeHandler; +import org.openhab.binding.boschshc.internal.devices.camera.CameraHandler; import org.openhab.binding.boschshc.internal.devices.climatecontrol.ClimateControlHandler; import org.openhab.binding.boschshc.internal.devices.lightcontrol.LightControlHandler; import org.openhab.binding.boschshc.internal.devices.motiondetector.MotionDetectorHandler; @@ -69,7 +70,9 @@ public class BoschSHCHandlerFactory extends BaseThingHandlerFactory { new ThingTypeHandlerMapping(THING_TYPE_SHUTTER_CONTROL, ShutterControlHandler::new), new ThingTypeHandlerMapping(THING_TYPE_THERMOSTAT, ThermostatHandler::new), new ThingTypeHandlerMapping(THING_TYPE_CLIMATE_CONTROL, ClimateControlHandler::new), - new ThingTypeHandlerMapping(THING_TYPE_WALL_THERMOSTAT, WallThermostatHandler::new)); + new ThingTypeHandlerMapping(THING_TYPE_WALL_THERMOSTAT, WallThermostatHandler::new), + new ThingTypeHandlerMapping(THING_TYPE_CAMERA_360, CameraHandler::new), + new ThingTypeHandlerMapping(THING_TYPE_CAMERA_EYES, CameraHandler::new)); @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/camera/CameraHandler.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/camera/CameraHandler.java new file mode 100644 index 000000000..06eb5f0a1 --- /dev/null +++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/devices/camera/CameraHandler.java @@ -0,0 +1,166 @@ +/** + * 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.camera; + +import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_CAMERA_NOTIFICATION; +import static org.openhab.binding.boschshc.internal.devices.BoschSHCBindingConstants.CHANNEL_PRIVACY_MODE; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.boschshc.internal.devices.BoschSHCHandler; +import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException; +import org.openhab.binding.boschshc.internal.services.cameranotification.CameraNotificationService; +import org.openhab.binding.boschshc.internal.services.cameranotification.CameraNotificationState; +import org.openhab.binding.boschshc.internal.services.cameranotification.dto.CameraNotificationServiceState; +import org.openhab.binding.boschshc.internal.services.privacymode.PrivacyModeService; +import org.openhab.binding.boschshc.internal.services.privacymode.PrivacyModeState; +import org.openhab.binding.boschshc.internal.services.privacymode.dto.PrivacyModeServiceState; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.Thing; +import org.openhab.core.types.Command; + +/** + * Handler for security cameras. + *
+ * This implementation handles services and commands that are common to all cameras, which are currently: + * + *
PrivacyMode - Controls whether the camera records imagesCameraNotification - Enables or disables notifications for the camera
+ * The Eyes outdoor camera advertises a CameraLight service, which unfortunately does not work properly.
+ * Valid states are ON and OFF.
+ * One of my two cameras returns HTTP 204 (No Content) when requesting the state.
+ * Once Bosch supports this service properly, a new subclass may be introduced for the Eyes outdoor camera.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class CameraHandler extends BoschSHCHandler {
+
+ private PrivacyModeService privacyModeService;
+ private CameraNotificationService cameraNotificationService;
+
+ public CameraHandler(Thing thing) {
+ super(thing);
+ this.privacyModeService = new PrivacyModeService();
+ this.cameraNotificationService = new CameraNotificationService();
+ }
+
+ @Override
+ protected void initializeServices() throws BoschSHCException {
+ super.initializeServices();
+
+ this.registerService(this.privacyModeService, this::updateChannels, List.of(CHANNEL_PRIVACY_MODE));
+ this.registerService(this.cameraNotificationService, this::updateChannels,
+ List.of(CHANNEL_CAMERA_NOTIFICATION));
+ }
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ requestInitialStates();
+ }
+
+ /**
+ * Requests the initial states for relevant services.
+ *
+ * If this is not done, items associated with the corresponding channels with stay in an uninitialized state
+ * (null).
+ * This in turn leads to events not being fired properly when switches are used in the UI.
+ *
+ * Unfortunately the long poll results do not contain camera-related updates, so this is the current approach
+ * to get the initial states.
+ */
+ private void requestInitialStates() {
+ requestInitialPrivacyState();
+ requestInitialNotificationState();
+ }
+
+ private void requestInitialPrivacyState() {
+ try {
+ @Nullable
+ PrivacyModeServiceState serviceState = privacyModeService.getState();
+ if (serviceState != null) {
+ super.updateState(CHANNEL_PRIVACY_MODE, serviceState.value.toOnOffType());
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ logger.debug("Could not retrieve the initial privacy state of camera {}", getBoschID());
+ } catch (TimeoutException | ExecutionException | BoschSHCException e) {
+ logger.debug("Could not retrieve the initial privacy state of camera {}", getBoschID());
+ }
+ }
+
+ private void requestInitialNotificationState() {
+ try {
+ @Nullable
+ CameraNotificationServiceState serviceState = cameraNotificationService.getState();
+ if (serviceState != null) {
+ super.updateState(CHANNEL_CAMERA_NOTIFICATION, serviceState.value.toOnOffType());
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ logger.debug("Could not retrieve the initial notification state of camera {}", getBoschID());
+ } catch (TimeoutException | ExecutionException | BoschSHCException e) {
+ logger.debug("Could not retrieve the initial notification state of camera {}", getBoschID());
+ }
+ }
+
+ @Override
+ public void handleCommand(ChannelUID channelUID, Command command) {
+ super.handleCommand(channelUID, command);
+
+ switch (channelUID.getId()) {
+ case CHANNEL_PRIVACY_MODE:
+ if (command instanceof OnOffType) {
+ updatePrivacyModeState((OnOffType) command);
+ }
+ break;
+
+ case CHANNEL_CAMERA_NOTIFICATION:
+ if (command instanceof OnOffType) {
+ updateCameraNotificationState((OnOffType) command);
+ }
+ break;
+ }
+ }
+
+ private void updatePrivacyModeState(OnOffType command) {
+ PrivacyModeServiceState serviceState = new PrivacyModeServiceState();
+ serviceState.value = PrivacyModeState.from(command);
+ this.updateServiceState(this.privacyModeService, serviceState);
+ }
+
+ private void updateCameraNotificationState(OnOffType command) {
+ CameraNotificationServiceState serviceState = new CameraNotificationServiceState();
+ serviceState.value = CameraNotificationState.from(command);
+ this.updateServiceState(this.cameraNotificationService, serviceState);
+ }
+
+ private void updateChannels(PrivacyModeServiceState state) {
+ super.updateState(CHANNEL_PRIVACY_MODE, state.value.toOnOffType());
+ }
+
+ private void updateChannels(CameraNotificationServiceState state) {
+ super.updateState(CHANNEL_CAMERA_NOTIFICATION, state.value.toOnOffType());
+ }
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/cameranotification/CameraNotificationService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/cameranotification/CameraNotificationService.java
new file mode 100644
index 000000000..f9036cf46
--- /dev/null
+++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/cameranotification/CameraNotificationService.java
@@ -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.services.cameranotification;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.services.BoschSHCService;
+import org.openhab.binding.boschshc.internal.services.cameranotification.dto.CameraNotificationServiceState;
+
+/**
+ * Service to enable or disable notifications for security cameras.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class CameraNotificationService extends BoschSHCServicevalue, otherwise JSON requests and responses can not be
+ * serialized/deserialized. The JSON message looks like this:
+ *
+ *
+ * {"@type":"cameraNotificationState","value":"ENABLED"}
+ *
+ */
+ public CameraNotificationState value;
+}
diff --git a/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/privacymode/PrivacyModeService.java b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/privacymode/PrivacyModeService.java
new file mode 100644
index 000000000..f8eeda09a
--- /dev/null
+++ b/bundles/org.openhab.binding.boschshc/src/main/java/org/openhab/binding/boschshc/internal/services/privacymode/PrivacyModeService.java
@@ -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.services.privacymode;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.boschshc.internal.services.BoschSHCService;
+import org.openhab.binding.boschshc.internal.services.privacymode.dto.PrivacyModeServiceState;
+
+/**
+ * Service to get and set the privacy mode of security cameras.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class PrivacyModeService extends BoschSHCServicevalue, otherwise JSON requests and responses can not be
+ * serialized/deserialized. The JSON message looks like this:
+ *
+ *
+ * {"@type":"privacyModeState","value":"ENABLED"}
+ *
+ */
+ public PrivacyModeState value;
+}
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 0af967fe0..a50b94e45 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
@@ -155,6 +155,64 @@
+