forked from openhab/openhab-addons
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[netatmo] Add support for the floodlight of the Presence camera (open…
…hab#7927) * [openhab#7912] Support for the floodlight of the Presence camera - Support for the floodlight of the Presence camera added (There are 2 new switches to set the floodlight auto-mode and to switch the floodlight on and off/auto). - Netatmo API swagger spec updated - Tests added * Exception handling and logging corrected * Potential crash fixed which could occur when a wrong JSON response is returned by the ping command request (when it is a valid JSON but without the expected attribute "local_url"). Signed-off-by: Sven Strohschein <[email protected]> Signed-off-by: Daan Meijer <[email protected]>
- Loading branch information
1 parent
8705f90
commit daf43c9
Showing
10 changed files
with
643 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
65 changes: 65 additions & 0 deletions
65
...ng.netatmo/src/main/java/org/openhab/binding/netatmo/internal/presence/CameraAddress.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* Copyright (c) 2010-2020 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.netatmo.internal.presence; | ||
|
||
import org.eclipse.jdt.annotation.NonNullByDefault; | ||
import org.eclipse.jdt.annotation.Nullable; | ||
|
||
import java.util.Objects; | ||
|
||
/** | ||
* {@link CameraAddress} handles the data to address a camera (VPN and local address). | ||
* | ||
* @author Sven Strohschein | ||
*/ | ||
@NonNullByDefault | ||
public class CameraAddress { | ||
|
||
private final String vpnURL; | ||
private final String localURL; | ||
|
||
CameraAddress(final String vpnURL, final String localURL) { | ||
this.vpnURL = vpnURL; | ||
this.localURL = localURL; | ||
} | ||
|
||
public String getVpnURL() { | ||
return vpnURL; | ||
} | ||
|
||
public String getLocalURL() { | ||
return localURL; | ||
} | ||
|
||
/** | ||
* Checks if the VPN URL was changed / isn't equal to the given VPN-URL. | ||
* @param vpnURL old / known VPN URL | ||
* @return true, when the VPN URL isn't equal given VPN URL, otherwise false | ||
*/ | ||
public boolean isVpnURLChanged(String vpnURL) { | ||
return !getVpnURL().equals(vpnURL); | ||
} | ||
|
||
@Override | ||
public boolean equals(@Nullable Object object) { | ||
if (this == object) return true; | ||
if (object == null || getClass() != object.getClass()) return false; | ||
CameraAddress that = (CameraAddress) object; | ||
return vpnURL.equals(that.vpnURL) && localURL.equals(that.localURL); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(vpnURL, localURL); | ||
} | ||
} |
176 changes: 176 additions & 0 deletions
176
.../src/main/java/org/openhab/binding/netatmo/internal/presence/NAPresenceCameraHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
/** | ||
* Copyright (c) 2010-2020 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.netatmo.internal.presence; | ||
|
||
import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.toOnOffType; | ||
|
||
import io.swagger.client.model.NAWelcomeCamera; | ||
import org.eclipse.jdt.annotation.NonNull; | ||
import org.eclipse.jdt.annotation.NonNullByDefault; | ||
import org.eclipse.smarthome.core.i18n.TimeZoneProvider; | ||
import org.eclipse.smarthome.core.library.types.OnOffType; | ||
import org.eclipse.smarthome.core.thing.ChannelUID; | ||
import org.eclipse.smarthome.core.thing.Thing; | ||
import org.eclipse.smarthome.core.types.Command; | ||
import org.eclipse.smarthome.core.types.State; | ||
import org.eclipse.smarthome.core.types.UnDefType; | ||
import org.eclipse.smarthome.io.net.http.HttpUtil; | ||
import org.json.JSONException; | ||
import org.json.JSONObject; | ||
import org.openhab.binding.netatmo.internal.camera.CameraHandler; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.util.Optional; | ||
|
||
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT; | ||
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE; | ||
|
||
/** | ||
* {@link NAPresenceCameraHandler} is the class used to handle Presence camera data | ||
* | ||
* @author Sven Strohschein | ||
*/ | ||
@NonNullByDefault | ||
public class NAPresenceCameraHandler extends CameraHandler { | ||
|
||
private static final String PING_URL_PATH = "/command/ping"; | ||
private static final String FLOODLIGHT_SET_URL_PATH = "/command/floodlight_set_config"; | ||
|
||
private final Logger logger = LoggerFactory.getLogger(NAPresenceCameraHandler.class); | ||
|
||
private Optional<CameraAddress> cameraAddress = Optional.empty(); | ||
private State floodlightAutoModeState = UnDefType.UNDEF; | ||
|
||
public NAPresenceCameraHandler(final Thing thing, final TimeZoneProvider timeZoneProvider) { | ||
super(thing, timeZoneProvider); | ||
} | ||
|
||
@Override | ||
public void handleCommand(ChannelUID channelUID, Command command) { | ||
String channelId = channelUID.getId(); | ||
switch (channelId) { | ||
case CHANNEL_CAMERA_FLOODLIGHT: | ||
if (command == OnOffType.ON) { | ||
switchFloodlight(true); | ||
} else if (command == OnOffType.OFF) { | ||
switchFloodlight(false); | ||
} | ||
break; | ||
case CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE: | ||
if (command == OnOffType.ON) { | ||
switchFloodlightAutoMode(true); | ||
} else if (command == OnOffType.OFF) { | ||
switchFloodlightAutoMode(false); | ||
} | ||
break; | ||
} | ||
super.handleCommand(channelUID, command); | ||
} | ||
|
||
@Override | ||
protected State getNAThingProperty(@NonNull String channelId) { | ||
switch (channelId) { | ||
case CHANNEL_CAMERA_FLOODLIGHT: | ||
return getFloodlightState(); | ||
case CHANNEL_CAMERA_FLOODLIGHT_AUTO_MODE: | ||
//The auto-mode state shouldn't be updated, because this isn't a dedicated information. When the | ||
// floodlight is switched on the state within the Netatmo API is "on" and the information if the previous | ||
// state was "auto" instead of "off" is lost... Therefore the binding handles its own auto-mode state. | ||
if (floodlightAutoModeState == UnDefType.UNDEF) { | ||
floodlightAutoModeState = getFloodlightAutoModeState(); | ||
} | ||
return floodlightAutoModeState; | ||
} | ||
return super.getNAThingProperty(channelId); | ||
} | ||
|
||
private State getFloodlightState() { | ||
if (module != null) { | ||
final boolean isOn = module.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.ON; | ||
return toOnOffType(isOn); | ||
} | ||
return UnDefType.UNDEF; | ||
} | ||
|
||
private State getFloodlightAutoModeState() { | ||
if (module != null) { | ||
return toOnOffType(module.getLightModeStatus() == NAWelcomeCamera.LightModeStatusEnum.AUTO); | ||
} | ||
return UnDefType.UNDEF; | ||
} | ||
|
||
private void switchFloodlight(boolean isOn) { | ||
if (isOn) { | ||
changeFloodlightMode(NAWelcomeCamera.LightModeStatusEnum.ON); | ||
} else { | ||
switchFloodlightAutoMode(floodlightAutoModeState == OnOffType.ON); | ||
} | ||
} | ||
|
||
private void switchFloodlightAutoMode(boolean isAutoMode) { | ||
floodlightAutoModeState = toOnOffType(isAutoMode); | ||
if (isAutoMode) { | ||
changeFloodlightMode(NAWelcomeCamera.LightModeStatusEnum.AUTO); | ||
} else { | ||
changeFloodlightMode(NAWelcomeCamera.LightModeStatusEnum.OFF); | ||
} | ||
} | ||
|
||
private void changeFloodlightMode(NAWelcomeCamera.LightModeStatusEnum mode) { | ||
Optional<String> localCameraURL = getLocalCameraURL(); | ||
if (localCameraURL.isPresent()) { | ||
String url = localCameraURL.get() | ||
+ FLOODLIGHT_SET_URL_PATH | ||
+ "?config=%7B%22mode%22:%22" | ||
+ mode.toString() | ||
+ "%22%7D"; | ||
executeGETRequest(url); | ||
} | ||
} | ||
|
||
private Optional<String> getLocalCameraURL() { | ||
String vpnURL = getVpnUrl(); | ||
if (vpnURL != null) { | ||
//The local address is (re-)requested when it wasn't already determined or when the vpn address was changed. | ||
if (!cameraAddress.isPresent() || cameraAddress.get().isVpnURLChanged(vpnURL)) { | ||
Optional<JSONObject> json = executeGETRequestJSON(vpnURL + PING_URL_PATH); | ||
cameraAddress = json.map(j -> j.optString("local_url", null)) | ||
.map(localURL -> new CameraAddress(vpnURL, localURL)); | ||
} | ||
} | ||
return cameraAddress.map(CameraAddress::getLocalURL); | ||
} | ||
|
||
private Optional<JSONObject> executeGETRequestJSON(String url) { | ||
try { | ||
return executeGETRequest(url).map(JSONObject::new); | ||
} catch (JSONException e) { | ||
logger.warn("Error on parsing the content as JSON!", e); | ||
} | ||
return Optional.empty(); | ||
} | ||
|
||
Optional<String> executeGETRequest(String url) { | ||
try { | ||
String content = HttpUtil.executeUrl("GET", url, 5000); | ||
if (content != null && !content.isEmpty()) { | ||
return Optional.of(content); | ||
} | ||
} catch (IOException e) { | ||
logger.warn("Error on accessing local camera url!", e); | ||
} | ||
return Optional.empty(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.