]> git.basschouten.com Git - openhab-addons.git/commitdiff
[netatmo] Fix Live Picture not always available (#16679)
authorGaël L'hopital <gael@lhopital.org>
Mon, 29 Apr 2024 11:30:00 +0000 (13:30 +0200)
committerGitHub <noreply@github.com>
Mon, 29 Apr 2024 11:30:00 +0000 (13:30 +0200)
* Adressing issue on live picture

Signed-off-by: gael@lhopital.org <gael@lhopital.org>
Signed-off-by: root <gael@lhopital.org>
bundles/org.openhab.binding.netatmo/README.md
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/WebhookEvent.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java
bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/utils/ChannelTypeUtils.java

index 9fa7a8fac7a6e50826387e07c179dcf895357a1b..fb80901a2d6170fb517fa2aa6666ea6c80ca29a7 100644 (file)
@@ -528,7 +528,7 @@ Warnings:
 | status         | monitoring           | Switch       | Read-write | State of the camera (video surveillance on/off)                                                                                             |
 | status         | sd-card              | String       | Read-only  | State of the SD card                                                                                                                        |
 | status         | alim                 | String       | Read-only  | State of the power connector                                                                                                                |
-| live           | picture              | Image        | Read-only  | Camera Live Snapshot                                                                                                                        |
+| live           | picture (**)         | Image        | Read-only  | Camera Live Snapshot                                                                                                                        |
 | live           | local-picture-url    | String       | Read-only  | Local Url of the live snapshot for this camera                                                                                              |
 | live           | vpn-picture-url      | String       | Read-only  | Url of the live snapshot for this camera through Netatmo VPN.                                                                               |
 | live           | local-stream-url (*) | String       | Read-only  | Local Url of the live stream for this camera (accessible if openhab server and camera are located on the same lan.                          |
@@ -547,6 +547,7 @@ Warnings:
 | last-event     | person-id            | String       | Read-only  | Id of the person the event is about (if any)                                                                                                |
 
 (*) This channel is configurable : low, poor, high.
+(**) This channel handles the REFRESH command for on demand update.
 
 **Supported channels for the Presence Camera thing:**
 
index 9d492207ce0f054279d816ce4b3a328db31ffa37..2eefa7bf7cbb42be12405452964a55110a0ac311 100644 (file)
@@ -63,7 +63,7 @@ public class WebhookEvent extends Event {
 
     @Override
     public @Nullable String getPersonId() {
-        return persons.size() > 0 ? persons.keySet().iterator().next() : null;
+        return persons.isEmpty() ? null : persons.keySet().iterator().next();
     }
 
     @Override
index 2debb89e65f6712bf40e2c64934396a957e62c7c..d110659c868231ae91d1055c7f9f0cebe373923c 100644 (file)
@@ -40,6 +40,7 @@ import org.openhab.core.config.core.Configuration;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.types.Command;
+import org.openhab.core.types.RefreshType;
 import org.openhab.core.types.State;
 import org.openhab.core.types.StateOption;
 import org.openhab.core.types.UnDefType;
@@ -141,6 +142,9 @@ public class CameraCapability extends HomeSecurityThingCapability {
     public void handleCommand(String channelName, Command command) {
         if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) {
             getSecurityCapability().ifPresent(cap -> cap.changeStatus(localUrl, OnOffType.ON.equals(command)));
+        } else if (command instanceof RefreshType && CHANNEL_LIVEPICTURE.equals(channelName)) {
+            handler.updateState(GROUP_CAM_LIVE, CHANNEL_LIVEPICTURE,
+                    toRawType(cameraHelper.getLivePictureURL(localUrl != null, true)));
         } else {
             super.handleCommand(channelName, command);
         }
index 5e63cf85d790f6a426efb800acc627083c286eb2..21dde6e409fff64c14c599fd9e1dbe7c4d343206 100644 (file)
@@ -36,7 +36,7 @@ import org.openhab.core.types.UnDefType;
 public class CameraChannelHelper extends ChannelHelper {
     private static final String QUALITY_CONF_ENTRY = "quality";
     private static final String LIVE_PICTURE = "/live/snapshot_720.jpg";
-    private boolean isLocal;
+
     private @Nullable String vpnUrl;
     private @Nullable String localUrl;
 
@@ -44,56 +44,66 @@ public class CameraChannelHelper extends ChannelHelper {
         super(providedGroups);
     }
 
-    public void setUrls(String vpnUrl, @Nullable String localUrl) {
+    public void setUrls(@Nullable String vpnUrl, @Nullable String localUrl) {
         this.localUrl = localUrl;
         this.vpnUrl = vpnUrl;
-        this.isLocal = localUrl != null;
-    }
-
-    public @Nullable String getLocalURL() {
-        return localUrl;
     }
 
     @Override
     protected @Nullable State internalGetProperty(String channelId, NAThing naThing, Configuration config) {
         if (naThing instanceof HomeStatusModule camera) {
-            boolean isMonitoring = OnOffType.ON.equals(camera.getMonitoring());
-            switch (channelId) {
-                case CHANNEL_MONITORING:
-                    return camera.getMonitoring();
-                case CHANNEL_SD_CARD:
-                    return toStringType(camera.getSdStatus());
-                case CHANNEL_ALIM_STATUS:
-                    return toStringType(camera.getAlimStatus());
-                case CHANNEL_LIVEPICTURE_VPN_URL:
-                    return toStringType(getLivePictureURL(false, isMonitoring));
-                case CHANNEL_LIVEPICTURE_LOCAL_URL:
-                    return toStringType(getLivePictureURL(true, isMonitoring));
-                case CHANNEL_LIVEPICTURE:
-                    return toRawType(getLivePictureURL(isLocal, isMonitoring));
-                case CHANNEL_LIVESTREAM_VPN_URL:
-                    return getLiveStreamURL(false, (String) config.get(QUALITY_CONF_ENTRY), isMonitoring);
-                case CHANNEL_LIVESTREAM_LOCAL_URL:
-                    return getLiveStreamURL(true, (String) config.get(QUALITY_CONF_ENTRY), isMonitoring);
-            }
+            return switch (channelId) {
+                case CHANNEL_MONITORING -> camera.getMonitoring();
+                case CHANNEL_SD_CARD -> toStringType(camera.getSdStatus());
+                case CHANNEL_ALIM_STATUS -> toStringType(camera.getAlimStatus());
+                default -> liveChannels(channelId, (String) config.get(QUALITY_CONF_ENTRY), camera,
+                        OnOffType.ON.equals(camera.getMonitoring()), localUrl != null);
+            };
         }
         return null;
     }
 
-    private @Nullable String getLivePictureURL(boolean local, boolean isMonitoring) {
-        String url = local ? localUrl : vpnUrl;
-        if (!isMonitoring || (local && !isLocal) || url == null) {
+    public @Nullable String getLivePictureURL(boolean local, boolean isMonitoring) {
+        String url = getUrl(local);
+        if (!isMonitoring || url == null) {
             return null;
         }
         return "%s%s".formatted(url, LIVE_PICTURE);
     }
 
+    private @Nullable State liveChannels(String channelId, String qualityConf, HomeStatusModule camera,
+            boolean isMonitoring, boolean isLocal) {
+        if (vpnUrl == null) {
+            setUrls(camera.getVpnUrl(), localUrl);
+        }
+        return switch (channelId) {
+            case CHANNEL_LIVESTREAM_LOCAL_URL ->
+                isLocal ? getLiveStreamURL(true, qualityConf, isMonitoring) : UnDefType.NULL;
+            case CHANNEL_LIVEPICTURE_LOCAL_URL ->
+                isLocal ? toStringType(getLivePictureURL(true, isMonitoring)) : UnDefType.NULL;
+            case CHANNEL_LIVESTREAM_VPN_URL -> getLiveStreamURL(false, qualityConf, isMonitoring);
+            case CHANNEL_LIVEPICTURE_VPN_URL -> toStringType(getLivePictureURL(false, isMonitoring));
+            case CHANNEL_LIVEPICTURE -> {
+                State result = toRawType(getLivePictureURL(isLocal, isMonitoring));
+                if (UnDefType.NULL.equals(result) && isLocal) {// If local read is unsuccessfull, try the VPN version
+                    result = toRawType(getLivePictureURL(false, isMonitoring));
+                }
+                yield result;
+            }
+            default -> null;
+        };
+    }
+
+    private @Nullable String getUrl(boolean local) {
+        return local ? localUrl : vpnUrl;
+    }
+
     private State getLiveStreamURL(boolean local, @Nullable String configQual, boolean isMonitoring) {
-        String url = local ? localUrl : vpnUrl;
-        if (!isMonitoring || (local && !isLocal) || url == null) {
+        String url = getUrl(local);
+        if (!isMonitoring || url == null) {
             return UnDefType.NULL;
         }
         String finalQual = configQual != null ? configQual : "poor";
-        return toStringType("%s/live/%s", url, local ? "files/%s/index.m3u8".formatted(finalQual) : "index.m3u8");
+        return toStringType("%s/live/%sindex.m3u8", url, local ? "files/%s/".formatted(finalQual) : "");
     }
 }
index 30f425fa2a12a03890b2c8752fec262c2a186c90..8fe4c3bf09efe91f0149ab83fe02d01448d607e6 100644 (file)
@@ -40,6 +40,7 @@ import org.openhab.core.types.UnDefType;
  */
 @NonNullByDefault
 public class ChannelTypeUtils {
+    private static final int DEFAULT_TIMEOUT_MS = 30000;
 
     public static @Nullable QuantityType<?> commandToQuantity(Command command, MeasureClass measureClass) {
         Measure measureDef = measureClass.measureDefinition;
@@ -90,7 +91,8 @@ public class ChannelTypeUtils {
 
     public static State toRawType(@Nullable String pictureUrl) {
         if (pictureUrl != null) {
-            RawType picture = HttpUtil.downloadImage(pictureUrl);
+            // Retrieving local picture can be quite long then extend the timeout.
+            RawType picture = HttpUtil.downloadImage(pictureUrl, DEFAULT_TIMEOUT_MS);
             if (picture != null) {
                 return picture;
             }