]> git.basschouten.com Git - openhab-addons.git/blob
910c8b778783f0614c45fc741092ae6ea8b0bea6
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.lifx.internal;
14
15 import static org.openhab.binding.lifx.internal.LifxBindingConstants.MIN_ZONE_INDEX;
16 import static org.openhab.binding.lifx.internal.LifxProduct.Feature.*;
17 import static org.openhab.binding.lifx.internal.util.LifxMessageUtil.infraredToPercentType;
18
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;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.lifx.internal.dto.GetColorZonesRequest;
27 import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
28 import org.openhab.binding.lifx.internal.dto.GetRequest;
29 import org.openhab.binding.lifx.internal.dto.GetTileEffectRequest;
30 import org.openhab.binding.lifx.internal.dto.GetWifiInfoRequest;
31 import org.openhab.binding.lifx.internal.dto.Packet;
32 import org.openhab.binding.lifx.internal.dto.StateLightInfraredResponse;
33 import org.openhab.binding.lifx.internal.dto.StateLightPowerResponse;
34 import org.openhab.binding.lifx.internal.dto.StateMultiZoneResponse;
35 import org.openhab.binding.lifx.internal.dto.StatePowerResponse;
36 import org.openhab.binding.lifx.internal.dto.StateResponse;
37 import org.openhab.binding.lifx.internal.dto.StateTileEffectResponse;
38 import org.openhab.binding.lifx.internal.dto.StateWifiInfoResponse;
39 import org.openhab.binding.lifx.internal.fields.HSBK;
40 import org.openhab.binding.lifx.internal.handler.LifxLightHandler.CurrentLightState;
41 import org.openhab.core.library.types.PercentType;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * The {@link LifxLightCurrentStateUpdater} sends packets to a light in order to update the {@code currentLightState} to
47  * the actual light state.
48  *
49  * @author Wouter Born - Initial contribution
50  */
51 @NonNullByDefault
52 public class LifxLightCurrentStateUpdater {
53
54     private static final int STATE_POLLING_INTERVAL = 3;
55
56     private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
57
58     private final String logId;
59     private final LifxProduct product;
60     private final CurrentLightState currentLightState;
61     private final ScheduledExecutorService scheduler;
62     private final LifxLightCommunicationHandler communicationHandler;
63
64     private final ReentrantLock lock = new ReentrantLock();
65
66     private boolean wasOnline;
67     private boolean updateSignalStrength;
68
69     private @Nullable ScheduledFuture<?> statePollingJob;
70
71     public LifxLightCurrentStateUpdater(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
72         this.logId = context.getLogId();
73         this.product = context.getProduct();
74         this.currentLightState = context.getCurrentLightState();
75         this.scheduler = context.getScheduler();
76         this.communicationHandler = communicationHandler;
77     }
78
79     public void pollLightState() {
80         try {
81             lock.lock();
82             if (currentLightState.isOnline()) {
83                 logger.trace("{} : Polling the state of the light", logId);
84                 sendLightStateRequests();
85             } else {
86                 logger.trace("{} : The light is not online, there is no point polling it", logId);
87             }
88             wasOnline = currentLightState.isOnline();
89         } catch (Exception e) {
90             logger.error("Error occurred while polling light state", e);
91         } finally {
92             lock.unlock();
93         }
94     }
95
96     public void setUpdateSignalStrength(boolean updateSignalStrength) {
97         this.updateSignalStrength = updateSignalStrength;
98     }
99
100     public void start() {
101         try {
102             lock.lock();
103             communicationHandler.addResponsePacketListener(this::handleResponsePacket);
104             ScheduledFuture<?> localStatePollingJob = statePollingJob;
105             if (localStatePollingJob == null || localStatePollingJob.isCancelled()) {
106                 statePollingJob = scheduler.scheduleWithFixedDelay(this::pollLightState, 0, STATE_POLLING_INTERVAL,
107                         TimeUnit.SECONDS);
108             }
109         } catch (Exception e) {
110             logger.error("Error occurred while starting light state updater", e);
111         } finally {
112             lock.unlock();
113         }
114     }
115
116     public void stop() {
117         try {
118             lock.lock();
119             communicationHandler.removeResponsePacketListener(this::handleResponsePacket);
120             ScheduledFuture<?> localStatePollingJob = statePollingJob;
121             if (localStatePollingJob != null && !localStatePollingJob.isCancelled()) {
122                 localStatePollingJob.cancel(true);
123                 statePollingJob = null;
124             }
125         } catch (Exception e) {
126             logger.error("Error occurred while stopping light state updater", e);
127         } finally {
128             lock.unlock();
129         }
130     }
131
132     private void sendLightStateRequests() {
133         communicationHandler.sendPacket(new GetRequest());
134
135         if (product.hasFeature(INFRARED)) {
136             communicationHandler.sendPacket(new GetLightInfraredRequest());
137         }
138         if (product.hasFeature(MULTIZONE)) {
139             communicationHandler.sendPacket(new GetColorZonesRequest());
140         }
141         if (product.hasFeature(TILE_EFFECT)) {
142             communicationHandler.sendPacket(new GetTileEffectRequest());
143         }
144         if (updateSignalStrength) {
145             communicationHandler.sendPacket(new GetWifiInfoRequest());
146         }
147     }
148
149     public void handleResponsePacket(Packet packet) {
150         try {
151             lock.lock();
152
153             if (packet instanceof StateResponse) {
154                 handleLightStatus((StateResponse) packet);
155             } else if (packet instanceof StatePowerResponse) {
156                 handlePowerStatus((StatePowerResponse) packet);
157             } else if (packet instanceof StateLightPowerResponse) {
158                 handleLightPowerStatus((StateLightPowerResponse) packet);
159             } else if (packet instanceof StateLightInfraredResponse) {
160                 handleInfraredStatus((StateLightInfraredResponse) packet);
161             } else if (packet instanceof StateMultiZoneResponse) {
162                 handleMultiZoneStatus((StateMultiZoneResponse) packet);
163             } else if (packet instanceof StateWifiInfoResponse) {
164                 handleWifiInfoStatus((StateWifiInfoResponse) packet);
165             } else if (packet instanceof StateTileEffectResponse) {
166                 handleTileEffectStatus((StateTileEffectResponse) packet);
167             }
168
169             currentLightState.setOnline();
170
171             if (currentLightState.isOnline() && !wasOnline) {
172                 wasOnline = true;
173                 logger.trace("{} : The light just went online, immediately polling the state of the light", logId);
174                 sendLightStateRequests();
175             }
176         } finally {
177             lock.unlock();
178         }
179     }
180
181     private void handleLightStatus(StateResponse packet) {
182         currentLightState.setColor(packet.getColor(), MIN_ZONE_INDEX);
183         currentLightState.setPowerState(packet.getPower());
184     }
185
186     private void handlePowerStatus(StatePowerResponse packet) {
187         currentLightState.setPowerState(packet.getState());
188     }
189
190     private void handleLightPowerStatus(StateLightPowerResponse packet) {
191         currentLightState.setPowerState(packet.getState());
192     }
193
194     private void handleInfraredStatus(StateLightInfraredResponse packet) {
195         PercentType infrared = infraredToPercentType(packet.getInfrared());
196         currentLightState.setInfrared(infrared);
197     }
198
199     private void handleMultiZoneStatus(StateMultiZoneResponse packet) {
200         HSBK[] colors = currentLightState.getColors();
201         if (colors.length != packet.getCount()) {
202             colors = new HSBK[packet.getCount()];
203         }
204         for (int i = 0; i < packet.getColors().length && packet.getIndex() + i < colors.length; i++) {
205             colors[packet.getIndex() + i] = packet.getColors()[i];
206         }
207
208         currentLightState.setColors(colors);
209     }
210
211     private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
212         currentLightState.setSignalStrength(packet.getSignalStrength());
213     }
214
215     private void handleTileEffectStatus(StateTileEffectResponse packet) {
216         currentLightState.setTileEffect(packet.getEffect());
217     }
218 }