org.openhab.binding.max.internal.message.C_Message.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.max.internal.message.C_Message.java

Source

/**
 * Copyright (c) 2014-2015 openHAB UG (haftungsbeschraenkt) 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.max.internal.message;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.net.util.Base64;
import org.openhab.binding.max.internal.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;

/**
 * The C message contains configuration about a MAX! device.
 * 
 * @author Andreas Heil (info@aheil.de)
 * @author Marcel Verpaalen - Detailed parsing, OH2 Update
 * @since 1.4.0
 */
public final class C_Message extends Message {

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

    private String rfAddress = null;
    private int length = 0;
    private DeviceType deviceType = null;
    private String serialNumber = null;
    private String tempComfort = null;
    private String tempEco = null;
    private String tempSetpointMax = null;
    private String tempSetpointMin = null;
    private String tempOffset = null;
    private String tempOpenWindow = null;
    private String durationOpenWindow = null;
    private String decalcification = null;
    private String valveMaximum = null;
    private String valveOffset = null;
    private String programData = null;
    private String boostDuration = null;
    private String boostValve = null;
    private Map<String, Object> properties = new HashMap<>();

    public C_Message(String raw) {
        super(raw);
        String[] tokens = this.getPayload().split(Message.DELIMETER);

        rfAddress = tokens[0];

        byte[] bytes = Base64.decodeBase64(tokens[1].getBytes());

        int[] data = new int[bytes.length];

        for (int i = 0; i < bytes.length; i++) {
            data[i] = bytes[i] & 0xFF;
        }

        length = data[0];
        if (length != data.length - 1) {
            logger.debug("C_Message malformed: wrong data length. Expected bytes {}, actual bytes {}", length,
                    data.length - 1);
        }

        String rfAddress2 = Utils.toHex(data[1], data[2], data[3]);
        if (!rfAddress.toUpperCase().equals(rfAddress2.toUpperCase())) {
            logger.debug("C_Message malformed: wrong RF address. Expected address {}, actual address {}",
                    rfAddress.toUpperCase(), rfAddress2.toUpperCase());
        }

        deviceType = DeviceType.create(data[4]);

        serialNumber = getSerialNumber(bytes);
        if (deviceType == DeviceType.HeatingThermostatPlus || deviceType == DeviceType.HeatingThermostat
                || deviceType == DeviceType.WallMountedThermostat)
            parseHeatingThermostatData(bytes);
        if (deviceType == DeviceType.EcoSwitch || deviceType == DeviceType.ShutterContact)
            logger.trace("Device {} type {} Data:", rfAddress, deviceType.toString(), parseData(bytes));
    }

    private String getSerialNumber(byte[] bytes) {
        byte[] sn = new byte[10];

        for (int i = 0; i < 10; i++) {
            sn[i] = (byte) bytes[i + 8];
        }

        try {
            return new String(sn, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.debug("Cannot encode serial number from C message due to encoding issues.");
        }

        return "";
    }

    private String parseData(byte[] bytes) {
        if (bytes.length <= 18)
            return "";
        try {
            int DataStart = 18;
            byte[] sn = new byte[bytes.length - DataStart];

            for (int i = 0; i < sn.length; i++) {
                sn[i] = (byte) bytes[i + DataStart];
            }
            logger.trace("DataBytes: " + Utils.getHex(sn));
            try {
                return new String(sn, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                logger.debug("Cannot encode device string from C message due to encoding issues.");
            }

        } catch (Exception e) {
            logger.debug("Exception occurred during parsing: {}", e.getMessage(), e);
        }

        return "";
    }

    private void parseHeatingThermostatData(byte[] bytes) {
        try {

            int plusDataStart = 18;
            int programDataStart = 11;
            tempComfort = Float.toString(bytes[plusDataStart] / 2);
            tempEco = Float.toString(bytes[plusDataStart + 1] / 2);
            tempSetpointMax = Float.toString(bytes[plusDataStart + 2] / 2);
            tempSetpointMin = Float.toString(bytes[plusDataStart + 3] / 2);
            properties.put("Temp Comfort", tempComfort);
            properties.put("Temp Eco", tempEco);
            properties.put("Temp Setpoint Max", tempSetpointMax);
            properties.put("Temp Setpoint Min", tempSetpointMin);
            if (bytes.length < 211) {
                // Device is a WallMountedThermostat
                programDataStart = 4;
                logger.trace("WallThermostat byte {}: {}", bytes.length - 3,
                        Float.toString(bytes[bytes.length - 3] & 0xFF));
                logger.trace("WallThermostat byte {}: {}", bytes.length - 2,
                        Float.toString(bytes[bytes.length - 2] & 0xFF));
                logger.trace("WallThermostat byte {}: {}", bytes.length - 1,
                        Float.toString(bytes[bytes.length - 1] & 0xFF));
            } else {
                // Device is a HeatingThermostat(+)
                tempOffset = Double.toString((bytes[plusDataStart + 4] / 2) - 3.5);
                tempOpenWindow = Float.toString(bytes[plusDataStart + 5] / 2);
                durationOpenWindow = Float.toString(bytes[plusDataStart + 6]);
                boostDuration = Float.toString(bytes[plusDataStart + 7] & 0xFF >> 5);
                boostValve = Float.toString((bytes[plusDataStart + 7] & 0x1F) * 5);
                decalcification = Float.toString(bytes[plusDataStart + 8]);
                valveMaximum = Float.toString(bytes[plusDataStart + 9] & 0xFF * 100 / 255);
                valveOffset = Float.toString(bytes[plusDataStart + 10] & 0xFF * 100 / 255);
                properties.put("Temp Offset", tempOffset);
                properties.put("Temp Open Window", tempOpenWindow);
                properties.put("Duration Open Windoww", durationOpenWindow);
                properties.put("Duration Boost", boostDuration);
                properties.put("Duration Boost", boostValve);
                properties.put("Decalcification", decalcification);
                properties.put("ValveMaximum", valveMaximum);
                properties.put("ValveOffset", valveOffset);
            }
            programData = "";
            int ln = 13 * 6; //first day = Sat 
            String startTime = "00:00h";
            for (int char_idx = plusDataStart + programDataStart; char_idx < (plusDataStart + programDataStart
                    + 26 * 7); char_idx++) {
                if (ln % 13 == 0) {
                    programData += "\r\n Day " + Integer.toString((ln / 13) % 7) + ": ";
                    startTime = "00:00h";
                }
                int progTime = (bytes[char_idx + 1] & 0xFF) * 5 + (bytes[char_idx] & 0x01) * 1280;
                int progMinutes = progTime % 60;
                int progHours = (progTime - progMinutes) / 60;
                String endTime = Integer.toString(progHours) + ":" + String.format("%02d", progMinutes) + "h";
                programData += startTime + "-" + endTime + " " + Double.toString(bytes[char_idx] / 4) + "C  ";
                startTime = endTime;
                char_idx++;
                ln++;
            }

        } catch (Exception e) {
            logger.debug("Exception occurred during heater data: {}", e.getMessage(), e);
        }
        return;
    }

    public String getSerialNumber() {
        return serialNumber;
    }

    @Override
    public MessageType getType() {
        return MessageType.C;
    }

    public String getRFAddress() {
        return rfAddress;
    }

    public DeviceType getDeviceType() {
        return deviceType;
    }

    @Override
    public void debug(Logger logger) {
        logger.trace("=== C_Message === ");
        logger.trace("\tRAW:                    {}", this.getPayload());
        logger.trace("DeviceType:               {}", deviceType.toString());
        logger.trace("SerialNumber:             {}", serialNumber);
        logger.trace("RFAddress:                {}", rfAddress);
        for (String key : properties.keySet()) {
            logger.trace("{}:{}{}", key, Strings.repeat(" ", 25 - key.length()), properties.get(key));
        }
        logger.trace("ProgramData:          {}", programData);
    }
}