/**
* Copyright (c) 2010-2016 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.openhab.binding.tellstick.internal;
import java.util.SortedMap;
import org.openhab.binding.tellstick.TellstickBindingConfig;
import org.openhab.binding.tellstick.TellstickValueSelector;
import org.openhab.binding.tellstick.internal.device.TellstickDevice;
import org.openhab.binding.tellstick.internal.device.TellstickException;
import org.openhab.binding.tellstick.internal.device.iface.DeviceIntf;
import org.openhab.binding.tellstick.internal.device.iface.DimmableDeviceIntf;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is the coordinator between openhab and telldus center, it is
* responsible for all updates in both directions.
*
* @since 1.5.0
* @author jarlebh
* @author Elias Gabrielsson
*
*/
public class TellstickController implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(TellstickController.class);
private long lastSend = 0;
public static final long DEFAULT_INTERVAL_BETWEEN_SEND = 250;
private SortedMap<TellstickDevice, TellstickSendEvent> messageQue;
public TellstickController(SortedMap<TellstickDevice, TellstickSendEvent> m) {
messageQue = m;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
TellstickSendEvent sendEvent;
// GET EVENT TO SEND
synchronized (messageQue) {
while (messageQue.isEmpty()) {
messageQue.wait();
}
sendEvent = messageQue.remove(messageQue.firstKey());
}
// SEND EVENT
try {
handleSendEvent(sendEvent.getConfig(), sendEvent.getDev(), sendEvent.getCommand());
} catch (TellstickException e) {
logger.error("Failed to send msg to {}, error: {}", sendEvent.getConfig(), e);
}
} catch (InterruptedException ie) {
break; // Terminate
}
}
}
private void handleSendEvent(TellstickBindingConfig config, TellstickDevice dev, Command command)
throws TellstickException {
int resend = config.getResend();
long resendInterval = config.getResendInterval();
for (int i = 0; i < resend; i++) {
checkLastAndWait(resendInterval);
logger.info("Send {} to {} time={} conf: {}", command, dev, i, config);
switch (config.getValueSelector()) {
case COMMAND:
if (command == OnOffType.ON) {
if (config.getUsageSelector() == TellstickValueSelector.DIMMABLE) {
turnOff(dev);
checkLastAndWait(resendInterval);
}
turnOn(config, dev);
} else if (command == OnOffType.OFF) {
turnOff(dev);
}
break;
case DIMMING_LEVEL:
if (command == OnOffType.ON) {
turnOn(config, dev);
} else if (command == OnOffType.OFF) {
turnOff(dev);
} else if (command instanceof PercentType) {
dim(dev, (PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
increaseDecrease(dev, ((IncreaseDecreaseType) command));
}
break;
default:
break;
}
}
}
private void increaseDecrease(TellstickDevice dev, IncreaseDecreaseType increaseDecreaseType)
throws TellstickException {
String strValue = dev.getData();
double value = 0;
if (strValue != null) {
value = Double.valueOf(strValue);
}
int percent = (int) Math.round((value / 255) * 100);
if (IncreaseDecreaseType.INCREASE == increaseDecreaseType) {
percent = Math.min(percent + 10, 100);
} else if (IncreaseDecreaseType.DECREASE == increaseDecreaseType) {
percent = Math.max(percent - 10, 0);
}
dim(dev, new PercentType(percent));
}
private void dim(TellstickDevice dev, PercentType command) throws TellstickException {
double value = command.doubleValue();
// 0 means OFF and 100 means ON
if (value == 0 && dev instanceof DeviceIntf) {
((DeviceIntf) dev).off();
} else if (value == 100 && dev instanceof DeviceIntf) {
((DeviceIntf) dev).on();
} else if (dev instanceof DimmableDeviceIntf) {
long tdVal = Math.round((value / 100) * 255);
((DimmableDeviceIntf) dev).dim((int) tdVal);
} else {
throw new RuntimeException("Cannot send DIM to " + dev);
}
}
private void turnOff(TellstickDevice dev) throws TellstickException {
if (dev instanceof DeviceIntf) {
((DeviceIntf) dev).off();
} else {
throw new RuntimeException("Cannot send OFF to " + dev);
}
}
private void turnOn(TellstickBindingConfig config, TellstickDevice dev) throws TellstickException {
if (dev instanceof DeviceIntf) {
((DeviceIntf) dev).on();
} else {
throw new RuntimeException("Cannot send ON to " + dev);
}
}
private void checkLastAndWait(long resendInterval) {
while ((System.currentTimeMillis() - lastSend) < resendInterval) {
logger.info("Wait for {} millisec", resendInterval);
try {
Thread.sleep(resendInterval);
} catch (InterruptedException e) {
logger.error("Failed to sleep", e);
}
}
lastSend = System.currentTimeMillis();
}
public long getLastSend() {
return lastSend;
}
public void setLastSend(long currentTimeMillis) {
lastSend = currentTimeMillis;
}
}