org.openhab.binding.loxone.internal.LoxoneBinding.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.loxone.internal.LoxoneBinding.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.loxone.internal;

import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.openhab.binding.loxone.LoxoneBindingProvider;
import org.openhab.binding.loxone.integration.LoxoneCommunicationException;
import org.openhab.binding.loxone.integration.LoxoneHost;
import org.openhab.binding.loxone.integration.MiniserverFactory;
import org.openhab.binding.loxone.integration.api.AbstractLoxoneFunction;
import org.openhab.binding.loxone.integration.api.IoResponse;
import org.openhab.binding.loxone.integration.api.LoxoneApplication;
import org.openhab.binding.loxone.integration.api.LoxoneEvent;
import org.openhab.binding.loxone.integration.api.LoxoneEventListener;
import org.openhab.binding.loxone.integration.api.Miniserver;
import org.openhab.core.binding.AbstractBinding;
import org.openhab.core.binding.BindingProvider;
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;

import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;

/**
 * Implement this class if you are going create an actively polling service like querying a Website/Device.
 * 
 * @author joris.deveirman
 * @since 1.7.0-SNAPSHOT
 */
public class LoxoneBinding extends AbstractBinding<LoxoneBindingProvider> implements ManagedService {

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

    private final MiniserverFactory miniserverFactory = MiniserverFactory.DEFAULT;
    private final LoxoneItemBindingRepository loxoneItemBindingRepository = new DefaultLoxoneItemBindingRepository();
    private final LoxoneEventListener loxoneEventListener = new InternalLoxoneEventListener();

    private final List<Miniserver> miniservers = new LinkedList<Miniserver>();

    public LoxoneBinding() {
    }

    public void activate() {
        logger.debug("Activate LoxoneBinding");
    }

    public void deactivate() {
        updateConfiguration(Collections.<String, LoxoneHost>emptyMap());
        logger.debug("Deactivate LoxoneBinding");
    }

    @Override
    public void allBindingsChanged(BindingProvider provider) {
        logger.debug("BindingProvider changed");
        // TODO update bindings with application
    }

    @Override
    public void bindingChanged(BindingProvider provider, String itemName) {
        logger.debug("Binding changed {}", itemName);
        // TODO update specific item with application
    }

    /**
     * @{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!");
        for (LoxoneBindingProvider provider : providers) {
            LoxoneItemBinding loxoneItemBinding = loxoneItemBindingRepository.findForItemName(itemName);
            final String instance = provider.getLoxoneInstance(itemName);
            if (loxoneItemBinding != null) {
                if (loxoneItemBinding.isReadOnly()) {
                    logger.warn("Did not update {} to loxone because it is marked readonly. Ignoring update.",
                            itemName);
                    continue;
                }
                LoxoneValue value = loxoneItemBinding.convertToLoxoneValue(command);
                if (value == null) {
                    logger.warn("Converted {} to NULL for {}. Ignoring update.", command, itemName);
                    continue;
                }
                applyValueToLoxone(instance, itemName, value);
            }
        }
    }

    /**
     * @{inheritDoc
     */
    @Override
    protected void internalReceiveUpdate(final 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!");
        for (LoxoneBindingProvider provider : providers) {
            LoxoneItemBinding loxoneItemBinding = loxoneItemBindingRepository.findForItemName(itemName);
            final String instance = provider.getLoxoneInstance(itemName);
            if (loxoneItemBinding != null) {
                if (loxoneItemBinding.isReadOnly()) {
                    logger.warn("Did not update {} to loxone because it is marked readonly. Ignoring update.",
                            itemName);
                    continue;
                }
                LoxoneValue value = loxoneItemBinding.convertToLoxoneValue(newState);
                if (value == null) {
                    logger.warn("Converted {} to NULL for {}. Ignoring update.", newState, itemName);
                    continue;
                }
                applyValueToLoxone(instance, itemName, value);
            }
        }
    }

    /**
     * @{inheritDoc
     */
    @Override
    public void updated(Dictionary<String, ?> config) throws ConfigurationException {
        if (config != null) {
            Map<String, LoxoneHost> hosts = new HashMap<String, LoxoneHost>();

            Enumeration<String> keys = config.keys();

            while (keys.hasMoreElements()) {
                String key = keys.nextElement();

                if ("service.pid".equals(key)) {
                    continue;
                }

                String[] parts = key.split("\\.");
                String name = parts[0];

                LoxoneHost host = hosts.get(name);
                if (host == null) {
                    host = new LoxoneHost(name);
                }

                String value = ((String) config.get(key)).trim();

                if ("host".equals(parts[1])) {
                    host.setHost(value);
                }
                if ("port".equals(parts[1])) {
                    host.setPort(Integer.valueOf(value));
                }
                if ("username".equals(parts[1])) {
                    host.setUsername(value);
                }
                if ("password".equals(parts[1])) {
                    host.setPassword(value);
                }

                hosts.put(name, host);
            }

            updateConfiguration(hosts);

            logger.debug("Loxone binding Updated");
        }
    }

    private void applyValueToLoxone(String instance, String itemName, LoxoneValue value) {
        Miniserver miniserver = findMiniserver(instance);
        try {
            IoResponse response = miniserver.sps().io(value.getUuid(), value.getValue());
            if (!response.success()) {
                logger.warn("Failed to update {} to value {}. Reponse is {}", itemName, value, response);
            } else {
                logger.debug("Updated {} to value {}", itemName, value);
            }
        } catch (LoxoneCommunicationException e) {
            logger.error("Failed to update {} to value {}. An unexpected error occured", itemName, value, e);
        }
    }

    private Miniserver findMiniserver(final String instance) {
        return Iterables.find(miniservers, new Predicate<Miniserver>() {
            public boolean apply(Miniserver miniserver) {
                return instance.equalsIgnoreCase(miniserver.host().getName());
            }
        }, Iterables.getFirst(miniservers, null));
    }

    /**
     * Updates the connections as specified by {@code code}. First it disconnects and disposes all existing connections.
     * Then is creates the connections and registers for events.
     * 
     * @param hosts
     */
    private void updateConfiguration(Map<String, LoxoneHost> hosts) {
        for (Miniserver miniserver : miniservers) {
            try {
                miniserver.dispose();
            } catch (LoxoneCommunicationException e) {
                logger.debug("error while disposing {}", miniserver, e);
            }
        }
        miniservers.clear();

        for (LoxoneHost host : hosts.values()) {
            if (!host.isValid()) {
                logger.warn("Ignoring {} because it is not valid!", host);
                continue;
            }
            try {
                Miniserver miniserver = miniserverFactory.createMiniserver(host);
                miniserver.addLoxoneEventListener(loxoneEventListener);
                miniservers.add(miniserver);
                logger.debug("Successfully established connection to {}", host);
            } catch (LoxoneCommunicationException e) {
                logger.warn("Failed to establish connnection to {}", host, e);
            }
        }
    }

    /**
     * 
     * @author joris.deveirman
     * 
     */
    private final class InternalLoxoneEventListener implements LoxoneEventListener {

        @Override
        public void onEvent(Miniserver miniserver, LoxoneEvent event) {
            LoxoneItemBinding loxoneItemBinding = loxoneItemBindingRepository.findForUuid(event.getUuid());
            if (loxoneItemBinding != null) {
                logger.debug("Handling {} for {}", event, loxoneItemBinding.getItemName());
                State state = loxoneItemBinding
                        .convertToLoxoneState(LoxoneValue.create(event.getUuid(), event.getValue()));
                if (state != null) {
                    eventPublisher.postUpdate(loxoneItemBinding.getItemName(), state);
                } else {
                    logger.warn("Converted value {} to State NULL for {}. Ignoring update.", event.getValue(),
                            loxoneItemBinding.getItemName());
                }
            } else {
                logger.trace("Did not process {} (miniserver={}) because no Item Binding is available", event,
                        miniserver.host());
            }
        }

        @Override
        public void onApplicationChanged(Miniserver miniserver, LoxoneApplication application) {
            loxoneItemBindingRepository.evictAll();
            for (LoxoneBindingProvider provider : providers) {
                for (AbstractLoxoneFunction function : application.getFunctions()) {
                    String itemName = provider.findItemNameByUUIDOrName(miniserver.host().getName(),
                            function.getUuidAction(), function.getName());
                    if (Strings.isNullOrEmpty(itemName)) {
                        logger.debug("No Item Binding for {}. Updates will be ignored.", function);
                        continue;
                    }
                    loxoneItemBindingRepository.create(itemName, function);
                }
            }
        }
    }
}