Skip to content

Commit

Permalink
[netatmo] Add support for Presence camera events (openhab#7807)
Browse files Browse the repository at this point in the history
* - Netatmo API updated (to support the sub-event structure which is used by the Presence events)
- The message and snapshot data of the Presence events is now available at the home thing
- New channels to the home thing added to report if a human, animal or vehicle was detected
- Process of updating the Netatmo API simplified (the retrofit code generation is now embedded within the Maven build, therefore the netatmo-swagger-api project doesn't require an additional update and release anymore)
* README extended for the Presence outdoor camera thing configuration example
* NonNullByDefault is now used because it was mentioned in the code-review
* The new 3 channels (for human, animal and vehicle detection) are now replaced by a trigger channel called "cameraEvent". Trigger channels are triggered after the other channels are updated (so a rule can react on a trigger and get the other event information from the other updated channels). Movement event option - A Presence camera reports also generic movements when a movement is not recognizable as a human, animal or vehicle.

Signed-off-by: Sven Strohschein <[email protected]>
  • Loading branch information
Novanic authored and knikhilwiz committed Jul 12, 2020
1 parent 4a53c85 commit b0e66b7
Show file tree
Hide file tree
Showing 20 changed files with 256 additions and 120 deletions.
6 changes: 3 additions & 3 deletions bundles/org.openhab.binding.netatmo/NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ oltu.oauth2
* Project: https://oltu.apache.org
* Source: https://svn.apache.org/viewvc/oltu/trunk

netatmo-java-retrofit
* License: Apache 2.0 License
netatmo-swagger-decl
* License: MIT License
* Project: https://dev.netatmo.com
* Source: https://github.com/cbornet/netatmo-swagger-api
* Source: https://github.com/cbornet/netatmo-swagger-decl

retrofit
* License: Apache 2.0 License
Expand Down
72 changes: 51 additions & 21 deletions bundles/org.openhab.binding.netatmo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Bridge netatmo:netatmoapi:home [ clientId="<CLIENT_ID>", clientSecret="<CLIENT_S
Thing NATherm1 thermostat [ id="xx:xx:xx:xx:xx:xx", parentId="bb:bb:bb:bb:bb:bb" ]
Thing NAWelcomeHome home [ id="58yyacaaexxxebca99x999x", refreshInterval=600000 ]
Thing NACamera camera [ id="cc:cc:cc:cc:cc:cc", parentId="58yyacaaexxxebca99x999x" ]
Thing NOC presenceOutdoorCamera [ id="dd:dd:dd:dd:dd:dd", parentId="58yyacaaexxxebca99x999x" ]
Thing NAWelcomePerson sysadmin [ id="aaaaaaaa-bbbb-cccc-eeee-zzzzzzzzzzzz", parentId="58yyacaaexxxebca99x999x" ]
...
}
Expand Down Expand Up @@ -446,29 +447,58 @@ All these channels except Sp_Temperature, SetpointMode and Planning are read onl

### Welcome Home

**Supported channels for the Home thing:**

| Channel ID | Item Type | Description |
|-------------------------|-----------|----------------------------------------------------------|
| welcomeHomeCity | String | City of the home |
| welcomeHomeCountry | String | Country of the home |
| welcomeHomeTimezone | String | Timezone of the home |
| welcomeHomePersonCount | Number | Total number of Persons that are at home |
| welcomeHomeUnknownCount | Number | Count how many Unknown Persons are at home |
| welcomeEventType | String | Type of event |
| welcomeEventTime | DateTime | Time of occurrence of event |
| welcomeEventCameraId | String | Camera that detected the event |
| welcomeEventPersonId | String | Id of the person the event is about (if any) |
| welcomeEventSnapshot | Image | picture of the last event, if it applies |
| welcomeEventSnapshotURL | String | if the last event (depending upon event type) in the home lead a snapshot picture, the picture URL will be available here |
| welcomeEventVideoURL | String | if the last event (depending upon event type) in the home lead a snapshot picture, the corresponding video URL will be available here |
| welcomeEventVideoStatus | String | Status of the video (recording, deleted or available) |
| welcomeEventIsArrival | Switch | If person was considered "away" before being seen during this event |
| welcomeEventMessage | String | Message sent by Netatmo corresponding to given event |
| welcomeEventSubType | String | Sub-type of SD and Alim events |

All these channels are read only.

**Supported channels for the Home thing:**

| Channel ID | Item Type | Description |
|--------------------------|-----------|----------------------------------------------------------|
| welcomeHomeCity | String | City of the home |
| welcomeHomeCountry | String | Country of the home |
| welcomeHomeTimezone | String | Timezone of the home |
| welcomeHomePersonCount | Number | Total number of Persons that are at home |
| welcomeHomeUnknownCount | Number | Count how many Unknown Persons are at home |
| welcomeEventType | String | Type of event |
| welcomeEventTime | DateTime | Time of occurrence of event |
| welcomeEventCameraId | String | Camera that detected the event |
| welcomeEventPersonId | String | Id of the person the event is about (if any) |
| welcomeEventSnapshot | Image | picture of the last event, if it applies |
| welcomeEventSnapshotURL | String | if the last event (depending upon event type) in the home lead a snapshot picture, the picture URL will be available here |
| welcomeEventVideoURL | String | if the last event (depending upon event type) in the home lead a snapshot picture, the corresponding video URL will be available here |
| welcomeEventVideoStatus | String | Status of the video (recording, deleted or available) |
| welcomeEventIsArrival | Switch | If person was considered "away" before being seen during this event |
| welcomeEventMessage | String | Message sent by Netatmo corresponding to given event |
| welcomeEventSubType | String | Sub-type of SD and Alim events |

**Supported trigger channels for the Home thing:**

| Channel Type ID | Options | Description |
|------------------|------------------------|-------------------------------------------------------|
| 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 |
| | HUMAN | Triggered when a human (or person) was detected |
| | ANIMAL | Triggered when an animal was detected |
| | MOVEMENT | Triggered when an unspecified movement was detected |
| | VEHICLE | Triggered when a vehicle was detected |
| welcomeHomeEvent | | A welcome home event is triggered directly via a configured webhook |
| | PERSON | Triggered when a concrete person was detected |
| | PERSON_AWAY | Triggered when a concrete person leaves |
| | MOVEMENT | Triggered when a movement was detected |
| | CONNECTION | Triggered when a camera connection gets created |
| | DISCONNECTION | Triggered when a camera connection got lost |
| | ON | Triggered when camera monitoring is switched on |
| | OFF | Triggered when camera monitoring is switched off |
| | BOOT | Triggered when a camera is booting |
| | SD | Triggered when a camera SD card status was changed |
| | ALIM | Triggered when a power supply status was changed |
| | NEW_MODULE | Triggered when a new module was discovered |
| | MODULE_CONNECT | Triggered when a module gets connected |
| | MODULE_DISCONNECT | Triggered when a module gets disconnected |
| | MODULE_LOW_BATTERY | Triggered when the battery of a module gets low |
| | MODULE_END_UPDATE | Triggered when a firmware update of a module is done |
| | TAG_BIG_MOVE | Triggered when a big movement of a tag was detected |
| | TAG_SMALL_MOVE | Triggered when a small movement of a tag was detected |
| | TAG_UNINSTALLED | Triggered when a tag gets uninstalled |
| | TAG_OPEN | Triggered when an open event of a tag was detected |

### Welcome and Presence Camera

Expand Down
31 changes: 25 additions & 6 deletions bundles/org.openhab.binding.netatmo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@
</properties>

<dependencies>
<dependency>
<groupId>com.github.cbornet.netatmo-swagger-api</groupId>
<artifactId>netatmo-java-retrofit</artifactId>
<version>1.1.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openhab.osgiify</groupId>
<artifactId>org.json.json</artifactId>
Expand Down Expand Up @@ -63,4 +57,29 @@
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.1.6</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>https://raw.githubusercontent.com/cbornet/netatmo-swagger-decl/master/spec/swagger.yaml</inputSpec>
<language>java</language>
<library>retrofit</library>
<configOptions>
<sourceFolder>src/main/java</sourceFolder>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ public class NetatmoBindingConstants {

public static final String CHANNEL_WELCOME_HOME_EVENT = "welcomeHomeEvent";

public static final String CHANNEL_CAMERA_EVENT = "cameraEvent";

public static final String CHANNEL_WELCOME_PERSON_LASTSEEN = "welcomePersonLastSeen";
public static final String CHANNEL_WELCOME_PERSON_ATHOME = "welcomePersonAtHome";
public static final String CHANNEL_WELCOME_PERSON_AVATAR_URL = "welcomePersonAvatarUrl";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ protected void updateProperties(NAWelcomeCamera moduleData) {

@SuppressWarnings("null")
@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
switch (channelId) {
case CHANNEL_CAMERA_STATUS:
return getStatusState();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@
import org.eclipse.smarthome.config.core.Configuration;
import org.eclipse.smarthome.core.library.unit.SIUnits;
import org.eclipse.smarthome.core.library.unit.SmartHomeUnits;
import org.eclipse.smarthome.core.thing.Bridge;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.*;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.binding.BridgeHandler;
import org.eclipse.smarthome.core.thing.type.ChannelKind;
Expand Down Expand Up @@ -120,7 +115,7 @@ private void initializeThing(ThingStatus bridgeStatus) {

protected abstract void initializeThing();

protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
Optional<State> result;

result = batteryHelper.flatMap(helper -> helper.getNAThingProperty(channelId));
Expand All @@ -137,16 +132,39 @@ protected State getNAThingProperty(String channelId) {
}

protected void updateChannels() {
getThing().getChannels().stream().filter(channel -> channel.getKind() != ChannelKind.TRIGGER)
updateDataChannels();

triggerEventChannels();
}

private void updateDataChannels() {
getThing().getChannels().stream().filter(channel -> !channel.getKind().equals(ChannelKind.TRIGGER))
.forEach(channel -> {
String channelId = channel.getUID().getId();
if (isLinked(channelId)) {
State state = getNAThingProperty(channelId);
if (state != null) {
updateState(channel.getUID(), state);
}
}
});

String channelId = channel.getUID().getId();
if (isLinked(channelId)) {
State state = getNAThingProperty(channelId);
if (state != null) {
updateState(channel.getUID(), state);
}
}
});
}

/**
* Triggers all event/trigger channels
* (when a channel is triggered, a rule can get all other information from the updated non-trigger channels)
*/
private void triggerEventChannels() {
getThing().getChannels().stream().filter(channel -> channel.getKind().equals(ChannelKind.TRIGGER))
.forEach(channel -> triggerChannelIfRequired(channel.getUID().getId()));
}

/**
* Triggers the trigger channel with the given channel id when required (when an update is available)
* @param channelId channel id
*/
protected void triggerChannelIfRequired(@NonNull String channelId) {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.library.types.DecimalType;
import org.eclipse.smarthome.core.library.types.PointType;
Expand Down Expand Up @@ -89,7 +90,7 @@ public void dispose() {
}
}

protected abstract DEVICE updateReadings();
protected abstract @Nullable DEVICE updateReadings();

protected void updateProperties(DEVICE deviceData) {
}
Expand Down Expand Up @@ -148,7 +149,7 @@ protected void updateChannels() {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
try {
switch (channelId) {
case CHANNEL_LAST_STATUS_STORE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.thing.ThingStatus;
Expand Down Expand Up @@ -71,7 +72,7 @@ public boolean childOf(AbstractNetatmoThingHandler naThingHandler) {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
try {
if (channelId.equalsIgnoreCase(CHANNEL_LAST_MESSAGE) && module != null) {
Method getLastMessage = module.getClass().getMethod("getLastMessage");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected void updateProperties(NAHealthyHomeCoach deviceData) {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (device != null) {
NADashboardData dashboardData = device.getDashboardData();
switch (channelId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.State;
Expand Down Expand Up @@ -165,7 +166,7 @@ private void updateMonthMeasurements() {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (device != null) {
NADashboardData dashboardData = device.getDashboardData();
if (dashboardData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.netatmo.internal.WeatherUtils;
Expand Down Expand Up @@ -101,7 +102,7 @@ private void updateMonthMeasurements() {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (module != null) {
NADashboardData dashboardData = module.getDashboardData();
if (dashboardData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static org.openhab.binding.netatmo.internal.ChannelTypeUtils.*;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.netatmo.internal.handler.NetatmoModuleHandler;
Expand All @@ -40,7 +41,7 @@ protected void updateProperties(NAStationModule moduleData) {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (module != null) {
NADashboardData dashboardData = module.getDashboardData();
if (dashboardData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void updateMeasurements() {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (module != null) {
NADashboardData dashboardData = module.getDashboardData();
if (dashboardData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.smarthome.core.thing.Thing;
import org.eclipse.smarthome.core.types.State;
import org.openhab.binding.netatmo.internal.WeatherUtils;
Expand Down Expand Up @@ -113,7 +114,7 @@ private void updateMonthMeasurements() {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
if (module != null) {
NADashboardData dashboardData = module.getDashboardData();
if (dashboardData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ protected void updateProperties(NAPlug deviceData) {
}

@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
switch (channelId) {
case CHANNEL_CONNECTED_BOILER:
return device != null ? toOnOffType(device.getPlugConnectedBoiler()) : UnDefType.UNDEF;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private void updateStateDescription(NAThermostat thermostat) {

@SuppressWarnings("null")
@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
switch (channelId) {
case CHANNEL_THERM_ORIENTATION:
return module != null ? toDecimalType(module.getThermOrientation()) : UnDefType.UNDEF;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public NAWelcomeCameraHandler(@NonNull Thing thing) {

@SuppressWarnings("null")
@Override
protected State getNAThingProperty(String channelId) {
protected State getNAThingProperty(@NonNull String channelId) {
switch (channelId) {
case CHANNEL_WELCOME_CAMERA_STATUS:
return getStatusState();
Expand Down
Loading

0 comments on commit b0e66b7

Please sign in to comment.