]> git.basschouten.com Git - openhab-addons.git/blob
deb9103e03e8bb4ce687386da116e6b6ff8a2f62
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 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.nikohomecontrol.internal.handler;
14
15 import static org.openhab.binding.nikohomecontrol.internal.NikoHomeControlBindingConstants.*;
16
17 import java.net.InetAddress;
18 import java.net.UnknownHostException;
19 import java.time.ZoneId;
20 import java.util.Collection;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.Set;
24 import java.util.concurrent.ScheduledFuture;
25 import java.util.concurrent.TimeUnit;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.nikohomecontrol.internal.discovery.NikoHomeControlDiscoveryService;
30 import org.openhab.binding.nikohomecontrol.internal.protocol.NhcControllerEvent;
31 import org.openhab.binding.nikohomecontrol.internal.protocol.NikoHomeControlCommunication;
32 import org.openhab.core.config.core.Configuration;
33 import org.openhab.core.i18n.TimeZoneProvider;
34 import org.openhab.core.thing.Bridge;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandlerService;
40 import org.openhab.core.types.Command;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * {@link NikoHomeControlBridgeHandler} is an abstract class representing a handler to all different interfaces to the
46  * Niko Home Control System. {@link NikoHomeControlBridgeHandler1} or {@link NikoHomeControlBridgeHandler2} should be
47  * used for the respective version of Niko Home Control.
48  *
49  * @author Mark Herwege - Initial Contribution
50  */
51 @NonNullByDefault
52 public abstract class NikoHomeControlBridgeHandler extends BaseBridgeHandler implements NhcControllerEvent {
53
54     private final Logger logger = LoggerFactory.getLogger(NikoHomeControlBridgeHandler.class);
55
56     protected @Nullable NikoHomeControlCommunication nhcComm;
57
58     private volatile @Nullable ScheduledFuture<?> refreshTimer;
59
60     protected final TimeZoneProvider timeZoneProvider;
61
62     public NikoHomeControlBridgeHandler(Bridge nikoHomeControlBridge, TimeZoneProvider timeZoneProvider) {
63         super(nikoHomeControlBridge);
64         this.timeZoneProvider = timeZoneProvider;
65     }
66
67     @Override
68     public void handleCommand(ChannelUID channelUID, Command command) {
69         // There is nothing to handle in the bridge handler
70     }
71
72     /**
73      * Create communication object to Niko Home Control IP-interface and start communication.
74      * Trigger discovery when communication setup is successful.
75      */
76     protected void startCommunication() {
77         NikoHomeControlCommunication comm = nhcComm;
78         if (comm == null) {
79             bridgeOffline();
80             return;
81         }
82
83         updateStatus(ThingStatus.UNKNOWN);
84
85         scheduler.submit(() -> {
86             comm.startCommunication();
87
88             int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
89             setupRefreshTimer(refreshInterval);
90
91             if (!comm.communicationActive()) {
92                 bridgeOffline();
93                 return;
94             }
95
96             updateProperties();
97
98             updateStatus(ThingStatus.ONLINE);
99         });
100     }
101
102     /**
103      * Schedule future communication refresh.
104      *
105      * @param refreshInterval Time before refresh in minutes.
106      */
107     private void setupRefreshTimer(int refreshInterval) {
108         ScheduledFuture<?> timer = refreshTimer;
109         if (timer != null) {
110             timer.cancel(true);
111             refreshTimer = null;
112         }
113
114         if (refreshInterval == 0) {
115             return;
116         }
117
118         // This timer will restart the bridge connection periodically
119         logger.debug("restart bridge connection every {} min", refreshInterval);
120         refreshTimer = scheduler.scheduleWithFixedDelay(() -> {
121             logger.debug("restart communication at scheduled time");
122
123             NikoHomeControlCommunication comm = nhcComm;
124             if (comm != null) {
125                 comm.restartCommunication();
126                 if (!comm.communicationActive()) {
127                     bridgeOffline();
128                     return;
129                 }
130
131                 updateProperties();
132
133                 updateStatus(ThingStatus.ONLINE);
134             }
135         }, refreshInterval, refreshInterval, TimeUnit.MINUTES);
136     }
137
138     /**
139      * Take bridge offline when error in communication with Niko Home Control IP-interface.
140      */
141     protected void bridgeOffline() {
142         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
143                 "@text/offline.communication-error");
144     }
145
146     /**
147      * Put bridge online when error in communication resolved.
148      */
149     public void bridgeOnline() {
150         updateProperties();
151         updateStatus(ThingStatus.ONLINE);
152     }
153
154     @Override
155     public void controllerOffline(String message) {
156         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, message);
157     }
158
159     @Override
160     public void controllerOnline() {
161         bridgeOnline();
162     }
163
164     /**
165      * Update bridge properties with properties returned from Niko Home Control Controller.
166      */
167     protected abstract void updateProperties();
168
169     @Override
170     public void dispose() {
171         ScheduledFuture<?> timer = refreshTimer;
172         if (timer != null) {
173             timer.cancel(true);
174         }
175         refreshTimer = null;
176
177         NikoHomeControlCommunication comm = nhcComm;
178         if (comm != null) {
179             comm.stopCommunication();
180         }
181         nhcComm = null;
182         super.dispose();
183     }
184
185     @Override
186     public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
187         NikoHomeControlCommunication comm = nhcComm;
188         // if the communication had not been started yet, just dispose and initialize again
189         if (comm == null) {
190             super.handleConfigurationUpdate(configurationParameters);
191             return;
192         }
193
194         Configuration configuration = editConfiguration();
195         for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
196             configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
197         }
198         updateConfiguration(configuration);
199
200         scheduler.submit(() -> {
201             comm.restartCommunication();
202             if (!comm.communicationActive()) {
203                 bridgeOffline();
204                 return;
205             }
206
207             updateProperties();
208
209             updateStatus(ThingStatus.ONLINE);
210
211             int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
212             setupRefreshTimer(refreshInterval);
213         });
214     }
215
216     @Override
217     public void alarmEvent(String alarmText) {
218         logger.debug("triggering alarm channel with {}", alarmText);
219         triggerChannel(CHANNEL_ALARM, alarmText);
220         updateStatus(ThingStatus.ONLINE);
221     }
222
223     @Override
224     public void noticeEvent(String alarmText) {
225         logger.debug("triggering notice channel with {}", alarmText);
226         triggerChannel(CHANNEL_NOTICE, alarmText);
227         updateStatus(ThingStatus.ONLINE);
228     }
229
230     @Override
231     public void updatePropertiesEvent() {
232         updateProperties();
233     }
234
235     /**
236      * Get the Niko Home Control communication object.
237      *
238      * @return Niko Home Control communication object
239      */
240     public @Nullable NikoHomeControlCommunication getCommunication() {
241         return nhcComm;
242     }
243
244     @Override
245     public @Nullable InetAddress getAddr() {
246         InetAddress addr = null;
247         NikoHomeControlBridgeConfig config = getConfig().as(NikoHomeControlBridgeConfig.class);
248         try {
249             addr = InetAddress.getByName(config.addr);
250         } catch (UnknownHostException e) {
251             logger.debug("Cannot resolve hostname {} to IP adress", config.addr);
252         }
253         return addr;
254     }
255
256     @Override
257     public int getPort() {
258         return getConfig().as(NikoHomeControlBridgeConfig.class).port;
259     }
260
261     @Override
262     public ZoneId getTimeZone() {
263         return timeZoneProvider.getTimeZone();
264     }
265
266     @Override
267     public Collection<Class<? extends ThingHandlerService>> getServices() {
268         return Set.of(NikoHomeControlDiscoveryService.class);
269     }
270 }