]> git.basschouten.com Git - openhab-addons.git/blob
a31ac029ebc6a422a00a9b37a963d750ba0b42e9
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 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.stopAllMeters();
180             comm.stopCommunication();
181         }
182         nhcComm = null;
183         super.dispose();
184     }
185
186     @Override
187     public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
188         NikoHomeControlCommunication comm = nhcComm;
189         // if the communication had not been started yet, just dispose and initialize again
190         if (comm == null) {
191             super.handleConfigurationUpdate(configurationParameters);
192             return;
193         }
194
195         Configuration configuration = editConfiguration();
196         for (Entry<String, Object> configurationParameter : configurationParameters.entrySet()) {
197             configuration.put(configurationParameter.getKey(), configurationParameter.getValue());
198         }
199         updateConfiguration(configuration);
200
201         scheduler.submit(() -> {
202             comm.restartCommunication();
203             if (!comm.communicationActive()) {
204                 bridgeOffline();
205                 return;
206             }
207
208             updateProperties();
209
210             updateStatus(ThingStatus.ONLINE);
211
212             int refreshInterval = getConfig().as(NikoHomeControlBridgeConfig.class).refresh;
213             setupRefreshTimer(refreshInterval);
214         });
215     }
216
217     @Override
218     public void alarmEvent(String alarmText) {
219         logger.debug("triggering alarm channel with {}", alarmText);
220         triggerChannel(CHANNEL_ALARM, alarmText);
221         updateStatus(ThingStatus.ONLINE);
222     }
223
224     @Override
225     public void noticeEvent(String alarmText) {
226         logger.debug("triggering notice channel with {}", alarmText);
227         triggerChannel(CHANNEL_NOTICE, alarmText);
228         updateStatus(ThingStatus.ONLINE);
229     }
230
231     @Override
232     public void updatePropertiesEvent() {
233         updateProperties();
234     }
235
236     /**
237      * Get the Niko Home Control communication object.
238      *
239      * @return Niko Home Control communication object
240      */
241     public @Nullable NikoHomeControlCommunication getCommunication() {
242         return nhcComm;
243     }
244
245     @Override
246     public @Nullable InetAddress getAddr() {
247         InetAddress addr = null;
248         NikoHomeControlBridgeConfig config = getConfig().as(NikoHomeControlBridgeConfig.class);
249         try {
250             addr = InetAddress.getByName(config.addr);
251         } catch (UnknownHostException e) {
252             logger.debug("Cannot resolve hostname {} to IP adress", config.addr);
253         }
254         return addr;
255     }
256
257     @Override
258     public int getPort() {
259         return getConfig().as(NikoHomeControlBridgeConfig.class).port;
260     }
261
262     @Override
263     public ZoneId getTimeZone() {
264         return timeZoneProvider.getTimeZone();
265     }
266
267     @Override
268     public Collection<Class<? extends ThingHandlerService>> getServices() {
269         return Set.of(NikoHomeControlDiscoveryService.class);
270     }
271 }