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