/**
* 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.milight.internal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openhab.binding.milight.MilightBindingProvider;
import org.openhab.binding.milight.internal.MilightBindingConfig.BindingType;
import org.openhab.core.binding.AbstractBinding;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.HSBType;
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.openhab.core.types.State;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This binding is able to do the following tasks with the Milight system:
* <ul>
* <li>Switching bulbs on and off.</li>
* <li>Change color temperature of a bulb, what results in a white color.</li>
* <li>Change the brightness of a bulb without changing the color.</li>
* <li>Change the RGB values of a bulb.</li>
* </ul>
*
* @author Hans-Joerg Merk
* @author Kai Kreuzer
* @since 1.3.0
*/
public class MilightBinding extends AbstractBinding<MilightBindingProvider>implements ManagedService {
private static final Logger logger = LoggerFactory.getLogger(MilightBinding.class);
/** RegEx to validate a config <code>'^(.*?)\\.(host|port)$'</code> */
private static final Pattern EXTRACT_CONFIG_PATTERN = Pattern.compile("^(.*?)\\.(host|port)$");
private final static int DEFAULT_PORT = 50000;
protected Map<String, DeviceConfig> deviceConfigs = new HashMap<String, DeviceConfig>();
protected Map<String, String> bridgeIpConfig = new HashMap<String, String>();
protected Map<String, Integer> bridgePortConfig = new HashMap<String, Integer>();
protected Map<String, PercentType> dimmerState = new HashMap<String, PercentType>();
public MilightBinding() {
}
@Override
public void activate() {
}
@Override
public void deactivate() {
}
/**
* @{inheritDoc}
*/
@Override
protected void internalReceiveCommand(String itemName, Command command) {
super.internalReceiveCommand(itemName, command);
MilightBindingConfig deviceConfig = getConfigForItemName(itemName);
if (deviceConfig == null) {
return;
}
try {
int bulb = deviceConfig.getChannelNumber();
int rgbwSteps = deviceConfig.getSteps();
String bridgeId = deviceConfig.getDeviceId();
if (deviceConfig.getCommandType().equals(BindingType.brightness)) {
logger.debug("milight: item is of type brightness");
if (OnOffType.ON.equals(command)) {
sendOn(bulb, bridgeId);
} else if (OnOffType.OFF.equals(command)) {
sendOff(bulb, bridgeId);
}
if (IncreaseDecreaseType.INCREASE.equals(command)) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
PercentType newValue = sendIncrease(bulb, rgbwSteps, bridgeId);
eventPublisher.postUpdate(itemName, newValue);
} else if (IncreaseDecreaseType.DECREASE.equals(command)) {
PercentType newValue = sendDecrease(bulb, rgbwSteps, bridgeId);
eventPublisher.postUpdate(itemName, newValue);
} else if (command instanceof PercentType) {
logger.debug("milight: command is of type PercentType");
sendPercent(bulb, rgbwSteps, bridgeId, (PercentType) command, BindingType.brightness);
}
} else if (deviceConfig.getCommandType().equals(BindingType.nightMode)) {
logger.debug("milight: item is of type nightMode");
if (OnOffType.ON.equals(command)) {
sendNightMode(bulb, bridgeId);
}
if (OnOffType.OFF.equals(command)) {
sendOff(bulb, bridgeId);
}
} else if (deviceConfig.getCommandType().equals(BindingType.whiteMode)) {
logger.debug("milight: item is of type whiteMode");
if (OnOffType.ON.equals(command)) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
sendWhiteMode(bulb, bridgeId);
}
if (OnOffType.OFF.equals(command)) {
sendOff(bulb, bridgeId);
}
} else if (deviceConfig.getCommandType().equals(BindingType.colorTemperature)) {
logger.debug("milight: item is of type warm/cold white");
if (OnOffType.ON.equals(command)) {
sendPercent(bulb, rgbwSteps, bridgeId, PercentType.HUNDRED, BindingType.colorTemperature);
} else if (OnOffType.OFF.equals(command)) {
sendPercent(bulb, rgbwSteps, bridgeId, PercentType.ZERO, BindingType.colorTemperature);
} else if (IncreaseDecreaseType.INCREASE.equals(command)) {
PercentType newValue = sendWarmer(bulb, bridgeId);
eventPublisher.postUpdate(itemName, newValue);
} else if (IncreaseDecreaseType.DECREASE.equals(command)) {
PercentType newValue = sendCooler(bulb, bridgeId);
eventPublisher.postUpdate(itemName, newValue);
} else if (command instanceof PercentType) {
sendPercent(bulb, rgbwSteps, bridgeId, (PercentType) command, BindingType.colorTemperature);
}
} else if (deviceConfig.getCommandType().equals(BindingType.discoMode)) {
logger.debug("milight: item is of type discoMode");
if (IncreaseDecreaseType.INCREASE.equals(command)) {
sendDiscoModeUp(bulb, bridgeId);
} else if (IncreaseDecreaseType.DECREASE.equals(command)) {
sendDiscoModeDown(bulb, bridgeId);
} else if (command instanceof PercentType) {
sendPercent(bulb, rgbwSteps, bridgeId, (PercentType) command, BindingType.discoMode);
}
} else if (deviceConfig.getCommandType().equals(BindingType.discoSpeed)) {
logger.debug("milight: item is of type discoSpeed");
if (IncreaseDecreaseType.INCREASE.equals(command)) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
sendIncreaseSpeed(bulb, bridgeId);
} else if (IncreaseDecreaseType.DECREASE.equals(command)) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
sendDecreaseSpeed(bulb, bridgeId);
} else if (command instanceof PercentType) {
sendPercent(bulb, rgbwSteps, bridgeId, (PercentType) command, BindingType.discoSpeed);
}
} else if (deviceConfig.getCommandType().equals(BindingType.rgb)) {
logger.debug("milight: item is of type rgb");
if (command instanceof HSBType) {
HSBType hsbCommand = (HSBType) command;
DecimalType saturation = hsbCommand.getSaturation();
if (saturation.equals(0)) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
sendWhiteMode(bulb, bridgeId);
} else {
sendColor(command, bridgeId, bulb);
}
} else if (command instanceof PercentType) {
sendPercent(bulb, rgbwSteps, bridgeId, (PercentType) command, BindingType.brightness);
}
}
} catch (Exception e) {
logger.error("milight: Failed to send {} command ", deviceConfig.getCommandType(), e);
}
}
private void sendPercent(int bulb, int rgbwSteps, String bridgeId, PercentType command,
MilightBindingConfig.BindingType type) {
logger.debug("milight: sendPercent");
if (BindingType.brightness.equals(type) && command.equals(PercentType.ZERO)) {
sendOff(bulb, bridgeId);
return;
}
if (BindingType.brightness.equals(type) && command.equals(PercentType.HUNDRED)) {
sendFull(bulb, rgbwSteps, bridgeId);
return;
}
PercentType oldPercent = getCurrentState(bulb, bridgeId, type);
// Make sure lights are on and engage current bulb via a preceding ON command:
sendOn(bulb, bridgeId);
try {
// White Bulbs: 10 levels of brightness + Off.
if (bulb < 5) {
double stepSize = 9.090909090909091;
// Assume lowest brightness level (about 9%) if just powered on.
if (oldPercent.equals(PercentType.ZERO)) {
oldPercent = new PercentType(9);
}
int repeatCount = Math.abs((int) Math.round(command.intValue() / stepSize)
- (int) Math.round(oldPercent.intValue() / stepSize));
logger.debug("milight: dim from '{}' with command '{}' via '{}' steps.", oldPercent.toString(),
command.toString(), repeatCount);
if (command.compareTo(oldPercent) > 0) {
for (int i = 0; i < repeatCount; i++) {
Thread.sleep(100);
if (BindingType.brightness.equals(type)) {
sendIncrease(bulb, rgbwSteps, bridgeId);
} else if (BindingType.colorTemperature.equals(type)) {
sendWarmer(bulb, bridgeId);
}
}
} else if (command.compareTo(oldPercent) < 0) {
for (int i = 0; i < repeatCount; i++) {
Thread.sleep(100);
if (BindingType.brightness.equals(type)) {
sendDecrease(bulb, rgbwSteps, bridgeId);
} else if (BindingType.colorTemperature.equals(type)) {
sendCooler(bulb, bridgeId);
}
}
}
// Old RGB Bulbs: 9 levels of brightness + Off.
} else if (bulb == 5) {
if (command.compareTo(oldPercent) > 0) {
int repeatCount = (command.intValue() - oldPercent.intValue()) / 10;
for (int i = 0; i < repeatCount; i++) {
Thread.sleep(100);
if (BindingType.brightness.equals(type) && bulb < 6) {
sendIncrease(bulb, rgbwSteps, bridgeId);
} else if (BindingType.colorTemperature.equals(type)) {
sendWarmer(bulb, bridgeId);
} else if (BindingType.discoSpeed.equals(type)) {
sendIncreaseSpeed(bulb, bridgeId);
} else if (BindingType.discoMode.equals(type)) {
sendDiscoModeUp(bulb, bridgeId);
}
}
} else if (command.compareTo(oldPercent) < 0) {
int repeatCount = (oldPercent.intValue() - command.intValue()) / 10;
for (int i = 0; i < repeatCount; i++) {
Thread.sleep(100);
if (BindingType.brightness.equals(type) && bulb < 6) {
sendDecrease(bulb, rgbwSteps, bridgeId);
} else if (BindingType.colorTemperature.equals(type)) {
sendCooler(bulb, bridgeId);
} else if (BindingType.discoSpeed.equals(type)) {
sendDecreaseSpeed(bulb, bridgeId);
} else if (BindingType.discoMode.equals(type)) {
sendDiscoModeDown(bulb, bridgeId);
}
}
}
// RGBW Bulbs:
} else if (bulb > 5) {
if (command.intValue() > 0 && command.intValue() < 100) {
int newCommand = (command.intValue() * (rgbwSteps - 2) / 100 + 2);
Thread.sleep(100);
String messageBytes = "4E:" + Integer.toHexString(newCommand) + ":55";
logger.debug("milight: send dimming packet '{}' to RGBW bulb channel '{}'", messageBytes, bulb);
sendMessage(messageBytes, bridgeId);
} else if (command.intValue() > 99) {
sendFull(bulb, rgbwSteps, bridgeId);
} else if (command.intValue() < 1) {
sendOff(bulb, bridgeId);
}
}
// store dimmerValue
setCurrentState(bulb, bridgeId, command, type);
} catch (InterruptedException e) {
logger.debug("Sleeping thread has been interrupted.");
}
}
private PercentType getCurrentState(int bulb, String bridgeId, BindingType type) {
PercentType percent = dimmerState.get(bridgeId + bulb + type);
if (percent == null) {
percent = PercentType.ZERO;
}
return percent;
}
private void setCurrentState(int bulb, String bridgeId, PercentType command, BindingType type) {
dimmerState.put(bridgeId + bulb + type, command);
}
private PercentType sendIncrease(int bulb, int rgbwSteps, String bridgeId) {
logger.debug("milight: sendIncrease");
String messageBytes = null;
switch (bulb) {
// increase brightness of white bulbs
case 0:
case 1:
case 2:
case 3:
case 4:
messageBytes = "3C:00:55";
break;
// increase brightness of rgb bulbs
case 5:
messageBytes = "23:00:55";
break;
}
int currentPercent = getCurrentState(bulb, bridgeId, BindingType.brightness).intValue();
if (currentPercent == 0) {
try {
sendOn(bulb, bridgeId);
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
int newPercent = currentPercent + 10;
if (newPercent > 100) {
newPercent = 100;
}
PercentType newValue = new PercentType(newPercent);
if (bulb > 5) {
int increasePercent = newPercent * (rgbwSteps - 2) / 100 + 2;
messageBytes = "4E:" + Integer.toHexString(increasePercent) + ":55";
logger.debug("Bulb '{}' set to '{}' dimming Steps", bulb, rgbwSteps);
} else if (bulb < 5) {
newPercent = (int) Math.round(
(Math.round(getCurrentState(bulb, bridgeId, BindingType.brightness).intValue() / 9.090909090909091)
+ 1) * 9.090909090909091);
newValue = new PercentType(newPercent);
logger.debug("milight: Bulb '{}' getting increased to '{}'", bulb, newPercent);
}
sendMessage(messageBytes, bridgeId);
setCurrentState(bulb, bridgeId, newValue, BindingType.brightness);
return newValue;
}
private PercentType sendDecrease(int bulb, int rgbwSteps, String bridgeId) {
logger.debug("milight: sendDecrease");
String messageBytes = null;
switch (bulb) {
// decrease brightness of white bulbs
case 0:
case 1:
case 2:
case 3:
case 4:
messageBytes = "34:00:55";
break;
// decrease brightness of rgb bulbs
case 5:
messageBytes = "24:00:55";
break;
}
int newPercent = getCurrentState(bulb, bridgeId, BindingType.brightness).intValue() - 10;
if (newPercent < 0) {
newPercent = 0;
}
PercentType newValue = new PercentType(newPercent);
if (newValue.equals(PercentType.ZERO)) {
sendOff(bulb, bridgeId);
} else {
if (bulb > 5) {
int decreasePercent = newPercent * (rgbwSteps - 2) / 100 + 2;
messageBytes = "4E:" + Integer.toHexString(decreasePercent) + ":55";
logger.debug("Bulb '{}' set to '{}' dimming Steps", bulb, rgbwSteps);
} else if (bulb < 5) {
newPercent = (int) Math.round((Math.round(
getCurrentState(bulb, bridgeId, BindingType.brightness).intValue() / 9.090909090909091) - 1)
* 9.090909090909091);
newValue = new PercentType(newPercent);
logger.debug("milight: Bulb '{}' getting decreased to '{}'", bulb, newPercent);
}
sendMessage(messageBytes, bridgeId);
}
setCurrentState(bulb, bridgeId, newValue, BindingType.brightness);
return newValue;
}
private PercentType sendWarmer(int bulb, String bridgeId) {
logger.debug("milight: sendWarmer");
int newPercent = getCurrentState(bulb, bridgeId, BindingType.brightness).intValue() + 10;
if (newPercent > 100) {
newPercent = 100;
}
PercentType newValue = new PercentType(newPercent);
String messageBytes = "3E:00:55";
sendMessage(messageBytes, bridgeId);
setCurrentState(bulb, bridgeId, newValue, BindingType.brightness);
return newValue;
}
private PercentType sendCooler(int bulb, String bridgeId) {
logger.debug("milight: sendCooler");
int newPercent = getCurrentState(bulb, bridgeId, BindingType.brightness).intValue() - 10;
if (newPercent < 0) {
newPercent = 0;
}
PercentType newValue = new PercentType(newPercent);
String messageBytes = "3F:00:55";
sendMessage(messageBytes, bridgeId);
setCurrentState(bulb, bridgeId, newValue, BindingType.brightness);
return newValue;
}
private void sendDiscoModeUp(int bulb, String bridgeId) {
logger.debug("milight: sendDiscoModeUp");
if (bulb < 6) {
String messageBytes = "27:00:55";
sendMessage(messageBytes, bridgeId);
}
if (bulb > 5) {
String messageBytes = "4D:00:55";
sendMessage(messageBytes, bridgeId);
}
}
private void sendDiscoModeDown(int bulb, String bridgeId) {
logger.debug("milight: sendDiscoModeDown");
String messageBytes = "28:00:55";
sendMessage(messageBytes, bridgeId);
}
private void sendIncreaseSpeed(int bulb, String bridgeId) {
logger.debug("milight: sendIncreaseSpeed");
String messageBytes = null;
switch (bulb) {
case 5:
// message increaseSpeed rgb bulbs
messageBytes = "25:00:55";
break;
case 6:
case 7:
case 8:
case 9:
case 10:
// message increaseSpeed rgb-w bulbs
messageBytes = "44:00:55";
break;
}
sendMessage(messageBytes, bridgeId);
}
private void sendDecreaseSpeed(int bulb, String bridgeId) {
logger.debug("milight: sendDecreaseSpeed");
String messageBytes = null;
switch (bulb) {
case 5:
// message decreaseSpeed rgb bulbs
messageBytes = "26:00:55";
break;
case 6:
case 7:
case 8:
case 9:
case 10:
// message decreaseSpeed rgb-w bulbs
messageBytes = "43:00:55";
break;
}
sendMessage(messageBytes, bridgeId);
}
private void sendNightMode(int bulb, String bridgeId) {
logger.debug("milight: sendNightMode");
String messageBytes = null;
String messageBytes2 = null;
switch (bulb) {
case 0:
// message nightMode all white bulbs
messageBytes = "B9:00:55";
break;
case 1:
// message nightMode white bulb channel 1
messageBytes = "BB:00:55";
break;
case 2:
// message nightMode white bulb channel 2
messageBytes = "B3:00:55";
break;
case 3:
// message nightMode white bulb channel 3
messageBytes = "BA:00:55";
break;
case 4:
// message nightMode white bulb channel 4
messageBytes = "B6:00:55";
break;
case 6:
// message nightMode all RGBW bulbs
messageBytes = "41:00:55";
messageBytes2 = "C1:00:55";
break;
case 7:
// message nightMode RGBW bulb channel 1
messageBytes = "46:00:55";
messageBytes2 = "C6:00:55";
break;
case 8:
// message nightMode RGBW bulb channel 2
messageBytes = "48:00:55";
messageBytes2 = "C8:00:55";
break;
case 9:
// message nightMode RGBW bulb channel 3
messageBytes = "4A:00:55";
messageBytes2 = "CA:00:55";
break;
case 10:
// message nightMode RGBW bulb channel 4
messageBytes = "4C:00:55";
messageBytes2 = "CC:00:55";
break;
}
sendMessage(messageBytes, bridgeId);
// nightMode for RGBW bulbs requires second message 100ms later.
if (bulb >= 6 && bulb <= 10) {
try {
Thread.sleep(100);
sendMessage(messageBytes2, bridgeId);
} catch (InterruptedException e) {
logger.debug("Sleeping thread has been interrupted.");
}
}
}
private void sendWhiteMode(int bulb, String bridgeId) {
logger.debug("milight: sendWhiteMode");
String messageBytes = null;
switch (bulb) {
case 6:
// message whiteMode all RGBW bulbs
messageBytes = "C2:00:55";
break;
case 7:
// message whiteMode RGBW bulb channel 1
messageBytes = "C5:00:55";
break;
case 8:
// message whiteMode RGBW bulb channel 2
messageBytes = "C7:00:55";
break;
case 9:
// message whiteMode RGBW bulb channel 3
messageBytes = "C9:00:55";
break;
case 10:
// message whiteMode RGBW bulb channel 4
messageBytes = "CB:00:55";
break;
}
sendMessage(messageBytes, bridgeId);
}
private void sendFull(int bulb, int rgbwSteps, String bridgeId) {
logger.debug("milight: sendFull");
String messageBytes = null;
switch (bulb) {
case 0:
// message fullBright all white bulbs
messageBytes = "B5:00:55";
break;
case 1:
// message fullBright white bulb channel 1
messageBytes = "B8:00:55";
break;
case 2:
// message fullBright white bulb channel 2
messageBytes = "BD:00:55";
break;
case 3:
// message fullBright white bulb channel 3
messageBytes = "B7:00:55";
break;
case 4:
// message fullBright white bulb channel 4
messageBytes = "B2:00:55";
break;
case 6:
case 7:
case 8:
case 9:
case 10:
try {
sendOn(bulb, bridgeId);
Thread.sleep(100);
messageBytes = "4E:" + Integer.toHexString(rgbwSteps) + ":55";
logger.debug("Bulb '{}' set to '{}' dimming Steps", bulb, rgbwSteps);
} catch (InterruptedException e) {
logger.debug("Sleeping thread has been interrupted.");
}
break;
}
sendMessage(messageBytes, bridgeId);
setCurrentState(bulb, bridgeId, PercentType.HUNDRED, BindingType.brightness);
}
private void sendOn(int bulb, String bridgeId) {
logger.debug("milight: sendOn");
String messageBytes = null;
switch (bulb) {
case 0:
// message all white bulbs ON
messageBytes = "35:00:55";
break;
case 1:
// message white bulb channel 1 ON
messageBytes = "38:00:55";
break;
case 2:
// message white bulb channel 2 ON
messageBytes = "3D:00:55";
break;
case 3:
// message white bulb channel 3 ON
messageBytes = "37:00:55";
break;
case 4:
// message white bulb channel 4 ON
messageBytes = "32:00:55";
break;
case 5:
// message rgb bulbs ON
messageBytes = "22:00:55";
break;
case 6:
// message all rgb-w bulbs ON
messageBytes = "42:00:55";
break;
case 7:
// message rgb-w bulbs channel1 ON
messageBytes = "45:00:55";
break;
case 8:
// message rgb-w bulbs channel2 ON
messageBytes = "47:00:55";
break;
case 9:
// message rgb-w bulbs channel3 ON
messageBytes = "49:00:55";
break;
case 10:
// message rgb-w bulbs channel4 ON
messageBytes = "4B:00:55";
break;
}
sendMessage(messageBytes, bridgeId);
}
private void sendOff(int bulb, String bridgeId) {
logger.debug("milight: sendOff");
String messageBytes = null;
switch (bulb) {
case 0:
// message all white bulbs OFF
messageBytes = "39:00:55";
break;
case 1:
// message white bulb channel 1 OFF
messageBytes = "3B:00:55";
break;
case 2:
// message white bulb channel 2 OFF
messageBytes = "33:00:55";
break;
case 3:
// message white bulb channel 3 OFF
messageBytes = "3A:00:55";
break;
case 4:
// message white bulb channel 4 OFF
messageBytes = "36:00:55";
break;
case 5:
// message rgb bulbs OFF
messageBytes = "21:00:55";
break;
case 6:
// message all rgb-w bulbs OFF
messageBytes = "41:00:55";
break;
case 7:
// message rgb-w bulbs channel1 OFF
messageBytes = "46:00:55";
break;
case 8:
// message rgb-w bulbs channel2 OFF
messageBytes = "48:00:55";
break;
case 9:
// message rgb-w bulbs channel3 OFF
messageBytes = "4A:00:55";
break;
case 10:
// message rgb-w bulbs channel4 OFF
messageBytes = "4C:00:55";
break;
}
// Bring white bulb to 10% before powering off.
if (bulb < 5) {
setCurrentState(bulb, bridgeId, PercentType.HUNDRED, BindingType.brightness);
for (int i = 0; i < 10; i++) {
sendDecrease(bulb, 27, bridgeId);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
sendMessage(messageBytes, bridgeId);
setCurrentState(bulb, bridgeId, PercentType.ZERO, BindingType.brightness);
}
private void sendColor(Command command, String bridgeId, int bulb) {
logger.debug("milight: sendColor");
HSBType hsbCommand = (HSBType) command;
DecimalType hue = hsbCommand.getHue();
// we have to map [0,360] to [0,0xFF], where red equals hue=0 and the milight color 0xB0 (=176)
Integer milightColorNo = (256 + 176 - (int) (hue.floatValue() / 360.0 * 255.0)) % 256;
try {
if (bulb == 5) {
String messageBytes = "20:" + Integer.toHexString(milightColorNo) + ":55";
sendMessage(messageBytes, bridgeId);
}
if (bulb > 5) {
sendOn(bulb, bridgeId);
Thread.sleep(100);
String messageBytes = "40:" + Integer.toHexString(milightColorNo) + ":55";
sendMessage(messageBytes, bridgeId);
}
} catch (InterruptedException e) {
logger.debug("Sleeping thread has been interrupted.");
}
}
/**
* @{inheritDoc}
*/
@Override
protected void internalReceiveUpdate(String itemName, State newState) {
// the code being executed when a state was sent on the openHAB
// event bus goes here. This method is only called if one of the
// BindingProviders provide a binding for the given 'itemName'.
logger.debug("internalReceiveUpdate() is called!");
}
protected void sendMessage(String messageBytes, String bridgeId) {
String bridgeIp = bridgeIpConfig.get(bridgeId);
Integer bridgePort = bridgePortConfig.get(bridgeId);
if (bridgePort == null) {
bridgePort = DEFAULT_PORT;
}
try {
byte[] buffer = getMessageBytes(messageBytes);
InetAddress IPAddress = InetAddress.getByName(bridgeIp);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, IPAddress, bridgePort);
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.send(packet);
datagramSocket.close();
logger.debug("Sent packet '{}' to bridge '{}' ({}:{})",
new Object[] { messageBytes, bridgeId, bridgeIp, bridgePort });
} catch (Exception e) {
logger.error("Failed to send Message to '{}': ", new Object[] { bridgeIp, e.getMessage() });
}
}
private byte[] getMessageBytes(String messageBytes) {
logger.debug("milight: messageBytes to transform: '{}'", messageBytes);
if (messageBytes == null) {
logger.error("messageBytes must not be null");
}
byte[] buffer = new byte[3];
String[] hex = messageBytes.split("(\\:|\\-)");
int hexIndex = 0;
for (hexIndex = 0; hexIndex < 3; hexIndex++) {
buffer[hexIndex] = (byte) Integer.parseInt(hex[hexIndex], 16);
}
return buffer;
}
/**
* Lookup of the configuration of the named item.
*
* @param itemName
* The name of the item.
* @return The configuration, null otherwise.
*/
private MilightBindingConfig getConfigForItemName(String itemName) {
for (MilightBindingProvider provider : this.providers) {
if (provider.getItemConfig(itemName) != null) {
return provider.getItemConfig(itemName);
}
}
return null;
}
protected void addBindingProvider(MilightBindingProvider bindingProvider) {
super.addBindingProvider(bindingProvider);
}
protected void removeBindingProvider(MilightBindingProvider bindingProvider) {
super.removeBindingProvider(bindingProvider);
}
/**
* @{inheritDoc}
*/
@Override
public void updated(Dictionary<String, ?> config) throws ConfigurationException {
if (config != null) {
Enumeration<String> keys = config.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
// the config-key enumeration contains additional keys that we
// don't want to process here ...
if ("service.pid".equals(key)) {
continue;
}
Matcher matcher = EXTRACT_CONFIG_PATTERN.matcher(key);
if (!matcher.matches()) {
logger.debug(
"given config key '" + key + "' does not follow the expected pattern '<id>.<host|port>'");
continue;
}
matcher.reset();
matcher.find();
String deviceId = matcher.group(1);
DeviceConfig deviceConfig = deviceConfigs.get(deviceId);
if (deviceConfig == null) {
deviceConfig = new DeviceConfig(deviceId);
deviceConfigs.put(deviceId, deviceConfig);
}
String configKey = matcher.group(2);
String value = (String) config.get(key);
if ("host".equals(configKey)) {
deviceConfig.host = value;
bridgeIpConfig.put(deviceId, value);
} else if ("port".equals(configKey)) {
deviceConfig.port = Integer.valueOf(value);
bridgePortConfig.put(deviceId, Integer.valueOf(value));
} else {
throw new ConfigurationException(configKey, "the given configKey '" + configKey + "' is unknown");
}
}
}
}
/**
* Internal data structure which carries the connection details of one
* device (there could be several)
*/
static class DeviceConfig {
String host;
int port = DEFAULT_PORT;
String deviceId;
public DeviceConfig(String deviceId) {
this.deviceId = deviceId;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
@Override
public String toString() {
return "Device [id=" + deviceId + ", host=" + host + ", port=" + port + "]";
}
}
}