org.openhab.binding.hexabus.internal.HexaBusBinding.java Source code

Java tutorial

Introduction

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

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Dictionary;
import java.util.List;

import org.openhab.binding.hexabus.HexaBusBindingProvider;

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.OnOffType;
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.sun.org.apache.xerces.internal.impl.dv.util.HexBin;

/**
 * @author cbirreck
 * @since 1.5.0
 */
public class HexaBusBinding extends AbstractActiveBinding<HexaBusBindingProvider> implements ManagedService {

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

    private final OnOffType ON = OnOffType.ON;
    private final OnOffType OFF = OnOffType.OFF;

    // values acquired with wire shark
    private final String ON_MESSAGE = "48583043040000000001010157b6";
    private final String OFF_MESSAGE = "485830430400000000010100463fff";
    private final String GET_MESSAGE = "48583043020000000002f7cb";

    private final int PLUG_PORT = 61616;
    private final int HEXABUS_RESPONSE_LENGTH = 79;

    //Socket information for the Jackdaw 6lowpan USB device
    private int jackdaw_port;
    private InetAddress jackdaw_ip;
    private DatagramSocket jackdaw_sock;

    // the standard refresh interval which is used to poll values from the HexaBus plug(s)
    // will be overwritten if a value is provided in the binding configuration
    private long refreshInterval = 60000;

    public void activate() {
        logger.debug("activate() is called.");

        // checks if the jackdaw_sock isn't created yet
        if (jackdaw_sock == null) {
            try {
                jackdaw_sock = new DatagramSocket(jackdaw_port, jackdaw_ip);
            } catch (SocketException e) {
                e.printStackTrace();
                logger.debug("Could not create Jackdaw Socket in activate()!");
            }
        }
    }

    public void deactivate() {
        // deallocate resources here that are no longer needed and 
        // should be reset when activating this binding again
        jackdaw_sock.close();
        jackdaw_sock = null; // probably redundant
    }

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

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

    /**
     * This method is called at the start of the binding lifecycle (@TODO verify!)
     * and each time the specified refreshInterval elapses.
     * It is used to pull the power consumption of the HexabusPlug Plus.
    -    * 
     */
    @Override
    protected void execute() {
        logger.debug("execute() method is called!");

        int val = -1;
        for (InetAddress target_ip : HexaBusGenericBindingProvider.getPullList()) {
            val = getConsumption(target_ip);
            Command decimal = new DecimalType(val);
            eventPublisher.sendCommand("hpp_power", decimal);
        }
        //target_ip = InetAddress.getByName("acdc::50:c4ff:fe04:8310");

    }

    /**
     * This method is called whenever a hexabus-item event is triggered.
     * 
     * @param itemName      the name of the hexabus item
     * @param command      the corresponding command
     */
    @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!");

        HexaBusBindingProvider provider = null;

        if (itemName != null) {
            logger.debug("Received command (item ='{}', state='{}', class='{}')",
                    new Object[] { itemName, command.toString(), command.getClass().toString() });
            provider = findBindingProvider(itemName);
        }

        if (provider != null) {
            // from .items-file; IDs have no functionality (for now)
            // int id = provider.getID(itemName);
            String type = provider.getPlugType(itemName);
            InetAddress ip = provider.getIP(itemName);

            if (type.equals("plug") || type.equals("plug+")) {
                switchPlug(ip, command);
            }

        } else {
            logger.debug("Provider is empty!");
        }
    }

    /**
     * Finds a binding provider for a given item. At the moment it checks
     * if the item has a correctly defined plug type (aka not null) in the
     * .items file.
     * 
     * @param itemName      the item to find a provider for
     * @return             reference to the provider
     */
    private HexaBusBindingProvider findBindingProvider(String itemName) {
        HexaBusBindingProvider provider = null;
        logger.debug("findBindingProvider() called.");

        for (HexaBusBindingProvider pro : this.providers) {
            String conf = pro.getPlugType(itemName);

            if (conf != null) {
                provider = pro;
                break;
            }
        }
        return provider;
    }

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

    /**
     * Parses the config file for Jackdaw Interface Values
     */
    @Override
    public void updated(Dictionary<String, ?> config) throws ConfigurationException {
        logger.debug("updated() called.");

        // conditions for a proper configuration
        boolean refreshFlag = false;
        boolean ipFlag = false;
        boolean portFlag = false;

        if (config != null) {
            String refreshIntervalString = (String) config.get("refresh");

            if (StringUtils.isNotBlank(refreshIntervalString)) {
                try {
                    refreshInterval = Long.parseLong(refreshIntervalString);
                    refreshFlag = true;
                } catch (NumberFormatException e) {
                    logger.debug(
                            "Could not parse the refresh interval value from the configuration file in updated()!");
                    e.printStackTrace();
                }
            }

            if (StringUtils.isNotBlank((String) config.get("ip"))) {
                try {
                    jackdaw_ip = InetAddress.getByName((String) config.get("ip"));
                    ipFlag = true;
                } catch (UnknownHostException e) {
                    logger.debug("IP address provided in configuration file is invalid! (Occured in updated())");
                    e.printStackTrace();
                }
            } else {
                logger.debug("Hexabus device IP could not be parsed from .items-file. Might be blank.");
            }

            if (StringUtils.isNotBlank((String) config.get("port"))) {
                try {
                    jackdaw_port = Integer.parseInt(((String) config.get("port")));
                    portFlag = true;
                } catch (NumberFormatException e) {
                    logger.debug("Port provided in configuration file is invalid! (Occured in updated())");
                    e.printStackTrace();
                }
            } else {
                logger.debug("Hexabus device port could not be parsed from .items-file. Might be blank.");
            }

            String temp = "From config file: \n IP: " + jackdaw_ip.toString() + "\n Port: " + jackdaw_port + "\n";
            logger.debug(temp);

            // checks if requirements are met
            if (refreshFlag && ipFlag && portFlag) {
                setProperlyConfigured(true);
            } else {
                setProperlyConfigured(false);
            }

            testSwitch();
        }
    }

    /**
     * Method to send UDP packets containing commands to the HexaBus Plugs
     * 
     * @param target        Target IP address
     * @param cmd          A string which represents a command
     */
    private void switchPlug(InetAddress target_ip, Command command) {
        logger.debug("switchPlug() called!");

        jackdaw_sock.connect(target_ip, PLUG_PORT);

        String msg = "";
        if (command.equals(ON)) {
            msg = ON_MESSAGE;
        } else if (command.equals(OFF)) {
            msg = OFF_MESSAGE;
        } else {
            logger.debug("Unrecognized cmd-String: " + command.toString());
            return;
        }
        byte[] bmsg = HexBin.decode(msg);
        logger.debug("InetAddress of Plug: " + target_ip);
        logger.debug("bmsg: " + bmsg.toString());
        DatagramPacket packet = new DatagramPacket(bmsg, bmsg.length);
        try {
            jackdaw_sock.send(packet);
        } catch (IOException e) {
            e.printStackTrace();
            logger.debug("Could not send command packet in switchPlug()!");
        }
    }

    /**
     * Gets the consumption of the targetted plug in Watt.
     * 
     * @param   target_ip    the ip of the targetted plug
     * 
     * @return    the power consumption in Watt
     * @throws IOException
     */
    private int getConsumption(InetAddress target_ip) {
        jackdaw_sock.connect(target_ip, PLUG_PORT);

        byte[] bmsg = HexBin.decode(GET_MESSAGE);
        byte[] receiveData = new byte[1024];

        DatagramPacket outgoing = new DatagramPacket(bmsg, bmsg.length);
        DatagramPacket incoming = new DatagramPacket(receiveData, HEXABUS_RESPONSE_LENGTH);

        try {
            jackdaw_sock.send(outgoing);
        } catch (IOException e) {
            logger.debug("Send failed on Jackdaw Socket while trying to GET consumption!");
            e.printStackTrace();
        }

        try {
            jackdaw_sock.receive(incoming);
        } catch (IOException e) {
            logger.debug("Receive failed on Jackdaw Socket while trying to GET consumption!");
            e.printStackTrace();
        }

        byte[] data = incoming.getData();

        // checks if no data was received.
        if (data.length == 0) {
            logger.debug("No data was transmitted in getConsumption!");
        }

        // the last four bytes contain the consumption integer
        byte[] temp = { data[11], data[12], data[13], data[14] };
        ByteBuffer wrapped = ByteBuffer.wrap(temp);
        int val = wrapped.getInt();

        logger.debug("Power Consumption of hpp: " + val);
        return val;
    }

    /*
     *  test-method; gets called in the beginning of the bindings life cycle
     */
    private void testSwitch() {
        InetAddress pp = null;

        try {
            pp = InetAddress.getByName("acdc::50:c4ff:fe04:8310");
        } catch (UnknownHostException e) {
            e.printStackTrace();
            logger.debug("Could create InetAddress in testSwitch()!");
        }
        logger.debug("Attempting to send 'off' and 'on' packets...");
        switchPlug(pp, ON);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.debug("Interrupted in testSwitch()!");
        }
        switchPlug(pp, OFF);
    }

    /*
     * test method
     */
    private void testConsumption() throws IOException, InterruptedException {
        InetAddress pp = InetAddress.getByName("acdc::50:c4ff:fe04:8310");
        logger.debug("Attempting to send 'get' packet...");
        getConsumption(pp);
    }
}