diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ChannelGroup.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ChannelGroup.java index 5529046ef96..7a69aeb48d3 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ChannelGroup.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ChannelGroup.java @@ -90,7 +90,7 @@ public class ChannelGroup { groupTypes.stream().map(NetatmoThingTypeProvider::toGroupName).collect(Collectors.toSet())); } catch (ReflectiveOperationException e) { throw new IllegalArgumentException( - "Error creating or initializing helper class : %s".formatted(e.getMessage())); + "Error creating or initializing helper class: %s".formatted(e.getMessage())); } } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeEvent.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeEvent.java index cac51625d73..58b3607a0c4 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeEvent.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeEvent.java @@ -38,6 +38,10 @@ public class HomeEvent extends Event { } private record Snapshot(String url, ZonedDateTime expiresAt) { + // If the snapshot is expired we consider it as not available, so do not provide the url + public @Nullable String url() { + return expiresAt.isAfter(ZonedDateTime.now().withZoneSameInstant(expiresAt.getZone())) ? url : null; + } } private ZonedDateTime time = ZonedDateTime.now(); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/ApiBridgeHandler.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/ApiBridgeHandler.java index 4df7a1978c1..cec105c5671 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/ApiBridgeHandler.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/ApiBridgeHandler.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.Deque; import java.util.HashMap; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -183,8 +182,9 @@ public class ApiBridgeHandler extends BaseBridgeHandler { updateStatus(ThingStatus.ONLINE); - getThing().getThings().stream().filter(Thing::isEnabled).map(Thing::getHandler).filter(Objects::nonNull) - .map(CommonInterface.class::cast).forEach(CommonInterface::expireData); + getThing().getThings().stream().filter(Thing::isEnabled).map(Thing::getHandler) + .filter(CommonInterface.class::isInstance).map(CommonInterface.class::cast) + .forEach(CommonInterface::expireData); } private boolean authenticate(@Nullable String code, @Nullable String redirectUri) { @@ -353,7 +353,7 @@ public class ApiBridgeHandler extends BaseBridgeHandler { throw exception; } catch (NetatmoException e) { if (e.getStatusCode() == ServiceError.MAXIMUM_USAGE_REACHED) { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "@text/maximum-usage-reached"); prepareReconnection(null, null); } throw e; diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java index ed161250197..398bd9a8764 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/CameraCapability.java @@ -37,6 +37,7 @@ import org.openhab.binding.netatmo.internal.handler.CommonInterface; import org.openhab.binding.netatmo.internal.handler.channelhelper.CameraChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper; import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider; +import org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils; import org.openhab.core.config.core.Configuration; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; @@ -96,9 +97,11 @@ public class CameraCapability extends HomeSecurityThingCapability { eventHelper.setUrls(newVpnUrl, localUrl); } vpnUrl = newVpnUrl; - if (!SdCardStatus.SD_CARD_WORKING.equals(newData.getSdStatus()) - || !AlimentationStatus.ALIM_CORRECT_POWER.equals(newData.getAlimStatus())) { - statusReason = "%s, %s".formatted(newData.getSdStatus(), newData.getAlimStatus()); + if (!SdCardStatus.SD_CARD_WORKING.equals(newData.getSdStatus())) { + statusReason = newData.getSdStatus().toString(); + } + if (!AlimentationStatus.ALIM_CORRECT_POWER.equals(newData.getAlimStatus())) { + statusReason = newData.getAlimStatus().toString(); } } @@ -125,12 +128,10 @@ public class CameraCapability extends HomeSecurityThingCapability { private void updateSubGroup(WebhookEvent event, String group) { handler.updateState(group, CHANNEL_EVENT_TYPE, toStringType(event.getEventType())); handler.updateState(group, CHANNEL_EVENT_TIME, toDateTimeType(event.getTime())); - handler.updateState(group, CHANNEL_EVENT_SNAPSHOT, toRawType(event.getSnapshotUrl())); - handler.updateState(group, CHANNEL_EVENT_SNAPSHOT_URL, toStringType(event.getSnapshotUrl())); - handler.updateState(group, CHANNEL_EVENT_VIGNETTE, toRawType(event.getVignetteUrl())); - handler.updateState(group, CHANNEL_EVENT_VIGNETTE_URL, toStringType(event.getVignetteUrl())); - handler.updateState(group, CHANNEL_EVENT_SUBTYPE, - Objects.requireNonNull(event.getSubTypeDescription().map(d -> toStringType(d)).orElse(UnDefType.NULL))); + updatePictureIfUrlPresent(event.getSnapshotUrl(), group, CHANNEL_EVENT_SNAPSHOT, CHANNEL_EVENT_SNAPSHOT_URL); + updatePictureIfUrlPresent(event.getVignetteUrl(), group, CHANNEL_EVENT_VIGNETTE, CHANNEL_EVENT_VIGNETTE_URL); + handler.updateState(group, CHANNEL_EVENT_SUBTYPE, Objects.requireNonNull( + event.getSubTypeDescription().map(ChannelTypeUtils::toStringType).orElse(UnDefType.NULL))); final String message = event.getName(); handler.updateState(group, CHANNEL_EVENT_MESSAGE, message == null || message.isBlank() ? UnDefType.NULL : toStringType(message)); @@ -139,6 +140,14 @@ public class CameraCapability extends HomeSecurityThingCapability { handler.updateState(personChannelUID, personId); } + private void updatePictureIfUrlPresent(@Nullable String snapShotUrl, String group, String pictureChannel, + String urlChannel) { + if (snapShotUrl != null) { + handler.updateState(group, pictureChannel, toRawType(snapShotUrl)); + handler.updateState(group, urlChannel, toStringType(snapShotUrl)); + } + } + @Override public void handleCommand(String channelName, Command command) { if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) { diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/PersonCapability.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/PersonCapability.java index 60b9f3fe511..da41d6444b2 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/PersonCapability.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/PersonCapability.java @@ -34,6 +34,7 @@ import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent; import org.openhab.binding.netatmo.internal.handler.CommonInterface; import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper; import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider; +import org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; import org.openhab.core.types.Command; @@ -79,8 +80,8 @@ public class PersonCapability extends HomeSecurityThingCapability { protected void updateWebhookEvent(WebhookEvent event) { super.updateWebhookEvent(event); - handler.updateState(GROUP_LAST_EVENT, CHANNEL_EVENT_SUBTYPE, - Objects.requireNonNull(event.getSubTypeDescription().map(d -> toStringType(d)).orElse(UnDefType.NULL))); + handler.updateState(GROUP_LAST_EVENT, CHANNEL_EVENT_SUBTYPE, Objects.requireNonNull( + event.getSubTypeDescription().map(ChannelTypeUtils::toStringType).orElse(UnDefType.NULL))); final String message = event.getName(); handler.updateState(GROUP_LAST_EVENT, CHANNEL_EVENT_MESSAGE, diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventCameraChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventCameraChannelHelper.java index 6348ea1d451..7283ec3955c 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventCameraChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventCameraChannelHelper.java @@ -13,7 +13,7 @@ package org.openhab.binding.netatmo.internal.handler.channelhelper; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; -import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.*; +import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.toStringType; import java.util.Set; @@ -43,10 +43,10 @@ public class EventCameraChannelHelper extends EventChannelHelper { case CHANNEL_EVENT_TYPE -> toStringType(event.getEventType()); case CHANNEL_EVENT_TIME -> new DateTimeType(event.getTime()); case CHANNEL_EVENT_MESSAGE -> toStringType(event.getName()); - case CHANNEL_EVENT_SNAPSHOT -> toRawType(event.getSnapshotUrl()); - case CHANNEL_EVENT_SNAPSHOT_URL -> toStringType(event.getSnapshotUrl()); - case CHANNEL_EVENT_VIGNETTE -> toRawType(event.getVignetteUrl()); - case CHANNEL_EVENT_VIGNETTE_URL -> toStringType(event.getVignetteUrl()); + case CHANNEL_EVENT_SNAPSHOT -> checkUrlPresence(event.getSnapshotUrl(), true); + case CHANNEL_EVENT_SNAPSHOT_URL -> checkUrlPresence(event.getSnapshotUrl(), false); + case CHANNEL_EVENT_VIGNETTE -> checkUrlPresence(event.getVignetteUrl(), true); + case CHANNEL_EVENT_VIGNETTE_URL -> checkUrlPresence(event.getVignetteUrl(), false); default -> super.internalGetHomeEvent(channelId, groupId, event); }; } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventChannelHelper.java index 947e47bf5a4..afbb4cea702 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventChannelHelper.java @@ -72,17 +72,24 @@ public class EventChannelHelper extends ChannelHelper { case CHANNEL_EVENT_CAMERA_ID -> toStringType(event.getCameraId()); case CHANNEL_EVENT_SUBTYPE -> event.getSubTypeDescription().map(ChannelTypeUtils::toStringType).orElse(UnDefType.NULL); - case CHANNEL_EVENT_SNAPSHOT -> toRawType(event.getSnapshotUrl()); - case CHANNEL_EVENT_SNAPSHOT_URL -> toStringType(event.getSnapshotUrl()); + case CHANNEL_EVENT_SNAPSHOT -> checkUrlPresence(event.getSnapshotUrl(), true); + case CHANNEL_EVENT_SNAPSHOT_URL -> checkUrlPresence(event.getSnapshotUrl(), false); default -> null; }; } + protected @Nullable State checkUrlPresence(@Nullable String url, boolean asRaw) { + return url != null ? asRaw ? toRawType(url) : toStringType(url) : null; + } + @Override protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) { + String videoId = event.getVideoId(); + if (videoId == null) { + return null; + } return switch (channelId) { - case CHANNEL_EVENT_VIDEO_STATUS -> - event.getVideoId() != null ? toStringType(event.getVideoStatus()) : UnDefType.NULL; + case CHANNEL_EVENT_VIDEO_STATUS -> toStringType(event.getVideoStatus()); case CHANNEL_EVENT_VIDEO_LOCAL_URL -> getStreamURL(true, event.getVideoId(), event.getVideoStatus()); case CHANNEL_EVENT_VIDEO_VPN_URL -> getStreamURL(false, event.getVideoId(), event.getVideoStatus()); default -> null; diff --git a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo.properties b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo.properties index 7df9236505b..820a91b98e7 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo.properties +++ b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo.properties @@ -465,6 +465,7 @@ device-not-connected = Thing is not reachable data-over-limit = Data seems quite old request-time-out = Request timed out - will attempt reconnection later deserialization-unknown = Deserialization lead to an unknown code +maximum-usage-reached = Maximum usage reached. Will try reconnection after `reconnectInterval` seconds. homestatus-unknown-error = Unknown error homestatus-internal-error = Internal error