[netatmo] Extend webhook support for doorbell and presence camera (#14252)

* [netatmo] Web hook extension for camera events

- Unused camera-event trigger channel removed
- README updated to the real supported channels (compared with channels.xml and code)
- Camera capabilities are now triggering the home-event trigger channel
- New home-event trigger channel introduced at camera level
- New sub-event channels introduced for the presence camera which is updated by web hook events.
- Language file updated
- README updated
- typos fixed
- security-event trigger channel added for the Welcome camera
- Handling of sub-event groups fixed to work with doorbell and presence cameras.

---------

Signed-off-by: Sven Strohschein <sven.strohschein@gmail.com>
Signed-off-by: Sven Strohschein <novanic@gmx.de>
This commit is contained in:
Sven Strohschein 2023-03-26 17:34:35 +02:00 committed by GitHub
parent 1726031ecc
commit a8d91b3950
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 275 additions and 155 deletions

View File

@ -478,33 +478,35 @@ All channels are read only.
**Supported trigger channels for the Security Home thing:** **Supported trigger channels for the Security Home thing:**
| Channel Type ID | Options | Description | **Supported trigger channels for the Security Home, Presence and Doorbell thing:**
| ---------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| cameraEvent | | A camera event is triggered with a short delay but without requiring a webhook. The information of the event can get retrieved from the other "welcomeEvent" home thing channels | | Channel Type ID | Options | Description |
| | HUMAN | Triggered when a human (or person) was detected | |-----------------|--------------------|---------------------------------------------------------------------|
| | ANIMAL | Triggered when an animal was detected | | home-event | | A welcome home event is triggered directly via a configured webhook |
| | MOVEMENT | Triggered when an unspecified movement was detected | | | PERSON | Triggered when a concrete person was detected |
| | VEHICLE | Triggered when a vehicle was detected | | | PERSON_AWAY | Triggered when a concrete person leaves |
| welcomeHomeEvent | | A welcome home event is triggered directly via a configured webhook | | | PERSON_HOME | Triggered when a concrete person entered the home |
| | PERSON | Triggered when a concrete person was detected | | | OUTDOOR | Triggered when a event of an outdoor camera was triggered |
| | PERSON_AWAY | Triggered when a concrete person leaves | | | MOVEMENT | Triggered when a movement was detected |
| | MOVEMENT | Triggered when a movement was detected | | | HUMAN | Triggered when a human was detected |
| | CONNECTION | Triggered when a camera connection gets created | | | ANIMAL | Triggered when an animal was detected |
| | DISCONNECTION | Triggered when a camera connection got lost | | | VEHICLE | Triggered when a vehicle was detected |
| | ON | Triggered when camera monitoring is switched on | | | NEW_MODULE | Triggered when a new module was discovered |
| | OFF | Triggered when camera monitoring is switched off | | | MODULE_CONNECT | Triggered when a module gets connected |
| | BOOT | Triggered when a camera is booting | | | MODULE_DISCONNECT | Triggered when a module gets disconnected |
| | SD | Triggered when a camera SD card status was changed | | | MODULE_LOW_BATTERY | Triggered when the battery of a module gets low |
| | ALIM | Triggered when a power supply status was changed | | | MODULE_END_UPDATE | Triggered when a firmware update of a module is done |
| | NEW_MODULE | Triggered when a new module was discovered | | | CONNECTION | Triggered when a camera connection gets created |
| | MODULE_CONNECT | Triggered when a module gets connected | | | DISCONNECTION | Triggered when a camera connection got lost |
| | MODULE_DISCONNECT | Triggered when a module gets disconnected | | | ON | Triggered when camera monitoring is switched on |
| | MODULE_LOW_BATTERY | Triggered when the battery of a module gets low | | | OFF | Triggered when camera monitoring is switched off |
| | MODULE_END_UPDATE | Triggered when a firmware update of a module is done | | | BOOT | Triggered when a camera is booting |
| | TAG_BIG_MOVE | Triggered when a big movement of a tag was detected | | | SD | Triggered when a camera SD card status was changed |
| | TAG_SMALL_MOVE | Triggered when a small movement of a tag was detected | | | ALIM | Triggered when a power supply status was changed |
| | TAG_UNINSTALLED | Triggered when a tag gets uninstalled | | | ACCEPTED_CALL | Triggered when a doorbell call was accepted |
| | TAG_OPEN | Triggered when an open event of a tag was detected | | | INCOMING_CALL | Triggered when a doorbell call is incoming |
| | RTC | Triggered when the doorbell button was pressed |
| | MISSED_CALL | Triggered when a doorbell call was missed |
### Welcome, Presence and Doorbell Cameras ### Welcome, Presence and Doorbell Cameras
@ -515,28 +517,29 @@ Warnings:
**Supported channels for the Welcome Camera thing:** **Supported channels for the Welcome Camera thing:**
| Channel Group | Channel ID | Item Type | Read/Write | Description | | Channel Group | Channel ID | Item Type | Read/Write | Description |
| ------------- | -------------------- | ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- | |----------------| -------------------- | ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| status | monitoring | Switch | Read-write | State of the camera (video surveillance on/off) | | security-event | home-event | | Read-only | Trigger channel which is triggered when the camera sent an event |
| status | sd-card | String | Read-only | State of the SD card | | status | monitoring | Switch | Read-write | State of the camera (video surveillance on/off) |
| status | alim | String | Read-only | State of the power connector | | status | sd-card | String | Read-only | State of the SD card |
| live | picture | Image | Read-only | Camera Live Snapshot | | status | alim | String | Read-only | State of the power connector |
| live | local-picture-url | String | Read-only | Local Url of the live snapshot for this camera | | live | picture | Image | Read-only | Camera Live Snapshot |
| live | vpn-picture-url | String | Read-only | Url of the live snapshot for this camera through Netatmo VPN. | | live | local-picture-url | String | Read-only | Local Url of the live snapshot for this camera |
| 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. | | live | vpn-picture-url | String | Read-only | Url of the live snapshot for this camera through Netatmo VPN. |
| live | vpn-stream-url (*) | String | Read-only | Url of the live stream 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. |
| signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) | | live | vpn-stream-url (*) | String | Read-only | Url of the live stream for this camera through Netatmo VPN. |
| signal | value | Number:Power | Read-only | Signal strength in dBm | | signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) |
| last-event | type | String | Read-only | Type of event | | signal | value | Number:Power | Read-only | Signal strength in dBm |
| last-event | subtype | String | Read-only | Sub-type of event | | last-event | type | String | Read-only | Type of event |
| last-event | time | DateTime | Read-only | Time of occurrence of event | | last-event | subtype | String | Read-only | Sub-type of event |
| last-event | message | String | Read-only | Message sent by Netatmo corresponding to given event | | last-event | time | DateTime | Read-only | Time of occurrence of event |
| last-event | snapshot | Image | Read-only | picture of the last event, if it applies | | last-event | message | String | Read-only | Message sent by Netatmo corresponding to given event |
| last-event | snapshot-url | String | Read-only | If the last event (depending upon event type) in the home lead a snapshot picture, the picture URL will be available here | | last-event | snapshot | Image | Read-only | picture of the last event, if it applies |
| 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 | snapshot-url | String | Read-only | If the last event (depending upon event type) in the home lead a snapshot picture, the picture 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 | | 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 | video-status | String | Read-only | Status of the video (recording, deleted or available) | | 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 |
| last-event | person-id | String | Read-only | Id of the person the event is about (if any) | | last-event | video-status | String | Read-only | Status of the video (recording, deleted or available) |
| 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 is configurable : low, poor, high.
@ -546,54 +549,63 @@ Warnings:
- The floodlight auto-mode (auto-mode) isn't updated it is changed by another application. Therefore the binding handles its own state of the auto-mode. This has the advantage that the user can define its own floodlight switch off behaviour. - The floodlight auto-mode (auto-mode) isn't updated it is changed by another application. Therefore the binding handles its own state of the auto-mode. This has the advantage that the user can define its own floodlight switch off behaviour.
| Channel Group | Channel ID | Item Type | Read/Write | Description | | Channel Group | Channel ID | Item Type | Read/Write | Description |
| ------------- | -------------------- | ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- | |----------------|----------------------| ------------ | ---------- |---------------------------------------------------------------------------------------------------------------------------------------------|
| status | monitoring | Switch | Read-write | State of the camera (video surveillance on/off) | | security-event | home-event | | Read-only | Trigger channel which is triggered when the camera sent an event |
| status | sd-card | String | Read-only | State of the SD card | | status | monitoring | Switch | Read-write | State of the camera (video surveillance on/off) |
| status | alim | String | Read-only | State of the power connector | | status | sd-card | String | Read-only | State of the SD card |
| live | picture | Image | Read-only | Camera Live Snapshot | | status | alim | String | Read-only | State of the power connector |
| live | picture-url | String | Read-only | Url of the live snapshot for this camera | | live | picture | Image | Read-only | Camera Live Snapshot |
| 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. | | live | picture-url | String | Read-only | Url of the live snapshot for this camera |
| live | vpn-stream-url (*) | String | Read-only | Url of the live stream 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. |
| signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) | | live | vpn-stream-url (*) | String | Read-only | Url of the live stream for this camera through Netatmo VPN. |
| signal | value | Number:Power | Read-only | Signal strength in dBm | | signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) |
| presence | floodlight | String | Read-write | Sets the floodlight to ON/OFF/AUTO | | signal | value | Number:Power | Read-only | Signal strength in dBm |
| last-event | type | String | Read-only | Type of event | | presence | floodlight | String | Read-write | Sets the floodlight to ON/OFF/AUTO |
| last-event | subtype | String | Read-only | Sub-type of event | | last-event | type | String | Read-only | Type of event |
| last-event | time | DateTime | Read-only | Time of occurrence of event | | last-event | subtype | String | Read-only | Sub-type of event |
| last-event | message | String | Read-only | Message sent by Netatmo corresponding to given event | | last-event | time | DateTime | Read-only | Time of occurrence of event |
| last-event | snapshot | Image | Read-only | picture of the last event, if it applies | | last-event | message | String | Read-only | Message sent by Netatmo corresponding to given event |
| last-event | snapshot-url | String | Read-only | if the last event (depending upon event type) in the home lead a snapshot picture, the picture URL will be available here | | last-event | snapshot | Image | Read-only | picture of the last event, if it applies |
| 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 | snapshot-url | String | Read-only | if the last event (depending upon event type) in the home lead a snapshot picture, the picture 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 | | 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 | video-status | String | Read-only | Status of the video (recording, deleted or available) | | 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 |
| last-event | person-id | String | Read-only | Id of the person the event is about (if any) | | last-event | video-status | String | Read-only | Status of the video (recording, deleted or available) |
| last-event | person-id | String | Read-only | Id of the person the event is about (if any) |
| 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 | vignette | Image | Read-only | picture of the vignette |
(*) This channel is configurable : low, poor, high. (*) This channel is configurable : low, poor, high.
**Supported channels for the Doorbell thing:** **Supported channels for the Doorbell thing:**
| Channel Group | Channel ID | Item Type | Read/Write | Description | | Channel Group | Channel ID | Item Type | Read/Write | Description |
| ------------- | ----------------- | ------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------- | |---------------------| ----------------- |--------------| ---------- |---------------------------------------------------------------------------------------------------------------------------------------------|
| status | sd-card | String | Read-only | State of the SD card | | security-event | home-event | | Read-only | Trigger channel which is triggered when the doorbell sent an event |
| status | alim | String | Read-only | State of the power connector | | status | sd-card | String | Read-only | State of the SD card |
| live | picture | Image | Read-only | Camera Live Snapshot | | status | alim | String | Read-only | State of the power connector |
| live | local-picture-url | String | Read-only | Local Url of the live snapshot for this camera | | live | picture | Image | Read-only | Camera Live Snapshot |
| live | vpn-picture-url | String | Read-only | Url of the live snapshot for this camera through Netatmo VPN. | | live | local-picture-url | String | Read-only | Local Url of the live snapshot for this camera |
| signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) | | live | vpn-picture-url | String | Read-only | Url of the live snapshot for this camera through Netatmo VPN. |
| signal | value | Number:Power | Read-only | Signal strength in dBm | | signal | strength | Number | Read-only | Signal strength (0 for no signal, 1 for weak...) |
| last-event | type | String | Read-only | Type of event | | signal | value | Number:Power | Read-only | Signal strength in dBm |
| last-event | video-status | String | Read-only | Status of the video (recording, deleted or available) | | last-event-doorbell | type | String | Read-only | Type of event |
| last-event | time | DateTime | Read-only | Time of occurrence of event | | last-event-doorbell | video-status | String | Read-only | Status of the video (recording, deleted or available) |
| 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-doorbell | time | DateTime | Read-only | Time of occurrence of event |
| 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 | | last-event-doorbell | 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 |
| sub-event | type | String | Read-only | Type of sub-event | | last-event-doorbell | 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 | time | DateTime | Read-only | Time of occurrence of sub-event | | sub-event-doorbell | type | String | Read-only | Type of sub-event |
| sub-event | message | String | Read-only | Message sent by Netatmo corresponding to given sub-event | | sub-event-doorbell | time | DateTime | Read-only | Time of occurrence of 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-doorbell | message | String | Read-only | Message sent by Netatmo corresponding to given sub-event |
| sub-event | vignette-url | String | Read-only | A vignette representing the snapshot | | sub-event-doorbell | 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 | snapshot | Image | Read-only | picture of the snapshot | | sub-event-doorbell | vignette-url | String | Read-only | A vignette representing the snapshot |
| sub-event | vignet | Image | Read-only | picture of the vignette | | sub-event-doorbell | snapshot | Image | Read-only | picture of the snapshot |
| sub-event-doorbell | vignette | Image | Read-only | picture of the vignette |
Note: live feeds either locally or via VPN are not available in Netatmo API. Note: live feeds either locally or via VPN are not available in Netatmo API.
@ -843,6 +855,26 @@ sitemap netatmo label="Netatmo" {
} }
``` ```
## Example Rules
```java
rule "Notification on home web hook event"
when
Channel "netatmo:home:mybridgeid:myclientid:home-event" triggered
then
logInfo("camera", "Received web hook on home level")
end
```
```java
rule "Notification on camera web hook event"
when
Channel "netatmo:presence:mybridgeid:myclientid:mythingid:home-event" triggered
then
logInfo("camera", "Received web hook on camera level")
end
```
## Rule Actions ## Rule Actions
Multiple actions are supported by this binding. In classic rules these are accessible as shown in this example (adjust getActions with your ThingId): Multiple actions are supported by this binding. In classic rules these are accessible as shown in this example (adjust getActions with your ThingId):

View File

@ -50,6 +50,7 @@ public class NetatmoBindingConstants {
public static final String GROUP_SIGNAL = "signal"; public static final String GROUP_SIGNAL = "signal";
public static final String GROUP_BATTERY = "battery"; public static final String GROUP_BATTERY = "battery";
public static final String GROUP_SECURITY = "security"; public static final String GROUP_SECURITY = "security";
public static final String GROUP_SECURITY_EVENT = "security-event";
public static final String GROUP_CAM_STATUS = "status"; public static final String GROUP_CAM_STATUS = "status";
public static final String GROUP_CAM_LIVE = "live"; public static final String GROUP_CAM_LIVE = "live";
public static final String GROUP_PRESENCE = "presence"; public static final String GROUP_PRESENCE = "presence";

View File

@ -43,7 +43,7 @@ import org.openhab.binding.netatmo.internal.handler.channelhelper.ApiBridgeChann
import org.openhab.binding.netatmo.internal.handler.channelhelper.CameraChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.CameraChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.DoorTagChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.DoorTagChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.EnergyChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.EnergyChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.EventDoorbellChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.EventCameraChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.EventPersonChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.EventPersonChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.PersonChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.PersonChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.PresenceChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.PresenceChannelHelper;
@ -70,7 +70,7 @@ public enum ModuleType {
HOME(FeatureArea.NONE, "NAHome", ACCOUNT, HOME(FeatureArea.NONE, "NAHome", ACCOUNT,
Set.of(DeviceCapability.class, HomeCapability.class, ChannelHelperCapability.class), Set.of(DeviceCapability.class, HomeCapability.class, ChannelHelperCapability.class),
new ChannelGroup(SecurityChannelHelper.class, GROUP_SECURITY), new ChannelGroup(SecurityChannelHelper.class, GROUP_SECURITY_EVENT, GROUP_SECURITY),
new ChannelGroup(EnergyChannelHelper.class, GROUP_ENERGY)), new ChannelGroup(EnergyChannelHelper.class, GROUP_ENERGY)),
PERSON(FeatureArea.SECURITY, "NAPerson", HOME, Set.of(PersonCapability.class, ChannelHelperCapability.class), PERSON(FeatureArea.SECURITY, "NAPerson", HOME, Set.of(PersonCapability.class, ChannelHelperCapability.class),
@ -79,7 +79,7 @@ public enum ModuleType {
WELCOME(FeatureArea.SECURITY, "NACamera", HOME, Set.of(CameraCapability.class, ChannelHelperCapability.class), WELCOME(FeatureArea.SECURITY, "NACamera", HOME, Set.of(CameraCapability.class, ChannelHelperCapability.class),
ChannelGroup.SIGNAL, ChannelGroup.EVENT, ChannelGroup.SIGNAL, ChannelGroup.EVENT,
new ChannelGroup(CameraChannelHelper.class, GROUP_CAM_STATUS, GROUP_CAM_LIVE)), new ChannelGroup(CameraChannelHelper.class, GROUP_SECURITY_EVENT, GROUP_CAM_STATUS, GROUP_CAM_LIVE)),
TAG(FeatureArea.SECURITY, "NACamDoorTag", WELCOME, Set.of(ChannelHelperCapability.class), ChannelGroup.SIGNAL, TAG(FeatureArea.SECURITY, "NACamDoorTag", WELCOME, Set.of(ChannelHelperCapability.class), ChannelGroup.SIGNAL,
ChannelGroup.BATTERY, ChannelGroup.TIMESTAMP, new ChannelGroup(DoorTagChannelHelper.class, GROUP_TAG)), ChannelGroup.BATTERY, ChannelGroup.TIMESTAMP, new ChannelGroup(DoorTagChannelHelper.class, GROUP_TAG)),
@ -89,12 +89,15 @@ public enum ModuleType {
PRESENCE(FeatureArea.SECURITY, "NOC", HOME, Set.of(PresenceCapability.class, ChannelHelperCapability.class), PRESENCE(FeatureArea.SECURITY, "NOC", HOME, Set.of(PresenceCapability.class, ChannelHelperCapability.class),
ChannelGroup.SIGNAL, ChannelGroup.EVENT, ChannelGroup.SIGNAL, ChannelGroup.EVENT,
new ChannelGroup(PresenceChannelHelper.class, GROUP_CAM_STATUS, GROUP_CAM_LIVE, GROUP_PRESENCE)), new ChannelGroup(PresenceChannelHelper.class, GROUP_SECURITY_EVENT, GROUP_CAM_STATUS, GROUP_CAM_LIVE,
GROUP_PRESENCE),
new ChannelGroup(EventCameraChannelHelper.class, GROUP_SUB_EVENT)),
DOORBELL(FeatureArea.SECURITY, "NDB", HOME, Set.of(DoorbellCapability.class, ChannelHelperCapability.class), DOORBELL(FeatureArea.SECURITY, "NDB", HOME, Set.of(DoorbellCapability.class, ChannelHelperCapability.class),
ChannelGroup.SIGNAL, ChannelGroup.SIGNAL,
new ChannelGroup(CameraChannelHelper.class, GROUP_DOORBELL_STATUS, GROUP_DOORBELL_LIVE), new ChannelGroup(CameraChannelHelper.class, GROUP_SECURITY_EVENT, GROUP_DOORBELL_STATUS,
new ChannelGroup(EventDoorbellChannelHelper.class, GROUP_DOORBELL_LAST_EVENT, GROUP_DOORBELL_SUB_EVENT)), GROUP_DOORBELL_LIVE),
new ChannelGroup(EventCameraChannelHelper.class, GROUP_DOORBELL_LAST_EVENT, GROUP_DOORBELL_SUB_EVENT)),
WEATHER_STATION(FeatureArea.WEATHER, "NAMain", ACCOUNT, WEATHER_STATION(FeatureArea.WEATHER, "NAMain", ACCOUNT,
Set.of(DeviceCapability.class, WeatherCapability.class, MeasureCapability.class, Set.of(DeviceCapability.class, WeatherCapability.class, MeasureCapability.class,

View File

@ -13,8 +13,8 @@
package org.openhab.binding.netatmo.internal.api.dto; package org.openhab.binding.netatmo.internal.api.dto;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.LinkedHashSet;
import java.util.List; import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
@ -72,8 +72,8 @@ public class WebhookEvent extends Event {
return vignetteUrl; return vignetteUrl;
} }
public List<String> getNAObjectList() { public Set<String> getNAObjectList() {
List<String> result = new ArrayList<>(); Set<String> result = new LinkedHashSet<>();
result.add(getCameraId()); result.add(getCameraId());
addNotBlank(result, homeId); addNotBlank(result, homeId);
addNotBlank(result, deviceId); addNotBlank(result, deviceId);
@ -82,9 +82,9 @@ public class WebhookEvent extends Event {
return result; return result;
} }
private void addNotBlank(List<String> list, String value) { private void addNotBlank(Set<String> collection, String value) {
if (!value.isBlank()) { if (!value.isBlank()) {
list.add(value); collection.add(value);
} }
} }
} }

View File

@ -13,6 +13,8 @@
package org.openhab.binding.netatmo.internal.handler.capability; package org.openhab.binding.netatmo.internal.handler.capability;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*; 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.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -26,6 +28,7 @@ import org.openhab.binding.netatmo.internal.api.dto.HomeDataPerson;
import org.openhab.binding.netatmo.internal.api.dto.HomeEvent; import org.openhab.binding.netatmo.internal.api.dto.HomeEvent;
import org.openhab.binding.netatmo.internal.api.dto.HomeStatusModule; import org.openhab.binding.netatmo.internal.api.dto.HomeStatusModule;
import org.openhab.binding.netatmo.internal.api.dto.NAObject; import org.openhab.binding.netatmo.internal.api.dto.NAObject;
import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap; import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap;
import org.openhab.binding.netatmo.internal.handler.CommonInterface; 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.CameraChannelHelper;
@ -33,8 +36,10 @@ import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider; import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.Command; import org.openhab.core.types.Command;
import org.openhab.core.types.StateOption; import org.openhab.core.types.StateOption;
import org.openhab.core.types.UnDefType;
/** /**
* {@link CameraCapability} give to handle Welcome Camera specifics * {@link CameraCapability} give to handle Welcome Camera specifics
@ -77,6 +82,35 @@ public class CameraCapability extends HomeSecurityThingCapability {
} }
} }
@Override
protected void updateWebhookEvent(WebhookEvent event) {
super.updateWebhookEvent(event);
final ThingUID thingUid = handler.getThing().getUID();
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_TYPE),
toStringType(event.getEventType()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_TIME),
toDateTimeType(event.getTime()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_SNAPSHOT),
toRawType(event.getSnapshotUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_SNAPSHOT_URL),
toStringType(event.getSnapshotUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_VIGNETTE),
toRawType(event.getVignetteUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_VIGNETTE_URL),
toStringType(event.getVignetteUrl()));
final String message = event.getName();
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_MESSAGE),
message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
// The channel should get triggered at last (after super and sub methods), because this allows rules to access
// the new updated data from the other channels.
final String eventType = event.getEventType().name();
handler.getHomeHandler().ifPresent(homeHandler -> homeHandler.triggerChannel(CHANNEL_HOME_EVENT, eventType));
handler.triggerChannel(CHANNEL_HOME_EVENT, eventType);
}
@Override @Override
public void handleCommand(String channelName, Command command) { public void handleCommand(String channelName, Command command) {
if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) { if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) {

View File

@ -12,19 +12,12 @@
*/ */
package org.openhab.binding.netatmo.internal.handler.capability; package org.openhab.binding.netatmo.internal.handler.capability;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
import static org.openhab.binding.netatmo.internal.utils.ChannelTypeUtils.*;
import java.util.List; import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
import org.openhab.binding.netatmo.internal.handler.CommonInterface; import org.openhab.binding.netatmo.internal.handler.CommonInterface;
import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper; import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider; import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.UnDefType;
/** /**
* {@link DoorbellCapability} give to handle Welcome Doorbell specifics * {@link DoorbellCapability} give to handle Welcome Doorbell specifics
@ -34,33 +27,9 @@ import org.openhab.core.types.UnDefType;
*/ */
@NonNullByDefault @NonNullByDefault
public class DoorbellCapability extends CameraCapability { public class DoorbellCapability extends CameraCapability {
private final ThingUID thingUid;
public DoorbellCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider, public DoorbellCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider,
List<ChannelHelper> channelHelpers) { List<ChannelHelper> channelHelpers) {
super(handler, descriptionProvider, channelHelpers); super(handler, descriptionProvider, channelHelpers);
thingUid = handler.getThing().getUID();
}
@Override
public void updateWebhookEvent(WebhookEvent event) {
super.updateWebhookEvent(event);
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_TYPE),
toStringType(event.getEventType()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_TIME),
toDateTimeType(event.getTime()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_SNAPSHOT),
toRawType(event.getSnapshotUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_SNAPSHOT_URL),
toStringType(event.getSnapshotUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_VIGNETTE),
toRawType(event.getVignetteUrl()));
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_VIGNETTE_URL),
toStringType(event.getVignetteUrl()));
String message = event.getName();
handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_MESSAGE),
message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
} }
} }

View File

@ -24,21 +24,21 @@ import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.types.State; import org.openhab.core.types.State;
/** /**
* The {@link EventDoorbellChannelHelper} handles specific channels of doorbell events * The {@link EventCameraChannelHelper} handles specific channels of sub-events (presence camera and doorbell).
* *
* @author Gaël L'hopital - Initial contribution * @author Gaël L'hopital - Initial contribution
* *
*/ */
@NonNullByDefault @NonNullByDefault
public class EventDoorbellChannelHelper extends EventChannelHelper { public class EventCameraChannelHelper extends EventChannelHelper {
public EventDoorbellChannelHelper(Set<String> providedGroups) { public EventCameraChannelHelper(Set<String> providedGroups) {
super(providedGroups); super(providedGroups);
} }
@Override @Override
protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) { protected @Nullable State internalGetHomeEvent(String channelId, @Nullable String groupId, HomeEvent event) {
if (groupId != null && GROUP_DOORBELL_SUB_EVENT.startsWith(groupId)) { if (groupId != null && groupId.startsWith(GROUP_SUB_EVENT)) {
switch (channelId) { switch (channelId) {
case CHANNEL_EVENT_TYPE: case CHANNEL_EVENT_TYPE:
return toStringType(event.getEventType()); return toStringType(event.getEventType());

View File

@ -71,6 +71,7 @@ channel-group-type.netatmo.rain.channel.sum-1.description = Quantity of water ov
channel-group-type.netatmo.rain.channel.sum-24.label = Rain 24h 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.rain.channel.sum-24.description = Quantity of water during the current day.
channel-group-type.netatmo.security.label = Home Security channel-group-type.netatmo.security.label = Home Security
channel-group-type.netatmo.security-event.label = Home Security Event
channel-group-type.netatmo.setpoint.label = Setpoint channel-group-type.netatmo.setpoint.label = Setpoint
channel-group-type.netatmo.setpoint.channel.end.label = Setpoint End channel-group-type.netatmo.setpoint.channel.end.label = Setpoint End
channel-group-type.netatmo.setpoint.channel.end.description = End time of the currently applied setpoint. channel-group-type.netatmo.setpoint.channel.end.description = End time of the currently applied setpoint.
@ -80,9 +81,16 @@ channel-group-type.netatmo.signal.label = Signal
channel-group-type.netatmo.siren.label = Siren Status channel-group-type.netatmo.siren.label = Siren Status
channel-group-type.netatmo.status-doorbell.label = Camera Status channel-group-type.netatmo.status-doorbell.label = Camera Status
channel-group-type.netatmo.status.label = Camera Status channel-group-type.netatmo.status.label = Camera Status
channel-group-type.netatmo.sub-event.label = Sub Event
channel-group-type.netatmo.sub-event.channel.time.label = Sub-Event Timestamp
channel-group-type.netatmo.sub-event.channel.time.description = Moment when the sub-event occurred.
channel-group-type.netatmo.sub-event.channel.vignette.label = Vignette
channel-group-type.netatmo.sub-event.channel.vignette.description = Vignette of the Snapshot.
channel-group-type.netatmo.sub-event.channel.vignette-url.label = Vignette URL
channel-group-type.netatmo.sub-event.channel.vignette-url.description = URL of the vignette.
channel-group-type.netatmo.sub-event-doorbell.label = Sub Event 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.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.time.description = Moment when the sub-event occurred.
channel-group-type.netatmo.sub-event-doorbell.channel.vignette.label = Vignette 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.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.label = Vignette URL
@ -136,7 +144,6 @@ channel-type.netatmo.avatar-picture.label = Avatar Picture
channel-type.netatmo.avatar-picture.description = Avatar of this person. channel-type.netatmo.avatar-picture.description = Avatar of this person.
channel-type.netatmo.battery-status.label = Battery Status channel-type.netatmo.battery-status.label = Battery Status
channel-type.netatmo.battery-status.description = Description of the battery status. channel-type.netatmo.battery-status.description = Description of the battery status.
channel-type.netatmo.camera-event.label = Camera Event
channel-type.netatmo.camera-id.label = Camera ID channel-type.netatmo.camera-id.label = Camera ID
channel-type.netatmo.camera-id.description = ID of the camera that triggered the event. channel-type.netatmo.camera-id.description = ID of the camera that triggered the event.
channel-type.netatmo.co2.label = CO2 channel-type.netatmo.co2.label = CO2

View File

@ -58,19 +58,6 @@
<state readOnly="true"/> <state readOnly="true"/>
</channel-type> </channel-type>
<channel-type id="camera-event">
<kind>trigger</kind>
<label>Camera Event</label>
<event>
<options>
<option value="ANIMAL"/>
<option value="HUMAN"/>
<option value="MOVEMENT"/>
<option value="VEHICLE"/>
</options>
</event>
</channel-type>
<channel-type id="battery-status"> <channel-type id="battery-status">
<item-type>String</item-type> <item-type>String</item-type>
<label>Battery Status</label> <label>Battery Status</label>

View File

@ -10,6 +10,12 @@
<channel id="person-count" typeId="person-count"/> <channel id="person-count" typeId="person-count"/>
<channel id="unknown-person-count" typeId="unknown-person-count"/> <channel id="unknown-person-count" typeId="unknown-person-count"/>
<channel id="unknown-person-picture" typeId="unknown-person-picture"/> <channel id="unknown-person-picture" typeId="unknown-person-picture"/>
</channels>
</channel-group-type>
<channel-group-type id="security-event">
<label>Home Security Event</label>
<channels>
<channel id="home-event" typeId="home-event"/> <channel id="home-event" typeId="home-event"/>
</channels> </channels>
</channel-group-type> </channel-group-type>
@ -98,13 +104,35 @@
</channels> </channels>
</channel-group-type> </channel-group-type>
<channel-group-type id="sub-event">
<label>Sub Event</label>
<channels>
<channel id="type" typeId="event-type"/>
<channel id="time" typeId="timestamp">
<label>Sub-Event Timestamp</label>
<description>Moment when the sub-event occurred.</description>
</channel>
<channel id="message" typeId="message"/>
<channel id="snapshot" typeId="event-picture"/>
<channel id="snapshot-url" typeId="event-picture-url"/>
<channel id="vignette" typeId="event-picture">
<label>Vignette</label>
<description>Vignette of the Snapshot.</description>
</channel>
<channel id="vignette-url" typeId="event-picture-url">
<label>Vignette URL</label>
<description>URL of the vignette.</description>
</channel>
</channels>
</channel-group-type>
<channel-group-type id="sub-event-doorbell"> <channel-group-type id="sub-event-doorbell">
<label>Sub Event</label> <label>Sub Event</label>
<channels> <channels>
<channel id="type" typeId="event-type"/> <channel id="type" typeId="event-type"/>
<channel id="time" typeId="timestamp"> <channel id="time" typeId="timestamp">
<label>Sub-Event Timestamp</label> <label>Sub-Event Timestamp</label>
<description>Moment when then sub-event occurred.</description> <description>Moment when the sub-event occurred.</description>
</channel> </channel>
<channel id="message" typeId="message"/> <channel id="message" typeId="message"/>
<channel id="snapshot" typeId="event-picture"/> <channel id="snapshot" typeId="event-picture"/>

View File

@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2023 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.junit.jupiter.api.Assertions.*;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
import java.util.Collections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.netatmo.internal.api.data.EventType;
import org.openhab.binding.netatmo.internal.api.dto.HomeEvent;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.State;
/**
* @author Sven Strohschein - Initial contribution
*/
public class EventCameraChannelHelperTest {
private EventCameraChannelHelper helper;
@BeforeEach
public void before() {
helper = new EventCameraChannelHelper(Collections.emptySet());
}
@Test
public void testInternalGetHomeEventGroupSubEvent() {
State state = helper.internalGetHomeEvent(CHANNEL_EVENT_TYPE, GROUP_SUB_EVENT, new HomeEvent());
assertTrue(state instanceof StringType);
assertEquals(EventType.UNKNOWN.name(), state.toString());
}
@Test
public void testInternalGetHomeEventGroupDoorbellSubEvent() {
State state = helper.internalGetHomeEvent(CHANNEL_EVENT_TYPE, GROUP_DOORBELL_SUB_EVENT, new HomeEvent());
assertTrue(state instanceof StringType);
assertEquals(EventType.UNKNOWN.name(), state.toString());
}
@Test
public void testInternalGetHomeEventGroupDoorbellStatus() {
State state = helper.internalGetHomeEvent(CHANNEL_EVENT_TYPE, GROUP_DOORBELL_STATUS, new HomeEvent());
// Only sub-event groups are handled by EventCameraChannelHelper. GROUP_DOORBELL_STATUS isn't a sub-event group.
assertNull(state);
}
}