org.openhab.binding.velux.internal.VeluxBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.velux.internal.VeluxBinding.java

Source

/**
 * Copyright (c) 2010-2019 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.velux.internal;

import static org.apache.commons.lang.StringUtils.isNotBlank;

import java.util.Dictionary;

import org.openhab.binding.velux.VeluxBindingConstants;
import org.openhab.binding.velux.VeluxBindingProvider;
import org.openhab.binding.velux.handler.VeluxBridgeHandlerOH1;
import org.openhab.binding.velux.internal.config.VeluxBridgeConfiguration;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.binding.BindingProvider;
import org.openhab.core.events.EventPublisher;
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;

/**
 * <B>Class for Velux binding which polls something and sends events frequently.</B>
 * <P>
 *
 * This binding is able to do the following tasks with the Velux KLF200 gateway:
 * <ul>
 * <LI>Startup phase:
 * <ul>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#VeluxBinding constructor}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#setEventPublisher setEventPublisher}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#addBindingProvider addBindingProvider}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#allBindingsChanged allBindingsChanged}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#getName getName}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#activate activate}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#getRefreshInterval getRefreshInterval}</li>
 * </ul>
 * </li>
 * <LI>Continuous phase:
 * <UL>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#execute execute}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#receiveCommand receiveCommand}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#internalReceiveCommand internalReceiveCommand}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#internalReceiveUpdate internalReceiveUpdate}</li>
 * </ul>
 * </li>
 * <LI>Reconfiguration phase:
 * <UL>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#updated updated}</li>
 * </ul>
 * </li>
 * <LI>Shutdown phase:
 * <UL>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#deactivate deactivate}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#unsetEventPublisher unsetEventPublisher}</li>
 * <li>{@link org.openhab.binding.velux.internal.VeluxBinding#removeBindingProvider removeBindingProvider}</li>
 * </ul>
 * </ul>
 *
 * @author Guenther Schreiner - Initial contribution
 * @since 1.13.0
 */
public class VeluxBinding extends AbstractActiveBinding<VeluxBindingProvider> implements ManagedService {
    private static Logger logger = LoggerFactory.getLogger(VeluxBinding.class);

    /**
     * The configuration parameters for accessing the Velux bridge.
     */
    private VeluxBridgeConfiguration config = null;

    /**
     * Velux binding provider will hold the related OpenHAB configuration.
     */
    private VeluxBindingProvider bindingProvider = null;

    /**
     * Velux bridge handler will provide the related interfacing information and methods.
     */
    private VeluxBridgeHandlerOH1 bridgeHandler = null;

    /**
     * Velux bridge handler will provide the related interfacing information and methods.
     */
    private int refreshCounter = 0;

    private boolean isModulo(int a, int b) {
        return ((a % b) == 0) ? true : false;
    }

    /***
     *** Startup methods
     ***/

    /**
     * Constructor
     *
     * initializes the interface towards the Velux bridge.
     */
    public VeluxBinding() {
        logger.trace("VeluxBinding(constructor) called.");
        this.config = new VeluxBridgeConfiguration();
        this.bridgeHandler = new VeluxBridgeHandlerOH1(config);
        logger.trace("VeluxBinding(constructor) done.");
    }

    @Override
    public void setEventPublisher(EventPublisher eventPublisher) {
        logger.trace("setEventPublisher() called.");
        this.eventPublisher = eventPublisher;
    }

    protected void addBindingProvider(VeluxBindingProvider thisBindingProvider) {
        logger.trace("addBindingProvider() called.");
        bindingProvider = thisBindingProvider;
        super.addBindingProvider(thisBindingProvider);
    }

    @Override
    public void allBindingsChanged(BindingProvider provider) {
        logger.trace("allBindingsChanged() called.");
        super.allBindingsChanged(provider);
    }

    /**
     * Activates the binding. Actually does nothing, because on activation
     * openHAB always calls updated to indicate that the configuration is updated.
     * Activation is done there.
     */
    @Override
    public void activate() {
        logger.trace("activate() called.");
        logger.info("Active items are: {}.", bindingProvider.getInBindingItemNames());
    }

    @Override
    protected String getName() {
        logger.trace("getName() called.");
        return VeluxBindingConstants.BINDING_ID + " Refresh Service";
    }

    @Override
    protected long getRefreshInterval() {
        logger.info("{} refresh interval set to {} milliseconds.", VeluxBindingConstants.BINDING_ID,
                this.config.refreshMSecs);
        logger.trace("getRefreshInterval() returns {}.", this.config.refreshMSecs);
        return this.config.refreshMSecs;
    }

    /***
     *** Continuous methods
     ***/

    @Override
    public void execute() {
        synchronized (this) {
            logger.debug("execute() called.");
            if (!bindingsExist()) {
                logger.debug("There is no existing Velux binding configuration => refresh cycle aborted!");
                return;
            }
            if (this.bindingProvider == null) {
                logger.debug("There is no existing Velux binding configuration => refresh cycle aborted.");
                return;
            }
            this.refreshCounter++;
            for (VeluxBindingProvider provider : providers) {
                logger.trace("execute(): working with VeluxBindingProvider {}.", provider);
                for (String itemName : provider.getInBindingItemNames()) {
                    VeluxBindingConfig itemConfig = this.bindingProvider.getConfigForItemName(itemName);
                    VeluxItemType itemType = itemConfig.getBindingItemType();
                    if (itemType.isToBeRefreshed()) {
                        if (isModulo(this.refreshCounter, itemType.getRefreshDivider())) {
                            logger.trace("execute(): refreshing item {}.", itemName);
                            this.bridgeHandler.handleCommandOnChannel(itemName, null, itemConfig, provider,
                                    this.eventPublisher);
                        } else {
                            logger.trace("execute(): refresh cycle not yet come for item {}.", itemName);
                        }
                    } else {
                        logger.trace("execute(): ignoring item {} as not-refreshable.", itemName);
                    }
                }
            }
            logger.debug("execute() done.");
        }
    }

    @Override
    public void receiveCommand(String itemName, Command command) {
        logger.trace("receiveCommand({},{}) called.", itemName, command.toString());

        if (this.eventPublisher == null) {
            logger.warn("receiveCommand(): eventPublisher is NULL. Should NEVER occur.");
            return;
        }
        super.receiveCommand(itemName, command);
    }

    @Override
    public void internalReceiveCommand(String itemName, Command command) {
        logger.trace("internalReceiveCommand({},{}) called.", itemName, command.toString());
        if (this.eventPublisher == null) {
            logger.warn("internalReceiveCommand(): eventPublisher is NULL. Should NEVER occur.");
            return;
        }
        VeluxBindingConfig itemConfig = this.bindingProvider.getConfigForItemName(itemName);
        VeluxItemType itemType = itemConfig.getBindingItemType();
        if (itemType.isWritable() || itemType.isExecutable()) {
            logger.trace("internalReceiveCommand() is about to send update to item {}.", itemName);
            for (VeluxBindingProvider provider : providers) {
                logger.trace("internalReceiveCommand() working with VeluxBindingProvider {}.", provider);
                bridgeHandler.handleCommandOnChannel(itemName, command, itemConfig, provider, this.eventPublisher);
            }
        } else {
            logger.warn("internalReceiveCommand() ignoring command to item {} as neither writable nor executable.",
                    itemName);
        }
        logger.trace("internalReceiveCommand() done.");
    }

    @Override
    public void internalReceiveUpdate(String itemName, State newState) {
        logger.trace("internalReceiveUpdate({},{}) called.", itemName, newState);
    }

    /***
     *** Reconfiguration methods
     ***/

    @Override
    public void updated(final Dictionary<String, ?> config) throws ConfigurationException {
        logger.debug("updated() called with {} dictionary entries.", config.size());
        if (config != null) {
            final String protocol = (String) config.get(VeluxBridgeConfiguration.BRIDGE_PROTOCOL);
            if (isNotBlank(protocol)) {
                this.config.bridgeProtocol = protocol;
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_PROTOCOL to {}.", this.config.bridgeProtocol);
            }
            final String ipAddressString = (String) config.get(VeluxBridgeConfiguration.BRIDGE_IPADDRESS);
            if (isNotBlank(ipAddressString)) {
                this.config.bridgeIPAddress = ipAddressString;
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_IPADDRESS to {}.", this.config.bridgeIPAddress);
            }
            final String tcpPortString = (String) config.get(VeluxBridgeConfiguration.BRIDGE_TCPPORT);
            if (isNotBlank(tcpPortString)) {
                try {
                    this.config.bridgeTCPPort = Integer.parseInt(tcpPortString);
                } catch (NumberFormatException e) {
                    throw new ConfigurationException(VeluxBridgeConfiguration.BRIDGE_TCPPORT, e.getMessage());
                }
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_TCPPORT to {}.", this.config.bridgeTCPPort);
            }
            final String passwordString = (String) config.get(VeluxBridgeConfiguration.BRIDGE_PASSWORD);
            if (isNotBlank(passwordString)) {
                this.config.bridgePassword = passwordString;
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_PASSWORD to {}.", this.config.bridgePassword);
            }
            final String timeoutMsecsString = (String) config.get(VeluxBridgeConfiguration.BRIDGE_TIMEOUT_MSECS);
            if (isNotBlank(timeoutMsecsString)) {
                try {
                    this.config.timeoutMsecs = Integer.parseInt(timeoutMsecsString);
                } catch (NumberFormatException e) {
                    throw new ConfigurationException(VeluxBridgeConfiguration.BRIDGE_TIMEOUT_MSECS, e.getMessage());
                }
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_TIMEOUT_MSECS to {}.", this.config.timeoutMsecs);
            }
            final String retryNoString = (String) config.get(VeluxBridgeConfiguration.BRIDGE_RETRIES);
            if (isNotBlank(retryNoString)) {
                try {
                    this.config.retries = Integer.parseInt(retryNoString);
                } catch (NumberFormatException e) {
                    throw new ConfigurationException(VeluxBridgeConfiguration.BRIDGE_RETRIES, e.getMessage());
                }
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_RETRIES to {}.", this.config.retries);
            }
            final String bulkRetrievalString = (String) config
                    .get(VeluxBridgeConfiguration.BRIDGE_IS_BULK_RETRIEVAL_ENABLED);
            if (isNotBlank(bulkRetrievalString)) {
                try {
                    this.config.isBulkRetrievalEnabled = Boolean.parseBoolean(bulkRetrievalString);
                } catch (NumberFormatException e) {
                    throw new ConfigurationException(VeluxBridgeConfiguration.BRIDGE_IS_BULK_RETRIEVAL_ENABLED,
                            e.getMessage());
                }
                this.config.hasChanged = true;
                logger.debug("updated(): adapted BRIDGE_IS_BULK_RETRIEVAL_ENABLED to {}.",
                        this.config.isBulkRetrievalEnabled);
            }
        }

        setProperlyConfigured(true);

        logger.info("{}Config[{}={},{}={},{}={},{}={},{}={},{}={},{}={},{}={}]", VeluxBindingConstants.BINDING_ID,
                VeluxBridgeConfiguration.BRIDGE_PROTOCOL, this.config.bridgeProtocol,
                VeluxBridgeConfiguration.BRIDGE_IPADDRESS, this.config.bridgeIPAddress,
                VeluxBridgeConfiguration.BRIDGE_TCPPORT, this.config.bridgeTCPPort,
                VeluxBridgeConfiguration.BRIDGE_PASSWORD, this.config.bridgePassword.replaceAll(".", "*"),
                VeluxBridgeConfiguration.BRIDGE_TIMEOUT_MSECS, this.config.timeoutMsecs,
                VeluxBridgeConfiguration.BRIDGE_RETRIES, this.config.retries,
                VeluxBridgeConfiguration.BRIDGE_REFRESH_MSECS, this.config.refreshMSecs,
                VeluxBridgeConfiguration.BRIDGE_IS_BULK_RETRIEVAL_ENABLED, this.config.isBulkRetrievalEnabled);

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

    /***
     *** Shutdown methods
     ***/

    /**
     * Deactivates the binding. Nothing to do ;-)
     */
    @Override
    public void deactivate() {
        logger.trace("deactivate() called.");
    }

    @Override
    public void unsetEventPublisher(EventPublisher eventPublisher) {
        logger.trace("unsetEventPublisher() called.");
        this.eventPublisher = null;
    }

    protected void removeBindingProvider(VeluxBindingProvider thisBindingProvider) {
        logger.trace("removeBindingProvider() called.");
        super.removeBindingProvider(thisBindingProvider);
        bindingProvider = null;
    }

}