/**
* Copyright (c) 2014-2017 by the respective copyright holders.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.smarthome.binding.lifx.internal;
import static org.eclipse.smarthome.binding.lifx.LifxBindingConstants.MIN_ZONE_INDEX;
import static org.eclipse.smarthome.binding.lifx.internal.LifxUtils.infraredToPercentType;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.smarthome.binding.lifx.LifxBindingConstants;
import org.eclipse.smarthome.binding.lifx.handler.LifxLightHandler.CurrentLightState;
import org.eclipse.smarthome.binding.lifx.internal.fields.HSBK;
import org.eclipse.smarthome.binding.lifx.internal.fields.MACAddress;
import org.eclipse.smarthome.binding.lifx.internal.listener.LifxResponsePacketListener;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetColorZonesRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetLightInfraredRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.GetWifiInfoRequest;
import org.eclipse.smarthome.binding.lifx.internal.protocol.Packet;
import org.eclipse.smarthome.binding.lifx.internal.protocol.Products;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateLightInfraredResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateLightPowerResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateMultiZoneResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StatePowerResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateResponse;
import org.eclipse.smarthome.binding.lifx.internal.protocol.StateWifiInfoResponse;
import org.eclipse.smarthome.core.common.ThreadPoolManager;
import org.eclipse.smarthome.core.library.types.PercentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link LifxLightCurrentStateUpdater} sends packets to a light in order to update the {@code currentLightState} to
* the actual light state.
*
* @author Wouter Born - Extracted class from LifxLightHandler
*/
public class LifxLightCurrentStateUpdater implements LifxResponsePacketListener {
private static final int STATE_POLLING_INTERVAL = 3;
private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
private final String macAsHex;
private final CurrentLightState currentLightState;
private final LifxLightCommunicationHandler communicationHandler;
private final Products product;
private final ReentrantLock lock = new ReentrantLock();
private ScheduledExecutorService scheduler = ThreadPoolManager
.getScheduledPool(LifxBindingConstants.THREADPOOL_NAME);
private boolean wasOnline;
private boolean updateSignalStrength;
private ScheduledFuture<?> statePollingJob;
private Runnable statePollingRunnable = new Runnable() {
@Override
public void run() {
try {
lock.lock();
if (currentLightState.isOnline()) {
logger.trace("{} : Polling the state of the light", macAsHex);
sendLightStateRequests();
} else {
logger.trace("{} : The light is not online, there is no point polling it", macAsHex);
}
wasOnline = currentLightState.isOnline();
} catch (Exception e) {
logger.error("Error occurred while polling light state", e);
} finally {
lock.unlock();
}
}
};
public LifxLightCurrentStateUpdater(MACAddress macAddress, CurrentLightState currentLightState,
LifxLightCommunicationHandler communicationHandler, Products product) {
this.macAsHex = macAddress.getHex();
this.currentLightState = currentLightState;
this.communicationHandler = communicationHandler;
this.product = product;
}
public void setUpdateSignalStrength(boolean updateSignalStrength) {
this.updateSignalStrength = updateSignalStrength;
}
public void start() {
try {
lock.lock();
communicationHandler.addResponsePacketListener(this);
if (statePollingJob == null || statePollingJob.isCancelled()) {
statePollingJob = scheduler.scheduleWithFixedDelay(statePollingRunnable, 0, STATE_POLLING_INTERVAL,
TimeUnit.SECONDS);
}
} catch (Exception e) {
logger.error("Error occurred while starting light state updater", e);
} finally {
lock.unlock();
}
}
public void stop() {
try {
lock.lock();
communicationHandler.removeResponsePacketListener(this);
if (statePollingJob != null && !statePollingJob.isCancelled()) {
statePollingJob.cancel(true);
statePollingJob = null;
}
} catch (Exception e) {
logger.error("Error occurred while stopping light state updater", e);
} finally {
lock.unlock();
}
}
private void sendLightStateRequests() {
GetRequest statePacket = new GetRequest();
communicationHandler.sendPacket(statePacket);
if (product.isInfrared()) {
GetLightInfraredRequest infraredPacket = new GetLightInfraredRequest();
communicationHandler.sendPacket(infraredPacket);
}
if (product.isMultiZone()) {
GetColorZonesRequest colorZonesPacket = new GetColorZonesRequest();
communicationHandler.sendPacket(colorZonesPacket);
}
if (updateSignalStrength) {
GetWifiInfoRequest wifiInfoPacket = new GetWifiInfoRequest();
communicationHandler.sendPacket(wifiInfoPacket);
}
}
@Override
public void handleResponsePacket(Packet packet) {
try {
lock.lock();
if (packet instanceof StateResponse) {
handleLightStatus((StateResponse) packet);
} else if (packet instanceof StatePowerResponse) {
handlePowerStatus((StatePowerResponse) packet);
} else if (packet instanceof StateLightPowerResponse) {
handleLightPowerStatus((StateLightPowerResponse) packet);
} else if (packet instanceof StateLightInfraredResponse) {
handleInfraredStatus((StateLightInfraredResponse) packet);
} else if (packet instanceof StateMultiZoneResponse) {
handleMultiZoneStatus((StateMultiZoneResponse) packet);
} else if (packet instanceof StateWifiInfoResponse) {
handleWifiInfoStatus((StateWifiInfoResponse) packet);
}
currentLightState.setOnline();
if (currentLightState.isOnline() && !wasOnline) {
wasOnline = true;
logger.trace("{} : The light just went online, immediately polling the state of the light", macAsHex);
sendLightStateRequests();
}
} finally {
lock.unlock();
}
}
private void handleLightStatus(StateResponse packet) {
currentLightState.setColor(packet.getColor(), MIN_ZONE_INDEX);
currentLightState.setPowerState(packet.getPower());
}
private void handlePowerStatus(StatePowerResponse packet) {
currentLightState.setPowerState(packet.getState());
}
private void handleLightPowerStatus(StateLightPowerResponse packet) {
currentLightState.setPowerState(packet.getState());
}
private void handleInfraredStatus(StateLightInfraredResponse packet) {
PercentType infrared = infraredToPercentType(packet.getInfrared());
currentLightState.setInfrared(infrared);
}
private void handleMultiZoneStatus(StateMultiZoneResponse packet) {
HSBK[] colors = currentLightState.getColors();
if (colors == null || colors.length != packet.getCount()) {
colors = new HSBK[packet.getCount()];
}
for (int i = 0; i < packet.getColors().length && packet.getIndex() + i < colors.length; i++) {
colors[packet.getIndex() + i] = packet.getColors()[i];
}
currentLightState.setColors(colors);
}
private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
currentLightState.setSignalStrength(packet.getSignalStrength());
}
}