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)
| 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
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
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";
}
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;
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) {
--- /dev/null
+/**
+ * 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.
+ * <p>
+ * This implementation handles services and commands that are common to all cameras, which are currently:
+ *
+ * <ul>
+ * <li><code>PrivacyMode</code> - Controls whether the camera records images</li>
+ * <li><code>CameraNotification</code> - Enables or disables notifications for the camera</li>
+ * </ul>
+ *
+ * <p>
+ * The Eyes outdoor camera advertises a <code>CameraLight</code> service, which unfortunately does not work properly.
+ * Valid states are <code>ON</code> and <code>OFF</code>.
+ * One of my two cameras returns <code>HTTP 204 (No Content)</code> 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.
+ * <p>
+ * If this is not done, items associated with the corresponding channels with stay in an uninitialized state
+ * (<code>null</code>).
+ * This in turn leads to events not being fired properly when switches are used in the UI.
+ * <p>
+ * 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());
+ }
+}
--- /dev/null
+/**
+ * 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 BoschSHCService<CameraNotificationServiceState> {
+
+ public CameraNotificationService() {
+ super("CameraNotification", CameraNotificationServiceState.class);
+ }
+}
--- /dev/null
+/**
+ * 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.core.library.types.OnOffType;
+
+/**
+ * Possible states for camera notifications.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public enum CameraNotificationState {
+ ENABLED,
+ DISABLED;
+
+ /**
+ * Converts an {@link OnOffType} state into a {@link CameraNotificationState}.
+ *
+ * @param onOff the on/off state
+ * @return the corresponding notification state
+ */
+ public static CameraNotificationState from(OnOffType onOff) {
+ return onOff == OnOffType.ON ? ENABLED : DISABLED;
+ }
+
+ /**
+ * Converts this {@link CameraNotificationState} into an {@link OnOffType}.
+ *
+ * @return the on/off state corresponding to the notification state of this enumeration literal
+ */
+ public OnOffType toOnOffType() {
+ return this == ENABLED ? OnOffType.ON : OnOffType.OFF;
+ }
+}
--- /dev/null
+/**
+ * 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.dto;
+
+import org.openhab.binding.boschshc.internal.services.cameranotification.CameraNotificationState;
+import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
+
+/**
+ * Represents the state of camera notifications as reported by the Smart Home Controller.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+public class CameraNotificationServiceState extends BoschSHCServiceState {
+
+ public CameraNotificationServiceState() {
+ super("cameraNotificationState");
+ }
+
+ /**
+ * The name of this member has to be <code>value</code>, otherwise JSON requests and responses can not be
+ * serialized/deserialized. The JSON message looks like this:
+ *
+ * <pre>
+ * {"@type":"cameraNotificationState","value":"ENABLED"}
+ * </pre>
+ */
+ public CameraNotificationState value;
+}
--- /dev/null
+/**
+ * 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 BoschSHCService<PrivacyModeServiceState> {
+
+ public PrivacyModeService() {
+ super("PrivacyMode", PrivacyModeServiceState.class);
+ }
+}
--- /dev/null
+/**
+ * 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.core.library.types.OnOffType;
+
+/**
+ * Possible privacy mode states of security cameras.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+public enum PrivacyModeState {
+
+ /**
+ * Privacy mode enabled / camera disabled
+ */
+ ENABLED,
+
+ /**
+ * Privacy mode disabled / camera enabled
+ */
+ DISABLED;
+
+ /**
+ * Converts an {@link OnOffType} state into a {@link PrivacyModeState}.
+ *
+ * @param onOff the on/off state
+ * @return the corresponding privacy mode state
+ */
+ public static PrivacyModeState from(OnOffType onOff) {
+ return onOff == OnOffType.ON ? ENABLED : DISABLED;
+ }
+
+ /**
+ * Converts this {@link PrivacyModeState} into an {@link OnOffType}.
+ *
+ * @return the on/off state corresponding to the privacy mode state of this enumeration literal
+ */
+ public OnOffType toOnOffType() {
+ return this == ENABLED ? OnOffType.ON : OnOffType.OFF;
+ }
+}
--- /dev/null
+/**
+ * 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.dto;
+
+import org.openhab.binding.boschshc.internal.services.dto.BoschSHCServiceState;
+import org.openhab.binding.boschshc.internal.services.privacymode.PrivacyModeState;
+
+/**
+ * Represents the privacy mode of cameras as reported by the Smart Home Controller.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+public class PrivacyModeServiceState extends BoschSHCServiceState {
+
+ public PrivacyModeServiceState() {
+ super("privacyModeState");
+ }
+
+ /**
+ * The name of this member has to be <code>value</code>, otherwise JSON requests and responses can not be
+ * serialized/deserialized. The JSON message looks like this:
+ *
+ * <pre>
+ * {"@type":"privacyModeState","value":"ENABLED"}
+ * </pre>
+ */
+ public PrivacyModeState value;
+}
</thing-type>
+ <thing-type id="security-camera-360">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="shc"/>
+ </supported-bridge-type-refs>
+
+ <label>Security Camera 360</label>
+ <description>Indoor security camera with 360° view and motion detection.</description>
+
+ <channels>
+ <channel id="privacy-mode" typeId="privacy-mode"/>
+ <channel id="camera-notification" typeId="camera-notification"/>
+ </channels>
+
+ <config-description-ref uri="thing-type:boschshc:device"/>
+
+ </thing-type>
+
+ <thing-type id="security-camera-eyes">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="shc"/>
+ </supported-bridge-type-refs>
+
+ <label>Security Camera Eyes</label>
+ <description>Outdoor security camera with motion detection and light.</description>
+
+ <channels>
+ <channel id="privacy-mode" typeId="privacy-mode"/>
+ <channel id="camera-notification" typeId="camera-notification"/>
+ </channels>
+
+ <config-description-ref uri="thing-type:boschshc:device"/>
+
+ </thing-type>
+
+ <channel-type id="privacy-mode">
+ <item-type>Switch</item-type>
+ <label>Privacy Mode</label>
+ <description>If privacy mode is enabled, the camera is disabled and vice versa.</description>
+ <state>
+ <options>
+ <option value="ENABLED">Privacy mode enabled (camera disabled)</option>
+ <option value="DISABLED">Privacy mode disabled (camera enabled)</option>
+ </options>
+ </state>
+ </channel-type>
+
+ <channel-type id="camera-notification">
+ <item-type>Switch</item-type>
+ <label>Camera Notifications</label>
+ <description>Enables or disables notifications for the camera.</description>
+ <state>
+ <options>
+ <option value="ENABLED">Enable notifications</option>
+ <option value="DISABLED">Disable notifications</option>
+ </options>
+ </state>
+ </channel-type>
+
<channel-type id="temperature">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
--- /dev/null
+/**
+ * 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 static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.core.library.types.OnOffType;
+
+/**
+ * Unit tests for {@link CameraNotificationState}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+class CameraNotificationStateTest {
+
+ @Test
+ void testFromOnOffType() {
+ assertSame(CameraNotificationState.ENABLED, CameraNotificationState.from(OnOffType.ON));
+ assertSame(CameraNotificationState.DISABLED, CameraNotificationState.from(OnOffType.OFF));
+ }
+
+ @Test
+ void testToOnOffType() {
+ assertSame(OnOffType.ON, CameraNotificationState.ENABLED.toOnOffType());
+ assertSame(OnOffType.OFF, CameraNotificationState.DISABLED.toOnOffType());
+ }
+}
--- /dev/null
+/**
+ * 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 static org.junit.jupiter.api.Assertions.assertSame;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.core.library.types.OnOffType;
+
+/**
+ * Unit tests for {@link PrivacyModeState}.
+ *
+ * @author David Pace - Initial contribution
+ *
+ */
+@NonNullByDefault
+class PrivacyModeStateTest {
+
+ @Test
+ void testFromOnOffType() {
+ assertSame(PrivacyModeState.ENABLED, PrivacyModeState.from(OnOffType.ON));
+ assertSame(PrivacyModeState.DISABLED, PrivacyModeState.from(OnOffType.OFF));
+ }
+
+ @Test
+ void testToOnOffType() {
+ assertSame(OnOffType.ON, PrivacyModeState.ENABLED.toOnOffType());
+ assertSame(OnOffType.OFF, PrivacyModeState.DISABLED.toOnOffType());
+ }
+}