/**
* 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.samsungtv.internal;
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.samsungtv.SamsungTvBindingProvider;
import org.openhab.core.binding.AbstractBinding;
import org.openhab.core.types.Command;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* Binding listening OpenHAB bus and send commands to Samsung devices when
* command is received.
*
* @author Pauli Anttila
* @since 1.2.0
*/
public class SamsungTvBinding extends AbstractBinding<SamsungTvBindingProvider>implements ManagedService {
private static final Logger logger = LoggerFactory.getLogger(SamsungTvBinding.class);
/** RegEx to validate a config <code>'^(.*?)\\.(host|port)$'</code> */
private static final Pattern EXTRACT_TV_CONFIG_PATTERN = Pattern.compile("^(.*?)\\.(host|port)$");
private final static int DEFAULT_TV_PORT = 55000;
protected Map<String, DeviceConfig> deviceConfigCache = new HashMap<String, DeviceConfig>();
public SamsungTvBinding() {
}
@Override
public void activate() {
}
@Override
public void deactivate() {
}
/**
* @{inheritDoc
*/
@Override
protected void internalReceiveCommand(String itemName, Command command) {
if (itemName != null) {
SamsungTvBindingProvider provider = findFirstMatchingBindingProvider(itemName, command.toString());
if (provider == null) {
logger.warn("Doesn't find matching binding provider [itemName={}, command={}]", itemName, command);
return;
}
logger.debug("Received command (item='{}', state='{}', class='{}')",
new Object[] { itemName, command.toString(), command.getClass().toString() });
String tmp = provider.getTVCommand(itemName, command.toString());
String[] commandParts = tmp.split(":");
String deviceId = commandParts[0];
String cmd = commandParts[1];
logger.debug("Get connection details for device id '{}'", deviceId);
DeviceConfig tvConfig = deviceConfigCache.get(deviceId);
if (tvConfig != null) {
SamsungTvConnection remoteController = tvConfig.getConnection();
if (remoteController != null) {
remoteController.send(cmd);
}
} else {
logger.warn("Cannot find connection details for device id '{}'", deviceId);
}
}
}
/**
* Find the first matching {@link SamsungTvBindingProvider} according to
* <code>itemName</code>.
*
* @param itemName
*
* @return the matching binding provider or <code>null</code> if no binding
* provider could be found
*/
private SamsungTvBindingProvider findFirstMatchingBindingProvider(String itemName, String command) {
SamsungTvBindingProvider firstMatchingProvider = null;
for (SamsungTvBindingProvider provider : this.providers) {
String tmp = provider.getTVCommand(itemName, command.toString());
if (tmp != null) {
firstMatchingProvider = provider;
break;
}
}
return firstMatchingProvider;
}
/**
* @{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_TV_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 = deviceConfigCache.get(deviceId);
if (deviceConfig == null) {
deviceConfig = new DeviceConfig(deviceId);
deviceConfigCache.put(deviceId, deviceConfig);
}
String configKey = matcher.group(2);
String value = (String) config.get(key);
if ("host".equals(configKey)) {
deviceConfig.host = value;
} else if ("port".equals(configKey)) {
deviceConfig.port = 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_TV_PORT;
SamsungTvConnection connection = null;
String deviceId;
public DeviceConfig(String deviceId) {
this.deviceId = deviceId;
}
@Override
public String toString() {
return "Device [id=" + deviceId + ", host=" + host + ", port=" + port + "]";
}
SamsungTvConnection getConnection() {
if (connection == null) {
connection = new SamsungTvConnection(host, port);
}
return connection;
}
}
}