]> git.basschouten.com Git - openhab-addons.git/blob
cba4319de0e454dd6c4430de35a2187790435efd
[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.flicbutton.internal.handler;
14
15 import java.io.IOException;
16 import java.net.UnknownHostException;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.concurrent.Future;
20 import java.util.concurrent.TimeUnit;
21
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.flicbutton.internal.discovery.FlicButtonDiscoveryService;
26 import org.openhab.core.thing.Bridge;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.ThingStatus;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.openhab.core.thing.binding.BaseBridgeHandler;
31 import org.openhab.core.types.Command;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import io.flic.fliclib.javaclient.FlicClient;
36
37 /**
38  * The {@link FlicDaemonBridgeHandler} handles a running instance of the fliclib-linux-hci server (flicd).
39  *
40  * @author Patrick Fink - Initial contribution
41  */
42 @NonNullByDefault
43 public class FlicDaemonBridgeHandler extends BaseBridgeHandler {
44     private final Logger logger = LoggerFactory.getLogger(FlicDaemonBridgeHandler.class);
45     private static final long REINITIALIZE_DELAY_SECONDS = 10;
46     // Config parameters
47     private @Nullable FlicDaemonBridgeConfiguration cfg;
48     // Services
49     private FlicButtonDiscoveryService buttonDiscoveryService;
50     private @Nullable Future<?> flicClientFuture;
51     // For disposal
52     private Collection<@Nullable Future<?>> startedTasks = new ArrayList<>(3);
53     private @Nullable FlicClient flicClient;
54
55     public FlicDaemonBridgeHandler(Bridge bridge, FlicButtonDiscoveryService buttonDiscoveryService) {
56         super(bridge);
57         this.buttonDiscoveryService = buttonDiscoveryService;
58     }
59
60     public @Nullable FlicClient getFlicClient() {
61         return flicClient;
62     }
63
64     @Override
65     public void initialize() {
66         startedTasks.add(scheduler.submit(this::initializeThing));
67     }
68
69     public void initializeThing() {
70         try {
71             initConfigParameters();
72             startFlicdClientAsync();
73             activateButtonDiscoveryService();
74             initThingStatus();
75         } catch (UnknownHostException ignored) {
76             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Hostname wrong or unknown!");
77         } catch (IOException e) {
78             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
79                     "Error connecting to flicd: " + e.getMessage());
80             dispose();
81             scheduleReinitialize();
82         }
83     }
84
85     private void initConfigParameters() {
86         cfg = getConfigAs(FlicDaemonBridgeConfiguration.class);
87     }
88
89     private void activateButtonDiscoveryService() {
90         if (flicClient != null) {
91             buttonDiscoveryService.activate((@NonNull FlicClient) flicClient);
92         } else {
93             throw new IllegalStateException("flicClient not properly initialized");
94         }
95     }
96
97     private void startFlicdClientAsync() throws IOException {
98         flicClient = new FlicClient(cfg.getHost().getHostAddress(), cfg.getPort());
99         Runnable flicClientService = () -> {
100             try {
101                 flicClient.handleEvents();
102                 flicClient.close();
103                 logger.debug("Listening to flicd ended");
104             } catch (IOException e) {
105                 logger.debug("Error occured while listening to flicd", e);
106             } finally {
107                 if (Thread.currentThread().isInterrupted()) {
108                     onClientFailure();
109                 }
110             }
111         };
112
113         if (!Thread.currentThread().isInterrupted()) {
114             flicClientFuture = scheduler.submit(flicClientService);
115             startedTasks.add(flicClientFuture);
116         }
117     }
118
119     private void onClientFailure() {
120         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
121                 "flicd client terminated, probably flicd is not reachable anymore.");
122         dispose();
123         scheduleReinitialize();
124     }
125
126     private void initThingStatus() {
127         if (!flicClientFuture.isDone()) {
128             updateStatus(ThingStatus.ONLINE);
129         } else {
130             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
131                     "flicd client could not be started, probably flicd is not reachable.");
132         }
133     }
134
135     @Override
136     public void dispose() {
137         super.dispose();
138         startedTasks.forEach(task -> task.cancel(true));
139         startedTasks = new ArrayList<>(2);
140         buttonDiscoveryService.deactivate();
141     }
142
143     private void scheduleReinitialize() {
144         startedTasks.add(scheduler.schedule(this::initialize, REINITIALIZE_DELAY_SECONDS, TimeUnit.SECONDS));
145     }
146
147     @Override
148     public void handleCommand(ChannelUID channelUID, Command command) {
149         // No commands to the fliclib-linux-hci are supported.
150         // So there is nothing to handle in the bridge handler
151     }
152 }