]> git.basschouten.com Git - openhab-addons.git/blob
1bc19c8e974758e6edafab907b24646286c15c84
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.netatmo.internal.handler.capability;
14
15 import java.time.ZonedDateTime;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.netatmo.internal.api.NetatmoException;
25 import org.openhab.binding.netatmo.internal.api.SecurityApi;
26 import org.openhab.binding.netatmo.internal.api.data.NetatmoConstants.FloodLightMode;
27 import org.openhab.binding.netatmo.internal.api.dto.HomeData;
28 import org.openhab.binding.netatmo.internal.api.dto.HomeDataModule;
29 import org.openhab.binding.netatmo.internal.api.dto.HomeDataPerson;
30 import org.openhab.binding.netatmo.internal.api.dto.HomeEvent;
31 import org.openhab.binding.netatmo.internal.api.dto.HomeStatusModule;
32 import org.openhab.binding.netatmo.internal.api.dto.HomeStatusPerson;
33 import org.openhab.binding.netatmo.internal.api.dto.NAHomeStatus.HomeStatus;
34 import org.openhab.binding.netatmo.internal.api.dto.NAObject;
35 import org.openhab.binding.netatmo.internal.deserialization.NAObjectMap;
36 import org.openhab.binding.netatmo.internal.handler.CommonInterface;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * The {@link SecurityCapability} is the base class for handler able to handle security features
42  *
43  * @author GaĆ«l L'hopital - Initial contribution
44  *
45  */
46 @NonNullByDefault
47 class SecurityCapability extends RestCapability<SecurityApi> {
48     private final Logger logger = LoggerFactory.getLogger(SecurityCapability.class);
49
50     private final Map<String, HomeEvent> eventBuffer = new HashMap<>();
51     private @Nullable ZonedDateTime freshestEventTime;
52
53     SecurityCapability(CommonInterface handler) {
54         super(handler, SecurityApi.class);
55     }
56
57     @Override
58     public void initialize() {
59         super.initialize();
60         freshestEventTime = null;
61     }
62
63     @Override
64     protected void updateHomeData(HomeData homeData) {
65         NAObjectMap<HomeDataPerson> persons = homeData.getPersons();
66         NAObjectMap<HomeDataModule> modules = homeData.getModules();
67         handler.getActiveChildren().forEach(childHandler -> {
68             String childId = childHandler.getId();
69             persons.getOpt(childId).ifPresentOrElse(personData -> {
70                 personData.setIgnoredForThingUpdate(true);
71                 childHandler.setNewData(personData);
72             }, () -> {
73                 modules.getOpt(childId).ifPresent(childData -> {
74                     childData.setIgnoredForThingUpdate(true);
75                     childHandler.setNewData(childData);
76                 });
77                 modules.values().stream().filter(module -> childId.equals(module.getBridge()))
78                         .forEach(bridgedModule -> {
79                             childHandler.setNewData(bridgedModule);
80                         });
81             });
82         });
83     }
84
85     @Override
86     protected void updateHomeStatus(HomeStatus homeStatus) {
87         NAObjectMap<HomeStatusPerson> persons = homeStatus.getPersons();
88         NAObjectMap<HomeStatusModule> modules = homeStatus.getModules();
89         handler.getActiveChildren().forEach(childHandler -> {
90             String childId = childHandler.getId();
91             persons.getOpt(childId).ifPresentOrElse(personData -> childHandler.setNewData(personData), () -> {
92                 modules.getOpt(childId).ifPresentOrElse(childData -> {
93                     childHandler.setNewData(childData);
94                     modules.values().stream().filter(module -> childId.equals(module.getBridge()))
95                             .forEach(bridgedModule -> {
96                                 childHandler.setNewData(bridgedModule);
97                             });
98
99                 }, () -> {
100                     // This module is not present in the homestatus data, so it is considered as unreachable
101                     HomeStatusModule module = new HomeStatusModule();
102                     module.setReachable(false);
103                     childHandler.setNewData(module);
104                 });
105             });
106         });
107     }
108
109     @Override
110     protected void updateHomeEvent(HomeEvent homeEvent) {
111         String personId = homeEvent.getPersonId();
112         if (personId != null) {
113             handler.getActiveChildren().stream().filter(handler -> personId.equals(handler.getId())).findFirst()
114                     .ifPresent(handler -> {
115                         homeEvent.setIgnoredForThingUpdate(true);
116                         handler.setNewData(homeEvent);
117                     });
118         }
119         String cameraId = homeEvent.getCameraId();
120         handler.getActiveChildren().stream().filter(handler -> cameraId.equals(handler.getId())).findFirst()
121                 .ifPresent(handler -> {
122                     homeEvent.setIgnoredForThingUpdate(true);
123                     handler.setNewData(homeEvent);
124                 });
125     }
126
127     @Override
128     protected List<NAObject> updateReadings(SecurityApi api) {
129         List<NAObject> result = new ArrayList<>();
130         try {
131             for (HomeEvent event : api.getHomeEvents(handler.getId(), freshestEventTime)) {
132                 HomeEvent previousEvent = eventBuffer.get(event.getCameraId());
133                 if (previousEvent == null || previousEvent.getTime().isBefore(event.getTime())) {
134                     eventBuffer.put(event.getCameraId(), event);
135                 }
136                 String personId = event.getPersonId();
137                 if (personId != null) {
138                     previousEvent = eventBuffer.get(personId);
139                     if (previousEvent == null || previousEvent.getTime().isBefore(event.getTime())) {
140                         eventBuffer.put(personId, event);
141                     }
142                 }
143                 if (freshestEventTime == null || event.getTime().isAfter(freshestEventTime)) {
144                     freshestEventTime = event.getTime();
145                 }
146             }
147         } catch (NetatmoException e) {
148             logger.warn("Error retrieving last events for home '{}' : {}", handler.getId(), e.getMessage());
149         }
150         return result;
151     }
152
153     public @Nullable HomeEvent getLastPersonEvent(String personId) {
154         HomeEvent event = eventBuffer.get(personId);
155         if (event == null) {
156             Collection<HomeEvent> events = requestPersonEvents(personId);
157             if (!events.isEmpty()) {
158                 event = events.iterator().next();
159                 eventBuffer.put(personId, event);
160             }
161         }
162         return event;
163     }
164
165     public @Nullable HomeEvent getDeviceLastEvent(String moduleId, String deviceType) {
166         HomeEvent event = eventBuffer.get(moduleId);
167         if (event == null) {
168             Collection<HomeEvent> events = requestDeviceEvents(moduleId, deviceType);
169             if (!events.isEmpty()) {
170                 event = events.iterator().next();
171                 eventBuffer.put(moduleId, event);
172             }
173         }
174         return event;
175     }
176
177     private Collection<HomeEvent> requestDeviceEvents(String moduleId, String deviceType) {
178         return getApi().map(api -> {
179             try {
180                 return api.getDeviceEvents(handler.getId(), moduleId, deviceType);
181             } catch (NetatmoException e) {
182                 logger.warn("Error retrieving last events of camera '{}' : {}", moduleId, e.getMessage());
183                 return null;
184             }
185         }).orElse(List.of());
186     }
187
188     private Collection<HomeEvent> requestPersonEvents(String personId) {
189         return getApi().map(api -> {
190             try {
191                 return api.getPersonEvents(handler.getId(), personId);
192             } catch (NetatmoException e) {
193                 logger.warn("Error retrieving last events of person '{}' : {}", personId, e.getMessage());
194                 return null;
195             }
196         }).orElse(List.of());
197     }
198
199     public void setPersonAway(String personId, boolean away) {
200         getApi().ifPresent(api -> {
201             try {
202                 api.setPersonAwayStatus(handler.getId(), personId, away);
203                 handler.expireData();
204             } catch (NetatmoException e) {
205                 logger.warn("Error setting person away/at home '{}' : {}", personId, e.getMessage());
206             }
207         });
208     }
209
210     public @Nullable String ping(String vpnUrl) {
211         return getApi().map(api -> {
212             return api.ping(vpnUrl);
213         }).orElse(null);
214     }
215
216     public void changeStatus(@Nullable String localURL, boolean status) {
217         if (localURL == null) {
218             logger.info("Monitoring changes can only be done on local camera.");
219             return;
220         }
221         getApi().ifPresent(api -> {
222             try {
223                 api.changeStatus(localURL, status);
224                 handler.expireData();
225             } catch (NetatmoException e) {
226                 logger.warn("Error changing camera monitoring status '{}' : {}", status, e.getMessage());
227             }
228         });
229     }
230
231     public void changeFloodlightMode(String cameraId, FloodLightMode mode) {
232         getApi().ifPresent(api -> {
233             try {
234                 api.changeFloodLightMode(handler.getId(), cameraId, mode);
235                 handler.expireData();
236             } catch (NetatmoException e) {
237                 logger.warn("Error changing Presence floodlight mode '{}' : {}", mode, e.getMessage());
238             }
239         });
240     }
241 }