/** * 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.sallegra.internal; import java.util.Collection; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.openhab.binding.sallegra.SallegraBindingProvider; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.StringType; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.osgi.framework.BundleContext; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implement this class if you are going create an actively polling service like querying a Website/Device. * * @author Benjamin Marty (Developed on behalf of Satelco.ch) * @since 1.8.0 */ public class SallegraBinding extends AbstractActiveBinding<SallegraBindingProvider>implements ManagedService { private static final Logger logger = LoggerFactory.getLogger(SallegraBinding.class); private HashMap<String, SallegraNode> sallegraNodes = new HashMap<String, SallegraNode>(); /** * The BundleContext. This is only valid when the bundle is ACTIVE. It is set in the activate() method and must not * be accessed anymore once the deactivate() method was called or before activate() was called. */ public BundleContext bundleContext; /** * the refresh interval which is used to poll values from the Sallegra server (optional, defaults to 60000ms) */ private long refreshInterval = 1000; public SallegraBinding() { } /** * {@inheritDoc} */ public void activate(final BundleContext bundleContext, final Map<String, Object> configuration) { this.bundleContext = bundleContext; logger.debug("Binding started!"); // read further config parameters here ... setProperlyConfigured(true); } /** * {@inheritDoc} */ public void modified(final Map<String, Object> configuration) { // update the internal configuration accordingly } /** * @{inheritDoc */ public void deactivate(final int reason) { this.bundleContext = null; // deallocate resources here that are no longer needed and // should be reset when activating this binding again } /** * @{inheritDoc */ @Override protected long getRefreshInterval() { return refreshInterval; } /** * @{inheritDoc */ @Override protected String getName() { return "Sallegra Refresh Service"; } /** * @{inheritDoc */ @Override protected void execute() { for (SallegraBindingProvider provider : providers) { Collection<String> names = provider.getItemNames(); for (String name : names) { logger.debug("Name {}", name); SallegraBindingConfig bindingConfig = provider.getBindingConfigFor(name); String deviceId = bindingConfig.getModuleName(); /* * check if a device with this id is already configured */ if (sallegraNodes.containsKey(deviceId)) { SallegraNode node = sallegraNodes.get(deviceId); /* * yes, there is a device with this id, now update it */ String value = null; switch (bindingConfig.getCmdId()) { case RELAY: value = node.getRelay(bindingConfig.getCmdValue()); break; case DIMMER: value = node.getDimmer(bindingConfig.getCmdValue()); break; case INPUT: value = node.getInput(bindingConfig.getCmdValue()); break; } // If a value is got returned update it in openhab if (value != null) { postUpdate(provider, bindingConfig, value); } } else { logger.error("Unknown deviceId \"{}\"", deviceId); } } } } /** * @{inheritDoc */ @Override protected void internalReceiveCommand(String itemName, Command command) { // the code being executed when a command 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("internalReceiveCommand({},{}) is called!", itemName, command); /* * do we have a binding for this item at all? */ if (providesBindingFor(itemName)) { /* * go through all the providers and look for a BindingConfig */ for (SallegraBindingProvider provider : providers) { SallegraBindingConfig bindingConfig = provider.getBindingConfigFor(itemName); if (bindingConfig != null) { /* * Found one */ SallegraNode node = sallegraNodes.get(bindingConfig.getModuleName()); if (node == null) { logger.error("Invalid deviceId {}", bindingConfig.getModuleName()); } switch (bindingConfig.getCmdId()) { case RELAY: node.setRelay(command, bindingConfig.getCmdValue()); break; case DIMMER: node.setDimmer(command, bindingConfig.getCmdValue()); break; case INPUT: logger.error("You can't set anything on the Sallegra Input Module"); break; default: logger.error("Unknown cmdId \"{}\"", bindingConfig.getCmdId()); } } } } else { logger.trace("No provider found for this item"); } } /** * @{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!", itemName, newState); } protected void addBindingProvider(SallegraBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(SallegraBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } /** * {@inheritDoc} */ @Override public void updated(Dictionary<String, ?> config) throws ConfigurationException { if (config != null) { String refreshIntervalString = (String) config.get("refresh"); if (StringUtils.isNotBlank(refreshIntervalString)) { refreshInterval = Long.parseLong(refreshIntervalString); } Enumeration<String> keys = config.keys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); // Escape of dot absolutely necessary String[] keyElements = key.split("\\."); String deviceId = keyElements[0]; if (keyElements.length >= 2) { SallegraNode node = sallegraNodes.get(deviceId); if (node == null) { node = new SallegraNode(); sallegraNodes.put(deviceId, node); } String option = keyElements[1]; if (option.equals("password")) { node.setPassword((String) config.get(key)); } else if (option.equals("hostname")) { node.setHostName((String) config.get(key)); } } } setProperlyConfigured(checkProperlyConfigured()); } } /** * Used to update Status of Items */ private void postUpdate(SallegraBindingProvider provider, SallegraBindingConfig string, final String value) { switch (string.getCmdId()) { case RELAY: eventPublisher.postUpdate(string.getItem(), OnOffType.valueOf(value)); break; case DIMMER: eventPublisher.postUpdate(string.getItem(), PercentType.valueOf(value)); break; case INPUT: eventPublisher.postUpdate(string.getItem(), StringType.valueOf(value)); break; } } private boolean checkProperlyConfigured() { for (SallegraNode node : this.sallegraNodes.values()) { if (!node.properlyConfigured()) { return false; } } return true; } }