org.openhab.binding.zigbee.internal.ZigbeeActiveBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.zigbee.internal.ZigbeeActiveBinding.java

Source

/**
 * Copyright (c) 2010-2014, 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.zigbee.internal;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.openhab.binding.zigbee.ZigbeeBindingConfig;
import org.openhab.binding.zigbee.ZigbeeBindingProvider;
import org.openhab.binding.zigbee.internal.config.ZigbeeConfiguration;
import org.openhab.binding.zigbee.internal.converter.ZigbeeConverterHandler;
import org.openhab.binding.zigbee.internal.protocol.SerialInterfaceException;
import org.openhab.binding.zigbee.internal.protocol.ZigbeeController;
import org.openhab.binding.zigbee.internal.protocol.ZigbeeEventListener;
import org.openhab.binding.zigbee.internal.protocol.event.ZigbeeCommandClassValueEvent;
import org.openhab.binding.zigbee.internal.protocol.event.ZigbeeEvent;
import org.openhab.binding.zigbee.internal.protocol.event.ZigbeeInitializationCompletedEvent;
import org.openhab.binding.zigbee.internal.protocol.event.ZigbeeTransactionCompletedEvent;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.binding.BindingProvider;
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;

/**
 * ZigbeeActiveBinding Class. Polls Zigbee nodes frequently,
 * responds to item commands, and also handles events coming 
 * from the Zigbee controller.
 * @author Victor Belov
 * @author Brian Crosby
 * @author Jan-Willem Spuij
 * @author Chris Jackson
 * @since 1.3.0
 */
public class ZigbeeActiveBinding extends AbstractActiveBinding<ZigbeeBindingProvider>
        implements ManagedService, ZigbeeEventListener {
    /**
     * The refresh interval which is used to poll values from the Zigbee binding. 
     */
    private long refreshInterval = 5000;

    private int pollingQueue = 1;

    private static final Logger logger = LoggerFactory.getLogger(ZigbeeActiveBinding.class);
    private String port;
    private String ipAddress;
    private boolean isSUC = false;
    private Integer healtime = null;
    private Integer timeout = null;
    private volatile ZigbeeController zController;
    private volatile ZigbeeConverterHandler converterHandler;

    private boolean isZigbeeNetworkReady = false;
    private boolean isZigbeeDevicesAllReady = false;

    private Iterator<ZigbeePollItem> pollingIterator = null;
    private List<ZigbeePollItem> pollingList = new ArrayList<ZigbeePollItem>();

    private Integer refresh_index = 0;
    private Integer REFRESH_MAX = 86400; //one day=60s*60*24

    // Configuration Service
    ZigbeeConfiguration zConfigurationService;

    // Network monitoring class
    ZigbeeNetworkMonitor networkMonitor;

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

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

    /**
     * Working method that executes refreshing of the bound items. The method is executed
     * at every refresh interval. The nodes are polled only every 6 refreshes.
     */
    @Override
    protected void execute() {
        //System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE: execute()");
        /*   if(!isZigbeeNetworkReady){
              logger.debug("Zigbee Network isn't ready yet!");
              if (this.zController != null)
        this.zController.checkForDeadOrSleepingNodes(providers);
              return;
           }*/

        // Call the network monitor
        ////networkMonitor.execute();
        logger.info("pollingList size: " + pollingList.size());
        // If we're not currently in a poll cycle, restart the polling table
        if (pollingIterator == null) {
            pollingIterator = pollingList.iterator();
        }

        // Loop through the polling list. We only allow a certain number of messages
        // into the send queue at a time to avoid congestion within the system.
        // Basically, we don't want the polling to slow down 'important' stuff.
        // The queue ensures all nodes get a chance - if we always started at the top
        // then the last items might never get polled.

        while (pollingIterator.hasNext()) {
            /*   if(zController.getSendQueueLength() >= pollingQueue) {
                  logger.trace("Polling queue full!");
                  break;
               }*/
            ZigbeePollItem poll = pollingIterator.next();
            logger.info("polling item: " + poll.item);
            logger.info("poll.provider: " + poll.provider);
            if (converterHandler == null)
                logger.info("converterHandler==null");

            //check polling item to poll
            ZigbeeBindingConfig bindingConfiguration = poll.provider.getZigbeeBindingConfig(poll.item);

            Integer refresh_interval = bindingConfiguration.getRefreshInterval();

            if (refresh_index % refresh_interval != 0) {
                continue;
            }
            logger.info("ZigbeeConverterHandler.executeRefresh()");
            converterHandler.executeRefresh(poll.provider, poll.item, false);
        }
        if (pollingIterator.hasNext() == false) {
            pollingIterator = null;
        }

        if (refresh_index == REFRESH_MAX - 1) {
            refresh_index = 0;
        } else {
            refresh_index += 1;
        }
    }

    /**
     * Called, if a single binding has changed. The given item could have been
     * added or removed. We refresh the binding in case it's in the done stage.
     * 
     * @param provider the binding provider where the binding has changed
     * @param itemName the item name for which the binding has changed
     */
    @Override
    public void bindingChanged(BindingProvider provider, String itemName) {
        logger.trace("bindingChanged {}", itemName);

        ZigbeeBindingProvider zProvider = (ZigbeeBindingProvider) provider;

        if (zProvider != null) {
            ZigbeeBindingConfig bindingConfig = zProvider.getZigbeeBindingConfig(itemName);

            if (bindingConfig != null && converterHandler != null) {
                converterHandler.executeRefresh(zProvider, itemName, true);
            }
        }

        // Bindings have changed - rebuild the polling table
        rebuildPollingTable();

        super.bindingChanged(provider, itemName);
    }

    /**
     * {@inheritDoc}
     */
    public void allBindingsChanged(BindingProvider provider) {
        logger.trace("allBindingsChanged");
        super.allBindingsChanged(provider);

        // Bindings have changed - rebuild the polling table
        rebuildPollingTable();
    }

    /**
     * This method rebuilds the polling table. The polling table is a list of items that have
     * polling enabled (ie a refresh interval is set). This list is then checked periodically
     * and any item that has passed its polling interval will be polled.
     */
    private void rebuildPollingTable() {
        // Rebuild the polling table
        pollingList.clear();

        // Loop all binding providers for the Z-wave binding.
        for (ZigbeeBindingProvider eachProvider : providers) {
            // loop all bound items for this provider
            for (String name : eachProvider.getItemNames()) {

                //            ZigbeePollItem item = new ZigbeePollItem();
                //            item.item = name;
                //            item.provider = eachProvider;
                //            pollingList.add(item);

                logger.trace("Polling list: Checking {} == {}", name,
                        converterHandler.getRefreshInterval(eachProvider, name));

                // This binding is configured to poll - add it to the list
                if (converterHandler.getRefreshInterval(eachProvider, name) > 0) {
                    ZigbeePollItem item = new ZigbeePollItem();
                    item.item = name;
                    item.provider = eachProvider;
                    pollingList.add(item);
                    logger.info("Polling list added {}", name);
                }
            }
        }
        pollingIterator = null;
    }

    /**
     * Handles a command update by sending the appropriate Zigbee instructions
     * to the controller.
     * {@inheritDoc}
     */
    @Override
    protected void internalReceiveCommand(String itemName, Command command) {
        boolean handled = false;
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE:" + itemName.toString());
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE:" + this.isProperlyConfigured());
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE:" + isZigbeeNetworkReady);
        // if we are not yet initialized, don't waste time and return
        if ((this.isProperlyConfigured() == false) | (isZigbeeNetworkReady == false)) {
            logger.debug(
                    "internalReceiveCommand Called, But Not Properly Configure yet or Zigbee Network Isn't Ready, returning.");
            return;
        }

        logger.trace("internalReceiveCommand(itemname = {}, Command = {})", itemName, command.toString());
        for (ZigbeeBindingProvider provider : providers) {

            if (!provider.providesBindingFor(itemName))
                continue;

            converterHandler.receiveCommand(provider, itemName, command);
            handled = true;
        }

        if (!handled)
            logger.warn("No converter found for item = {}, command = {}, ignoring.", itemName, command.toString());
    }

    /**
     * Activates the binding. Actually does nothing, because on activation
     * OpenHAB always calls updated to indicate that the config is updated.
     * Activation is done there.
     */
    @Override
    public void activate() {

    }

    /**
     * Deactivates the binding. The Controller is stopped and the serial interface
     * is closed as well.
     */
    @Override
    public void deactivate() {
        isZigbeeNetworkReady = false;
        if (this.converterHandler != null) {
            this.converterHandler = null;
        }

        if (this.zConfigurationService != null) {
            this.zController.removeEventListener(this.zConfigurationService);
            this.zConfigurationService = null;
        }

        ZigbeeController controller = this.zController;
        if (controller != null) {
            this.zController = null;
            controller.close();
            controller.removeEventListener(this);
        }
    }

    /**
     * Initialises the binding. This is called after the 'updated' method
     * has been called and all configuration has been passed.
     * @throws ConfigurationException 
     */
    private void initialise() throws ConfigurationException {
        try {
            this.setProperlyConfigured(true);
            this.deactivate();
            //isZigbeeNetworkReady = true;
            this.zController = new ZigbeeController(isSUC, port, timeout);
            this.converterHandler = new ZigbeeConverterHandler(this.zController, this.eventPublisher);
            zController.initialize();
            zController.addEventListener(this);
            System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE:" + port);
            // The network monitor service needs to know the controller...
            this.networkMonitor = new ZigbeeNetworkMonitor(this.zController);
            if (healtime != null)
                this.networkMonitor.setHealTime(healtime);

            // The config service needs to know the controller and the network monitor...
            this.zConfigurationService = new ZigbeeConfiguration(this.zController, this.networkMonitor);
            zController.addEventListener(this.zConfigurationService);

            if (zController.isZigbeeNetowrkStarted())
                isZigbeeNetworkReady = true;

            rebuildPollingTable();
            return;
        } catch (SerialInterfaceException ex) {
            this.setProperlyConfigured(false);
            throw new ConfigurationException("ipAddress", ex.getLocalizedMessage(), ex);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void updated(Dictionary<String, ?> config) throws ConfigurationException {
        if (config == null)
            return;
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE:" + config.toString());
        // Check the serial port configuration value.
        // This value is mandatory.
        if (StringUtils.isNotBlank((String) config.get("port"))) {
            port = (String) config.get("port");
            logger.info("Update config, port = {}", port);
        }
        if (StringUtils.isNotBlank((String) config.get("ip"))) {
            ipAddress = (String) config.get("ip");
            logger.info("Update config, ipAddress = {}", ipAddress);
        }
        if (StringUtils.isNotBlank((String) config.get("healtime"))) {
            try {
                healtime = Integer.parseInt((String) config.get("healtime"));
                logger.info("Update config, healtime = {}", healtime);
            } catch (NumberFormatException e) {
                healtime = null;
                logger.error(
                        "Error parsing 'healtime'. This must be a single number to set the hour to perform the heal.");
            }
        }
        if (StringUtils.isNotBlank((String) config.get("refreshInterval"))) {
            try {
                refreshInterval = Integer.parseInt((String) config.get("refreshInterval"));
                logger.info("Update config, refreshInterval = {}", refreshInterval);
            } catch (NumberFormatException e) {
                refreshInterval = 10000;
                logger.error("Error parsing 'refreshInterval'. This must be a single number time in milliseconds.");
            }
        }
        if (StringUtils.isNotBlank((String) config.get("pollingQueue"))) {
            try {
                pollingQueue = Integer.parseInt((String) config.get("pollingQueue"));
                logger.info("Update config, pollingQueue = {}", pollingQueue);
            } catch (NumberFormatException e) {
                pollingQueue = 2;
                logger.error("Error parsing 'pollingQueue'. This must be a single number time in milliseconds.");
            }
        }
        if (StringUtils.isNotBlank((String) config.get("timeout"))) {
            try {
                timeout = Integer.parseInt((String) config.get("timeout"));
                logger.info("Update config, timeout = {}", timeout);
            } catch (NumberFormatException e) {
                timeout = null;
                logger.error("Error parsing 'timeout'. This must be an Integer.");
            }
        }
        if (StringUtils.isNotBlank((String) config.get("setSUC"))) {
            try {
                isSUC = Boolean.parseBoolean((String) config.get("setSUC"));
                logger.info("Update config, setSUC = {}", isSUC);
            } catch (NumberFormatException e) {
                isSUC = false;
                logger.error("Error parsing 'setSUC'. This must be boolean.");
            }
        }

        // Now that we've read ALL the configuration, initialise the binding.
        initialise();
    }

    /**
     * Returns the port value.
     * @return
     */
    public String getPort() {
        return port;
    }

    /**
     * Returns the ipAddress value.
     * @return
     */
    public String getIP() {
        return ipAddress;
    }

    /**
     * Event handler method for incoming Zigbee events.
     * @param event the incoming Zigbee event.
     */
    @Override
    public void ZigbeeIncomingEvent(ZigbeeEvent event) {
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE: ZigbeeIncomingEvent" + event.getClass());
        // if we are not yet initialized, don't waste time and return
        if (!this.isProperlyConfigured())
            return;
        System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE: ZigbeeIncomingEvent1");
        if (!isZigbeeNetworkReady) {
            if (event instanceof ZigbeeInitializationCompletedEvent) {
                logger.debug("ZigbeeIncomingEvent Called, Network Event, Init Done. Setting Zigbee Network Ready.");
                isZigbeeNetworkReady = true;
                System.out.println("ZIGBEEEEEEEEEEEEEEEEEEEE: ZigbeeIncomingEvent2");
                // Initialise the polling table
                rebuildPollingTable();

                return;
            }
        }

        logger.debug("ZigbeeIncomingEvent");

        // ignore transaction completed events.
        if (event instanceof ZigbeeTransactionCompletedEvent)
            return;

        // handle command class value events.
        if (event instanceof ZigbeeCommandClassValueEvent) {
            handleZigbeeCommandClassValueEvent((ZigbeeCommandClassValueEvent) event);
            return;
        }
    }

    /**
     * Handle an incoming Command class value event
     * @param event the incoming Zigbee event.
     */
    private void handleZigbeeCommandClassValueEvent(ZigbeeCommandClassValueEvent event) {
        boolean handled = false;

        logger.debug(
                "Got a value event from Zigbee network for nodeId = {}, endpoint = {}, command class = {}, value = {}",
                new Object[] { event.getNodeId(), event.getEndpoint(), event.getCommandClass().getLabel(),
                        event.getValue() });

        for (ZigbeeBindingProvider provider : providers) {
            for (String itemName : provider.getItemNames()) {
                ZigbeeBindingConfig bindingConfig = provider.getZigbeeBindingConfig(itemName);

                if (bindingConfig.getNodeId() != event.getNodeId()
                        || bindingConfig.getEndpoint() != event.getEndpoint())
                    continue;

                converterHandler.handleEvent(provider, itemName, event);
                handled = true;
            }
        }

        if (!handled)
            logger.warn(
                    "No item bound for event from nodeId = {}, endpoint = {}, command class = {}, value = {}, ignoring.",
                    new Object[] { event.getNodeId(), event.getEndpoint(), event.getCommandClass().getLabel(),
                            event.getValue() });
    }

    class ZigbeePollItem {
        ZigbeeBindingProvider provider;
        String item;
    }
}