| securityId | String | No | Id of a home holding security monitoring devices |
At least one of these parameter must be filled - at most two :
+
* id or securityId
* id or energyId
* securityId and energyId
import java.time.ZonedDateTime;
import java.util.Comparator;
import java.util.List;
-import java.util.stream.Collectors;
import javax.ws.rs.core.UriBuilder;
// Remove unneeded events being before oldestKnown
return events.stream().filter(event -> freshestEventTime == null || event.getTime().isAfter(freshestEventTime))
- .sorted(Comparator.comparing(HomeEvent::getTime).reversed()).collect(Collectors.toList());
+ .sorted(Comparator.comparing(HomeEvent::getTime).reversed()).toList();
}
public List<HomeEvent> getPersonEvents(String homeId, String personId) throws NetatmoException {
BATTERY_VERY_LOW(1, EventType.BATTERY_STATUS),
SMOKE_CLEARED(0, EventType.SMOKE),
SMOKE_DETECTED(1, EventType.SMOKE),
+ HUSH_ACTIVATED(0, EventType.HUSH),
+ HUSH_DEACTIVATED(1, EventType.HUSH),
SOUND_TEST_OK(0, EventType.SOUND_TEST),
SOUND_TEST_ERROR(1, EventType.SOUND_TEST),
DETECTOR_READY(0, EventType.TAMPERED),
@NonNullByDefault
public enum EventType {
UNKNOWN(),
+ @SerializedName("webhook_activation") // Ack of a 'webhook set' Api Call
+ WEBHOOK_ACTIVATION(ModuleType.ACCOUNT),
@SerializedName("person") // When the Indoor Camera detects a face
PERSON(ModuleType.PERSON, ModuleType.WELCOME),
@SerializedName("module_end_update") // Module's firmware update is over
MODULE_END_UPDATE(ModuleType.WELCOME),
+ @SerializedName("tag_big_move") // Module's firmware update is over
+ TAG_BIG_MOVE(ModuleType.WELCOME),
+
+ @SerializedName("tag_open") // Module's firmware update is over
+ TAG_OPEN(ModuleType.WELCOME),
+
+ @SerializedName("tag_small_move") // Module's firmware update is over
+ TAG_SMALL_MOVE(ModuleType.WELCOME),
+
@SerializedName("connection") // When the camera connects to Netatmo servers
CONNECTION(ModuleType.WELCOME, ModuleType.PRESENCE),
public class HomesDataResponse extends ApiResponse<ListBodyResponse<HomeData>> {
}
+ public class Security extends HomeData {
+ private NAObjectMap<HomeDataPerson> persons = new NAObjectMap<>();
+
+ public NAObjectMap<HomeDataPerson> getPersons() {
+ return persons;
+ }
+
+ public List<HomeDataPerson> getKnownPersons() {
+ return persons.values().stream().filter(HomeDataPerson::isKnown).toList();
+ }
+ }
+
+ public class Energy extends HomeData {
+ private String temperatureControlMode = "";
+ private SetpointMode thermMode = SetpointMode.UNKNOWN;
+ private int thermSetpointDefaultDuration;
+ private List<ThermProgram> schedules = List.of();
+
+ public int getThermSetpointDefaultDuration() {
+ return thermSetpointDefaultDuration;
+ }
+
+ public SetpointMode getThermMode() {
+ return thermMode;
+ }
+
+ public String getTemperatureControlMode() {
+ return temperatureControlMode;
+ }
+
+ public List<ThermProgram> getThermSchedules() {
+ return schedules;
+ }
+
+ public @Nullable ThermProgram getActiveProgram() {
+ return schedules.stream().filter(ThermProgram::isSelected).findFirst().orElse(null);
+ }
+ }
+
private double altitude;
private double[] coordinates = {};
private @Nullable String country;
private @Nullable String timezone;
- private @Nullable String temperatureControlMode;
- private SetpointMode thermMode = SetpointMode.UNKNOWN;
- private int thermSetpointDefaultDuration;
- private List<ThermProgram> schedules = List.of();
-
- private NAObjectMap<HomeDataPerson> persons = new NAObjectMap<>();
private NAObjectMap<HomeDataRoom> rooms = new NAObjectMap<>();
private NAObjectMap<HomeDataModule> modules = new NAObjectMap<>();
return Optional.ofNullable(timezone);
}
- public int getThermSetpointDefaultDuration() {
- return thermSetpointDefaultDuration;
- }
-
- public SetpointMode getThermMode() {
- return thermMode;
- }
-
- public NAObjectMap<HomeDataPerson> getPersons() {
- return persons;
- }
-
- public List<HomeDataPerson> getKnownPersons() {
- return persons.values().stream().filter(HomeDataPerson::isKnown).collect(Collectors.toList());
- }
-
- public Optional<String> getTemperatureControlMode() {
- return Optional.ofNullable(temperatureControlMode);
- }
-
public NAObjectMap<HomeDataRoom> getRooms() {
return rooms;
}
public Set<FeatureArea> getFeatures() {
return getModules().values().stream().map(m -> m.getType().feature).collect(Collectors.toSet());
}
-
- public List<ThermProgram> getThermSchedules() {
- return schedules;
- }
-
- public @Nullable ThermProgram getActiveProgram() {
- return schedules.stream().filter(ThermProgram::isSelected).findFirst().orElse(null);
- }
}
return ModuleType.PERSON;
}
- public boolean isOutOfSight() {
- return outOfSight;
+ public boolean atHome() {
+ return !outOfSight;
}
}
public class HomeStatus extends NAThing {
private @Nullable NAObjectMap<HomeStatusModule> modules;
- private @Nullable NAObjectMap<HomeStatusPerson> persons;
- private @Nullable NAObjectMap<Room> rooms;
public NAObjectMap<HomeStatusModule> getModules() {
NAObjectMap<HomeStatusModule> localModules = modules;
return localModules != null ? localModules : new NAObjectMap<>();
}
+ }
- public NAObjectMap<HomeStatusPerson> getPersons() {
- NAObjectMap<HomeStatusPerson> localPersons = persons;
- return localPersons != null ? localPersons : new NAObjectMap<>();
- }
+ public class Energy extends HomeStatus {
+ private NAObjectMap<Room> rooms = new NAObjectMap<>();
public NAObjectMap<Room> getRooms() {
- NAObjectMap<Room> localRooms = rooms;
- return localRooms != null ? localRooms : new NAObjectMap<>();
+ return rooms;
+ }
+ }
+
+ public class Security extends HomeStatus {
+ private NAObjectMap<HomeStatusPerson> persons = new NAObjectMap<>();
+
+ public NAObjectMap<HomeStatusPerson> getPersons() {
+ return persons;
}
}
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.netatmo.internal.api.NetatmoException;
import org.openhab.binding.netatmo.internal.api.data.ModuleType;
+import org.openhab.binding.netatmo.internal.api.dto.HomeData;
+import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus;
+import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
.registerTypeAdapter(NAObjectMap.class, new NAObjectMapDeserializer())
.registerTypeAdapter(NAPushType.class, new NAPushTypeDeserializer())
.registerTypeAdapter(ModuleType.class, new ModuleTypeDeserializer())
- .registerTypeAdapter(ZonedDateTime.class,
- (JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> {
- long netatmoTS = json.getAsJsonPrimitive().getAsLong();
- Instant i = Instant.ofEpochSecond(netatmoTS);
- return ZonedDateTime.ofInstant(i, timeZoneProvider.getTimeZone());
- })
+ .registerTypeAdapter(HomeStatus.class,
+ (JsonDeserializer<HomeStatus>) (json, type, context) -> context.deserialize(json,
+ json.getAsJsonObject().has("persons") ? NAHomeStatus.Security.class
+ : NAHomeStatus.Energy.class))
+ .registerTypeAdapter(HomeData.class,
+ (JsonDeserializer<HomeData>) (json, type, context) -> context.deserialize(json,
+ json.getAsJsonObject().has("therm_mode") ? HomeData.Energy.class
+ : HomeData.Security.class))
+ .registerTypeAdapter(ZonedDateTime.class, (JsonDeserializer<ZonedDateTime>) (json, type, context) -> {
+ long netatmoTS = json.getAsJsonPrimitive().getAsLong();
+ Instant i = Instant.ofEpochSecond(netatmoTS);
+ return ZonedDateTime.ofInstant(i, timeZoneProvider.getTimeZone());
+ })
.registerTypeAdapter(OnOffType.class,
- (JsonDeserializer<OnOffType>) (json, type, jsonDeserializationContext) -> OnOffType
+ (JsonDeserializer<OnOffType>) (json, type, context) -> OnOffType
.from(json.getAsJsonPrimitive().getAsString()))
- .registerTypeAdapter(OpenClosedType.class,
- (JsonDeserializer<OpenClosedType>) (json, type, jsonDeserializationContext) -> {
- String value = json.getAsJsonPrimitive().getAsString().toUpperCase();
- return "TRUE".equals(value) || "1".equals(value) ? OpenClosedType.CLOSED
- : OpenClosedType.OPEN;
- })
- .create();
+ .registerTypeAdapter(OpenClosedType.class, (JsonDeserializer<OpenClosedType>) (json, type, context) -> {
+ String value = json.getAsJsonPrimitive().getAsString().toUpperCase();
+ return "TRUE".equals(value) || "1".equals(value) ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
+ }).create();
}
public <T> T deserialize(Class<T> clazz, String json) throws NetatmoException {
*/
@NonNullByDefault
class NAPushTypeDeserializer implements JsonDeserializer<NAPushType> {
+
private final Logger logger = LoggerFactory.getLogger(NAPushTypeDeserializer.class);
@Override
final String[] elements = string.split("-");
ModuleType moduleType = ModuleType.UNKNOWN;
EventType eventType = EventType.UNKNOWN;
+
if (elements.length == 2) {
moduleType = fromNetatmoObject(elements[0]);
eventType = fromEvent(elements[1]);
- } else {
- logger.warn("Unexpected syntax received for push_type field : {}", string);
+ } else if (elements.length == 1) {
+ moduleType = ModuleType.ACCOUNT;
+ eventType = fromEvent(string);
}
+
if (moduleType.equals(ModuleType.UNKNOWN) || eventType.equals(EventType.UNKNOWN)) {
logger.warn("Unknown module or event type : {}, deserialized to '{}-{}'", string, moduleType, eventType);
}
+
return new NAPushType(moduleType, eventType);
}
import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.FeatureArea;
import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.Scope;
import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.ServiceError;
+import org.openhab.binding.netatmo.internal.api.dto.HomeData;
import org.openhab.binding.netatmo.internal.api.dto.HomeDataModule;
import org.openhab.binding.netatmo.internal.api.dto.NAMain;
import org.openhab.binding.netatmo.internal.api.dto.NAModule;
|| h.getFeatures().contains(FeatureArea.WEATHER) && h.getFeatures().size() == 1))
.forEach(home -> {
action.apply(home, accountUID).ifPresent(homeUID -> {
- home.getKnownPersons().forEach(person -> action.apply(person, homeUID));
-
+ if (home instanceof HomeData.Security securityData) {
+ securityData.getKnownPersons().forEach(person -> action.apply(person, homeUID));
+ }
Map<String, ThingUID> bridgesUids = new HashMap<>();
home.getRooms().values().stream().forEach(room -> {
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
if (thing instanceof Bridge) {
return ((Bridge) thing).getThings().stream().filter(Thing::isEnabled)
.filter(th -> th.getStatusInfo().getStatusDetail() != ThingStatusDetail.BRIDGE_OFFLINE)
- .map(Thing::getHandler).filter(Objects::nonNull).map(CommonInterface.class::cast)
- .collect(Collectors.toList());
+ .map(Thing::getHandler).filter(Objects::nonNull).map(CommonInterface.class::cast).toList();
}
return List.of();
}
*/
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 org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.netatmo.internal.api.dto.NAObject;
+import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
import org.openhab.binding.netatmo.internal.handler.CommonInterface;
import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
+import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.types.UnDefType;
/**
* {@link AlarmEventCapability} gives the ability to handle Alarm modules events
super(handler, descriptionProvider, channelHelpers);
}
+ @Override
+ protected void updateWebhookEvent(WebhookEvent event) {
+ super.updateWebhookEvent(event);
+
+ final ThingUID thingUid = handler.getThing().getUID();
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_TYPE),
+ toStringType(event.getEventType()));
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_TIME),
+ toDateTimeType(event.getTime()));
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_SUBTYPE),
+ event.getSubTypeDescription().map(d -> toStringType(d)).orElse(UnDefType.NULL));
+ final String message = event.getName();
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_MESSAGE),
+ message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
+ }
+
@Override
public List<NAObject> updateReadings() {
return getSecurityCapability().map(cap -> cap.getDeviceLastEvent(handler.getId(), moduleType.apiName))
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.Command;
+import org.openhab.core.types.State;
import org.openhab.core.types.StateOption;
import org.openhab.core.types.UnDefType;
protected @Nullable String localUrl;
protected @Nullable String vpnUrl;
+ private boolean hasSubEventGroup;
+ private boolean hasLastEventGroup;
public CameraCapability(CommonInterface handler, NetatmoDescriptionProvider descriptionProvider,
List<ChannelHelper> channelHelpers) {
"CameraCapability must find a CameraChannelHelper, please file a bug report."));
}
+ @Override
+ public void initialize() {
+ Thing thing = handler.getThing();
+ hasSubEventGroup = !thing.getChannelsOfGroup(GROUP_SUB_EVENT).isEmpty();
+ hasLastEventGroup = !thing.getChannelsOfGroup(GROUP_LAST_EVENT).isEmpty();
+ }
+
@Override
public void updateHomeStatusModule(HomeStatusModule newData) {
super.updateHomeStatusModule(newData);
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()));
+ if (hasSubEventGroup) {
+ updateSubGroup(event, thing.getUID(), GROUP_SUB_EVENT);
+ }
- final String message = event.getName();
- handler.updateState(new ChannelUID(thingUid, GROUP_SUB_EVENT, CHANNEL_EVENT_MESSAGE),
- message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
+ if (hasLastEventGroup) {
+ updateSubGroup(event, thing.getUID(), GROUP_LAST_EVENT);
+ }
// 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.
handler.triggerChannel(CHANNEL_HOME_EVENT, eventType);
}
+ private void updateSubGroup(WebhookEvent event, ThingUID thingUid, String group) {
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_TYPE), toStringType(event.getEventType()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_TIME), toDateTimeType(event.getTime()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_SNAPSHOT), toRawType(event.getSnapshotUrl()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_SNAPSHOT_URL),
+ toStringType(event.getSnapshotUrl()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_VIGNETTE), toRawType(event.getVignetteUrl()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_VIGNETTE_URL),
+ toStringType(event.getVignetteUrl()));
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_SUBTYPE),
+ event.getSubTypeDescription().map(d -> toStringType(d)).orElse(UnDefType.NULL));
+ final String message = event.getName();
+ handler.updateState(new ChannelUID(thingUid, group, CHANNEL_EVENT_MESSAGE),
+ message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
+ State personId = event.getPersons().isEmpty() ? UnDefType.NULL
+ : toStringType(event.getPersons().values().iterator().next().getId());
+ handler.updateState(personChannelUID, personId);
+ }
+
@Override
public void handleCommand(String channelName, Command command) {
if (command instanceof OnOffType && CHANNEL_MONITORING.equals(channelName)) {
super.beforeNewData();
getSecurityCapability().ifPresent(cap -> {
NAObjectMap<HomeDataPerson> persons = cap.getPersons();
- descriptionProvider.setStateOptions(personChannelUID, persons.values().stream()
- .map(p -> new StateOption(p.getId(), p.getName())).collect(Collectors.toList()));
+ descriptionProvider.setStateOptions(personChannelUID,
+ persons.values().stream().map(p -> new StateOption(p.getId(), p.getName())).toList());
});
}
public final @Nullable String setNewData(NAObject newData) {
beforeNewData();
- if (newData instanceof HomeData) {
- updateHomeData((HomeData) newData);
+ if (newData instanceof HomeData homeData) {
+ updateHomeData(homeData);
}
- if (newData instanceof HomeStatus) {
- updateHomeStatus((HomeStatus) newData);
+ if (newData instanceof HomeStatus homeStatus) {
+ updateHomeStatus(homeStatus);
}
- if (newData instanceof HomeStatusModule) {
- updateHomeStatusModule((HomeStatusModule) newData);
+ if (newData instanceof HomeStatusModule homeStatusModule) {
+ updateHomeStatusModule(homeStatusModule);
}
- if (newData instanceof Event) {
- updateEvent((Event) newData);
- }
- if (newData instanceof WebhookEvent) {
- updateWebhookEvent((WebhookEvent) newData);
- }
- if (newData instanceof HomeEvent) {
- updateHomeEvent((HomeEvent) newData);
+
+ if (newData instanceof HomeEvent homeEvent) {
+ updateHomeEvent(homeEvent);
+ } else if (newData instanceof WebhookEvent webhookEvent && webhookEvent.getEventType().validFor(moduleType)) {
+ updateWebhookEvent(webhookEvent);
+ } else if (newData instanceof Event event) {
+ updateEvent(event);
}
- if (newData instanceof NAThing) {
- updateNAThing((NAThing) newData);
+
+ if (newData instanceof NAThing naThing) {
+ updateNAThing(naThing);
}
- if (newData instanceof NAMain) {
- updateNAMain((NAMain) newData);
+ if (newData instanceof NAMain naMain) {
+ updateNAMain(naMain);
}
- if (newData instanceof Device) {
- updateNADevice((Device) newData);
+ if (newData instanceof Device device) {
+ updateNADevice(device);
}
afterNewData(newData);
return statusReason;
import static org.openhab.binding.netatmo.internal.NetatmoBindingConstants.*;
import java.time.ZonedDateTime;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.netatmo.internal.api.EnergyApi;
import org.openhab.binding.netatmo.internal.api.dto.HomeDataModule;
import org.openhab.binding.netatmo.internal.api.dto.HomeDataRoom;
import org.openhab.binding.netatmo.internal.api.dto.HomeStatusModule;
+import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus;
import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
import org.openhab.binding.netatmo.internal.api.dto.Room;
import org.openhab.binding.netatmo.internal.config.HomeConfiguration;
@Override
protected void updateHomeData(HomeData homeData) {
- NAObjectMap<HomeDataRoom> rooms = homeData.getRooms();
- NAObjectMap<HomeDataModule> modules = homeData.getModules();
- handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
- String childId = childHandler.getId();
- rooms.getOpt(childId)
- .ifPresentOrElse(roomData -> childHandler.setNewData(roomData.ignoringForThingUpdate()), () -> {
- modules.getOpt(childId)
- .ifPresent(childData -> childHandler.setNewData(childData.ignoringForThingUpdate()));
- modules.values().stream().filter(module -> childId.equals(module.getBridge()))
- .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
- });
- });
- descriptionProvider.setStateOptions(new ChannelUID(thing.getUID(), GROUP_ENERGY, CHANNEL_PLANNING),
- homeData.getThermSchedules().stream().map(p -> new StateOption(p.getId(), p.getName()))
- .collect(Collectors.toList()));
- setPointDefaultDuration = homeData.getThermSetpointDefaultDuration();
+ if (homeData instanceof HomeData.Energy energyData) {
+ NAObjectMap<HomeDataRoom> rooms = energyData.getRooms();
+ NAObjectMap<HomeDataModule> modules = energyData.getModules();
+ handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
+ String childId = childHandler.getId();
+ rooms.getOpt(childId)
+ .ifPresentOrElse(roomData -> childHandler.setNewData(roomData.ignoringForThingUpdate()), () -> {
+ modules.getOpt(childId).ifPresent(
+ childData -> childHandler.setNewData(childData.ignoringForThingUpdate()));
+ modules.values().stream().filter(module -> childId.equals(module.getBridge()))
+ .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ });
+ });
+ descriptionProvider.setStateOptions(new ChannelUID(thing.getUID(), GROUP_ENERGY, CHANNEL_PLANNING),
+ energyData.getThermSchedules().stream().map(p -> new StateOption(p.getId(), p.getName())).toList());
+ setPointDefaultDuration = energyData.getThermSetpointDefaultDuration();
+ }
}
@Override
protected void updateHomeStatus(HomeStatus homeStatus) {
- NAObjectMap<Room> rooms = homeStatus.getRooms();
- NAObjectMap<HomeStatusModule> modules = homeStatus.getModules();
- handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
- String childId = childHandler.getId();
- rooms.getOpt(childId).ifPresentOrElse(roomData -> childHandler.setNewData(roomData), () -> {
- modules.getOpt(childId).ifPresent(moduleData -> {
- childHandler.setNewData(moduleData);
- modules.values().stream().filter(module -> childId.equals(module.getBridge()))
- .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ if (homeStatus instanceof NAHomeStatus.Energy energyStatus) {
+ NAObjectMap<Room> rooms = energyStatus.getRooms();
+ NAObjectMap<HomeStatusModule> modules = energyStatus.getModules();
+ handler.getActiveChildren(FeatureArea.ENERGY).forEach(childHandler -> {
+ String childId = childHandler.getId();
+ rooms.getOpt(childId).ifPresentOrElse(roomData -> childHandler.setNewData(roomData), () -> {
+ modules.getOpt(childId).ifPresent(moduleData -> {
+ childHandler.setNewData(moduleData);
+ modules.values().stream().filter(module -> childId.equals(module.getBridge()))
+ .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ });
});
});
- });
+ }
}
public void setThermPoint(String roomId, SetpointMode mode, long endtime, double temp) {
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.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.netatmo.internal.api.dto.HomeDataModule;
import org.openhab.binding.netatmo.internal.api.dto.HomeEvent;
import org.openhab.binding.netatmo.internal.api.dto.NAObject;
+import org.openhab.binding.netatmo.internal.api.dto.WebhookEvent;
import org.openhab.binding.netatmo.internal.handler.CommonInterface;
import org.openhab.binding.netatmo.internal.handler.channelhelper.ChannelHelper;
import org.openhab.binding.netatmo.internal.providers.NetatmoDescriptionProvider;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.ChannelUID;
+import org.openhab.core.thing.ThingUID;
import org.openhab.core.types.Command;
import org.openhab.core.types.StateOption;
+import org.openhab.core.types.UnDefType;
/**
* {@link PersonCapability} gives the ability to handle Person specifics
Stream<HomeDataModule> cameras = cap.getModules().values().stream()
.filter(module -> module.getType() == ModuleType.WELCOME);
descriptionProvider.setStateOptions(cameraChannelUID,
- cameras.map(p -> new StateOption(p.getId(), p.getName())).collect(Collectors.toList()));
+ cameras.map(p -> new StateOption(p.getId(), p.getName())).toList());
});
}
}
}
+ @Override
+ protected void updateWebhookEvent(WebhookEvent event) {
+ super.updateWebhookEvent(event);
+
+ ThingUID thingUid = thing.getUID();
+
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_SUBTYPE),
+ event.getSubTypeDescription().map(d -> toStringType(d)).orElse(UnDefType.NULL));
+
+ final String message = event.getName();
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_MESSAGE),
+ message == null || message.isBlank() ? UnDefType.NULL : toStringType(message));
+
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_TIME),
+ toDateTimeType(event.getTime()));
+
+ handler.updateState(new ChannelUID(thingUid, GROUP_LAST_EVENT, CHANNEL_EVENT_SNAPSHOT),
+ toRawType(event.getSnapshotUrl()));
+
+ handler.updateState(cameraChannelUID, toStringType(event.getCameraId()));
+ }
+
@Override
public void updateEvent(Event event) {
super.updateEvent(event);
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.HomeStatusPerson;
+import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus;
import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
import org.openhab.binding.netatmo.internal.api.dto.NAObject;
import org.openhab.binding.netatmo.internal.config.HomeConfiguration;
@Override
protected void updateHomeData(HomeData homeData) {
- persons = homeData.getPersons();
- modules = homeData.getModules();
- handler.getActiveChildren(FeatureArea.SECURITY).forEach(childHandler -> {
- String childId = childHandler.getId();
- persons.getOpt(childId)
- .ifPresentOrElse(personData -> childHandler.setNewData(personData.ignoringForThingUpdate()), () -> {
- modules.getOpt(childId)
- .ifPresent(childData -> childHandler.setNewData(childData.ignoringForThingUpdate()));
- modules.values().stream().filter(module -> childId.equals(module.getBridge()))
- .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
- });
- });
+ if (homeData instanceof HomeData.Security securityData) {
+ persons = securityData.getPersons();
+ modules = homeData.getModules();
+ handler.getActiveChildren(FeatureArea.SECURITY).forEach(childHandler -> {
+ String childId = childHandler.getId();
+ persons.getOpt(childId).ifPresentOrElse(
+ personData -> childHandler.setNewData(personData.ignoringForThingUpdate()), () -> {
+ modules.getOpt(childId).ifPresent(
+ childData -> childHandler.setNewData(childData.ignoringForThingUpdate()));
+ modules.values().stream().filter(module -> childId.equals(module.getBridge()))
+ .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ });
+ });
+ }
}
@Override
protected void updateHomeStatus(HomeStatus homeStatus) {
- NAObjectMap<HomeStatusPerson> persons = homeStatus.getPersons();
- NAObjectMap<HomeStatusModule> modules = homeStatus.getModules();
- handler.getActiveChildren(FeatureArea.SECURITY).forEach(childHandler -> {
- String childId = childHandler.getId();
- persons.getOpt(childId).ifPresentOrElse(personData -> childHandler.setNewData(personData), () -> {
- modules.getOpt(childId).ifPresent(childData -> {
- childHandler.setNewData(childData);
- modules.values().stream().filter(module -> childId.equals(module.getBridge()))
- .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ if (homeStatus instanceof NAHomeStatus.Security securityStatus) {
+ NAObjectMap<HomeStatusPerson> persons = securityStatus.getPersons();
+ NAObjectMap<HomeStatusModule> modules = securityStatus.getModules();
+ handler.getActiveChildren(FeatureArea.SECURITY).forEach(childHandler -> {
+ String childId = childHandler.getId();
+ persons.getOpt(childId).ifPresentOrElse(personData -> childHandler.setNewData(personData), () -> {
+ modules.getOpt(childId).ifPresent(childData -> {
+ childHandler.setNewData(childData);
+ modules.values().stream().filter(module -> childId.equals(module.getBridge()))
+ .forEach(bridgedModule -> childHandler.setNewData(bridgedModule));
+ });
});
});
- });
+ }
}
@Override
@Override
protected @Nullable State internalGetProperty(String channelId, NAThing data, Configuration config) {
- if (data instanceof HomeData) {
- HomeData homeData = (HomeData) data;
- SetpointMode thermMode = homeData.getThermMode();
- ThermProgram currentProgram = homeData.getActiveProgram();
+ if (data instanceof HomeData.Energy energyData) {
+ SetpointMode thermMode = energyData.getThermMode();
+ ThermProgram currentProgram = energyData.getActiveProgram();
switch (channelId) {
case CHANNEL_SETPOINT_DURATION:
- return toQuantityType(homeData.getThermSetpointDefaultDuration(), Units.MINUTE);
+ return toQuantityType(energyData.getThermSetpointDefaultDuration(), Units.MINUTE);
case CHANNEL_PLANNING:
return (currentProgram != null ? toStringType(currentProgram.getName()) : null);
case CHANNEL_SETPOINT_END_TIME:
HomeStatusPerson person = (HomeStatusPerson) naThing;
switch (channelId) {
case CHANNEL_PERSON_AT_HOME:
- return OnOffType.from(!person.isOutOfSight());
+ return OnOffType.from(person.atHome());
case CHANNEL_LAST_SEEN:
return toDateTimeType(person.getLastSeen());
}
import java.util.List;
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.dto.HomeData;
+import org.openhab.binding.netatmo.internal.api.dto.HomeDataPerson;
import org.openhab.binding.netatmo.internal.api.dto.HomeStatusPerson;
-import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
+import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus;
import org.openhab.binding.netatmo.internal.api.dto.NAObject;
-import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
@Override
public void setNewData(@Nullable NAObject data) {
super.setNewData(data);
- if (data instanceof HomeData) {
- HomeData homeData = (HomeData) data;
- knownIds = homeData.getPersons().values().stream().filter(person -> person.isKnown()).map(p -> p.getId())
- .collect(Collectors.toList());
- }
- if (data instanceof HomeStatus) {
- HomeStatus status = (HomeStatus) data;
- NAObjectMap<HomeStatusPerson> allPersons = status.getPersons();
- List<HomeStatusPerson> present = allPersons.values().stream().filter(p -> !p.isOutOfSight())
- .collect(Collectors.toList());
+ if (data instanceof HomeData.Security securityData) {
+ knownIds = securityData.getKnownPersons().stream().map(HomeDataPerson::getId).toList();
+ } else if (data instanceof NAHomeStatus.Security securityStatus) {
+ List<HomeStatusPerson> present = securityStatus.getPersons().values().stream()
+ .filter(HomeStatusPerson::atHome).toList();
persons = present.size();
unknowns = present.stream().filter(person -> !knownIds.contains(person.getId())).count();
import java.util.List;
import java.util.Locale;
import java.util.Optional;
-import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@Override
public Collection<ThingType> getThingTypes(@Nullable Locale locale) {
return ModuleType.AS_SET.stream().filter(mt -> mt != ModuleType.UNKNOWN)
- .map(mt -> Optional.ofNullable(getThingType(mt.thingTypeUID, locale))).map(Optional::get)
- .collect(Collectors.toList());
+ .map(mt -> Optional.ofNullable(getThingType(mt.thingTypeUID, locale))).map(Optional::get).toList();
}
@Override
private List<ChannelGroupDefinition> getGroupDefinitions(ModuleType thingType) {
return thingType.getGroupTypes().stream().map(groupType -> new ChannelGroupDefinition(toGroupName(groupType),
- new ChannelGroupTypeUID(BINDING_ID, groupType))).collect(Collectors.toList());
+ new ChannelGroupTypeUID(BINDING_ID, groupType))).toList();
}
public static String toGroupName(String groupeTypeName) {
channel-group-type.netatmo.rain.channel.sum-1.description = Quantity of water over last hour.
channel-group-type.netatmo.rain.channel.sum-24.label = Rain 24h
channel-group-type.netatmo.rain.channel.sum-24.description = Quantity of water during the current day.
-channel-group-type.netatmo.security.label = Home Security
channel-group-type.netatmo.security-event.label = Home Security Event
+channel-group-type.netatmo.security.label = Home Security
channel-group-type.netatmo.setpoint.label = Setpoint
channel-group-type.netatmo.setpoint.channel.end.label = Setpoint End
channel-group-type.netatmo.setpoint.channel.end.description = End time of the currently applied setpoint.
channel-group-type.netatmo.siren.label = Siren Status
channel-group-type.netatmo.status-doorbell.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.channel.time.label = Sub-Event Timestamp
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.description = Vignette of the Snapshot.
channel-group-type.netatmo.sub-event-doorbell.channel.vignette-url.label = Vignette URL
channel-group-type.netatmo.sub-event-doorbell.channel.vignette-url.description = URL of the vignette.
+channel-group-type.netatmo.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.tag.label = Door Tag
channel-group-type.netatmo.temperature-extended.label = Temperature
channel-group-type.netatmo.temperature-extended.channel.max-time.label = Today Max Timestamp
channel-type.netatmo.event-subtype.state.option.BATTERY_VERY_LOW = Battery very low
channel-type.netatmo.event-subtype.state.option.SMOKE_CLEARED = Smoke cleared
channel-type.netatmo.event-subtype.state.option.SMOKE_DETECTED = Smoke detected
+channel-type.netatmo.event-subtype.state.option.HUSH_ACTIVATED = Smoke detection activated
+channel-type.netatmo.event-subtype.state.option.HUSH_DEACTIVATED = Smoke detection deactivated
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
<option value="BATTERY_VERY_LOW">Battery very low</option>
<option value="SMOKE_CLEARED">Smoke cleared</option>
<option value="SMOKE_DETECTED">Smoke detected</option>
+ <option value="HUSH_ACTIVATED">Smoke detection activated</option>
+ <option value="HUSH_DEACTIVATED">Smoke detection deactivated</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>
import java.util.Collections;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.binding.netatmo.internal.api.data.EventType;
/**
* @author Sven Strohschein - Initial contribution
*/
+@NonNullByDefault
public class EventCameraChannelHelperTest {
- private EventCameraChannelHelper helper;
+ private @NonNullByDefault({}) EventCameraChannelHelper helper;
@BeforeEach
public void before() {