* [boschshc] Support Bosch Smart Home Cameras (#12666) - add thing definitions for indoor security camera 360 and outdoor security camera Eyes - implement services for privacy mode and camera notifications - implement camera handler - add unit tests - update documentation * [boschshc] Enhance logging and comments (#12666) * only log on debug level when initial state can not be retrieved * do not log stack traces * minor Javadoc fixes closes #12666 Signed-off-by: David Pace <dev@davidpace.de>
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
* <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());
|
||||
}
|
||||
}
|
||||
@@ -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 BoschSHCService<CameraNotificationServiceState> {
|
||||
|
||||
public CameraNotificationService() {
|
||||
super("CameraNotification", CameraNotificationServiceState.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -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 BoschSHCService<PrivacyModeServiceState> {
|
||||
|
||||
public PrivacyModeService() {
|
||||
super("PrivacyMode", PrivacyModeServiceState.class);
|
||||
}
|
||||
}
|
||||
@@ -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.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@@ -155,6 +155,64 @@
|
||||
|
||||
</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>
|
||||
|
||||
Reference in New Issue
Block a user