]> git.basschouten.com Git - openhab-addons.git/blob
072fb5a68b04821cc886d6556934c28b495e7e8a
[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.jablotron.internal.handler;
14
15 import static org.openhab.binding.jablotron.JablotronBindingConstants.*;
16
17 import java.time.Instant;
18 import java.time.ZoneId;
19 import java.time.ZonedDateTime;
20 import java.time.format.DateTimeFormatter;
21 import java.util.List;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24
25 import org.eclipse.jdt.annotation.NonNullByDefault;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.openhab.binding.jablotron.internal.config.JablotronDeviceConfig;
28 import org.openhab.binding.jablotron.internal.model.JablotronControlResponse;
29 import org.openhab.binding.jablotron.internal.model.JablotronDataUpdateResponse;
30 import org.openhab.binding.jablotron.internal.model.JablotronDiscoveredService;
31 import org.openhab.binding.jablotron.internal.model.JablotronHistoryDataEvent;
32 import org.openhab.binding.jablotron.internal.model.JablotronService;
33 import org.openhab.binding.jablotron.internal.model.JablotronServiceData;
34 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetail;
35 import org.openhab.binding.jablotron.internal.model.JablotronServiceDetailSegment;
36 import org.openhab.core.cache.ExpiringCache;
37 import org.openhab.core.library.types.DateTimeType;
38 import org.openhab.core.library.types.StringType;
39 import org.openhab.core.thing.Bridge;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingStatus;
42 import org.openhab.core.thing.ThingStatusDetail;
43 import org.openhab.core.thing.ThingStatusInfo;
44 import org.openhab.core.thing.binding.BaseThingHandler;
45 import org.openhab.core.types.State;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 import com.google.gson.Gson;
50
51 /**
52  * The {@link JablotronAlarmHandler} is responsible for handling commands, which are
53  * sent to one of the channels.
54  *
55  * @author Ondrej Pecta - Initial contribution
56  */
57 @NonNullByDefault
58 public abstract class JablotronAlarmHandler extends BaseThingHandler {
59
60     private final Logger logger = LoggerFactory.getLogger(getClass());
61
62     protected final Gson gson = new Gson();
63
64     protected JablotronDeviceConfig thingConfig = new JablotronDeviceConfig();
65
66     private String lastWarningTime = "";
67
68     protected String alarmName = "";
69
70     private boolean inService = false;
71
72     protected @Nullable ScheduledFuture<?> future = null;
73
74     protected @Nullable ExpiringCache<JablotronDataUpdateResponse> dataCache;
75     protected ExpiringCache<List<JablotronHistoryDataEvent>> eventCache;
76
77     public JablotronAlarmHandler(Thing thing, String alarmName) {
78         super(thing);
79         this.alarmName = alarmName;
80         eventCache = new ExpiringCache<>(CACHE_TIMEOUT_MS, this::sendGetEventHistory);
81     }
82
83     @Override
84     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
85         super.bridgeStatusChanged(bridgeStatusInfo);
86         if (ThingStatus.OFFLINE == bridgeStatusInfo.getStatus()
87                 || ThingStatus.UNINITIALIZED == bridgeStatusInfo.getStatus()) {
88             cleanup();
89         }
90         if (ThingStatus.ONLINE == bridgeStatusInfo.getStatus()) {
91             initialize();
92         }
93     }
94
95     @Override
96     public void dispose() {
97         super.dispose();
98         cleanup();
99     }
100
101     @Override
102     public void initialize() {
103         logger.debug("Initializing the alarm: {}", getThing().getUID());
104         thingConfig = getConfigAs(JablotronDeviceConfig.class);
105         future = scheduler.scheduleWithFixedDelay(this::updateAlarmStatus, 1, thingConfig.getRefresh(),
106                 TimeUnit.SECONDS);
107         updateStatus(ThingStatus.ONLINE);
108     }
109
110     public boolean isInService() {
111         return inService;
112     }
113
114     public String getAlarmName() {
115         return alarmName;
116     }
117
118     protected abstract void updateSegmentStatus(JablotronServiceDetailSegment segment);
119
120     protected void updateSegmentStatus(String segmentName, @Nullable JablotronDataUpdateResponse dataUpdate) {
121         if (dataUpdate == null || !dataUpdate.isStatus()) {
122             return;
123         }
124         List<JablotronServiceData> serviceData = dataUpdate.getData().getServiceData();
125         for (JablotronServiceData data : serviceData) {
126             if (!thingConfig.getServiceId().equals(data.getServiceId())) {
127                 continue;
128             }
129             List<JablotronService> services = data.getData();
130             for (JablotronService service : services) {
131                 JablotronServiceDetail detail = service.getData();
132                 for (JablotronServiceDetailSegment segment : detail.getSegments()) {
133                     if (segmentName.toUpperCase().equals(segment.getSegmentId())) {
134                         updateSegmentStatus(segment);
135                     }
136                 }
137             }
138         }
139     }
140
141     private void cleanup() {
142         logger.debug("doing cleanup...");
143         ScheduledFuture<?> localFuture = future;
144         if (localFuture != null) {
145             localFuture.cancel(true);
146         }
147     }
148
149     protected State getCheckTime() {
150         ZonedDateTime zdt = ZonedDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
151         return new DateTimeType(zdt);
152     }
153
154     protected synchronized @Nullable JablotronDataUpdateResponse sendGetStatusRequest() {
155         JablotronBridgeHandler handler = getBridgeHandler();
156         if (handler != null) {
157             return handler.sendGetStatusRequest(getThing());
158         }
159         return null;
160     }
161
162     protected synchronized boolean updateAlarmStatus() {
163         logger.debug("Updating status of alarm: {}", getThing().getUID());
164         JablotronDataUpdateResponse dataUpdate = sendGetStatusRequest();
165         if (dataUpdate == null) {
166             return false;
167         }
168
169         if (dataUpdate.isStatus()) {
170             updateState(CHANNEL_LAST_CHECK_TIME, getCheckTime());
171             List<JablotronServiceData> serviceData = dataUpdate.getData().getServiceData();
172             for (JablotronServiceData data : serviceData) {
173                 if (!thingConfig.getServiceId().equals(data.getServiceId())) {
174                     continue;
175                 }
176                 List<JablotronService> services = data.getData();
177                 for (JablotronService service : services) {
178                     JablotronServiceDetail detail = service.getData();
179                     for (JablotronServiceDetailSegment segment : detail.getSegments()) {
180                         updateSegmentStatus(segment);
181                     }
182                 }
183
184             }
185         } else {
186             logger.debug("Error during alarm status update: {}", dataUpdate.getErrorMessage());
187         }
188
189         List<JablotronHistoryDataEvent> events = sendGetEventHistory();
190         if (events != null && !events.isEmpty()) {
191             JablotronHistoryDataEvent event = events.get(0);
192             updateLastEvent(event);
193         }
194
195         return true;
196     }
197
198     protected @Nullable List<JablotronHistoryDataEvent> sendGetEventHistory() {
199         return sendGetEventHistory(alarmName);
200     }
201
202     private @Nullable List<JablotronHistoryDataEvent> sendGetEventHistory(String alarm) {
203         JablotronBridgeHandler handler = getBridgeHandler();
204         if (handler != null) {
205             return handler.sendGetEventHistory(getThing(), alarm);
206         }
207         return null;
208     }
209
210     protected void updateLastEvent(JablotronHistoryDataEvent event) {
211         updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(getZonedDateTime(event.getDate())));
212         updateState(CHANNEL_LAST_EVENT, new StringType(event.getEventText()));
213         updateState(CHANNEL_LAST_EVENT_CLASS, new StringType(event.getIconType()));
214         updateState(CHANNEL_LAST_EVENT_INVOKER, new StringType(event.getInvokerName()));
215
216         // oasis does not have sections
217         if (getThing().getChannel(CHANNEL_LAST_EVENT_SECTION) != null) {
218             updateState(CHANNEL_LAST_EVENT_SECTION, new StringType(event.getSectionName()));
219         }
220     }
221
222     protected void updateEventChannel(String channel) {
223         List<JablotronHistoryDataEvent> events = eventCache.getValue();
224         if (events != null && !events.isEmpty()) {
225             JablotronHistoryDataEvent event = events.get(0);
226             switch (channel) {
227                 case CHANNEL_LAST_EVENT_TIME:
228                     updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(getZonedDateTime(event.getDate())));
229                     break;
230                 case CHANNEL_LAST_EVENT:
231                     updateState(CHANNEL_LAST_EVENT, new StringType(event.getEventText()));
232                     break;
233                 case CHANNEL_LAST_EVENT_CLASS:
234                     updateState(CHANNEL_LAST_EVENT_CLASS, new StringType(event.getIconType()));
235                     break;
236                 case CHANNEL_LAST_EVENT_INVOKER:
237                     updateState(CHANNEL_LAST_EVENT_INVOKER, new StringType(event.getInvokerName()));
238                     break;
239                 case CHANNEL_LAST_EVENT_SECTION:
240                     updateState(CHANNEL_LAST_EVENT_SECTION, new StringType(event.getSectionName()));
241                     break;
242             }
243         }
244     }
245
246     public ZonedDateTime getZonedDateTime(String date) {
247         return ZonedDateTime.parse(date.substring(0, 22) + ":" + date.substring(22, 24),
248                 DateTimeFormatter.ISO_DATE_TIME);
249     }
250
251     protected @Nullable JablotronControlResponse sendUserCode(String section, String key, String status, String code) {
252         JablotronBridgeHandler handler = getBridgeHandler();
253         if (handler != null) {
254             return handler.sendUserCode(getThing(), section, key, status, code);
255         }
256         return null;
257     }
258
259     protected @Nullable JablotronBridgeHandler getBridgeHandler() {
260         Bridge br = getBridge();
261         if (br != null && br.getHandler() != null) {
262             return (JablotronBridgeHandler) br.getHandler();
263         }
264         return null;
265     }
266
267     public void setStatus(ThingStatus status, ThingStatusDetail detail, String message) {
268         updateStatus(status, detail, message);
269     }
270
271     public void triggerAlarm(JablotronDiscoveredService service) {
272         if (!service.getWarningTime().equals(lastWarningTime)) {
273             logger.debug("Service id: {} is triggering an alarm: {}", thing.getUID().getId(), service.getWarning());
274             lastWarningTime = service.getWarningTime();
275             triggerChannel(CHANNEL_ALARM, service.getWarning());
276         }
277     }
278
279     public void setInService(boolean inService) {
280         this.inService = inService;
281     }
282 }