Skip to content

Commit 5f7282b

Browse files
authored
[netatmo] Fix Live Picture not always available (openhab#16679)
* Adressing issue on live picture Signed-off-by: [email protected] <[email protected]> Signed-off-by: root <[email protected]>
1 parent cf21184 commit 5f7282b

File tree

5 files changed

+52
-35
lines changed

5 files changed

+52
-35
lines changed

bundles/org.openhab.binding.netatmo/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ Warnings:
528528
| status | monitoring | Switch | Read-write | State of the camera (video surveillance on/off) |
529529
| status | sd-card | String | Read-only | State of the SD card |
530530
| status | alim | String | Read-only | State of the power connector |
531-
| live | picture | Image | Read-only | Camera Live Snapshot |
531+
| live | picture (**) | Image | Read-only | Camera Live Snapshot |
532532
| live | local-picture-url | String | Read-only | Local Url of the live snapshot for this camera |
533533
| live | vpn-picture-url | String | Read-only | Url of the live snapshot for this camera through Netatmo VPN. |
534534
| 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:
547547
| last-event | person-id | String | Read-only | Id of the person the event is about (if any) |
548548

549549
(*) This channel is configurable : low, poor, high.
550+
(**) This channel handles the REFRESH command for on demand update.
550551

551552
**Supported channels for the Presence Camera thing:**
552553

bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/WebhookEvent.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public ZonedDateTime getTime() {
6363

6464
@Override
6565
public @Nullable String getPersonId() {
66-
return persons.size() > 0 ? persons.keySet().iterator().next() : null;
66+
return persons.isEmpty() ? null : persons.keySet().iterator().next();
6767
}
6868

6969
@Override

bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.openhab.core.library.types.OnOffType;
4141
import org.openhab.core.thing.ChannelUID;
4242
import org.openhab.core.types.Command;
43+
import org.openhab.core.types.RefreshType;
4344
import org.openhab.core.types.State;
4445
import org.openhab.core.types.StateOption;
4546
import org.openhab.core.types.UnDefType;
@@ -141,6 +142,9 @@ private void updateSubGroup(WebhookEvent event, String group) {
141142
public void handleCommand(String channelName, Command command) {
142143
if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) {
143144
getSecurityCapability().ifPresent(cap -> cap.changeStatus(localUrl, OnOffType.ON.equals(command)));
145+
} else if (command instanceof RefreshType && CHANNEL_LIVEPICTURE.equals(channelName)) {
146+
handler.updateState(GROUP_CAM_LIVE, CHANNEL_LIVEPICTURE,
147+
toRawType(cameraHelper.getLivePictureURL(localUrl != null, true)));
144148
} else {
145149
super.handleCommand(channelName, command);
146150
}

bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java

+42-32
Original file line numberDiff line numberDiff line change
@@ -36,64 +36,74 @@
3636
public class CameraChannelHelper extends ChannelHelper {
3737
private static final String QUALITY_CONF_ENTRY = "quality";
3838
private static final String LIVE_PICTURE = "/live/snapshot_720.jpg";
39-
private boolean isLocal;
39+
4040
private @Nullable String vpnUrl;
4141
private @Nullable String localUrl;
4242

4343
public CameraChannelHelper(Set<String> providedGroups) {
4444
super(providedGroups);
4545
}
4646

47-
public void setUrls(String vpnUrl, @Nullable String localUrl) {
47+
public void setUrls(@Nullable String vpnUrl, @Nullable String localUrl) {
4848
this.localUrl = localUrl;
4949
this.vpnUrl = vpnUrl;
50-
this.isLocal = localUrl != null;
51-
}
52-
53-
public @Nullable String getLocalURL() {
54-
return localUrl;
5550
}
5651

5752
@Override
5853
protected @Nullable State internalGetProperty(String channelId, NAThing naThing, Configuration config) {
5954
if (naThing instanceof HomeStatusModule camera) {
60-
boolean isMonitoring = OnOffType.ON.equals(camera.getMonitoring());
61-
switch (channelId) {
62-
case CHANNEL_MONITORING:
63-
return camera.getMonitoring();
64-
case CHANNEL_SD_CARD:
65-
return toStringType(camera.getSdStatus());
66-
case CHANNEL_ALIM_STATUS:
67-
return toStringType(camera.getAlimStatus());
68-
case CHANNEL_LIVEPICTURE_VPN_URL:
69-
return toStringType(getLivePictureURL(false, isMonitoring));
70-
case CHANNEL_LIVEPICTURE_LOCAL_URL:
71-
return toStringType(getLivePictureURL(true, isMonitoring));
72-
case CHANNEL_LIVEPICTURE:
73-
return toRawType(getLivePictureURL(isLocal, isMonitoring));
74-
case CHANNEL_LIVESTREAM_VPN_URL:
75-
return getLiveStreamURL(false, (String) config.get(QUALITY_CONF_ENTRY), isMonitoring);
76-
case CHANNEL_LIVESTREAM_LOCAL_URL:
77-
return getLiveStreamURL(true, (String) config.get(QUALITY_CONF_ENTRY), isMonitoring);
78-
}
55+
return switch (channelId) {
56+
case CHANNEL_MONITORING -> camera.getMonitoring();
57+
case CHANNEL_SD_CARD -> toStringType(camera.getSdStatus());
58+
case CHANNEL_ALIM_STATUS -> toStringType(camera.getAlimStatus());
59+
default -> liveChannels(channelId, (String) config.get(QUALITY_CONF_ENTRY), camera,
60+
OnOffType.ON.equals(camera.getMonitoring()), localUrl != null);
61+
};
7962
}
8063
return null;
8164
}
8265

83-
private @Nullable String getLivePictureURL(boolean local, boolean isMonitoring) {
84-
String url = local ? localUrl : vpnUrl;
85-
if (!isMonitoring || (local && !isLocal) || url == null) {
66+
public @Nullable String getLivePictureURL(boolean local, boolean isMonitoring) {
67+
String url = getUrl(local);
68+
if (!isMonitoring || url == null) {
8669
return null;
8770
}
8871
return "%s%s".formatted(url, LIVE_PICTURE);
8972
}
9073

74+
private @Nullable State liveChannels(String channelId, String qualityConf, HomeStatusModule camera,
75+
boolean isMonitoring, boolean isLocal) {
76+
if (vpnUrl == null) {
77+
setUrls(camera.getVpnUrl(), localUrl);
78+
}
79+
return switch (channelId) {
80+
case CHANNEL_LIVESTREAM_LOCAL_URL ->
81+
isLocal ? getLiveStreamURL(true, qualityConf, isMonitoring) : UnDefType.NULL;
82+
case CHANNEL_LIVEPICTURE_LOCAL_URL ->
83+
isLocal ? toStringType(getLivePictureURL(true, isMonitoring)) : UnDefType.NULL;
84+
case CHANNEL_LIVESTREAM_VPN_URL -> getLiveStreamURL(false, qualityConf, isMonitoring);
85+
case CHANNEL_LIVEPICTURE_VPN_URL -> toStringType(getLivePictureURL(false, isMonitoring));
86+
case CHANNEL_LIVEPICTURE -> {
87+
State result = toRawType(getLivePictureURL(isLocal, isMonitoring));
88+
if (UnDefType.NULL.equals(result) && isLocal) {// If local read is unsuccessfull, try the VPN version
89+
result = toRawType(getLivePictureURL(false, isMonitoring));
90+
}
91+
yield result;
92+
}
93+
default -> null;
94+
};
95+
}
96+
97+
private @Nullable String getUrl(boolean local) {
98+
return local ? localUrl : vpnUrl;
99+
}
100+
91101
private State getLiveStreamURL(boolean local, @Nullable String configQual, boolean isMonitoring) {
92-
String url = local ? localUrl : vpnUrl;
93-
if (!isMonitoring || (local && !isLocal) || url == null) {
102+
String url = getUrl(local);
103+
if (!isMonitoring || url == null) {
94104
return UnDefType.NULL;
95105
}
96106
String finalQual = configQual != null ? configQual : "poor";
97-
return toStringType("%s/live/%s", url, local ? "files/%s/index.m3u8".formatted(finalQual) : "index.m3u8");
107+
return toStringType("%s/live/%sindex.m3u8", url, local ? "files/%s/".formatted(finalQual) : "");
98108
}
99109
}

bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/utils/ChannelTypeUtils.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
@NonNullByDefault
4242
public class ChannelTypeUtils {
43+
private static final int DEFAULT_TIMEOUT_MS = 30000;
4344

4445
public static @Nullable QuantityType<?> commandToQuantity(Command command, MeasureClass measureClass) {
4546
Measure measureDef = measureClass.measureDefinition;
@@ -90,7 +91,8 @@ public static State toQuantityType(@Nullable Number value, Unit<?> unit) {
9091

9192
public static State toRawType(@Nullable String pictureUrl) {
9293
if (pictureUrl != null) {
93-
RawType picture = HttpUtil.downloadImage(pictureUrl);
94+
// Retrieving local picture can be quite long then extend the timeout.
95+
RawType picture = HttpUtil.downloadImage(pictureUrl, DEFAULT_TIMEOUT_MS);
9496
if (picture != null) {
9597
return picture;
9698
}

0 commit comments

Comments
 (0)