From 55beb413bddafcc6877f8b438bd94db15258e8a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Tue, 24 May 2022 21:56:55 +0200 Subject: [PATCH] [netatmo] Add doorbell support (#12776) * Adding doorbell handling to netatmo Closes #8571 Signed-off-by: clinique --- bundles/org.openhab.binding.netatmo/README.md | 89 ++++++++++++------- .../internal/NetatmoBindingConstants.java | 28 ++++-- .../netatmo/internal/api/AircareApi.java | 2 +- .../netatmo/internal/api/EnergyApi.java | 8 +- .../binding/netatmo/internal/api/HomeApi.java | 6 +- .../netatmo/internal/api/SecurityApi.java | 15 ++-- .../netatmo/internal/api/WeatherApi.java | 6 +- .../netatmo/internal/api/data/EventType.java | 28 ++++-- .../netatmo/internal/api/data/ModuleType.java | 18 ++-- .../internal/api/data/NetatmoConstants.java | 31 +++---- .../netatmo/internal/api/dto/HomeEvent.java | 20 ++++- .../internal/api/dto/HomeStatusModule.java | 4 +- .../handler/capability/CameraCapability.java | 6 +- .../handler/capability/PersonCapability.java | 4 +- .../capability/SecurityCapability.java | 4 +- .../channelhelper/CameraChannelHelper.java | 6 +- .../handler/channelhelper/ChannelHelper.java | 11 +++ .../channelhelper/DoorbellChannelHelper.java | 31 +++++++ .../channelhelper/EventChannelHelper.java | 30 ++++--- .../EventDoorbellChannelHelper.java | 59 ++++++++++++ .../EventPersonChannelHelper.java | 13 +-- .../channelhelper/PresenceChannelHelper.java | 5 +- .../channelhelper/RoomChannelHelper.java | 2 +- .../channelhelper/SetpointChannelHelper.java | 2 +- .../channelhelper/Therm1ChannelHelper.java | 2 +- .../providers/NetatmoThingTypeProvider.java | 6 +- .../resources/OH-INF/i18n/netatmo.properties | 42 ++++++--- .../OH-INF/i18n/netatmo_it.properties | 6 +- .../main/resources/OH-INF/thing/channels.xml | 10 ++- .../main/resources/OH-INF/thing/energy.xml | 8 +- .../main/resources/OH-INF/thing/security.xml | 63 ++++++++++++- 31 files changed, 424 insertions(+), 141 deletions(-) create mode 100644 bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/DoorbellChannelHelper.java create mode 100644 bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventDoorbellChannelHelper.java diff --git a/bundles/org.openhab.binding.netatmo/README.md b/bundles/org.openhab.binding.netatmo/README.md index 9e7cb90c6..9da4a5704 100644 --- a/bundles/org.openhab.binding.netatmo/README.md +++ b/bundles/org.openhab.binding.netatmo/README.md @@ -350,16 +350,16 @@ All these channels are read only. **Supported channels for the Room thing:** -| Channel Group | Channel Id | Item Type | Description | -|------------------|-----------------------|----------------------|---------------------------------------------------------| -| room-temperature | value | Number:Temperature | Current temperature in the room | -| room-properties | window-open | Contact | Windows of the room are opened | -| room-properties | anticipating | Switch | Anticipates next scheduled setpoint | -| room-properties | heating-power-request | Number:Dimensionless | Percentage of heating power | -| setpoint | value | Number:Temperature | Thermostat temperature setpoint | -| setpoint | mode | String | Chosen thermostat mode (home, frost guard, manual, max) | -| setpoint | start | DateTime | Start time of the currently applied setpoint | -| setpoint | end | DateTime | End time of the currently applied setpoint | +| Channel Group | Channel Id | Item Type | Description | +|---------------|-----------------------|----------------------|---------------------------------------------------------| +| temperature | value | Number:Temperature | Current temperature in the room | +| properties | window-open | Contact | Windows of the room are opened | +| properties | anticipating | Switch | Anticipates next scheduled setpoint | +| properties | heating-power-request | Number:Dimensionless | Percentage of heating power | +| setpoint | value | Number:Temperature | Thermostat temperature setpoint | +| setpoint | mode | String | Chosen thermostat mode (home, frost guard, manual, max) | +| setpoint | start | DateTime | Start time of the currently applied setpoint | +| setpoint | end | DateTime | End time of the currently applied setpoint | All these channels except setpoint and setpoint-mode are read only. @@ -368,14 +368,14 @@ All these channels except setpoint and setpoint-mode are read only. **Supported channels for the thermostat module:** -| Channel Group | Channel Id | Item Type | Description | -|---------------------|--------------------|----------------------|--------------------------------------------------| -| th-properties | relay-status | Contact | Indicates if the boiler is currently heating | -| signal | strength | Number | Signal strength (0 for no signal, 1 for weak...) | -| signal | value | Number:Power | Signal strength in dBm | -| battery | value | Number | Battery level | -| battery | low-battery | Switch | Low battery | -| battery | status | String | Description of the battery status (*) | +| Channel Group | Channel Id | Item Type | Description | +|---------------|-------------|--------------|--------------------------------------------------| +| properties | relay | Contact | Indicates if the boiler is currently heating | +| signal | strength | Number | Signal strength (0 for no signal, 1 for weak...) | +| signal | value | Number:Power | Signal strength in dBm | +| battery | value | Number | Battery level | +| battery | low-battery | Switch | Low battery | +| battery | status | String | Description of the battery status (*) | (*) Can be UNDEF on some modules @@ -438,7 +438,7 @@ All these channels are read only. | | TAG_UNINSTALLED | Triggered when a tag gets uninstalled | | | TAG_OPEN | Triggered when an open event of a tag was detected | -### Welcome and Presence Camera +### Welcome, Presence and Doorbell Cameras Warnings: @@ -503,6 +503,33 @@ Warnings: (*) This channel is configurable : low, poor, high. +**Supported channels for the Welcome Doorbell thing:** + +| Channel Group | Channel ID | Item Type | Read/Write | Description | +|---------------|-------------------|--------------|------------|---------------------------------------------------------------------------------------------------------------------------------------------| +| 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 | 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. | +| signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) | +| signal | value | Number:Power | Read-only | Signal strength in dBm | +| last-event | type | String | Read-only | Type of event | +| last-event | video-status | String | Read-only | Status of the video (recording, deleted or available) | +| last-event | time | DateTime | Read-only | Time of occurrence of event | +| last-event | local-video-url | String | Read-only | If the last event (depending upon event type) in the home lead a snapshot picture, the corresponding local video URL will be available here | +| last-event | vpn-video-url | String | Read-only | If the last event (depending upon event type) in the home lead a snapshot picture, the corresponding VPN video URL will be available here | +| sub-event | type | String | Read-only | Type of sub-event | +| sub-event | time | DateTime | Read-only | Time of occurrence of sub-event | +| sub-event | message | String | Read-only | Message sent by Netatmo corresponding to given sub-event | +| sub-event | snapshot-url | String | Read-only | Depending upon event type in the home, a snapshot picture of the corresponding local video URL will be available here | +| sub-event | vignette-url | String | Read-only | A vignette representing the snapshot | +| sub-event | snapshot | Image | Read-only | picture of the snapshot | +| sub-event | vignet | Image | Read-only | picture of the vignette | + + +Note: live feeds either locally or via VPN are not available in Netatmo API. + ### Welcome Person @@ -515,18 +542,18 @@ Person things are automatically created in discovery process for all known perso **Supported channels for the Person thing:** -| Channel Group | Channel ID | Item Type | Description | -|----------------|----------------|--------------|--------------------------------------------------------| -| person | avatar-url | String | URL for the avatar of this person | -| person | avatar | Image | Avatar of this person | -| person | at-home | Switch | Indicates if this person is known to be at home or not | -| person | last-seen | DateTime | Moment when this person was last seen | -| person-event | subtype | String | Sub-type of event | -| person-event | message | String | Last event message from this person | -| person-event | time | DateTime | Moment of the last event for this person | -| person-event | snapshot | Image | Picture of the last event for this person | -| person-event | snapshot-url | String | URL for the picture of the last event for this person | -| person-event | camera-id | String | ID of the camera that triggered the event | +| Channel Group | Channel ID | Item Type | Description | +|---------------|--------------|-----------|--------------------------------------------------------| +| person | avatar-url | String | URL for the avatar of this person | +| person | avatar | Image | Avatar of this person | +| person | at-home | Switch | Indicates if this person is known to be at home or not | +| person | last-seen | DateTime | Moment when this person was last seen | +| last-event | subtype | String | Sub-type of event | +| last-event | message | String | Last event message from this person | +| last-event | time | DateTime | Moment of the last event for this person | +| last-event | snapshot | Image | Picture of the last event for this person | +| last-event | snapshot-url | String | URL for the picture of the last event for this person | +| last-event | camera-id | String | ID of the camera that triggered the event | All these channels except at-home are read only. diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBindingConstants.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBindingConstants.java index fc556be85..c4a3d585f 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBindingConstants.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/NetatmoBindingConstants.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.netatmo.internal; +import java.util.Set; + import org.eclipse.jdt.annotation.NonNullByDefault; /** @@ -35,6 +37,7 @@ public class NetatmoBindingConstants { // Channel group ids public static final String GROUP_LAST_EVENT = "last-event"; + public static final String GROUP_SUB_EVENT = "sub-event"; public static final String GROUP_TEMPERATURE = "temperature"; public static final String GROUP_HUMIDITY = "humidity"; public static final String GROUP_AIR_QUALITY = "airquality"; @@ -51,22 +54,33 @@ public class NetatmoBindingConstants { public static final String GROUP_CAM_LIVE = "live"; public static final String GROUP_PRESENCE = "presence"; public static final String GROUP_PERSON = "person"; - public static final String GROUP_PERSON_EVENT = "person-event"; - public static final String GROUP_ROOM_TEMPERATURE = "room-temperature"; - public static final String GROUP_ROOM_PROPERTIES = "room-properties"; - public static final String GROUP_TH_PROPERTIES = "th-properties"; - public static final String GROUP_TH_SETPOINT = "setpoint"; + public static final String GROUP_PROPERTIES = "properties"; + public static final String GROUP_SETPOINT = "setpoint"; public static final String GROUP_LOCATION = "location"; // Alternative extended groups public static final String OPTION_EXTENDED = "-extended"; public static final String OPTION_OUTSIDE = "-outside"; + public static final String OPTION_DOORBELL = "-doorbell"; + public static final String OPTION_PERSON = "-person"; + public static final String OPTION_ROOM = "-room"; + public static final String OPTION_THERMOSTAT = "-thermostat"; + public static final Set GROUP_VARIATIONS = Set.of(OPTION_EXTENDED, OPTION_OUTSIDE, OPTION_DOORBELL, + OPTION_PERSON, OPTION_ROOM, OPTION_THERMOSTAT); public static final String GROUP_TYPE_TIMESTAMP_EXTENDED = GROUP_TIMESTAMP + OPTION_EXTENDED; public static final String GROUP_TYPE_BATTERY_EXTENDED = GROUP_BATTERY + OPTION_EXTENDED; public static final String GROUP_TYPE_PRESSURE_EXTENDED = GROUP_PRESSURE + OPTION_EXTENDED; public static final String GROUP_TYPE_TEMPERATURE_EXTENDED = GROUP_TEMPERATURE + OPTION_EXTENDED; public static final String GROUP_TYPE_AIR_QUALITY_EXTENDED = GROUP_AIR_QUALITY + OPTION_EXTENDED; public static final String GROUP_TYPE_TEMPERATURE_OUTSIDE = GROUP_TEMPERATURE + OPTION_OUTSIDE; + public static final String GROUP_DOORBELL_STATUS = GROUP_CAM_STATUS + OPTION_DOORBELL; + public static final String GROUP_DOORBELL_LIVE = GROUP_CAM_LIVE + OPTION_DOORBELL; + public static final String GROUP_DOORBELL_LAST_EVENT = GROUP_LAST_EVENT + OPTION_DOORBELL; + public static final String GROUP_DOORBELL_SUB_EVENT = GROUP_SUB_EVENT + OPTION_DOORBELL; + public static final String GROUP_PERSON_LAST_EVENT = GROUP_LAST_EVENT + OPTION_PERSON; + public static final String GROUP_TYPE_ROOM_TEMPERATURE = GROUP_TEMPERATURE + OPTION_ROOM; + public static final String GROUP_TYPE_ROOM_PROPERTIES = GROUP_PROPERTIES + OPTION_ROOM; + public static final String GROUP_TYPE_TH_PROPERTIES = GROUP_PROPERTIES + OPTION_THERMOSTAT; // Channel ids public static final String CHANNEL_VALUE = "value"; @@ -99,7 +113,7 @@ public class NetatmoBindingConstants { public static final String CHANNEL_SETPOINT_MODE = "mode"; public static final String CHANNEL_SETPOINT_START_TIME = "start"; public static final String CHANNEL_SETPOINT_END_TIME = "end"; - public static final String CHANNEL_THERM_RELAY = "relay-status"; + public static final String CHANNEL_THERM_RELAY = "relay"; public static final String CHANNEL_ANTICIPATING = "anticipating"; public static final String CHANNEL_ROOM_WINDOW_OPEN = "window-open"; public static final String CHANNEL_ROOM_HEATING_POWER = "heating-power-request"; @@ -122,6 +136,8 @@ public class NetatmoBindingConstants { public static final String CHANNEL_EVENT_TIME = "time"; public static final String CHANNEL_EVENT_SNAPSHOT = "snapshot"; public static final String CHANNEL_EVENT_SNAPSHOT_URL = "snapshot-url"; + public static final String CHANNEL_EVENT_VIGNETTE = "vignette"; + public static final String CHANNEL_EVENT_VIGNETTE_URL = "vignette-url"; public static final String CHANNEL_EVENT_VIDEO_VPN_URL = "vpn-video-url"; public static final String CHANNEL_EVENT_VIDEO_LOCAL_URL = "local-video-url"; public static final String CHANNEL_EVENT_PERSON_ID = "person-id"; diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/AircareApi.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/AircareApi.java index a2d41dbea..82121dcdd 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/AircareApi.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/AircareApi.java @@ -43,7 +43,7 @@ public class AircareApi extends RestManager { * @throws NetatmoException If fail to call the API, e.g. server error or deserializing */ public StationDataResponse getHomeCoachData(@Nullable String deviceId) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMECOACH, PARAM_DEVICEID, deviceId); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMECOACH, PARAM_DEVICE_ID, deviceId); return get(uriBuilder, StationDataResponse.class); } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/EnergyApi.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/EnergyApi.java index f5a36405d..b213fb592 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/EnergyApi.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/EnergyApi.java @@ -45,7 +45,7 @@ public class EnergyApi extends RestManager { * response body */ public void switchSchedule(String homeId, String scheduleId) throws NetatmoException { - UriBuilder uriBuilder = getAppUriBuilder(SUB_PATH_SWITCHSCHEDULE, PARAM_HOMEID, homeId, PARAM_SCHEDULEID, + UriBuilder uriBuilder = getAppUriBuilder(SUB_PATH_SWITCH_SCHEDULE, PARAM_HOME_ID, homeId, PARAM_SCHEDULE_ID, scheduleId); post(uriBuilder, ApiResponse.Ok.class, null, null); } @@ -63,7 +63,7 @@ public class EnergyApi extends RestManager { * @throws NetatmoCommunicationException when call failed, e.g. server error or cannot deserialize */ public void setThermMode(String homeId, String mode) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_SETTHERMMODE, PARAM_HOMEID, homeId, PARAM_MODE, mode); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_SET_THERM_MODE, PARAM_HOME_ID, homeId, PARAM_MODE, mode); post(uriBuilder, ApiResponse.Ok.class, null, null); } @@ -80,8 +80,8 @@ public class EnergyApi extends RestManager { */ public void setThermpoint(String homeId, String roomId, SetpointMode mode, long endtime, double temp) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_SETROOMTHERMPOINT, PARAM_HOMEID, homeId, PARAM_ROOMID, roomId, - PARAM_MODE, mode.apiDescriptor); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_SET_ROOM_THERMPOINT, PARAM_HOME_ID, homeId, PARAM_ROOM_ID, + roomId, PARAM_MODE, mode.apiDescriptor); if (mode == SetpointMode.MANUAL || mode == SetpointMode.MAX) { uriBuilder.queryParam("endtime", endtime); if (mode == SetpointMode.MANUAL) { diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/HomeApi.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/HomeApi.java index 5ce35d0f1..ace5fffe4 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/HomeApi.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/HomeApi.java @@ -44,7 +44,7 @@ public class HomeApi extends RestManager { } public @Nullable HomeStatus getHomeStatus(String homeId) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMESTATUS, PARAM_HOMEID, homeId); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMESTATUS, PARAM_HOME_ID, homeId); NAHomeStatusResponse response = get(uriBuilder, NAHomeStatusResponse.class); NAHomeStatus body = response.getBody(); @@ -58,10 +58,10 @@ public class HomeApi extends RestManager { public Collection getHomesData(@Nullable String homeId, @Nullable ModuleType type) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMES_DATA, PARAM_HOMEID, homeId); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_HOMES_DATA, PARAM_HOME_ID, homeId); if (type != null) { - uriBuilder.queryParam(PARAM_GATEWAYTYPE, type.name()); + uriBuilder.queryParam(PARAM_GATEWAY_TYPE, type.name()); } HomeData.HomesDataResponse response = get(uriBuilder, HomeData.HomesDataResponse.class); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/SecurityApi.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/SecurityApi.java index a04f2fc79..31ad916b1 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/SecurityApi.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/SecurityApi.java @@ -46,7 +46,7 @@ public class SecurityApi extends RestManager { * @throws NetatmoException If fail to call the API, e.g. server error or deserializing */ public void dropWebhook() throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_DROPWEBHOOK); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_DROP_WEBHOOK); post(uriBuilder, ApiResponse.Ok.class, null, null); } @@ -57,13 +57,13 @@ public class SecurityApi extends RestManager { * @throws NetatmoException If fail to call the API, e.g. server error or deserializing */ public boolean addwebhook(URI uri) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_ADDWEBHOOK, PARAM_URL, uri.toString()); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_ADD_WEBHOOK, PARAM_URL, uri.toString()); post(uriBuilder, ApiResponse.Ok.class, null, null); return true; } public Collection getPersonEvents(String homeId, String personId) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GETEVENTS, PARAM_HOMEID, homeId, PARAM_PERSONID, personId, + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GET_EVENTS, PARAM_HOME_ID, homeId, PARAM_PERSON_ID, personId, PARAM_OFFSET, 1); NAEventsDataResponse response = get(uriBuilder, NAEventsDataResponse.class); BodyResponse body = response.getBody(); @@ -77,10 +77,11 @@ public class SecurityApi extends RestManager { throw new NetatmoException("home should not be null"); } - public Collection getCameraEvents(String homeId, String cameraId) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GETEVENTS, PARAM_HOMEID, homeId, PARAM_DEVICEID, cameraId); - NAEventsDataResponse response = get(uriBuilder, NAEventsDataResponse.class); - BodyResponse body = response.getBody(); + public Collection getCameraEvents(String homeId, String deviceId, String deviceType) + throws NetatmoException { + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GET_EVENTS, PARAM_HOME_ID, homeId, PARAM_DEVICE_ID, deviceId, + PARAM_DEVICES_TYPE, deviceType); + BodyResponse body = get(uriBuilder, NAEventsDataResponse.class).getBody(); if (body != null) { Home home = body.getElement(); if (home != null) { diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/WeatherApi.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/WeatherApi.java index 5249a7168..bdb8905c1 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/WeatherApi.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/WeatherApi.java @@ -56,7 +56,7 @@ public class WeatherApi extends RestManager { */ private StationDataResponse getStationsData(@Nullable String deviceId, boolean getFavorites) throws NetatmoException { - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GETSTATION, PARAM_DEVICEID, deviceId, // + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GET_STATION, PARAM_DEVICE_ID, deviceId, // PARAM_FAVORITES, getFavorites); StationDataResponse response = get(uriBuilder, StationDataResponse.class); return response; @@ -127,8 +127,8 @@ public class WeatherApi extends RestManager { private MeasureBodyElem getMeasure(String deviceId, @Nullable String moduleId, @Nullable String scale, String measureType) throws NetatmoException { // NAMeasuresResponse is not designed for optimize=false - UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GETMEASURE, PARAM_DEVICEID, deviceId, "real_time", true, - "date_end", "last", "optimize", true, "type", measureType.toLowerCase(), PARAM_MODULEID, moduleId); + UriBuilder uriBuilder = getApiUriBuilder(SUB_PATH_GET_MEASURE, PARAM_DEVICE_ID, deviceId, "real_time", true, + "date_end", "last", "optimize", true, "type", measureType.toLowerCase(), PARAM_MODULE_ID, moduleId); if (scale != null) { uriBuilder.queryParam("scale", scale.toLowerCase()); diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/EventType.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/EventType.java index 6f48291f7..d1560f661 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/EventType.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/EventType.java @@ -46,11 +46,14 @@ public enum EventType { @SerializedName("movement") // When the Indoor Camera detects motion MOVEMENT(ModuleType.WELCOME), - @SerializedName("human") // When the Indoor Camera detects human motion - HUMAN(ModuleType.WELCOME), + @SerializedName("human") // When the camera detects human motion + HUMAN(ModuleType.WELCOME, ModuleType.OUTDOOR, ModuleType.DOORBELL), - @SerializedName("animal") // When the Indoor Camera detects animal motion - ANIMAL(ModuleType.WELCOME), + @SerializedName("animal") // When the camera detects animal motion + ANIMAL(ModuleType.WELCOME, ModuleType.OUTDOOR), + + @SerializedName("vehicle") // When the Outdoor Camera detects a car + VEHICLE(ModuleType.OUTDOOR), @SerializedName("new_module") // A new Module has been paired with the Indoor Camera NEW_MODULE(ModuleType.WELCOME), @@ -67,10 +70,10 @@ public enum EventType { @SerializedName("module_end_update") // Module's firmware update is over MODULE_END_UPDATE(ModuleType.WELCOME), - @SerializedName("connection") // When the Camera connects to Netatmo servers + @SerializedName("connection") // When the camera connects to Netatmo servers CONNECTION(ModuleType.WELCOME, ModuleType.PRESENCE), - @SerializedName("disconnection") // When the Camera loses connection with Netatmo servers + @SerializedName("disconnection") // When the camera loses connection with Netatmo servers DISCONNECTION(ModuleType.WELCOME, ModuleType.PRESENCE), @SerializedName("on") // When Camera Monitoring is resumed @@ -86,7 +89,16 @@ public enum EventType { SD(ModuleType.WELCOME, ModuleType.PRESENCE), @SerializedName("alim") // When Camera power supply status changes - ALIM(ModuleType.WELCOME, ModuleType.PRESENCE); + ALIM(ModuleType.WELCOME, ModuleType.PRESENCE), + + @SerializedName("accepted_call") // When a call is incoming + ACCEPTED_CALL(ModuleType.DOORBELL), + + @SerializedName("incoming_call") // When a call as been answered by a user + INCOMING_CALL(ModuleType.DOORBELL), + + @SerializedName("missed_call") // When a call has not been answered by anyone + MISSED_CALL(ModuleType.DOORBELL); private final Set appliesTo; @@ -99,7 +111,7 @@ public enum EventType { return name().toLowerCase(); } - public boolean appliesOn(ModuleType searched) { + public boolean validFor(ModuleType searched) { return appliesTo.contains(searched); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ModuleType.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ModuleType.java index 82a2c7e7b..5a0f9acb8 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ModuleType.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/ModuleType.java @@ -41,7 +41,9 @@ import org.openhab.binding.netatmo.internal.handler.channelhelper.BatteryChannel import org.openhab.binding.netatmo.internal.handler.channelhelper.BatteryExtChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.CameraChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper; +import org.openhab.binding.netatmo.internal.handler.channelhelper.DoorbellChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.EventChannelHelper; +import org.openhab.binding.netatmo.internal.handler.channelhelper.EventDoorbellChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.EventPersonChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.HomeEnergyChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.HomeSecurityChannelHelper; @@ -75,8 +77,8 @@ import com.google.gson.annotations.SerializedName; */ @NonNullByDefault public enum ModuleType { - UNKNOWN(FeatureArea.NONE, null, null, List.of(), List.of()), - ACCOUNT(FeatureArea.NONE, null, null, List.of(), List.of()), + UNKNOWN(FeatureArea.NONE, "", null, List.of(), List.of()), + ACCOUNT(FeatureArea.NONE, "", null, List.of(), List.of()), @SerializedName("NAHome") HOME(FeatureArea.NONE, "NAHome", ACCOUNT, List.of(DeviceCapability.class, EventCapability.class, HomeCapability.class, ChannelHelperCapability.class), @@ -92,14 +94,14 @@ public enum ModuleType { @SerializedName("NOC") PRESENCE(FeatureArea.SECURITY, "NOC", HOME, List.of(EventCapability.class, PresenceCapability.class, ChannelHelperCapability.class), - List.of(CameraChannelHelper.class, PresenceChannelHelper.class, SignalChannelHelper.class, - EventChannelHelper.class)), + List.of(PresenceChannelHelper.class, SignalChannelHelper.class, EventChannelHelper.class)), @SerializedName("NIS") SIREN(FeatureArea.SECURITY, "NIS", HOME, List.of(ChannelHelperCapability.class), List.of(BatteryChannelHelper.class, TimestampChannelHelper.class, SignalChannelHelper.class)), @SerializedName("NDB") - DOORBELL(FeatureArea.SECURITY, "NDB", HOME, List.of(ChannelHelperCapability.class), - List.of(SignalChannelHelper.class)), + DOORBELL(FeatureArea.SECURITY, "NDB", HOME, + List.of(EventCapability.class, CameraCapability.class, ChannelHelperCapability.class), + List.of(DoorbellChannelHelper.class, SignalChannelHelper.class, EventDoorbellChannelHelper.class)), @SerializedName("NAMain") WEATHER_STATION(FeatureArea.WEATHER, "NAMain", ACCOUNT, List.of(DeviceCapability.class, WeatherCapability.class, MeasureCapability.class, @@ -156,9 +158,9 @@ public enum ModuleType { public final List> capabilities; public final ThingTypeUID thingTypeUID; public final FeatureArea feature; - public final @Nullable String apiName; + public final String apiName; - ModuleType(FeatureArea feature, @Nullable String apiName, @Nullable ModuleType bridge, + ModuleType(FeatureArea feature, String apiName, @Nullable ModuleType bridge, List> capabilities, List> helpers) { this.channelHelpers = helpers; this.bridgeType = bridge; diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/NetatmoConstants.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/NetatmoConstants.java index 69756ac2b..80e8ef6cc 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/NetatmoConstants.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/data/NetatmoConstants.java @@ -125,30 +125,31 @@ public class NetatmoConstants { public static final String SUB_PATH_PERSON_AWAY = "setpersonsaway"; public static final String SUB_PATH_PERSON_HOME = "setpersonshome"; public static final String SUB_PATH_HOMES_DATA = "homesdata"; - public static final String SUB_PATH_ADDWEBHOOK = "addwebhook"; - public static final String SUB_PATH_DROPWEBHOOK = "dropwebhook"; - public static final String SUB_PATH_SETROOMTHERMPOINT = "setroomthermpoint"; - public static final String SUB_PATH_SETTHERMMODE = "setthermmode"; - public static final String SUB_PATH_SWITCHSCHEDULE = "switchschedule"; - public static final String SUB_PATH_GETSTATION = "getstationsdata"; - public static final String SUB_PATH_GETMEASURE = "getmeasure"; + public static final String SUB_PATH_ADD_WEBHOOK = "addwebhook"; + public static final String SUB_PATH_DROP_WEBHOOK = "dropwebhook"; + public static final String SUB_PATH_SET_ROOM_THERMPOINT = "setroomthermpoint"; + public static final String SUB_PATH_SET_THERM_MODE = "setthermmode"; + public static final String SUB_PATH_SWITCH_SCHEDULE = "switchschedule"; + public static final String SUB_PATH_GET_STATION = "getstationsdata"; + public static final String SUB_PATH_GET_MEASURE = "getmeasure"; public static final String SUB_PATH_HOMESTATUS = "homestatus"; public static final String SUB_PATH_HOMECOACH = "gethomecoachsdata"; - public static final String SUB_PATH_GETEVENTS = "getevents"; + public static final String SUB_PATH_GET_EVENTS = "getevents"; public static final String SUB_PATH_PING = "ping"; public static final String SUB_PATH_CHANGESTATUS = "changestatus"; - public static final String PARAM_DEVICEID = "device_id"; - public static final String PARAM_MODULEID = "module_id"; - public static final String PARAM_HOMEID = "home_id"; - public static final String PARAM_ROOMID = "room_id"; - public static final String PARAM_PERSONID = "person_id"; - public static final String PARAM_SCHEDULEID = "schedule_id"; + public static final String PARAM_DEVICE_ID = "device_id"; + public static final String PARAM_MODULE_ID = "module_id"; + public static final String PARAM_HOME_ID = "home_id"; + public static final String PARAM_ROOM_ID = "room_id"; + public static final String PARAM_PERSON_ID = "person_id"; + public static final String PARAM_SCHEDULE_ID = "schedule_id"; public static final String PARAM_OFFSET = "offset"; - public static final String PARAM_GATEWAYTYPE = "gateway_types"; + public static final String PARAM_GATEWAY_TYPE = "gateway_types"; public static final String PARAM_MODE = "mode"; public static final String PARAM_URL = "url"; public static final String PARAM_FAVORITES = "get_favorites"; public static final String PARAM_STATUS = "status"; + public static final String PARAM_DEVICES_TYPE = "device_types"; // Autentication process params public static final String PARAM_ERROR = "error"; 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 6a56c2cbc..ebb0ade4e 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 @@ -13,6 +13,7 @@ package org.openhab.binding.netatmo.internal.api.dto; import java.time.ZonedDateTime; +import java.util.List; import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -40,9 +41,11 @@ public class HomeEvent extends Event { private @Nullable String personId; private EventCategory category = EventCategory.UNKNOWN; private @Nullable Snapshot snapshot; + private @Nullable Snapshot vignette; private @Nullable String videoId; private VideoStatus videoStatus = VideoStatus.UNKNOWN; private boolean isArrival; + private List subevents = List.of(); @Override public ZonedDateTime getTime() { @@ -90,7 +93,20 @@ public class HomeEvent extends Event { @Override public @Nullable String getSnapshotUrl() { - Snapshot localSnap = snapshot; - return localSnap != null ? localSnap.getUrl() : null; + Snapshot image = snapshot; + return image != null ? image.getUrl() : null; + } + + public @Nullable String getVignetteUrl() { + Snapshot image = vignette; + return image != null ? image.getUrl() : null; + } + + public List getSubevents() { + return subevents; + } + + public @Nullable Snapshot getVignette() { + return vignette; } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeStatusModule.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeStatusModule.java index ac53c2a34..219b47d6b 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeStatusModule.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/api/dto/HomeStatusModule.java @@ -16,6 +16,7 @@ import java.util.Optional; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.netatmo.internal.api.data.ModuleType; import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.AlimentationStatus; import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.BatteryState; import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.FloodLightMode; @@ -73,7 +74,8 @@ public class HomeStatusModule extends NAThing { public State getMonitoring() { OnOffType localStatus = monitoring; - return localStatus != null ? localStatus : UnDefType.NULL; + return localStatus != null ? localStatus // Monitoring is always active on Doorbell + : getType().equals(ModuleType.DOORBELL) ? OnOffType.ON : UnDefType.NULL; } public FloodLightMode getFloodlight() { 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 8f6246dbc..5e4b94899 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 @@ -97,9 +97,11 @@ public class CameraCapability extends HomeSecurityThingCapability { public List updateReadings() { List result = new ArrayList<>(); securityCapability.ifPresent(cap -> { - Collection events = cap.getCameraEvents(handler.getId()); + Collection events = cap.getCameraEvents(handler.getId(), moduleType.apiName); if (!events.isEmpty()) { - result.add(events.iterator().next()); + HomeEvent event = events.iterator().next(); + result.add(event); + result.addAll(event.getSubevents()); } }); return result; 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 3ef4d112f..f03d1306f 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 @@ -51,7 +51,7 @@ public class PersonCapability extends HomeSecurityThingCapability { public PersonCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider, List channelHelpers) { super(handler, descriptionProvider, channelHelpers); - this.cameraChannelUID = new ChannelUID(thing.getUID(), GROUP_PERSON_EVENT, CHANNEL_EVENT_CAMERA_ID); + this.cameraChannelUID = new ChannelUID(thing.getUID(), GROUP_PERSON_LAST_EVENT, CHANNEL_EVENT_CAMERA_ID); } @Override @@ -78,7 +78,7 @@ public class PersonCapability extends HomeSecurityThingCapability { EventType eventType = event.getEventType(); ZonedDateTime localLast = lastEventTime; ZonedDateTime eventTime = event.getTime(); - if ((localLast != null && !eventTime.isAfter(localLast)) || !eventType.appliesOn(ModuleType.PERSON)) { + if ((localLast != null && !eventTime.isAfter(localLast)) || !eventType.validFor(ModuleType.PERSON)) { return; // ignore incoming events if they are deprecated } lastEventTime = eventTime; diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/SecurityCapability.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/SecurityCapability.java index b488348dd..c19757d4a 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/SecurityCapability.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/capability/SecurityCapability.java @@ -99,10 +99,10 @@ class SecurityCapability extends RestCapability { }); } - public Collection getCameraEvents(String cameraId) { + public Collection getCameraEvents(String cameraId, String deviceType) { return getApi().map(api -> { try { - return api.getCameraEvents(handler.getId(), cameraId); + return api.getCameraEvents(handler.getId(), cameraId, deviceType); } catch (NetatmoException e) { logger.warn("Error retrieving last events of camera '{}' : {}", cameraId, e.getMessage()); return null; diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java index db73b2dee..9b63f1218 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/CameraChannelHelper.java @@ -39,7 +39,11 @@ public class CameraChannelHelper extends ChannelHelper { private @Nullable String localUrl; public CameraChannelHelper() { - super(GROUP_CAM_STATUS, GROUP_CAM_LIVE); + this(GROUP_CAM_STATUS, GROUP_CAM_LIVE); + } + + protected CameraChannelHelper(String... providedGroups) { + super(providedGroups); } public void setUrls(String vpnUrl, @Nullable String localUrl) { diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/ChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/ChannelHelper.java index a5c9adbef..246380beb 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/ChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/ChannelHelper.java @@ -20,6 +20,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.MeasureClass; import org.openhab.binding.netatmo.internal.api.dto.Dashboard; import org.openhab.binding.netatmo.internal.api.dto.Event; +import org.openhab.binding.netatmo.internal.api.dto.HomeEvent; import org.openhab.binding.netatmo.internal.api.dto.NAObject; import org.openhab.binding.netatmo.internal.api.dto.NAThing; import org.openhab.binding.netatmo.internal.providers.NetatmoThingTypeProvider; @@ -57,6 +58,12 @@ public abstract class ChannelHelper { State result = null; if (channelGroups.isEmpty() || (groupId != null && channelGroups.contains(groupId))) { NAObject localData = data; + if (localData instanceof HomeEvent) { + result = internalGetHomeEvent(channelId, groupId, (HomeEvent) localData); + if (result != null) { + return result; + } + } if (localData instanceof Event) { result = internalGetEvent(channelId, (Event) localData); if (result != null) { @@ -108,6 +115,10 @@ public abstract class ChannelHelper { return null; } + protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) { + return null; + } + public Set getChannelGroupTypes() { return channelGroupTypes; } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/DoorbellChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/DoorbellChannelHelper.java new file mode 100644 index 000000000..9dee8b960 --- /dev/null +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/DoorbellChannelHelper.java @@ -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.netatmo.internal.handler.channelhelper; + +import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; + +/** + * The {@link DoorbellChannelHelper} handles specific channels of doorbells + * + * @author Gaël L'hopital - Initial contribution + * + */ +@NonNullByDefault +public class DoorbellChannelHelper extends CameraChannelHelper { + + public DoorbellChannelHelper() { + super(GROUP_DOORBELL_STATUS, GROUP_DOORBELL_LIVE); + } +} 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 a5fe003f7..e8b8fdc6f 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 @@ -36,14 +36,14 @@ import org.openhab.core.types.UnDefType; public class EventChannelHelper extends ChannelHelper { private boolean isLocal; private @Nullable String vpnUrl, localUrl; - private ModuleType moduleType = ModuleType.UNKNOWN; + protected ModuleType moduleType = ModuleType.UNKNOWN; public EventChannelHelper() { this(GROUP_LAST_EVENT); } - protected EventChannelHelper(String groupName) { - super(groupName); + protected EventChannelHelper(String... providedGroups) { + super(providedGroups); } public void setModuleType(ModuleType moduleType) { @@ -60,7 +60,7 @@ public class EventChannelHelper extends ChannelHelper { public void setNewData(@Nullable NAObject data) { if (data instanceof Event) { Event event = (Event) data; - if (!event.getEventType().appliesOn(moduleType)) { + if (!event.getEventType().validFor(moduleType)) { return; } } @@ -87,16 +87,18 @@ public class EventChannelHelper extends ChannelHelper { case CHANNEL_EVENT_SNAPSHOT_URL: return toStringType(event.getSnapshotUrl()); } - if (event instanceof HomeEvent) { - HomeEvent homeEvent = (HomeEvent) event; - switch (channelId) { - case CHANNEL_EVENT_VIDEO_STATUS: - return homeEvent.getVideoId() != null ? toStringType(homeEvent.getVideoStatus()) : UnDefType.NULL; - case CHANNEL_EVENT_VIDEO_LOCAL_URL: - return getStreamURL(true, homeEvent.getVideoId(), homeEvent.getVideoStatus()); - case CHANNEL_EVENT_VIDEO_VPN_URL: - return getStreamURL(false, homeEvent.getVideoId(), homeEvent.getVideoStatus()); - } + return null; + } + + @Override + protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) { + switch (channelId) { + case CHANNEL_EVENT_VIDEO_STATUS: + return event.getVideoId() != null ? toStringType(event.getVideoStatus()) : UnDefType.NULL; + case CHANNEL_EVENT_VIDEO_LOCAL_URL: + return getStreamURL(true, event.getVideoId(), event.getVideoStatus()); + case CHANNEL_EVENT_VIDEO_VPN_URL: + return getStreamURL(false, event.getVideoId(), event.getVideoStatus()); } return null; } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventDoorbellChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventDoorbellChannelHelper.java new file mode 100644 index 000000000..f024fc78c --- /dev/null +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventDoorbellChannelHelper.java @@ -0,0 +1,59 @@ +/** + * 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.netatmo.internal.handler.channelhelper; + +import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; +import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.netatmo.internal.api.dto.HomeEvent; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.types.State; + +/** + * The {@link EventDoorbellChannelHelper} handles specific channels of doorbell events + * + * @author Gaël L'hopital - Initial contribution + * + */ +@NonNullByDefault +public class EventDoorbellChannelHelper extends EventChannelHelper { + + public EventDoorbellChannelHelper() { + super(GROUP_DOORBELL_LAST_EVENT, GROUP_DOORBELL_SUB_EVENT); + } + + @Override + protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) { + if (groupId != null && GROUP_DOORBELL_SUB_EVENT.startsWith(groupId)) { + switch (channelId) { + case CHANNEL_EVENT_TYPE: + return toStringType(event.getEventType()); + case CHANNEL_EVENT_TIME: + return new DateTimeType(event.getTime()); + case CHANNEL_EVENT_MESSAGE: + return toStringType(event.getName()); + case CHANNEL_EVENT_SNAPSHOT: + return toRawType(event.getSnapshotUrl()); + case CHANNEL_EVENT_SNAPSHOT_URL: + return toStringType(event.getSnapshotUrl()); + case CHANNEL_EVENT_VIGNETTE: + return toRawType(event.getVignetteUrl()); + case CHANNEL_EVENT_VIGNETTE_URL: + return toStringType(event.getVignetteUrl()); + } + } + return super.internalGetHomeEvent(channelId, groupId, event); + } +} diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventPersonChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventPersonChannelHelper.java index ff4054be6..bc46b3dae 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventPersonChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/EventPersonChannelHelper.java @@ -14,10 +14,11 @@ package org.openhab.binding.netatmo.internal.handler.channelhelper; import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; +import java.util.Set; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.netatmo.internal.api.data.EventType; -import org.openhab.binding.netatmo.internal.api.data.ModuleType; import org.openhab.binding.netatmo.internal.api.dto.Event; import org.openhab.core.library.types.OnOffType; import org.openhab.core.types.State; @@ -30,16 +31,16 @@ import org.openhab.core.types.State; */ @NonNullByDefault public class EventPersonChannelHelper extends EventChannelHelper { + public EventPersonChannelHelper() { - super(GROUP_PERSON_EVENT); + super(GROUP_PERSON_LAST_EVENT); } @Override protected @Nullable State internalGetEvent(String channelId, Event event) { EventType eventType = event.getEventType(); - if (eventType.appliesOn(ModuleType.PERSON) && CHANNEL_PERSON_AT_HOME.equals(channelId)) { - return OnOffType.from(EventType.PERSON.equals(eventType) || EventType.PERSON_HOME.equals(eventType)); - } - return super.internalGetEvent(channelId, event); + return eventType.validFor(moduleType) && CHANNEL_PERSON_AT_HOME.equals(channelId) + ? OnOffType.from(Set.of(EventType.PERSON, EventType.PERSON_HOME).contains(eventType)) + : super.internalGetEvent(channelId, event); } } diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/PresenceChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/PresenceChannelHelper.java index c2449c953..13ddd1c53 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/PresenceChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/PresenceChannelHelper.java @@ -29,9 +29,10 @@ import org.openhab.core.types.State; * */ @NonNullByDefault -public class PresenceChannelHelper extends ChannelHelper { +public class PresenceChannelHelper extends CameraChannelHelper { + public PresenceChannelHelper() { - super(GROUP_PRESENCE); + super(GROUP_CAM_STATUS, GROUP_CAM_LIVE, GROUP_PRESENCE); } @Override diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/RoomChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/RoomChannelHelper.java index 2914d2e92..33bb81cba 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/RoomChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/RoomChannelHelper.java @@ -33,7 +33,7 @@ import org.openhab.core.types.State; public class RoomChannelHelper extends ChannelHelper { public RoomChannelHelper() { - super(GROUP_ROOM_PROPERTIES, GROUP_ROOM_TEMPERATURE); + super(GROUP_TYPE_ROOM_TEMPERATURE, GROUP_TYPE_ROOM_PROPERTIES); } @Override diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/SetpointChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/SetpointChannelHelper.java index 56d9f8744..81b901cd6 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/SetpointChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/SetpointChannelHelper.java @@ -33,7 +33,7 @@ import org.openhab.core.types.UnDefType; public class SetpointChannelHelper extends ChannelHelper { public SetpointChannelHelper() { - super(GROUP_TH_SETPOINT); + super(GROUP_SETPOINT); } @Override diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/Therm1ChannelHelper.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/Therm1ChannelHelper.java index 5cb2a2bfd..c78806abf 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/Therm1ChannelHelper.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/handler/channelhelper/Therm1ChannelHelper.java @@ -31,7 +31,7 @@ import org.openhab.core.types.State; public class Therm1ChannelHelper extends ChannelHelper { public Therm1ChannelHelper() { - super(GROUP_TH_PROPERTIES); + super(GROUP_TYPE_TH_PROPERTIES); } @Override diff --git a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/providers/NetatmoThingTypeProvider.java b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/providers/NetatmoThingTypeProvider.java index 7f5608beb..c94ef9180 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/providers/NetatmoThingTypeProvider.java +++ b/bundles/org.openhab.binding.netatmo/src/main/java/org/openhab/binding/netatmo/internal/providers/NetatmoThingTypeProvider.java @@ -99,6 +99,10 @@ public class NetatmoThingTypeProvider implements ThingTypeProvider { } public static String toGroupName(String groupeTypeName) { - return groupeTypeName.replace(OPTION_EXTENDED, "").replace(OPTION_OUTSIDE, ""); + String result = groupeTypeName; + for (String variation : GROUP_VARIATIONS) { + result = result.replace(variation, ""); + } + return result; } } 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 c24c75c09..aa356e5a3 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 @@ -18,6 +18,19 @@ channel-group-type.netatmo.energy.label = Home Energy channel-group-type.netatmo.energy.channel.end.label = Mode End channel-group-type.netatmo.energy.channel.end.description = End time of the currently applied setpoint. channel-group-type.netatmo.humidity.label = Humidity +channel-group-type.netatmo.last-event-doorbell.label = Last Event +channel-group-type.netatmo.last-event-doorbell.channel.local-video-url.label = Video Local URL +channel-group-type.netatmo.last-event-doorbell.channel.local-video-url.description = Local URL of the event recording. +channel-group-type.netatmo.last-event-doorbell.channel.time.label = Event Timestamp +channel-group-type.netatmo.last-event-doorbell.channel.time.description = Moment when event occurred. +channel-group-type.netatmo.last-event-doorbell.channel.vpn-video-url.label = Video VPN URL +channel-group-type.netatmo.last-event-doorbell.channel.vpn-video-url.description = URL of the event recording through Netatmo VPN. +channel-group-type.netatmo.last-event-person.label = Last Event +channel-group-type.netatmo.last-event-person.channel.message.description = Last event message from this person. +channel-group-type.netatmo.last-event-person.channel.snapshot.description = Picture of the last event for this person. +channel-group-type.netatmo.last-event-person.channel.snapshot-url.description = URL for the picture of the last event for this person. +channel-group-type.netatmo.last-event-person.channel.time.label = Person Timestamp +channel-group-type.netatmo.last-event-person.channel.time.description = Moment of the last event for this person. channel-group-type.netatmo.last-event.label = Last Event channel-group-type.netatmo.last-event.channel.local-video-url.label = Video Local URL channel-group-type.netatmo.last-event.channel.local-video-url.description = Local URL of the event recording. @@ -25,6 +38,9 @@ channel-group-type.netatmo.last-event.channel.time.label = Event Timestamp channel-group-type.netatmo.last-event.channel.time.description = Moment when event occurred. channel-group-type.netatmo.last-event.channel.vpn-video-url.label = Video VPN URL channel-group-type.netatmo.last-event.channel.vpn-video-url.description = URL of the event recording through Netatmo VPN. +channel-group-type.netatmo.live-doorbell.label = Live Monitoring +channel-group-type.netatmo.live-doorbell.channel.local-picture-url.label = Live Snapshot Local URL +channel-group-type.netatmo.live-doorbell.channel.local-picture-url.description = Local URL of the live snapshot for this camera. channel-group-type.netatmo.live.label = Live Monitoring channel-group-type.netatmo.live.channel.local-picture-url.label = Live Snapshot Local URL channel-group-type.netatmo.live.channel.local-picture-url.description = Local URL of the live snapshot for this camera. @@ -36,12 +52,6 @@ channel-group-type.netatmo.live.channel.vpn-stream-url.label = Live Stream VPN U channel-group-type.netatmo.live.channel.vpn-stream-url.description = URL of the live stream for this camera through Netatmo VPN. channel-group-type.netatmo.location.label = Location channel-group-type.netatmo.noise.label = Noise -channel-group-type.netatmo.person-event.label = Last Event -channel-group-type.netatmo.person-event.channel.message.description = Last event message from this person. -channel-group-type.netatmo.person-event.channel.snapshot.description = Picture of the last event for this person. -channel-group-type.netatmo.person-event.channel.snapshot-url.description = URL for the picture of the last event for this person. -channel-group-type.netatmo.person-event.channel.time.label = Person Timestamp -channel-group-type.netatmo.person-event.channel.time.description = Moment of the last event for this person. channel-group-type.netatmo.person.label = Person channel-group-type.netatmo.person.channel.last-seen.label = Last Seen channel-group-type.netatmo.person.channel.last-seen.description = Moment when this person was last seen. @@ -55,8 +65,8 @@ channel-group-type.netatmo.rain.channel.sum-1.label = Rain 1h channel-group-type.netatmo.rain.channel.sum-1.description = Quantity of water over last hour. channel-group-type.netatmo.rain.channel.sum-24.label = Rain 24h channel-group-type.netatmo.rain.channel.sum-24.description = Quantity of water during the current day. -channel-group-type.netatmo.room-properties.label = Room Status -channel-group-type.netatmo.room-temperature.label = Room Temperature +channel-group-type.netatmo.properties-room.label = Room Status +channel-group-type.netatmo.temperature-room.label = Room Temperature channel-group-type.netatmo.security.label = Home Security channel-group-type.netatmo.setpoint.label = Setpoint channel-group-type.netatmo.setpoint.channel.end.label = Setpoint End @@ -64,7 +74,15 @@ channel-group-type.netatmo.setpoint.channel.end.description = End time of the cu channel-group-type.netatmo.setpoint.channel.start.label = Setpoint Start channel-group-type.netatmo.setpoint.channel.start.description = Start time of the currently applied setpoint. channel-group-type.netatmo.signal.label = Signal +channel-group-type.netatmo.status-doorbell.label = Camera Status channel-group-type.netatmo.status.label = Camera Status +channel-group-type.netatmo.sub-event-doorbell.label = Sub Event +channel-group-type.netatmo.sub-event-doorbell.channel.time.label = Sub-Event Timestamp +channel-group-type.netatmo.sub-event-doorbell.channel.time.description = Moment when then sub-event occurred. +channel-group-type.netatmo.sub-event-doorbell.channel.vignette.label = Vignette +channel-group-type.netatmo.sub-event-doorbell.channel.vignette.description = Vignette of the Snapshot. +channel-group-type.netatmo.sub-event-doorbell.channel.vignette-url.label = Vignette URL +channel-group-type.netatmo.sub-event-doorbell.channel.vignette-url.description = URL of the vignette. channel-group-type.netatmo.temperature-extended.label = Temperature channel-group-type.netatmo.temperature-extended.channel.max-time.label = Today Max Timestamp channel-group-type.netatmo.temperature-extended.channel.max-time.description = Moment when temperature was measured at its maximum today. @@ -82,7 +100,7 @@ channel-group-type.netatmo.temperature.channel.max-time.label = Today Max Timest channel-group-type.netatmo.temperature.channel.max-time.description = Moment when temperature was measured at its maximum today. channel-group-type.netatmo.temperature.channel.min-time.label = Today Min Timestamp channel-group-type.netatmo.temperature.channel.min-time.description = Moment when temperature was measured at its minimum today. -channel-group-type.netatmo.th-properties.label = Thermostat +channel-group-type.netatmo.properties-thermostat.label = Thermostat channel-group-type.netatmo.timestamp-extended.label = Timestamp channel-group-type.netatmo.timestamp-extended.channel.last-seen.label = Last Seen channel-group-type.netatmo.timestamp-extended.channel.last-seen.description = Last time the module reported its presence. @@ -154,10 +172,11 @@ channel-type.netatmo.event-type.description = Description of the event. channel-type.netatmo.event-type.state.option.PERSON = Face detected channel-type.netatmo.event-type.state.option.PERSON_AWAY = Person has left home channel-type.netatmo.event-type.state.option.PERSON_HOME = Person is at home -channel-type.netatmo.event-type.state.option.OUTDOOR = Motion detected by Presence +channel-type.netatmo.event-type.state.option.OUTDOOR = Motion detected by Outdoor Camera channel-type.netatmo.event-type.state.option.MOVEMENT = Motion detected channel-type.netatmo.event-type.state.option.HUMAN = Human seen channel-type.netatmo.event-type.state.option.ANIMAL = Animal seen +channel-type.netatmo.event-type.state.option.VEHICLE = Car seen channel-type.netatmo.event-type.state.option.NEW_MODULE = New Module has been paired channel-type.netatmo.event-type.state.option.MODULE_CONNECT = Module is connected with the Indoor Camera channel-type.netatmo.event-type.state.option.MODULE_DISCONNECT = Module lost its connection with the Indoor Camera @@ -170,6 +189,9 @@ channel-type.netatmo.event-type.state.option.OFF = Monitoring stopped channel-type.netatmo.event-type.state.option.BOOT = Camera booting channel-type.netatmo.event-type.state.option.SD = SD card status changed channel-type.netatmo.event-type.state.option.ALIM = Power status changed +channel-type.netatmo.event-type.state.option.ACCEPTED_CALL = Call is incoming +channel-type.netatmo.event-type.state.option.INCOMING_CALL = Call has been answered by a user +channel-type.netatmo.event-type.state.option.MISSED_CALL = Call has not been answered by anyone channel-type.netatmo.floodlight-mode.label = Floodlight channel-type.netatmo.floodlight-mode.description = State of the floodlight (On/Off/Auto) channel-type.netatmo.floodlight-mode.state.option.ON = On diff --git a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo_it.properties b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo_it.properties index 3cdf85459..2ad22e4bb 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo_it.properties +++ b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/i18n/netatmo_it.properties @@ -55,8 +55,8 @@ channel-group-type.netatmo.rain.channel.sum-1.label = Pioggia 1h channel-group-type.netatmo.rain.channel.sum-1.description = Quantità di acqua nell'ultima ora. channel-group-type.netatmo.rain.channel.sum-24.label = Pioggia 24h channel-group-type.netatmo.rain.channel.sum-24.description = Quantità di acqua durante il giorno corrente. -channel-group-type.netatmo.room-properties.label = Stato Stanza -channel-group-type.netatmo.room-temperature.label = Temperatura Stanza +channel-group-type.netatmo.properties-room.label = Stato Stanza +channel-group-type.netatmo.temperature-room.label = Temperatura Stanza channel-group-type.netatmo.security.label = Sicurezza Domestica channel-group-type.netatmo.setpoint.label = Valore Impostato channel-group-type.netatmo.setpoint.channel.end.label = Fine Setpoint @@ -82,7 +82,7 @@ channel-group-type.netatmo.temperature.channel.max-time.label = Ora Temp Massima channel-group-type.netatmo.temperature.channel.max-time.description = Momento quando oggi la temperatura è stata misurata al suo massimo. channel-group-type.netatmo.temperature.channel.min-time.label = Ora Temperatura Minima Oggi channel-group-type.netatmo.temperature.channel.min-time.description = Momento in cui la temperatura è stata misurata al suo minimo oggi. -channel-group-type.netatmo.th-properties.label = Termostato +channel-group-type.netatmo.properties-thermostat.label = Termostato channel-group-type.netatmo.timestamp-extended.label = Data/Ora channel-group-type.netatmo.timestamp-extended.channel.last-seen.label = Visto per l'ultima volta channel-group-type.netatmo.timestamp-extended.channel.last-seen.description = L'ultima volta che il modulo ha segnalato la sua presenza. diff --git a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/thing/channels.xml index 13c6e55ef..9c174af72 100644 --- a/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.netatmo/src/main/resources/OH-INF/thing/channels.xml @@ -318,10 +318,11 @@ - + + @@ -334,6 +335,9 @@ + + + @@ -375,6 +379,7 @@