- _Doorbell_
- _Smoke Detector_
- _Smart Door Sensor_
+- _Carbon Monoxide Detector_
See <https://www.netatmo.com/> for details on their product.
| room | Thing | NARoom | A room in your house. | id |
| valve | Thing | NRV | A valve controlling a radiator. | id |
| tag | Thing | NACamDoorTag | A door / window sensor | id |
+| smoke-detector | Thing | NSD | A Smoke Detector | id |
+| co-detector | Thing | NCO | A Carbon Monoxide Alarm | id |
### Webhook
| last-event | subtype | String | Sub-type of event |
| last-event | message | String | Last event message from this person |
+### Netatmo Smart Carbon Monoxide Detector
+
+All these channels are read only.
+
+**Supported channels for the Carbon Monoxide Detector thing:**
+
+| Channel Group | Channel Id | Item Type | Description |
+| ------------- | ---------- | ------------ | ------------------------------------------------ |
+| signal | strength | Number | Signal strength (0 for no signal, 1 for weak...) |
+| signal | value | Number:Power | Signal strength in dBm |
+| timestamp | last-seen | DateTime | Last time the module reported its presence |
+| last-event | type | String | Type of event |
+| last-event | time | DateTime | Moment of the last event for this detector |
+| last-event | subtype | String | Sub-type of event |
+| last-event | message | String | Last event message from this detector |
+
## Configuration Examples
### things/netatmo.things
public static final String OPTION_PERSON = "-person";
public static final String OPTION_ROOM = "-room";
public static final String OPTION_THERMOSTAT = "-thermostat";
- public static final String OPTION_SMOKE = "-smoke";
+ public static final String OPTION_ALARM = "-alarm";
public static final Set<String> GROUP_VARIATIONS = Set.of(OPTION_EXTENDED, OPTION_OUTSIDE, OPTION_DOORBELL,
- OPTION_PERSON, OPTION_ROOM, OPTION_THERMOSTAT, OPTION_SMOKE);
+ OPTION_PERSON, OPTION_ROOM, OPTION_THERMOSTAT, OPTION_ALARM);
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_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_SMOKE_LAST_EVENT = GROUP_LAST_EVENT + OPTION_SMOKE;
+ public static final String GROUP_ALARM_LAST_EVENT = GROUP_LAST_EVENT + OPTION_ALARM;
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;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
+import org.openhab.binding.netatmo.internal.api.data.ChannelGroup;
import org.openhab.binding.netatmo.internal.api.data.ModuleType;
import org.openhab.binding.netatmo.internal.config.BindingConfiguration;
import org.openhab.binding.netatmo.internal.deserialization.NADeserializer;
import org.openhab.binding.netatmo.internal.handler.DeviceHandler;
import org.openhab.binding.netatmo.internal.handler.ModuleHandler;
import org.openhab.binding.netatmo.internal.handler.capability.AirCareCapability;
+import org.openhab.binding.netatmo.internal.handler.capability.AlarmEventCapability;
import org.openhab.binding.netatmo.internal.handler.capability.CameraCapability;
import org.openhab.binding.netatmo.internal.handler.capability.Capability;
import org.openhab.binding.netatmo.internal.handler.capability.ChannelHelperCapability;
import org.openhab.binding.netatmo.internal.handler.capability.PersonCapability;
import org.openhab.binding.netatmo.internal.handler.capability.PresenceCapability;
import org.openhab.binding.netatmo.internal.handler.capability.RoomCapability;
-import org.openhab.binding.netatmo.internal.handler.capability.SmokeCapability;
import org.openhab.binding.netatmo.internal.handler.capability.WeatherCapability;
import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
CommonInterface handler = moduleType.isABridge() ? new DeviceHandler((Bridge) thing) : new ModuleHandler(thing);
List<ChannelHelper> helpers = new ArrayList<>();
- moduleType.channelGroups
- .forEach(channelGroup -> channelGroup.getHelperInstance().ifPresent(helper -> helpers.add(helper)));
+
+ helpers.addAll(moduleType.channelGroups.stream().map(ChannelGroup::getHelperInstance).toList());
moduleType.capabilities.forEach(capability -> {
Capability newCap = null;
newCap = new PersonCapability(handler, stateDescriptionProvider, helpers);
} else if (capability == CameraCapability.class) {
newCap = new CameraCapability(handler, stateDescriptionProvider, helpers);
- } else if (capability == SmokeCapability.class) {
- newCap = new SmokeCapability(handler, stateDescriptionProvider, helpers);
+ } else if (capability == AlarmEventCapability.class) {
+ newCap = new AlarmEventCapability(handler, stateDescriptionProvider, helpers);
} else if (capability == PresenceCapability.class) {
newCap = new PresenceCapability(handler, stateDescriptionProvider, helpers);
} else if (capability == MeasureCapability.class) {
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
-import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.openhab.binding.netatmo.internal.handler.channelhelper.TemperatureChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.TimestampChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoThingTypeProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The {@link ChannelGroup} makes the link between a channel helper and some group types. It also
GROUP_NOISE);
public static final ChannelGroup HUMIDITY = new ChannelGroup(HumidityChannelHelper.class, MeasureClass.HUMIDITY,
GROUP_HUMIDITY);
+ public static final ChannelGroup ALARM_LAST_EVENT = new ChannelGroup(EventChannelHelper.class,
+ GROUP_ALARM_LAST_EVENT);
- private final Logger logger = LoggerFactory.getLogger(ChannelGroup.class);
private final Class<? extends ChannelHelper> helper;
public final Set<String> groupTypes;
public final Set<String> extensions;
this.extensions = extensions;
}
- public Optional<ChannelHelper> getHelperInstance() {
+ public ChannelHelper getHelperInstance() {
try {
- return Optional.of(helper.getConstructor(Set.class).newInstance(
- groupTypes.stream().map(NetatmoThingTypeProvider::toGroupName).collect(Collectors.toSet())));
+ return helper.getConstructor(Set.class).newInstance(
+ groupTypes.stream().map(NetatmoThingTypeProvider::toGroupName).collect(Collectors.toSet()));
} catch (ReflectiveOperationException e) {
- logger.warn("Error creating or initializing helper class : {}", e.getMessage());
+ throw new IllegalArgumentException(
+ "Error creating or initializing helper class : %s".formatted(e.getMessage()));
}
- return Optional.empty();
}
}
SD_CARD_INCOMPATIBLE_SPEED(6, EventType.SD),
SD_CARD_INSUFFICIENT_SPACE(7, EventType.SD),
- // Alimentation sub events
+ // Power sub events
ALIM_INCORRECT_POWER(1, EventType.ALIM),
ALIM_CORRECT_POWER(2, EventType.ALIM),
SOUND_TEST_ERROR(1, EventType.SOUND_TEST),
DETECTOR_READY(0, EventType.TAMPERED),
DETECTOR_TAMPERED(1, EventType.TAMPERED),
+
+ // Carbon Monoxide Alarm
+ CO_OK(0, EventType.CO_DETECTED),
+ CO_PRE_ALARM(1, EventType.CO_DETECTED),
+ CO_ALARM(2, EventType.CO_DETECTED),
+
WIFI_STATUS_OK(1, EventType.WIFI_STATUS),
WIFI_STATUS_ERROR(0, EventType.WIFI_STATUS),
SMOKE(ModuleType.SMOKE_DETECTOR),
@SerializedName("tampered") // When smoke detector is ready or tampered
- TAMPERED(ModuleType.SMOKE_DETECTOR),
+ TAMPERED(ModuleType.SMOKE_DETECTOR, ModuleType.CO_DETECTOR),
@SerializedName("wifi_status") // When wifi status is updated
- WIFI_STATUS(ModuleType.SMOKE_DETECTOR),
+ WIFI_STATUS(ModuleType.SMOKE_DETECTOR, ModuleType.CO_DETECTOR),
@SerializedName("battery_status") // When battery status is too low
- BATTERY_STATUS(ModuleType.SMOKE_DETECTOR),
+ BATTERY_STATUS(ModuleType.SMOKE_DETECTOR, ModuleType.CO_DETECTOR),
@SerializedName("detection_chamber_status") // When the detection chamber is dusty or clean
DETECTION_CHAMBER_STATUS(ModuleType.SMOKE_DETECTOR),
@SerializedName("sound_test") // Sound test result
- SOUND_TEST(ModuleType.SMOKE_DETECTOR),
+ SOUND_TEST(ModuleType.SMOKE_DETECTOR, ModuleType.CO_DETECTOR),
@SerializedName("new_device")
- NEW_DEVICE(ModuleType.HOME);
+ NEW_DEVICE(ModuleType.HOME),
+
+ @SerializedName("co_detected")
+ CO_DETECTED(ModuleType.CO_DETECTOR);
public static final EnumSet<EventType> AS_SET = EnumSet.allOf(EventType.class);
import java.net.URI;
import java.util.EnumSet;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.FeatureArea;
import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.MeasureClass;
import org.openhab.binding.netatmo.internal.handler.capability.AirCareCapability;
+import org.openhab.binding.netatmo.internal.handler.capability.AlarmEventCapability;
import org.openhab.binding.netatmo.internal.handler.capability.CameraCapability;
import org.openhab.binding.netatmo.internal.handler.capability.Capability;
import org.openhab.binding.netatmo.internal.handler.capability.ChannelHelperCapability;
import org.openhab.binding.netatmo.internal.handler.capability.PersonCapability;
import org.openhab.binding.netatmo.internal.handler.capability.PresenceCapability;
import org.openhab.binding.netatmo.internal.handler.capability.RoomCapability;
-import org.openhab.binding.netatmo.internal.handler.capability.SmokeCapability;
import org.openhab.binding.netatmo.internal.handler.capability.WeatherCapability;
import org.openhab.binding.netatmo.internal.handler.channelhelper.AirQualityChannelHelper;
import org.openhab.binding.netatmo.internal.handler.channelhelper.ApiBridgeChannelHelper;
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.EnergyChannelHelper;
-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.PersonChannelHelper;
import org.openhab.core.thing.ThingTypeUID;
/**
- * This enum all handled Netatmo modules and devices along with their capabilities
+ * This enum describes all Netatmo modules and devices along with their capabilities.
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public enum ModuleType {
UNKNOWN(FeatureArea.NONE, "", null, Set.of()),
+
ACCOUNT(FeatureArea.NONE, "", null, Set.of(), new ChannelGroup(ApiBridgeChannelHelper.class, GROUP_MONITORING)),
HOME(FeatureArea.NONE, "NAHome", ACCOUNT,
new ChannelGroup(RoomChannelHelper.class, GROUP_TYPE_ROOM_PROPERTIES, GROUP_TYPE_ROOM_TEMPERATURE),
new ChannelGroup(SetpointChannelHelper.class, GROUP_SETPOINT)),
- SMOKE_DETECTOR(FeatureArea.SECURITY, "NSD", HOME, Set.of(SmokeCapability.class, ChannelHelperCapability.class),
- ChannelGroup.SIGNAL, ChannelGroup.TIMESTAMP,
- new ChannelGroup(EventChannelHelper.class, GROUP_SMOKE_LAST_EVENT));
+ SMOKE_DETECTOR(FeatureArea.SECURITY, "NSD", HOME, Set.of(AlarmEventCapability.class, ChannelHelperCapability.class),
+ ChannelGroup.SIGNAL, ChannelGroup.TIMESTAMP, ChannelGroup.ALARM_LAST_EVENT),
+
+ CO_DETECTOR(FeatureArea.SECURITY, "NCO", HOME, Set.of(AlarmEventCapability.class, ChannelHelperCapability.class),
+ ChannelGroup.SIGNAL, ChannelGroup.TIMESTAMP, ChannelGroup.ALARM_LAST_EVENT);
public static final EnumSet<ModuleType> AS_SET = EnumSet.allOf(ModuleType.class);
- private final @Nullable ModuleType bridgeType;
+ private final Optional<ModuleType> bridgeType;
public final Set<ChannelGroup> channelGroups;
public final Set<Class<? extends Capability>> capabilities;
public final ThingTypeUID thingTypeUID;
ModuleType(FeatureArea feature, String apiName, @Nullable ModuleType bridge,
Set<Class<? extends Capability>> capabilities, ChannelGroup... channelGroups) {
- this.bridgeType = bridge;
+ this.bridgeType = Optional.ofNullable(bridge);
this.feature = feature;
this.capabilities = capabilities;
this.apiName = apiName;
return !channelGroups.contains(ChannelGroup.SIGNAL);
}
- public boolean isABridge() {
- for (ModuleType mt : ModuleType.values()) {
- if (this.equals(mt.bridgeType)) {
- return true;
- }
- }
- return false;
+ public boolean isABridge() { // I am a bridge if any module references me as being so
+ return AS_SET.stream().anyMatch(mt -> this.equals(mt.getBridge()));
}
public List<String> getExtensions() {
- return channelGroups.stream().map(cg -> cg.extensions).flatMap(Set::stream).collect(Collectors.toList());
+ return channelGroups.stream().map(cg -> cg.extensions).flatMap(Set::stream).toList();
}
- public Set<String> getGroupTypes() {
- return channelGroups.stream().map(cg -> cg.groupTypes).flatMap(Set::stream).collect(Collectors.toSet());
+ public List<String> getGroupTypes() {
+ return channelGroups.stream().map(cg -> cg.groupTypes).flatMap(Set::stream).toList();
}
public int[] getSignalLevels() {
: WIFI_SIGNAL_LEVELS;
}
throw new IllegalArgumentException(
- "This should not be called for module type : " + name() + ", please file a bug report.");
+ "getSignalLevels should not be called for module type : '%s', please file a bug report."
+ .formatted(name()));
}
public ModuleType getBridge() {
- ModuleType bridge = bridgeType;
- return bridge != null ? bridge : ModuleType.UNKNOWN;
+ return bridgeType.orElse(UNKNOWN);
}
public URI getConfigDescription() {
return URI.create(BINDING_ID + ":"
+ (equals(ACCOUNT) ? "api_bridge"
: equals(HOME) ? "home"
- : (isLogical() ? "virtual"
- : ModuleType.UNKNOWN.equals(getBridge()) ? "configurable" : "device")));
+ : (isLogical() ? "virtual" : UNKNOWN.equals(getBridge()) ? "configurable" : "device")));
}
public int getDepth() {
- ModuleType parent = bridgeType;
- return parent == null ? 1 : 1 + parent.getDepth();
+ ModuleType parent = getBridge();
+ return parent == UNKNOWN ? 1 : parent.getDepth() + 1;
}
public static ModuleType from(ThingTypeUID thingTypeUID) {
- return ModuleType.AS_SET.stream().filter(mt -> mt.thingTypeUID.equals(thingTypeUID)).findFirst()
- .orElseThrow(() -> new IllegalArgumentException());
+ return AS_SET.stream().filter(mt -> mt.thingTypeUID.equals(thingTypeUID)).findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(
+ "No known ModuleType matched '%s'".formatted(thingTypeUID.toString())));
}
}
WRITE_DOORBELL,
@SerializedName("access_doorbell")
ACCESS_DOORBELL,
+ @SerializedName("read_carbonmonoxidedetector")
+ READ_CARBONMONOXIDEDETECTOR,
UNKNOWN;
}
private static final Scope[] SMOKE_SCOPES = { Scope.READ_SMOKEDETECTOR };
+ private static final Scope[] CARBON_MONOXIDE_SCOPES = { Scope.READ_CARBONMONOXIDEDETECTOR };
private static final Scope[] AIR_CARE_SCOPES = { Scope.READ_HOMECOACH };
private static final Scope[] WEATHER_SCOPES = { Scope.READ_STATION };
private static final Scope[] THERMOSTAT_SCOPES = { Scope.READ_THERMOSTAT, Scope.WRITE_THERMOSTAT };
AIR_CARE(AIR_CARE_SCOPES),
WEATHER(WEATHER_SCOPES),
ENERGY(THERMOSTAT_SCOPES),
- SECURITY(WELCOME_SCOPES, PRESENCE_SCOPES, SMOKE_SCOPES, DOORBELL_SCOPES),
+ SECURITY(WELCOME_SCOPES, PRESENCE_SCOPES, SMOKE_SCOPES, DOORBELL_SCOPES, CARBON_MONOXIDE_SCOPES),
NONE();
public static String ALL_SCOPES = EnumSet.allOf(FeatureArea.class).stream().map(fa -> fa.scopes)
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.InputStreamContentProvider;
+import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
String refreshToken = connectApi.authorize(configuration, code, redirectUri);
if (configuration.refreshToken.isBlank()) {
+ logger.trace("Adding refresh token to configuration : {}", refreshToken);
Configuration thingConfig = editConfiguration();
thingConfig.put(ApiHandlerConfiguration.REFRESH_TOKEN, refreshToken);
updateConfiguration(thingConfig);
try (InputStreamContentProvider inputStreamContentProvider = new InputStreamContentProvider(stream)) {
request.content(inputStreamContentProvider, contentType);
}
+ logger.trace(" -with payload : {} ", payload);
}
if (isLinked(requestCountChannelUID)) {
}
updateState(requestCountChannelUID, new DecimalType(requestsTimestamps.size()));
}
+ logger.trace(" -with headers : {} ",
+ String.join(", ", request.getHeaders().stream().map(HttpField::toString).toList()));
ContentResponse response = request.send();
Code statusCode = HttpStatus.getCode(response.getStatus());
String responseBody = new String(response.getContent(), StandardCharsets.UTF_8);
- logger.trace("executeUri returned : code {} body {}", statusCode, responseBody);
+ logger.trace(" -returned : code {} body {}", statusCode, responseBody);
- if (statusCode != Code.OK) {
- try {
- ApiError error = deserializer.deserialize(ApiError.class, responseBody);
- throw new NetatmoException(error);
- } catch (NetatmoException e) {
- logger.debug("Error deserializing payload from error response", e);
- throw new NetatmoException(statusCode.getMessage());
- }
+ if (statusCode == Code.OK) {
+ return deserializer.deserialize(clazz, responseBody);
+ }
+
+ NetatmoException exception;
+ try {
+ exception = new NetatmoException(deserializer.deserialize(ApiError.class, responseBody));
+ } catch (NetatmoException e) {
+ exception = new NetatmoException("Error deserializing error : %s".formatted(statusCode.getMessage()));
}
- return deserializer.deserialize(clazz, responseBody);
+ throw exception;
} catch (NetatmoException e) {
if (e.getStatusCode() == ServiceError.MAXIMUM_USAGE_REACHED) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
--- /dev/null
+/**
+ * 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.capability;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.netatmo.internal.api.dto.NAObject;
+import org.openhab.binding.netatmo.internal.handler.CommonInterface;
+import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
+import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
+
+/**
+ * {@link AlarmEventCapability} gives the ability to handle Alarm modules events
+ *
+ * @author Gaël L'hopital - Initial contribution
+ *
+ */
+@NonNullByDefault
+public class AlarmEventCapability extends HomeSecurityThingCapability {
+
+ public AlarmEventCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider,
+ List<ChannelHelper> channelHelpers) {
+ super(handler, descriptionProvider, channelHelpers);
+ }
+
+ @Override
+ public List<NAObject> updateReadings() {
+ return securityCapability.map(cap -> cap.getDeviceLastEvent(handler.getId(), moduleType.apiName))
+ .map(event -> List.of((NAObject) event)).orElse(List.of());
+ }
+}
public List<NAObject> updateReadings() {
List<NAObject> result = new ArrayList<>();
securityCapability.ifPresent(cap -> {
- HomeEvent event = cap.getLastDeviceEvent(handler.getId(), moduleType.apiName);
+ HomeEvent event = cap.getDeviceLastEvent(handler.getId(), moduleType.apiName);
if (event != null) {
result.add(event);
result.addAll(event.getSubevents());
return event;
}
- public @Nullable HomeEvent getLastDeviceEvent(String cameraId, String deviceType) {
- HomeEvent event = eventBuffer.get(cameraId);
+ public @Nullable HomeEvent getDeviceLastEvent(String moduleId, String deviceType) {
+ HomeEvent event = eventBuffer.get(moduleId);
if (event == null) {
- Collection<HomeEvent> events = requestDeviceEvents(cameraId, deviceType);
+ Collection<HomeEvent> events = requestDeviceEvents(moduleId, deviceType);
if (!events.isEmpty()) {
event = events.iterator().next();
- eventBuffer.put(cameraId, event);
+ eventBuffer.put(moduleId, event);
}
}
return event;
}
- private Collection<HomeEvent> requestDeviceEvents(String cameraId, String deviceType) {
+ private Collection<HomeEvent> requestDeviceEvents(String moduleId, String deviceType) {
return getApi().map(api -> {
try {
- return api.getDeviceEvents(handler.getId(), cameraId, deviceType);
+ return api.getDeviceEvents(handler.getId(), moduleId, deviceType);
} catch (NetatmoException e) {
- logger.warn("Error retrieving last events of camera '{}' : {}", cameraId, e.getMessage());
+ logger.warn("Error retrieving last events of camera '{}' : {}", moduleId, e.getMessage());
return null;
}
}).orElse(List.of());
+++ /dev/null
-/**
- * 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.capability;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.openhab.binding.netatmo.internal.api.dto.HomeEvent;
-import org.openhab.binding.netatmo.internal.api.dto.NAObject;
-import org.openhab.binding.netatmo.internal.handler.CommonInterface;
-import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
-import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
-
-/**
- * {@link SmokeCapability} gives the ability to handle Smoke detector specifics
- *
- * @author Gaël L'hopital - Initial contribution
- *
- */
-@NonNullByDefault
-public class SmokeCapability extends HomeSecurityThingCapability {
-
- public SmokeCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider,
- List<ChannelHelper> channelHelpers) {
- super(handler, descriptionProvider, channelHelpers);
- }
-
- @Override
- public List<NAObject> updateReadings() {
- List<NAObject> result = new ArrayList<>();
- securityCapability.ifPresent(cap -> {
- HomeEvent event = cap.getLastDeviceEvent(handler.getId(), moduleType.apiName);
- if (event != null) {
- result.add(event);
- }
- });
- return result;
- }
-}
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-alarm.label = Last Event
+channel-group-type.netatmo.last-event-alarm.channel.time.label = Event Timestamp
+channel-group-type.netatmo.last-event-alarm.channel.time.description = Moment when event occurred.
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-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-smoke.label = Last Event
-channel-group-type.netatmo.last-event-smoke.channel.time.label = Event Timestamp
-channel-group-type.netatmo.last-event-smoke.channel.time.description = Moment when event occurred.
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.
channel-type.netatmo.event-subtype.state.option.MOVEMENT_ANIMAL = Animal seen
channel-type.netatmo.event-subtype.state.option.SOUND_TEST_OK = Alarm test successful
channel-type.netatmo.event-subtype.state.option.SOUND_TEST_ERROR = Alarm test failed
-channel-type.netatmo.event-subtype.state.option.DETECTOR_READY = Smoke detector installed
-channel-type.netatmo.event-subtype.state.option.DETECTOR_TAMPERED = Smoke detector tampered
+channel-type.netatmo.event-subtype.state.option.DETECTOR_READY = Detector installed
+channel-type.netatmo.event-subtype.state.option.DETECTOR_TAMPERED = Detector tampered
channel-type.netatmo.event-subtype.state.option.DETECTION_CHAMBER_CLEAN = Detection chamber clean
channel-type.netatmo.event-subtype.state.option.DETECTION_CHAMBER_DIRTY = Detection chamber dusty
channel-type.netatmo.event-subtype.state.option.BATTERY_LOW = Battery low
channel-type.netatmo.event-subtype.state.option.SMOKE_DETECTED = Smoke detected
channel-type.netatmo.event-subtype.state.option.WIFI_STATUS_OK = Wi-Fi status ok
channel-type.netatmo.event-subtype.state.option.WIFI_STATUS_ERROR = Wi-Fi status error
+channel-type.netatmo.event-subtype.state.option.CO_OK = Carbon Monoxide OK
+channel-type.netatmo.event-subtype.state.option.CO_PRE_ALARM = Carbon Monoxide Pre-alarm
+channel-type.netatmo.event-subtype.state.option.CO_ALARM = Carbon Monoxide alarrm
channel-type.netatmo.event-type.label = Event Type
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.MISSED_CALL = Call has not been answered by anyone
channel-type.netatmo.event-type.state.option.HUSH = Smoke detector status
channel-type.netatmo.event-type.state.option.SMOKE = Smoke detection
-channel-type.netatmo.event-type.state.option.TAMPERED = Smoke Detector tamper
+channel-type.netatmo.event-type.state.option.TAMPERED = Detector tamper
channel-type.netatmo.event-type.state.option.WIFI_STATUS = Wifi status
channel-type.netatmo.event-type.state.option.BATTERY_STATUS = Battery status
channel-type.netatmo.event-type.state.option.DETECTION_CHAMBER_STATUS = Detection chamber status
channel-type.netatmo.event-type.state.option.SOUND_TEST = Sound test
channel-type.netatmo.event-type.state.option.NEW_DEVICE = A device has been added
+channel-type.netatmo.event-type.state.option.CO_DETECTED = Carbon Monoxide detection
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
thing-type.netatmo.account.label = Netatmo Account
thing-type.netatmo.account.description = This bridge represents an account, gateway to Netatmo API.
+thing-type.netatmo.co-detector.label = Carbon Monoxide Alarm
+thing-type.netatmo.co-detector.description = The Netatmo Smart Carbon Monoxide Alarm device.
thing-type.netatmo.doorbell.label = Smart Video Doorbell
thing-type.netatmo.doorbell.description = The Netatmo Smart Video Doorbell device.
thing-type.netatmo.tag.label = Smart Door Sensor
<option value="MISSED_CALL">Call has not been answered by anyone</option>
<option value="HUSH">Smoke detector status</option>
<option value="SMOKE">Smoke detection</option>
- <option value="TAMPERED">Smoke Detector tamper</option>
+ <option value="TAMPERED">Detector tamper</option>
<option value="WIFI_STATUS">Wifi status</option>
<option value="BATTERY_STATUS">Battery status</option>
<option value="DETECTION_CHAMBER_STATUS">Detection chamber status</option>
<option value="SOUND_TEST">Sound test</option>
<option value="NEW_DEVICE">A device has been added</option>
+ <option value="CO_DETECTED">Carbon Monoxide detection</option>
</options>
</state>
</channel-type>
<option value="MOVEMENT_ANIMAL">Animal seen</option>
<option value="SOUND_TEST_OK">Alarm test successful</option>
<option value="SOUND_TEST_ERROR">Alarm test failed</option>
- <option value="DETECTOR_READY">Smoke detector installed</option>
- <option value="DETECTOR_TAMPERED">Smoke detector tampered</option>
+ <option value="DETECTOR_READY">Detector installed</option>
+ <option value="DETECTOR_TAMPERED">Detector tampered</option>
<option value="DETECTION_CHAMBER_CLEAN">Detection chamber clean</option>
<option value="DETECTION_CHAMBER_DIRTY">Detection chamber dusty</option>
<option value="BATTERY_LOW">Battery low</option>
<option value="SMOKE_DETECTED">Smoke detected</option>
<option value="WIFI_STATUS_OK">Wi-Fi status ok</option>
<option value="WIFI_STATUS_ERROR">Wi-Fi status error</option>
+ <option value="CO_OK">Carbon Monoxide OK</option>
+ <option value="CO_PRE_ALARM">Carbon Monoxide Pre-alarm</option>
+ <option value="CO_ALARM">Carbon Monoxide alarrm</option>
</options>
</state>
</channel-type>
</channels>
</channel-group-type>
- <channel-group-type id="last-event-smoke">
+ <channel-group-type id="last-event-alarm">
<label>Last Event</label>
<channels>
<channel id="type" typeId="event-type"/>