org.openhab.binding.iec6205621meter.internal.Iec6205621MeterBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.iec6205621meter.internal.Iec6205621MeterBinding.java

Source

/**
 * Copyright (c) 2010-2015, openHAB.org and others.
 *
 * 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.iec6205621meter.internal;

import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.openhab.binding.iec6205621meter.Iec6205621MeterBindingProvider;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.items.Item;
import org.openhab.core.library.items.NumberItem;
import org.openhab.core.library.items.StringItem;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openmuc.j62056.DataSet;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * iec 62056-21 meter binding implementation
 * 
 * @author Peter Kreutzer
 * @author Gnter Speckhofer
 * @since 1.5.0
 */
public class Iec6205621MeterBinding extends AbstractActiveBinding<Iec6205621MeterBindingProvider>
        implements ManagedService {

    private static final Logger logger = LoggerFactory.getLogger(Iec6205621MeterBinding.class);

    // regEx to validate a meter config
    // <code>'^(.*?)\\.(serialPort|baudRateChangeDelay|echoHandling)$'</code>
    private final Pattern METER_CONFIG_PATTERN = Pattern
            .compile("^(.*?)\\.(serialPort|baudRateChangeDelay|echoHandling)$");

    private static final long DEFAULT_REFRESH_INTERVAL = 60000;

    /**
     * the refresh interval which is used to poll values from the IEC 62056-21 Meter
     * server (optional, defaults to 10 minutes)
     */
    private long refreshInterval = DEFAULT_REFRESH_INTERVAL;

    // configured meter devices - keyed by meter device name
    private final Map<String, Meter> meterDeviceConfigurtions = new HashMap<String, Meter>();

    public Iec6205621MeterBinding() {
    }

    public void activate() {

    }

    public void deactivate() {
        meterDeviceConfigurtions.clear();
    }

    /**
     * @{inheritDoc
     */
    @Override
    protected long getRefreshInterval() {
        return refreshInterval;
    }

    /**
     * @{inheritDoc
     */
    @Override
    protected String getName() {
        return "iec6205621meter Refresh Service";
    }

    private final Meter createIec6205621MeterConfig(String name, MeterConfig config) {

        Meter reader = null;
        reader = new Meter(name, config);
        return reader;
    }

    /**
     * @{inheritDoc
     */
    @Override
    protected void execute() {
        // the frequently executed code (polling) goes here ...
        Map<String, Map<String, DataSet>> cache = new HashMap<String, Map<String, DataSet>>();
        for (Iec6205621MeterBindingProvider provider : providers) {

            for (String itemName : provider.getItemNames()) {
                for (Entry<String, Meter> entry : meterDeviceConfigurtions.entrySet()) {
                    Meter reader = entry.getValue();
                    String meterName = provider.getMeterName(itemName);
                    if (meterName != null && meterName.equals(entry.getKey())) {
                        Map<String, DataSet> dataSets;
                        if ((dataSets = cache.get(meterName)) == null) {
                            if (logger.isDebugEnabled())
                                logger.debug(
                                        "Read meter: " + meterName + "; " + reader.getConfig().getSerialPort());
                            dataSets = reader.read();
                            cache.put(meterName, dataSets);
                        }
                        String obis = provider.getObis(itemName);
                        if (obis != null && dataSets.containsKey(obis)) {
                            DataSet dataSet = dataSets.get(obis);
                            if (logger.isDebugEnabled())
                                logger.debug("Updateing item " + itemName + " with OBIS code " + obis
                                        + " and value " + dataSet.getValue());
                            Class<? extends Item> itemType = provider.getItemType(itemName);
                            if (itemType.isAssignableFrom(NumberItem.class)) {
                                eventPublisher.postUpdate(itemName, new DecimalType(dataSet.getValue()));
                            }
                            if (itemType.isAssignableFrom(StringItem.class)) {
                                String value = dataSet.getValue();
                                eventPublisher.postUpdate(itemName, new StringType(value));
                            }
                        }
                    }
                }
            }

        }
    }

    /**
     * @{inheritDoc
     */
    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!");
    }

    /**
     * @{inheritDoc
     */
    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("internalReceiveCommand() is called!");
    }

    /**
     * @{inheritDoc
     */
    @Override
    public void updated(Dictionary<String, ?> config) throws ConfigurationException {

        if (config == null || config.isEmpty()) {
            logger.warn("Empty or null configuration. Ignoring.");
            return;
        }

        Set<String> names = getNames(config);

        for (String name : names) {

            String value = (String) config.get(name + ".serialPort");
            String serialPort = value != null ? value : MeterConfig.DEFAULT_SERIAL_PORT;

            value = (String) config.get(name + ".baudRateChangeDelay");
            int baudRateChangeDelay = value != null ? Integer.valueOf(value)
                    : MeterConfig.DEFAULT_BAUD_RATE_CHANGE_DELAY;

            value = (String) config.get(name + ".echoHandling");
            boolean echoHandling = value != null ? Boolean.valueOf(value) : MeterConfig.DEFAULT_ECHO_HANDLING;

            Meter meterConfig = createIec6205621MeterConfig(name,
                    new MeterConfig(serialPort, baudRateChangeDelay, echoHandling));

            if (meterDeviceConfigurtions.put(meterConfig.getName(), meterConfig) != null) {
                logger.info("Recreated reader {} with  {}!", meterConfig.getName(), meterConfig.getConfig());
            } else {
                logger.info("Created reader {} with  {}!", meterConfig.getName(), meterConfig.getConfig());
            }
        }

        if (config != null) {
            // to override the default refresh interval one has to add a
            // parameter to openhab.cfg like
            // <bindingName>:refresh=<intervalInMs>
            if (StringUtils.isNotBlank((String) config.get("refresh"))) {
                refreshInterval = Long.parseLong((String) config.get("refresh"));
            }
            setProperlyConfigured(true);
        }
    }

    /**
     * Analyze configuration to get meter names
     * 
     * @return set of String of meter names
     */
    private Set<String> getNames(Dictionary<String, ?> config) {
        Set<String> set = new HashSet<String>();

        Enumeration<String> 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) || "refresh".equals(key)) {
                continue;
            }

            Matcher meterMatcher = METER_CONFIG_PATTERN.matcher(key);

            if (!meterMatcher.matches()) {
                logger.debug("given config key '" + key
                        + "' does not follow the expected pattern '<meterName>.<serialPort|baudRateChangeDelay|echoHandling>'");
                continue;
            }

            meterMatcher.reset();
            meterMatcher.find();

            set.add(meterMatcher.group(1));
        }
        return set;
    }

}