2 * Copyright (c) 2010-2020 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
13 package org.openhab.binding.lifx.internal;
15 import static org.openhab.binding.lifx.internal.LifxBindingConstants.MIN_ZONE_INDEX;
16 import static org.openhab.binding.lifx.internal.protocol.Product.Feature.*;
17 import static org.openhab.binding.lifx.internal.util.LifxMessageUtil.infraredToPercentType;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.ScheduledFuture;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.locks.ReentrantLock;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.lifx.internal.fields.HSBK;
27 import org.openhab.binding.lifx.internal.handler.LifxLightHandler.CurrentLightState;
28 import org.openhab.binding.lifx.internal.protocol.GetColorZonesRequest;
29 import org.openhab.binding.lifx.internal.protocol.GetLightInfraredRequest;
30 import org.openhab.binding.lifx.internal.protocol.GetRequest;
31 import org.openhab.binding.lifx.internal.protocol.GetTileEffectRequest;
32 import org.openhab.binding.lifx.internal.protocol.GetWifiInfoRequest;
33 import org.openhab.binding.lifx.internal.protocol.Packet;
34 import org.openhab.binding.lifx.internal.protocol.Product;
35 import org.openhab.binding.lifx.internal.protocol.StateLightInfraredResponse;
36 import org.openhab.binding.lifx.internal.protocol.StateLightPowerResponse;
37 import org.openhab.binding.lifx.internal.protocol.StateMultiZoneResponse;
38 import org.openhab.binding.lifx.internal.protocol.StatePowerResponse;
39 import org.openhab.binding.lifx.internal.protocol.StateResponse;
40 import org.openhab.binding.lifx.internal.protocol.StateTileEffectResponse;
41 import org.openhab.binding.lifx.internal.protocol.StateWifiInfoResponse;
42 import org.openhab.core.library.types.PercentType;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 * The {@link LifxLightCurrentStateUpdater} sends packets to a light in order to update the {@code currentLightState} to
48 * the actual light state.
50 * @author Wouter Born - Extracted class from LifxLightHandler
53 public class LifxLightCurrentStateUpdater {
55 private static final int STATE_POLLING_INTERVAL = 3;
57 private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
59 private final String logId;
60 private final Product product;
61 private final CurrentLightState currentLightState;
62 private final ScheduledExecutorService scheduler;
63 private final LifxLightCommunicationHandler communicationHandler;
65 private final ReentrantLock lock = new ReentrantLock();
67 private boolean wasOnline;
68 private boolean updateSignalStrength;
70 private @Nullable ScheduledFuture<?> statePollingJob;
72 public LifxLightCurrentStateUpdater(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
73 this.logId = context.getLogId();
74 this.product = context.getProduct();
75 this.currentLightState = context.getCurrentLightState();
76 this.scheduler = context.getScheduler();
77 this.communicationHandler = communicationHandler;
80 public void pollLightState() {
83 if (currentLightState.isOnline()) {
84 logger.trace("{} : Polling the state of the light", logId);
85 sendLightStateRequests();
87 logger.trace("{} : The light is not online, there is no point polling it", logId);
89 wasOnline = currentLightState.isOnline();
90 } catch (Exception e) {
91 logger.error("Error occurred while polling light state", e);
97 public void setUpdateSignalStrength(boolean updateSignalStrength) {
98 this.updateSignalStrength = updateSignalStrength;
101 public void start() {
104 communicationHandler.addResponsePacketListener(this::handleResponsePacket);
105 ScheduledFuture<?> localStatePollingJob = statePollingJob;
106 if (localStatePollingJob == null || localStatePollingJob.isCancelled()) {
107 statePollingJob = scheduler.scheduleWithFixedDelay(this::pollLightState, 0, STATE_POLLING_INTERVAL,
110 } catch (Exception e) {
111 logger.error("Error occurred while starting light state updater", e);
120 communicationHandler.removeResponsePacketListener(this::handleResponsePacket);
121 ScheduledFuture<?> localStatePollingJob = statePollingJob;
122 if (localStatePollingJob != null && !localStatePollingJob.isCancelled()) {
123 localStatePollingJob.cancel(true);
124 statePollingJob = null;
126 } catch (Exception e) {
127 logger.error("Error occurred while stopping light state updater", e);
133 private void sendLightStateRequests() {
134 communicationHandler.sendPacket(new GetRequest());
136 if (product.hasFeature(INFRARED)) {
137 communicationHandler.sendPacket(new GetLightInfraredRequest());
139 if (product.hasFeature(MULTIZONE)) {
140 communicationHandler.sendPacket(new GetColorZonesRequest());
142 if (product.hasFeature(TILE_EFFECT)) {
143 communicationHandler.sendPacket(new GetTileEffectRequest());
145 if (updateSignalStrength) {
146 communicationHandler.sendPacket(new GetWifiInfoRequest());
150 public void handleResponsePacket(Packet packet) {
154 if (packet instanceof StateResponse) {
155 handleLightStatus((StateResponse) packet);
156 } else if (packet instanceof StatePowerResponse) {
157 handlePowerStatus((StatePowerResponse) packet);
158 } else if (packet instanceof StateLightPowerResponse) {
159 handleLightPowerStatus((StateLightPowerResponse) packet);
160 } else if (packet instanceof StateLightInfraredResponse) {
161 handleInfraredStatus((StateLightInfraredResponse) packet);
162 } else if (packet instanceof StateMultiZoneResponse) {
163 handleMultiZoneStatus((StateMultiZoneResponse) packet);
164 } else if (packet instanceof StateWifiInfoResponse) {
165 handleWifiInfoStatus((StateWifiInfoResponse) packet);
166 } else if (packet instanceof StateTileEffectResponse) {
167 handleTileEffectStatus((StateTileEffectResponse) packet);
170 currentLightState.setOnline();
172 if (currentLightState.isOnline() && !wasOnline) {
174 logger.trace("{} : The light just went online, immediately polling the state of the light", logId);
175 sendLightStateRequests();
182 private void handleLightStatus(StateResponse packet) {
183 currentLightState.setColor(packet.getColor(), MIN_ZONE_INDEX);
184 currentLightState.setPowerState(packet.getPower());
187 private void handlePowerStatus(StatePowerResponse packet) {
188 currentLightState.setPowerState(packet.getState());
191 private void handleLightPowerStatus(StateLightPowerResponse packet) {
192 currentLightState.setPowerState(packet.getState());
195 private void handleInfraredStatus(StateLightInfraredResponse packet) {
196 PercentType infrared = infraredToPercentType(packet.getInfrared());
197 currentLightState.setInfrared(infrared);
200 private void handleMultiZoneStatus(StateMultiZoneResponse packet) {
201 HSBK[] colors = currentLightState.getColors();
202 if (colors.length != packet.getCount()) {
203 colors = new HSBK[packet.getCount()];
205 for (int i = 0; i < packet.getColors().length && packet.getIndex() + i < colors.length; i++) {
206 colors[packet.getIndex() + i] = packet.getColors()[i];
209 currentLightState.setColors(colors);
212 private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
213 currentLightState.setSignalStrength(packet.getSignalStrength());
216 private void handleTileEffectStatus(StateTileEffectResponse packet) {
217 currentLightState.setTileEffect(packet.getEffect());