/** * 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.bticino.internal; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.openhab.binding.bticino.internal.BticinoGenericBindingProvider.BticinoBindingConfig; import org.openhab.core.binding.AbstractBinding; import org.openhab.core.events.EventPublisher; 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; /** * This class implements a binding of bticino devices to openHAB. The binding * configurations are provided by the {@link GenericItemProvider}. * * @author Tom De Vlaminck * @serial 1.0 * @since 1.7.0 */ public class BticinoBinding extends AbstractBinding<BticinoBindingProvider> implements ManagedService { private static final Logger logger = LoggerFactory.getLogger(BticinoBinding.class); /** * RegEx to validate a bticino gateway config * <code>'^(.*?)\\.(host|port)$'</code> */ private static final Pattern EXTRACT_BTICINO_GATEWAY_CONFIG_PATTERN = Pattern .compile("^(.*?)\\.(host|port|rescan_secs)$"); // indicates that the updated has been run once boolean m_binding_initialized = false; private EventPublisher eventPublisher = null; // (interfaceid, deviceconfig) private Map<String, BticinoConfig> m_bticino_devices_config = new HashMap<String, BticinoConfig>(); // (interfaceid, device) private Map<String, BticinoDevice> m_bticino_devices = new HashMap<String, BticinoDevice>(); static class BticinoConfig { String id; String host; // Default port is 20000 for a MH200 int port = 20000; // Default rescan interval is 300 seconds int rescan_secs = 300; @Override public String toString() { return "Bticino [id=" + id + ", host=" + host + ", port=" + port + ", rescan secs=" + rescan_secs + "]"; } } @Override public void setEventPublisher(EventPublisher eventPublisher) { this.eventPublisher = eventPublisher; for (BticinoDevice bticinodevice : m_bticino_devices.values()) { bticinodevice.setEventPublisher(eventPublisher); } } @Override public void unsetEventPublisher(EventPublisher eventPublisher) { this.eventPublisher = null; for (BticinoDevice bticinodevice : m_bticino_devices.values()) { bticinodevice.setEventPublisher(null); } } /** * For the given item, get the bticino binding configuration * * @param itemName * @return * @throws Exception */ public BticinoBindingConfig getBticinoBindingConfigForItem(String itemName) { // Get the bticino binding config for the associated item BticinoBindingConfig l_item_binding = null; for (BticinoBindingProvider provider : providers) { if (provider.providesBindingFor(itemName)) { l_item_binding = provider.getConfig(itemName); break; } } // the item must have a config if (l_item_binding == null) { throw new RuntimeException("BindingConfig not found for item [" + itemName + "]"); } return l_item_binding; } /** * Returns the BticinoBindingConfig(s) associated with the who / where * config * * @param who * @param where * @return */ public List<BticinoBindingConfig> getItemForBticinoBindingConfig(String who, String where) { // Find all the bindings for the who-where combination (multiple // possible) List<BticinoBindingConfig> l_item_bindings = new LinkedList<BticinoBindingConfig>(); // Get all the bticino providers for (BticinoBindingProvider provider : providers) { // Get all the items it provides binding for for (String l_item_name : provider.getItemNames()) { // Check if this config item provides binding for the given // who/where BticinoBindingConfig l_binding_config = provider.getConfig(l_item_name); if (l_binding_config.who.equals(who) && l_binding_config.where.equals(where)) { // Add it to the list l_item_bindings.add(l_binding_config); } } } return l_item_bindings; } /** * {@inheritDoc} */ @Override public void internalReceiveCommand(String itemName, Command command) { super.internalReceiveCommand(itemName, command); // Get the bticino interface id from the itemconfig BticinoBindingConfig l_item_binding = getBticinoBindingConfigForItem(itemName); // Get the interface from the item config String l_interface_id = l_item_binding.gatewayID; // Get the bticino device from the map (if it exists) if (m_bticino_devices.containsKey(l_interface_id)) { BticinoDevice l_bticino_device = m_bticino_devices.get(l_interface_id); l_bticino_device.receiveCommand(itemName, command, l_item_binding); } else { // just to know that something is wrong logger.error("Item [" + itemName + "] uses Bticino interface with ID [" + l_interface_id + "] but this gateway doesn't exist : check items.cfg and openhab.cfg!"); } } protected void addBindingProvider(BticinoBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(BticinoBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } /** * {@inheritDoc} */ public void updated(Dictionary<String, ?> properties) throws ConfigurationException { if (!m_binding_initialized) { // remove all configs m_bticino_devices_config.clear(); // remove all interfaces m_bticino_devices.clear(); // We will read every configuration key, and encounter // hostname, port for the configured bticino gateways Enumeration<String> keys = properties.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_BTICINO_GATEWAY_CONFIG_PATTERN.matcher(key); if (!matcher.matches()) { logger.debug("given bticino gateway-config-key '" + key + "' does not follow the expected pattern '<gateway_name>.<host|port>'"); continue; } matcher.reset(); matcher.find(); // Get the interface id String l_gw_if_id = matcher.group(1); // Search the config, to update the values (row / row) BticinoConfig l_bticino_config = m_bticino_devices_config.get(l_gw_if_id); // Create a new config if it wasnt found now if (l_bticino_config == null) { l_bticino_config = new BticinoConfig(); // set the id l_bticino_config.id = l_gw_if_id; // add (if_id, bticino config) entry m_bticino_devices_config.put(l_gw_if_id, l_bticino_config); } String configKey = matcher.group(2); String value = Objects.toString(properties.get(key), null); // parameter host if ("host".equals(configKey)) { l_bticino_config.host = value; } // parameter port else if ("port".equals(configKey)) { l_bticino_config.port = Integer.valueOf(value); } else if ("rescan_secs".equals(configKey)) { l_bticino_config.rescan_secs = Integer.valueOf(value); } else { throw new ConfigurationException(configKey, "the given configKey '" + configKey + "' with value '" + value + "' is unknown"); } } // Now for all the bticino gateways configured in the configuration, // connect to the physical gateways connectAllBticinoDevices(); // Now start all the bticino gateways startAllBticinoDevices(); // Indicate that this binding has been initialized m_binding_initialized = true; } } private void connectAllBticinoDevices() throws ConfigurationException { for (String l_gw_if_id : m_bticino_devices_config.keySet()) { BticinoConfig l_current_device_config = m_bticino_devices_config.get(l_gw_if_id); // Create a gw service object BticinoDevice l_bticino_device = new BticinoDevice(l_current_device_config.id, this); l_bticino_device.setEventPublisher(eventPublisher); l_bticino_device.setHost(l_current_device_config.host); l_bticino_device.setPort(l_current_device_config.port); l_bticino_device.setRescanInterval(l_current_device_config.rescan_secs); try { l_bticino_device.initialize(); } catch (InitializationException e) { throw new ConfigurationException(l_gw_if_id, "Could not open create BTicino interface with ID [" + l_gw_if_id + "], Exception : " + e.getMessage()); } catch (Throwable e) { throw new ConfigurationException(l_gw_if_id, "Could not open create BTicino interface with ID [" + l_gw_if_id + "], Exception : " + e.getMessage()); } m_bticino_devices.put(l_gw_if_id, l_bticino_device); } } private void startAllBticinoDevices() throws ConfigurationException { for (String l_gw_if_id : m_bticino_devices.keySet()) { BticinoDevice l_bticino_device = m_bticino_devices.get(l_gw_if_id); l_bticino_device.startDevice(); } } }