org.openhab.binding.gpioremotecontrol.internal.GpioRemoteControlBinding.java Source code

Java tutorial

Introduction

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

import home.control.model.*;
import home.control.model.HostAndTempAndPinConfiguration.ConfigMode;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import org.java_websocket.WebSocket;
import com.google.gson.Gson;
import org.openhab.binding.gpioremotecontrol.GpioRemoteControlBindingProvider;
import org.apache.commons.lang.StringUtils;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.IncreaseDecreaseType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.osgi.framework.BundleContext;
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 MichaelP
 * @since 1.0
 */
public class GpioRemoteControlBinding extends AbstractActiveBinding<GpioRemoteControlBindingProvider> {

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

    /**
     * The BundleContext. This is only valid when the bundle is ACTIVE. It is set in the activate()
     * method and must not be accessed anymore once the deactivate() method was called or before activate()
     * was called.
     */
    private BundleContext bundleContext;
    Gson gson = new Gson();

    /** 
     * the refresh interval which is used to poll values from the GpioRemoteControl
     * server (optional, defaults to 60000ms)
     */
    private long refreshInterval = 10000;

    public GpioRemoteControlBinding() {
        logger.debug("GpioRemoteControlBinding binding started");
    }

    /**
     * Called by the SCR to activate the component with its configuration read from CAS
     * 
     * @param bundleContext BundleContext of the Bundle that defines this component
     * @param configuration Configuration properties for this component obtained from the ConfigAdmin service
     */
    public void activate(final BundleContext bundleContext, final Map<String, Object> configuration) {
        this.bundleContext = bundleContext;

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

        setProperlyConfigured(true);
    }

    /**
     * Called by the SCR when the configuration of a binding has been changed through the ConfigAdmin service.
     * @param configuration Updated configuration properties
     */
    public void modified(final Map<String, Object> configuration) {
        // update the internal configuration accordingly
    }

    /**
     * Called by the SCR to deactivate the component when either the configuration is removed or
     * mandatory references are no longer satisfied or the component has simply been stopped.
     * @param reason Reason code for the deactivation:<br>
     * <ul>
     * <li> 0  Unspecified
      * <li> 1  The component was disabled
      * <li> 2  A reference became unsatisfied
      * <li> 3  A configuration was changed
      * <li> 4  A configuration was deleted
      * <li> 5  The component was disposed
      * <li> 6  The bundle was stopped
      * </ul>
     */
    public void deactivate(final int reason) {
        this.bundleContext = null;
        // deallocate resources here that are no longer needed and 
        // should be reset when activating this binding again
    }

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

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

    /**
     * @{inheritDoc}
     */
    @Override
    protected void execute() {
        // the frequently executed code (polling) goes here ...
        removeUnusedConnections();
        checkConnections();
    }

    private void checkConnections() {
        for (GpioRemoteControlBindingProvider provider : providers) {
            for (URI keyUri : provider.getClientMap().keySet()) {
                if (provider.getClientMap().get(keyUri) == null) {
                    logger.debug("checkConnections: Client was NULL. Connect client: " + keyUri.toString());
                    provider.getClientMap().put(keyUri, new Client(keyUri, this)); //Override old, confused WebSocket               
                    provider.getClientMap().get(keyUri).connect(); //Connect it
                } else if (provider.getClientMap().get(keyUri)
                        .getReadyState() == WebSocket.READY_STATE_CONNECTING) { //If client is not connected yet
                    logger.debug("checkConnections: Connect client: " + keyUri.toString());
                    provider.getClientMap().put(keyUri, new Client(keyUri, this)); //Override old, confused WebSocket               
                    provider.getClientMap().get(keyUri).connect(); //Connect it               
                } else if (provider.getClientMap().get(keyUri).getReadyState() == WebSocket.READY_STATE_OPEN) {
                    logger.debug("checkConnections: running connection: " + keyUri.toString());
                    //fine
                } else { //If else Client state, start and connect new Websocket  
                    logger.debug("checkConnections: Create new client and connect: " + keyUri.toString());
                    provider.getClientMap().put(keyUri, new Client(keyUri, this)); //Override old, confused WebSocket
                    provider.getClientMap().get(keyUri).connect(); //Connect again
                }
            }
        }
    }

    private void removeUnusedConnections() {
        try {
            for (GpioRemoteControlBindingProvider provider : providers) {
                keyLoop: for (URI keyUri : provider.getClientMap().keySet()) {
                    for (String itemName : provider.getItemNames()) {
                        URI uri = new URI("ws://" + provider.getConfig(itemName).getHostWithPort());
                        if (uri.equals(keyUri)) {
                            continue keyLoop;
                        }
                        provider.getClientMap().get(keyUri).close(); //Close unused connection   
                        provider.getClientMap().remove(keyUri); //If non Item uses the URI, remove the connection            
                    }
                }
            }
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (Exception e) {
            logger.debug("Exception in removeUnusedConnections. Shit happens...");
        }
    }

    /**
     * @{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("GpioRemoteControl: internalReceiveCommand({},{}) is called!", itemName, command);

        for (GpioRemoteControlBindingProvider provider : providers) {
            if (provider.getConfig(itemName).configMode != ConfigMode.OUTPUT) {
                logger.warn("The Item '{}' wasn't configured as output item. It can't receive any commands!",
                        itemName);
                return; //If it is not a output Item, stop here            
            }
            try {
                int pinNumber = provider.getConfig(itemName).pinConfiguration.getNumber();
                PinConfiguration pinConf = null;
                logger.debug("GpioRemoteControl: internalReceiveCommand: Event Auswahl folgt... "
                        + "ItemName: {}, Command: {}", itemName, command);
                if (command == OnOffType.ON || command.toString().toLowerCase().equals("on")) {
                    pinConf = new PinConfiguration(Event.SET, pinNumber, true);
                    provider.getConfig(itemName).pinConfiguration.setPwmValue(100);

                } else if (command == OnOffType.OFF || command.toString().toLowerCase().equals("off")) {
                    pinConf = new PinConfiguration(Event.SET, pinNumber, false);
                    provider.getConfig(itemName).pinConfiguration.setPwmValue(0);

                } else if (command.toString().toLowerCase().equals("toggle")) {
                    pinConf = handleToggleCommand(provider, itemName, pinNumber, command);

                } else if (command == IncreaseDecreaseType.INCREASE
                        || command.toString().toLowerCase().equals("increase")) {
                    provider.getConfig(itemName).pinConfiguration
                            .setPwmValue(provider.getConfig(itemName).pinConfiguration.getPwmValue() + 1);
                    pinConf = new PinConfiguration(Event.DIM, pinNumber,
                            provider.getConfig(itemName).pinConfiguration.getPwmValue() + 1);

                } else if (command == IncreaseDecreaseType.DECREASE
                        || command.toString().toLowerCase().equals("decrease")) {
                    provider.getConfig(itemName).pinConfiguration
                            .setPwmValue(provider.getConfig(itemName).pinConfiguration.getPwmValue() - 1);
                    pinConf = new PinConfiguration(Event.DIM, pinNumber,
                            provider.getConfig(itemName).pinConfiguration.getPwmValue());

                } else if (command.toString().toLowerCase().contains("dim_")) {
                    String[] split = command.toString().split("_");
                    //Should be: 0:dim;1:pwmValue
                    pinConf = new PinConfiguration(Event.DIM, pinNumber, Integer.parseInt(split[1]));
                    provider.getConfig(itemName).pinConfiguration.setPwmValue(Integer.parseInt(split[1])); //Save value of PWM

                } else if (command.toString().toLowerCase().contains("fade_")) {
                    pinConf = handleEvent(provider, itemName, pinNumber, command, Event.FADE);

                } else if (command.toString().toLowerCase().contains("fadeupdown_")) {
                    pinConf = handleEvent(provider, itemName, pinNumber, command, Event.FADE_UP_DOWN);

                } else if (command.toString().toLowerCase().contains("blink_")) {
                    pinConf = handleBlinkEvent(provider, itemName, pinNumber, command);

                } else {
                    //parseable as Integer? 
                    int tempPwmVal = Integer.parseUnsignedInt(command.toString());
                    provider.getConfig(itemName).pinConfiguration.setPwmValue(tempPwmVal); //pinConfiguration.setPwmValue ensures the value is 0-100
                    pinConf = new PinConfiguration(Event.DIM, pinNumber,
                            provider.getConfig(itemName).pinConfiguration.getPwmValue());
                }

                URI uriOfPin = new URI("ws://" + provider.getConfig(itemName).getHostWithPort());

                provider.getClientMap().get(uriOfPin).send(gson.toJson(pinConf)); //Send Command to Remote GPIO Pin
                //            provider.getClientMap().get(uriOfPin).send(gson.toJson("{\"event\":\"TEMP\",\"deviceId\":\"28-00044a72b1ff\"}"));
            } catch (IndexOutOfBoundsException e) {
                logger.warn(
                        "GpioRemoteControl: internalReceiveCommand: EventConfig not readable! Maybe wrong parameter in Sitemap? "
                                + "ItemName: {}, Command: {}",
                        itemName, command);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            } catch (NumberFormatException e) {
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private PinConfiguration handleToggleCommand(GpioRemoteControlBindingProvider provider, String itemName,
            int pinNumber, Command command) {
        if (provider.getConfig(itemName).pinConfiguration.getPwmValue() < 100) {
            provider.getConfig(itemName).pinConfiguration.setPwmValue(100);
            return new PinConfiguration(Event.SET, pinNumber, true);
        } else {
            provider.getConfig(itemName).pinConfiguration.setPwmValue(0);
            return new PinConfiguration(Event.SET, pinNumber, false);
        }
    }

    private PinConfiguration handleBlinkEvent(GpioRemoteControlBindingProvider provider, String itemName,
            int pinNumber, Command command) {
        String[] split = command.toString().split("_");
        //Should be: 0:blink;1:uptime;2:downtime;3:pwmValue;4:repeat;5:cycles
        provider.getConfig(itemName).pinConfiguration.setPwmValue(0); //Save endVal of PWM
        if (split.length == 2) { //Short version: Only uptime - one flash to 100%.
            return new PinConfiguration(Event.BLINK, pinNumber, Integer.parseInt(split[1]), 1, 100, false, 0); //default values for no loop                  
        } else {
            return new PinConfiguration(Event.BLINK, pinNumber, Integer.parseInt(split[1]),
                    Integer.parseInt(split[2]), Integer.parseInt(split[3]), Boolean.parseBoolean(split[4]),
                    Integer.parseInt(split[5]));
        }
    }

    private PinConfiguration handleEvent(GpioRemoteControlBindingProvider provider, String itemName, int pinNumber,
            Command command, Event event) {
        String[] split = command.toString().split("_");
        //Should be: 0:fade;1:cycleDuration;2:startVal;3:endVal;4:repeat;5:cycles;6:cyclePause
        provider.getConfig(itemName).pinConfiguration.setPwmValue(Integer.parseInt(split[3])); //Save endVal of PWM
        if (split.length == 4) { //Short version: If only cycleDuration and start- and EndValue given 
            return new PinConfiguration(event, pinNumber, Integer.parseInt(split[1]), Integer.parseInt(split[2]),
                    Integer.parseInt(split[3]), false, 0, 0); //default values for no loop
        } else {
            return new PinConfiguration(event, pinNumber, Integer.parseInt(split[1]), Integer.parseInt(split[2]),
                    Integer.parseInt(split[3]), Boolean.parseBoolean(split[4]), Integer.parseInt(split[5]),
                    Integer.parseInt(split[6]));
        }
    }

    /**
     * @{inheritDoc}
     */
    @Override
    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("internalReceiveUpdate({},{}) is called!", itemName, newState);
    }

    public void receiveServerMessage(String message) {
        //      logger.debug(">>>>> GpioRemoteControl: receiveServerMessage!");
        try {
            parseAndUpdatePinInput(message); // NOT TESTED YET, NO INPUT PIN AVAILABLE //   
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            parseAndUpdateTemperature(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // METHOD NOT TESTED YET //
    private void parseAndUpdatePinInput(String message) {
        PinInput pinConfig = gson.fromJson(message, PinInput.class);
        if (pinConfig.getNumber() != -1) { //Was successfully parsed 
            if (providers.iterator().next()
                    .getConfig(getItemNameByPinNumber(pinConfig.getNumber())).configMode == ConfigMode.INPUT) {
                logger.debug("GpioRemoteControl: receiveServerMessage: PinConfig: {}, {}", pinConfig.getNumber(),
                        pinConfig.getIsHigh());
                providers.iterator().next()
                        .getConfig(getItemNameByPinNumber(pinConfig.getNumber())).pinInput = pinConfig; //Replace pinConfiguration with received config
                if (pinConfig.getIsHigh()) {
                    eventPublisher.postUpdate(getItemNameByPinNumber(pinConfig.getNumber()), OnOffType.ON);
                } else {
                    eventPublisher.postUpdate(getItemNameByPinNumber(pinConfig.getNumber()), OnOffType.OFF);
                }
            }
        }
    }

    private void parseAndUpdateTemperature(String message) {
        //      logger.debug("GpioRemoteControl: parseAndUpdateTemperature.");
        Temperature tempConfig = gson.fromJson(message, Temperature.class);
        if (tempConfig.getDeviceId() != "") { //Was successfully parsed      
            //         logger.debug("GpioRemoteControl: receiveServerMessage: TemperatureConfig: {}, {}, {}", tempConfig.getDeviceId(), tempConfig.getTemperature(), getItemNameByTemperatureDeviceId(tempConfig.getDeviceId()));
            if (providers.iterator().next().getConfig(getItemNameByTemperatureDeviceId(
                    tempConfig.getDeviceId())).configMode == ConfigMode.TEMPERATURE) {
                providers.iterator().next().getConfig(
                        getItemNameByTemperatureDeviceId(tempConfig.getDeviceId())).temperature = tempConfig;
                Float temperatureRaw = (float) (tempConfig.getTemperature());
                Float temperature = temperatureRaw / 1000; //Received value is like 22500 for 22,5C 
                //            logger.debug("GpioRemoteControl: parseAndUpdateTemperature: {}", temperature.toString());
                eventPublisher.postUpdate(getItemNameByTemperatureDeviceId(tempConfig.getDeviceId()),
                        DecimalType.valueOf(temperature.toString()));
            }
        }
    }

    private String getItemNameByPinNumber(int pinNumber) {
        for (GpioRemoteControlBindingProvider provider : providers) {
            for (String itemName : provider.getItemNames()) {
                if (provider.getConfig(itemName).pinConfiguration.getNumber() == pinNumber) {
                    return itemName;
                }
            }
        }
        return "ItemNotFound in getItemName in gpioRemoteControl Pin";
    }

    private String getItemNameByTemperatureDeviceId(String deviceId) {
        for (GpioRemoteControlBindingProvider provider : providers) {
            for (String itemName : provider.getItemNames()) {
                if (provider.getConfig(itemName).temperature.getDeviceId().equals(deviceId)) {
                    return itemName;
                }
            }
        }
        return "ItemNotFound in getItemName in gpioRemoteControl Temperature";
    }
}