]> git.basschouten.com Git - openhab-addons.git/blob
9029ef5167b719b5945b931a0395388f77c1e85a
[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.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.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.flicbutton.internal.discovery.FlicButtonDiscoveryService;
25 import org.openhab.core.thing.Bridge;
26 import org.openhab.core.thing.ChannelUID;
27 import org.openhab.core.thing.ThingStatus;
28 import org.openhab.core.thing.ThingStatusDetail;
29 import org.openhab.core.thing.binding.BaseBridgeHandler;
30 import org.openhab.core.types.Command;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import io.flic.fliclib.javaclient.FlicClient;
35
36 /**
37  * The {@link FlicDaemonBridgeHandler} handles a running instance of the fliclib-linux-hci server (flicd).
38  *
39  * @author Patrick Fink - Initial contribution
40  */
41 @NonNullByDefault
42 public class FlicDaemonBridgeHandler extends BaseBridgeHandler {
43     private final Logger logger = LoggerFactory.getLogger(FlicDaemonBridgeHandler.class);
44     private static final long REINITIALIZE_DELAY_SECONDS = 10;
45     // Config parameters
46     private @Nullable FlicDaemonBridgeConfiguration cfg;
47     // Services
48     private FlicButtonDiscoveryService buttonDiscoveryService;
49     private @Nullable Future<?> flicClientFuture;
50     // For disposal
51     private Collection<@Nullable Future<?>> startedTasks = new ArrayList<>(3);
52     private @Nullable FlicClient flicClient;
53
54     public FlicDaemonBridgeHandler(Bridge bridge, FlicButtonDiscoveryService buttonDiscoveryService) {
55         super(bridge);
56         this.buttonDiscoveryService = buttonDiscoveryService;
57     }
58
59     public @Nullable FlicClient getFlicClient() {
60         return flicClient;
61     }
62
63     @Override
64     public void initialize() {
65         startedTasks.add(scheduler.submit(this::initializeThing));
66     }
67
68     public void initializeThing() {
69         try {
70             initConfigParameters();
71             startFlicdClientAsync();
72             activateButtonDiscoveryService();
73             initThingStatus();
74         } catch (UnknownHostException ignored) {
75             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Hostname wrong or unknown!");
76         } catch (IOException e) {
77             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
78                     "Error connecting to flicd: " + e.getMessage());
79             dispose();
80             scheduleReinitialize();
81         }
82     }
83
84     private void initConfigParameters() {
85         cfg = getConfigAs(FlicDaemonBridgeConfiguration.class);
86     }
87
88     private void activateButtonDiscoveryService() {
89         FlicClient flicClient = this.flicClient;
90         if (flicClient != null) {
91             buttonDiscoveryService.activate(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 }