/** * 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.vdr.internal; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.hampelratte.svdrp.commands.CHAN; import org.hampelratte.svdrp.commands.HITK; import org.hampelratte.svdrp.commands.MESG; import org.hampelratte.svdrp.commands.VOLU; import org.openhab.binding.vdr.VDRBindingProvider; import org.openhab.binding.vdr.VDRCommandType; 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; /** * The VDR binding connects to a VDR on the svdr port. The following features * are implemented * * - Show message on OSD - power off - channel up / down - volume up / down - is * recoding * * @author Wolfgang Willinghoefer * @since 0.9.0 */ public class VDRBinding extends AbstractBinding<VDRBindingProvider> implements ManagedService { private static final Logger logger = LoggerFactory.getLogger(VDRBinding.class); /** RegEx to validate a vdr config <code>'^(.*?)\\.(host|port)$'</code> */ private static final Pattern EXTRACT_VDR_CONFIG_PATTERN = Pattern.compile("^(.*?)\\.(host|port)$"); protected Map<String, VDRConfig> vdrConfigCache = new HashMap<String, VDRConfig>(); @Override public void activate() { } @Override public void deactivate() { } /** * @{inheritDoc */ @Override public void internalReceiveCommand(String itemName, Command command) { VDRBindingProvider provider = findFirstMatchingBindingProvider(itemName); if (provider == null) { logger.warn("cannot find matching binding provider [itemName={}, command={}]", itemName, command); return; } List<String> vdrCommands = provider.getVDRCommand(itemName); List<String> ids = provider.getVDRId(itemName); if (ids != null) { int i = 0; for (String vdrId : ids) { String vdrCommand = vdrCommands.get(i); VDRCommandType vdrCmdType = VDRCommandType.create(vdrCommand, command); if (vdrCmdType != null) { executeCommand(vdrId, vdrCmdType, command); } else { logger.error("wrong command type for binding [vdrId={}, command={}]", itemName, command); } i++; } } } private void executeCommand(String vdrId, VDRCommandType vdrCommandType, Command command) { VDRConnection connection = getVDRConnection(vdrId); if (connection != null && vdrCommandType != null) { switch (vdrCommandType) { case MESSAGE: connection.send(new MESG(command.toString())); break; case POWEROFF: connection.send(new HITK("Power")); break; case CHANNEL_UP: connection.send(new CHAN("+")); break; case CHANNEL_DOWN: connection.send(new CHAN("-")); break; case CHANNEL: connection.send(new CHAN(command.toString())); break; case VOLUME_UP: connection.send(new VOLU("+")); break; case VOLUME_DOWN: connection.send(new VOLU("-")); break; case VOLUME: connection.send(new VOLU(command.toString())); break; } } } private VDRConnection getVDRConnection(String vdrId) { VDRConfig vdrConfig = vdrConfigCache.get(vdrId); if (vdrConfig != null) { return vdrConfig.getVDRConnection(); } return null; } /** * Find the first matching {@link VDRBindingProvider} according to * <code>itemName</code> * * @param itemName * * @return the matching binding provider or <code>null</code> if no binding * provider could be found */ private VDRBindingProvider findFirstMatchingBindingProvider(String itemName) { VDRBindingProvider firstMatchingProvider = null; for (VDRBindingProvider provider : this.providers) { List<String> vdrIds = provider.getVDRId(itemName); if (vdrIds != null && vdrIds.size() > 0) { firstMatchingProvider = provider; break; } } return firstMatchingProvider; } /** * Find the first matching {@link VDRBindingProvider} according to * <code>itemName</code> and <code>command</code>. * * @param itemName * @param command * * @return the matching binding provider or <code>null</code> if no binding * provider could be found */ protected VDRBindingProvider findFirstMatchingBindingProviderByVDRId(String vdrId) { VDRBindingProvider firstMatchingProvider = null; for (VDRBindingProvider provider : this.providers) { String bindingItemName = provider.getBindingItemName(vdrId, VDRCommandType.MESSAGE); if (bindingItemName != null) { firstMatchingProvider = provider; break; } } return firstMatchingProvider; } protected void addBindingProvider(VDRBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(VDRBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } @Override @SuppressWarnings("rawtypes") public void updated(Dictionary config) throws ConfigurationException { if (config != null) { Enumeration keys = config.keys(); while (keys.hasMoreElements()) { String key = (String) 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_VDR_CONFIG_PATTERN.matcher(key); if (!matcher.matches()) { logger.debug("given vdr-config-key '" + key + "' does not follow the expected pattern '<vdrId>.<host|port>'"); continue; } matcher.reset(); matcher.find(); String playerId = matcher.group(1); VDRConfig playerConfig = vdrConfigCache.get(playerId); if (playerConfig == null) { playerConfig = new VDRConfig(playerId); vdrConfigCache.put(playerId, playerConfig); } String configKey = matcher.group(2); String value = (String) config.get(key); if ("host".equals(configKey)) { playerConfig.host = value; } else if ("port".equals(configKey)) { playerConfig.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 VDR * (there could be several) * * @author Wolfgang Willinghoefer */ static class VDRConfig { String host; int port; VDRConnection vdrConnection = null; String vdrId; public VDRConfig(String pVDRId) { vdrId = pVDRId; } @Override public String toString() { return "VDR [id=" + vdrId + ", host=" + host + ", port=" + port + "]"; } VDRConnection getVDRConnection() { if (vdrConnection == null) { vdrConnection = new VDRConnection(host, port); } return vdrConnection; } } }