2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
14 package org.openhab.binding.pilight.internal.handler;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.ScheduledFuture;
22 import java.util.concurrent.TimeUnit;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.pilight.internal.IPilightCallback;
27 import org.openhab.binding.pilight.internal.PilightBridgeConfiguration;
28 import org.openhab.binding.pilight.internal.PilightConnector;
29 import org.openhab.binding.pilight.internal.discovery.PilightDeviceDiscoveryService;
30 import org.openhab.binding.pilight.internal.dto.*;
31 import org.openhab.core.common.NamedThreadFactory;
32 import org.openhab.core.thing.*;
33 import org.openhab.core.thing.binding.BaseBridgeHandler;
34 import org.openhab.core.thing.binding.ThingHandler;
35 import org.openhab.core.thing.binding.ThingHandlerService;
36 import org.openhab.core.types.Command;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * The {@link PilightBridgeHandler} is responsible dispatching commands for the child
42 * things to the Pilight daemon and sending status updates to the child things.
44 * @author Stefan Röllin - Initial contribution
45 * @author Niklas Dörfler - Port pilight binding to openHAB 3 + add device discovery
48 public class PilightBridgeHandler extends BaseBridgeHandler {
50 private static final int REFRESH_CONFIG_MSEC = 500;
52 private final Logger logger = LoggerFactory.getLogger(PilightBridgeHandler.class);
54 private @Nullable PilightConnector connector = null;
56 private @Nullable ScheduledFuture<?> refreshJob = null;
58 private @Nullable PilightDeviceDiscoveryService discoveryService = null;
60 private final ExecutorService connectorExecutor = Executors
61 .newSingleThreadExecutor(new NamedThreadFactory(getThing().getUID().getAsString(), true));
63 public PilightBridgeHandler(Bridge bridge) {
68 public void handleCommand(ChannelUID channelUID, Command command) {
69 logger.debug("Pilight Bridge is read-only and does not handle commands.");
73 public void initialize() {
74 PilightBridgeConfiguration config = getConfigAs(PilightBridgeConfiguration.class);
76 final @Nullable PilightDeviceDiscoveryService discoveryService = this.discoveryService;
77 PilightConnector connector = new PilightConnector(config, new IPilightCallback() {
79 public void updateThingStatus(ThingStatus status, ThingStatusDetail statusDetail,
80 @Nullable String description) {
81 updateStatus(status, statusDetail, description);
82 if (status == ThingStatus.ONLINE) {
83 refreshConfigAndStatus();
88 public void statusReceived(List<Status> allStatus) {
89 for (Status status : allStatus) {
90 processStatus(status);
93 if (discoveryService != null) {
94 discoveryService.setStatus(allStatus);
99 public void configReceived(Config config) {
100 processConfig(config);
104 public void versionReceived(Version version) {
105 getThing().setProperty(Thing.PROPERTY_FIRMWARE_VERSION, version.getVersion());
109 updateStatus(ThingStatus.UNKNOWN);
111 connectorExecutor.execute(connector);
112 this.connector = connector;
116 public void dispose() {
117 final @Nullable ScheduledFuture<?> future = this.refreshJob;
118 if (future != null) {
122 final @Nullable PilightConnector connector = this.connector;
123 if (connector != null) {
125 this.connector = null;
128 connectorExecutor.shutdown();
132 * send action to pilight daemon
134 * @param action action to send
136 public void sendAction(Action action) {
137 final @Nullable PilightConnector connector = this.connector;
138 if (connector != null) {
139 connector.sendAction(action);
144 * refresh config and status by requesting config and all values from pilight daemon
146 public synchronized void refreshConfigAndStatus() {
147 if (thing.getStatus() == ThingStatus.ONLINE) {
148 final @Nullable ScheduledFuture<?> refreshJob = this.refreshJob;
149 if (refreshJob == null || refreshJob.isCancelled() || refreshJob.isDone()) {
150 logger.debug("schedule refresh of config and status");
151 this.refreshJob = scheduler.schedule(this::doRefreshConfigAndStatus, REFRESH_CONFIG_MSEC,
152 TimeUnit.MILLISECONDS);
155 logger.warn("Bridge is not online - ignoring refresh of config and status.");
159 private void doRefreshConfigAndStatus() {
160 final @Nullable PilightConnector connector = this.connector;
161 if (connector != null) {
162 // the config is required for dimmers to get the minimum and maximum dim levels
163 connector.refreshConfig();
164 connector.refreshStatus();
169 * Processes a status update received from pilight
171 * @param status The new Status
173 private void processStatus(Status status) {
174 final Integer type = status.getType();
175 logger.trace("processStatus device '{}' type {}", status.getDevices().get(0), type);
177 if (!DeviceType.SERVER.equals(type)) {
178 for (Thing thing : getThing().getThings()) {
179 final @Nullable ThingHandler handler = thing.getHandler();
180 if (handler instanceof PilightBaseHandler) {
181 ((PilightBaseHandler) handler).updateFromStatusIfMatches(status);
188 public Collection<Class<? extends ThingHandlerService>> getServices() {
189 return Collections.singleton(PilightDeviceDiscoveryService.class);
193 * Register discovery service to this bridge instance.
195 public boolean registerDiscoveryListener(PilightDeviceDiscoveryService listener) {
196 if (discoveryService == null) {
197 discoveryService = listener;
204 * Unregister discovery service from this bridge instance.
206 public boolean unregisterDiscoveryListener() {
207 if (discoveryService != null) {
208 discoveryService = null;
216 * Processes a config received from pilight
218 * @param config The new config
220 private void processConfig(Config config) {
221 for (Thing thing : getThing().getThings()) {
222 final @Nullable ThingHandler handler = thing.getHandler();
223 if (handler instanceof PilightBaseHandler) {
224 ((PilightBaseHandler) handler).updateFromConfigIfMatches(config);
228 final @Nullable PilightDeviceDiscoveryService discoveryService = this.discoveryService;
229 if (discoveryService != null) {
230 discoveryService.setConfig(config);