]> git.basschouten.com Git - openhab-addons.git/blob
34dea37d5ef1456bb3468a5817424b9e452a99c3
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.protocol.Product.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.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;
45
46 /**
47  * The {@link LifxLightCurrentStateUpdater} sends packets to a light in order to update the {@code currentLightState} to
48  * the actual light state.
49  *
50  * @author Wouter Born - Extracted class from LifxLightHandler
51  */
52 @NonNullByDefault
53 public class LifxLightCurrentStateUpdater {
54
55     private static final int STATE_POLLING_INTERVAL = 3;
56
57     private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
58
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;
64
65     private final ReentrantLock lock = new ReentrantLock();
66
67     private boolean wasOnline;
68     private boolean updateSignalStrength;
69
70     private @Nullable ScheduledFuture<?> statePollingJob;
71
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;
78     }
79
80     public void pollLightState() {
81         try {
82             lock.lock();
83             if (currentLightState.isOnline()) {
84                 logger.trace("{} : Polling the state of the light", logId);
85                 sendLightStateRequests();
86             } else {
87                 logger.trace("{} : The light is not online, there is no point polling it", logId);
88             }
89             wasOnline = currentLightState.isOnline();
90         } catch (Exception e) {
91             logger.error("Error occurred while polling light state", e);
92         } finally {
93             lock.unlock();
94         }
95     }
96
97     public void setUpdateSignalStrength(boolean updateSignalStrength) {
98         this.updateSignalStrength = updateSignalStrength;
99     }
100
101     public void start() {
102         try {
103             lock.lock();
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,
108                         TimeUnit.SECONDS);
109             }
110         } catch (Exception e) {
111             logger.error("Error occurred while starting light state updater", e);
112         } finally {
113             lock.unlock();
114         }
115     }
116
117     public void stop() {
118         try {
119             lock.lock();
120             communicationHandler.removeResponsePacketListener(this::handleResponsePacket);
121             ScheduledFuture<?> localStatePollingJob = statePollingJob;
122             if (localStatePollingJob != null && !localStatePollingJob.isCancelled()) {
123                 localStatePollingJob.cancel(true);
124                 statePollingJob = null;
125             }
126         } catch (Exception e) {
127             logger.error("Error occurred while stopping light state updater", e);
128         } finally {
129             lock.unlock();
130         }
131     }
132
133     private void sendLightStateRequests() {
134         communicationHandler.sendPacket(new GetRequest());
135
136         if (product.hasFeature(INFRARED)) {
137             communicationHandler.sendPacket(new GetLightInfraredRequest());
138         }
139         if (product.hasFeature(MULTIZONE)) {
140             communicationHandler.sendPacket(new GetColorZonesRequest());
141         }
142         if (product.hasFeature(TILE_EFFECT)) {
143             communicationHandler.sendPacket(new GetTileEffectRequest());
144         }
145         if (updateSignalStrength) {
146             communicationHandler.sendPacket(new GetWifiInfoRequest());
147         }
148     }
149
150     public void handleResponsePacket(Packet packet) {
151         try {
152             lock.lock();
153
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);
168             }
169
170             currentLightState.setOnline();
171
172             if (currentLightState.isOnline() && !wasOnline) {
173                 wasOnline = true;
174                 logger.trace("{} : The light just went online, immediately polling the state of the light", logId);
175                 sendLightStateRequests();
176             }
177         } finally {
178             lock.unlock();
179         }
180     }
181
182     private void handleLightStatus(StateResponse packet) {
183         currentLightState.setColor(packet.getColor(), MIN_ZONE_INDEX);
184         currentLightState.setPowerState(packet.getPower());
185     }
186
187     private void handlePowerStatus(StatePowerResponse packet) {
188         currentLightState.setPowerState(packet.getState());
189     }
190
191     private void handleLightPowerStatus(StateLightPowerResponse packet) {
192         currentLightState.setPowerState(packet.getState());
193     }
194
195     private void handleInfraredStatus(StateLightInfraredResponse packet) {
196         PercentType infrared = infraredToPercentType(packet.getInfrared());
197         currentLightState.setInfrared(infrared);
198     }
199
200     private void handleMultiZoneStatus(StateMultiZoneResponse packet) {
201         HSBK[] colors = currentLightState.getColors();
202         if (colors.length != packet.getCount()) {
203             colors = new HSBK[packet.getCount()];
204         }
205         for (int i = 0; i < packet.getColors().length && packet.getIndex() + i < colors.length; i++) {
206             colors[packet.getIndex() + i] = packet.getColors()[i];
207         }
208
209         currentLightState.setColors(colors);
210     }
211
212     private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
213         currentLightState.setSignalStrength(packet.getSignalStrength());
214     }
215
216     private void handleTileEffectStatus(StateTileEffectResponse packet) {
217         currentLightState.setTileEffect(packet.getEffect());
218     }
219 }