/** * 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.ecotouch.internal; import java.math.BigDecimal; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.openhab.binding.ecotouch.EcoTouchBindingProvider; import org.openhab.binding.ecotouch.EcoTouchTags; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.library.items.NumberItem; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; 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; /** * Implement this class if you are going create an actively polling service like * querying a Website/Device. * * @author Sebastian Held <sebastian.held@gmx.de> * @since 1.5.0 */ public class EcoTouchBinding extends AbstractActiveBinding<EcoTouchBindingProvider> implements ManagedService { private static final Logger logger = LoggerFactory.getLogger(EcoTouchBinding.class); /** * the refresh interval which is used to poll values from the EcoTouch * server (optional, defaults to 60000ms) */ private long refreshInterval = 60000; private String ip; private String username; private String password; private List<String> cookies = null; // authentication information public EcoTouchBinding() { } @Override public void activate() { } @Override public void deactivate() { } /** * @{inheritDoc */ @Override protected long getRefreshInterval() { return refreshInterval; } /** * @{inheritDoc */ @Override protected String getName() { return "EcoTouch Refresh Service"; } /** * @{inheritDoc */ @Override protected void execute() { if (!bindingsExist()) { logger.debug("There is no existing EcoTouch binding configuration => refresh cycle aborted!"); return; } try { // collect all tags which are actively used in items Set<String> tags = new HashSet<String>(); for (EcoTouchBindingProvider provider : providers) { for (String tag : provider.getActiveTags()) { tags.add(tag); } } EcoTouchConnector connector = new EcoTouchConnector(ip, username, password, cookies); // collect raw values from heat pump HashMap<String, Integer> rawvalues = new HashMap<String, Integer>(); // request values (this could later be handled more efficiently // inside connector.getValues(tags)) for (String tag : tags) { try { // raw value from heat pump (needs interpretation) int rawvalue = connector.getValue(tag); rawvalues.put(tag, rawvalue); } catch (Exception e) { // the connector already logged the exception cause // let's ignore it and try the next value (intermittent // network problem?) continue; } } // post updates to event bus for (EcoTouchBindingProvider provider : providers) { for (EcoTouchTags item : provider.getActiveItems()) { if (!rawvalues.containsKey(item.getTagName())) { // could not get the value from the heat pump continue; } int heatpumpValue = rawvalues.get(item.getTagName()); State value; if (item.getType() == EcoTouchTags.Type.Analog) { // analog value encoded as a scaled integer BigDecimal decimal = new BigDecimal(heatpumpValue).divide(new BigDecimal(10)); value = new DecimalType(decimal); } else if (item.getType() == EcoTouchTags.Type.Word) { // integer if (NumberItem.class.equals(item.getItemClass())) { value = new DecimalType(heatpumpValue); } else { // assume SwitchItem if (heatpumpValue == 0) { value = OnOffType.OFF; } else { value = OnOffType.ON; } } } else { // bit field heatpumpValue >>= item.getBitNum(); heatpumpValue &= 1; if (NumberItem.class.equals(item.getItemClass())) { value = new DecimalType(heatpumpValue); } else { // assume SwitchItem if (heatpumpValue == 0) { value = OnOffType.OFF; } else { value = OnOffType.ON; } } } // now consider special cases if (item == EcoTouchTags.TYPE_ADAPT_HEATING) { double adapt = ((DecimalType) value).intValue(); adapt = Math.max(0, adapt); adapt = Math.min(8, adapt); adapt = (adapt - 4) / 2.0; value = new DecimalType(adapt); } handleEventType(value, item); } } // store authentication info cookies = connector.getCookies(); } finally { } } private void handleEventType(State state, EcoTouchTags heatpumpCommandType) { for (EcoTouchBindingProvider provider : providers) { for (String itemName : provider.getItemNamesForType(heatpumpCommandType)) { eventPublisher.postUpdate(itemName, state); } } } protected void addBindingProvider(EcoTouchBindingProvider bindingProvider) { super.addBindingProvider(bindingProvider); } protected void removeBindingProvider(EcoTouchBindingProvider bindingProvider) { super.removeBindingProvider(bindingProvider); } /** * @{inheritDoc */ @Override public void updated(Dictionary<String, ?> config) throws ConfigurationException { setProperlyConfigured(false); if (config != null) { String refreshIntervalString = Objects.toString(config.get("refresh"), null); if (StringUtils.isNotBlank(refreshIntervalString)) { refreshInterval = Long.parseLong(refreshIntervalString); } String ip = Objects.toString(config.get("ip"), null); //$NON-NLS-1$ if (StringUtils.isBlank(ip)) { throw new ConfigurationException("ip", "The ip address must not be empty."); } this.ip = ip; String username = Objects.toString(config.get("username"), null); //$NON-NLS-1$ if (StringUtils.isBlank(username)) { throw new ConfigurationException("username", "The username must not be empty."); } this.username = username; String password = Objects.toString(config.get("password"), null); //$NON-NLS-1$ if (StringUtils.isBlank(password)) { throw new ConfigurationException("password", "The password must not be empty."); } this.password = password; setProperlyConfigured(true); } } @Override protected void internalReceiveCommand(String itemName, Command command) { // find the EcoTouch binding for the itemName EcoTouchTags tag = null; for (EcoTouchBindingProvider provider : providers) { try { tag = provider.getTypeForItemName(itemName); break; } catch (Exception e) { } } // consider special cases if (tag == EcoTouchTags.TYPE_ADAPT_HEATING) { double adapt = Double.parseDouble(command.toString()); adapt = (adapt + 2) * 2; adapt = Math.max(0, adapt); adapt = Math.min(8, adapt); command = new DecimalType((int) adapt); } EcoTouchConnector connector = new EcoTouchConnector(ip, username, password, cookies); int value = 0; switch (tag.getType()) { case Analog: value = (int) (Double.parseDouble(command.toString()) * 10); break; case Word: if (command == OnOffType.ON) { value = 1; } else if (command == OnOffType.OFF) { value = 0; } else { value = Integer.parseInt(command.toString()); } break; case Bitfield: try { // read-modify-write style value = connector.getValue(tag.getTagName()); int bitmask = 1 << tag.getBitNum(); if (command == OnOffType.OFF || Integer.parseInt(command.toString()) == 0) { value = value & ~bitmask; } else { value = value | bitmask; } } catch (Exception e1) { // connector.getValue() already logged a specific debug message logger.warn("cannot send command '" + command + "' to item '" + itemName + "'"); return; } } try { connector.setValue(tag.getTagName(), value); // It does not make sense to check the returned value from // setValue(). // Even if the tag is read only, one would get the newly set value // back. } catch (Exception e) { // connector.setValue() already logged a specific debug message logger.warn("cannot send command '" + command + "' to item '" + itemName + "'"); } } }