org.openhab.binding.max.internal.command.MCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.binding.max.internal.command.MCommand.java

Source

/**
 * Copyright (c) 2010-2019 Contributors to the openHAB project
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.openhab.binding.max.internal.command;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.util.Base64;
import org.openhab.binding.max.internal.Utils;
import org.openhab.binding.max.internal.device.Device;
import org.openhab.binding.max.internal.device.RoomInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The {@link MCommand} Creates the MAX! Cube the room & device name information update message.
 *
 * @author Marcel Verpaalen - Initial Contribution
 */
public class MCommand extends CubeCommand {
    private final Logger logger = LoggerFactory.getLogger(MCommand.class);

    private static final byte MAGIC_NR = 86;
    private static final byte M_VERSION = 2;
    private static final int MAX_NAME_LENGTH = 32;
    private static final int MAX_GROUP_COUNT = 20;
    private static final int MAX_DEVICES_COUNT = 140;
    private static final int MAX_MSG_LENGTH = 1900;

    private final List<Device> devices;
    public final List<RoomInformation> rooms;

    public MCommand(List<Device> devices) {
        this(devices, new ArrayList<>());
    }

    public MCommand(List<Device> devices, List<RoomInformation> rooms) {
        this.devices = new ArrayList<>(devices);
        this.rooms = new ArrayList<>(rooms);
        roombuilder();
    }

    public void listRooms() {
        for (RoomInformation room : rooms) {
            logger.debug("M Command room info: {}", room);
        }
    }

    public List<RoomInformation> getRooms() {
        return rooms;
    }

    private void roombuilder() {
        for (Device di : devices) {
            boolean foundRoom = false;

            for (RoomInformation room : rooms) {
                if (room.getPosition() == di.getRoomId()) {
                    foundRoom = true;
                }
            }
            // Add new rooms based on device information.
            // TODO check if it is allowed to have any device creating a room, or should it be a thermostat
            if (!foundRoom && di.getRoomId() != 0 && rooms.size() < MAX_GROUP_COUNT) {
                RoomInformation room = new RoomInformation(di.getRoomId(), di.getRoomName(), di.getRFAddress());
                rooms.add(room);
            }
        }
    }

    public byte[] concatenateByteArrays(List<byte[]> blocks) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        for (byte[] b : blocks) {
            os.write(b, 0, b.length);
        }
        return os.toByteArray();
    }

    @Override
    public String getCommandString() {
        int deviceCount = 0;
        int roomCount = 0;

        ByteArrayOutputStream message = new ByteArrayOutputStream();

        try {
            byte[] header = { MAGIC_NR, M_VERSION, (byte) rooms.size() };
            message.write(header);

            Set<Integer> sortedRooms = new TreeSet<>();
            for (RoomInformation room : rooms) {
                sortedRooms.add(room.getPosition());
            }

            for (Integer roomPos : sortedRooms) {
                for (RoomInformation room : rooms) {
                    if (room.getPosition() == roomPos) {
                        if (roomCount < MAX_GROUP_COUNT) {
                            byte[] roomName = StringUtils.abbreviate(room.getName(), MAX_NAME_LENGTH)
                                    .getBytes(StandardCharsets.UTF_8);
                            byte[] nameLength = new byte[] { (byte) roomName.length };
                            byte[] rfAddress = Utils.hexStringToByteArray(room.getRFAddress());
                            message.write(roomPos.byteValue());
                            message.write(nameLength);
                            message.write(roomName);
                            message.write(rfAddress);
                        } else {
                            logger.warn("{} exceeds max number of rooms ({}). Ignored", room, MAX_GROUP_COUNT);
                        }
                        roomCount++;
                    }
                }
            }
            for (Device di : devices) {
                if (deviceCount < MAX_DEVICES_COUNT) {
                    deviceCount++;
                } else {
                    logger.warn("{} exceeds max number of devices ({}). Ignored", di, MAX_DEVICES_COUNT);
                }
            }
            message.write((byte) deviceCount);
            for (Device di : devices) {
                if (deviceCount > 0) {
                    byte[] deviceType = { (byte) di.getType().getValue() };
                    byte[] rfAddress = Utils.hexStringToByteArray(di.getRFAddress());
                    byte[] deviceName = StringUtils.abbreviate(di.getName(), MAX_NAME_LENGTH)
                            .getBytes(StandardCharsets.UTF_8);
                    byte[] nameLength = { (byte) deviceName.length };
                    byte[] serialNumber = di.getSerialNumber().getBytes(StandardCharsets.UTF_8);
                    byte[] roomId = { (byte) di.getRoomId() };

                    message.write(deviceType);
                    message.write(rfAddress);
                    message.write(serialNumber);
                    message.write(nameLength);
                    message.write(deviceName);
                    message.write(roomId);
                } else {
                    logger.warn("{} exceeds max number of devices ({}). Ignored", di, MAX_DEVICES_COUNT);
                }
                deviceCount--;
            }

            byte[] dst = { 0x01 };
            message.write(dst);

        } catch (IOException e) {
            logger.debug("Error while generating m: command: {}", e.getMessage(), e);

        }

        final String encodedString = Base64.encodeBase64StringUnChunked(message.toByteArray());
        final StringBuilder commandStringBuilder = new StringBuilder();
        int parts = (int) Math.round(encodedString.length() / MAX_MSG_LENGTH + 0.5);
        for (int i = 0; i < parts; i++) {
            String partString = StringUtils.abbreviate(encodedString.substring((i) * MAX_MSG_LENGTH),
                    MAX_MSG_LENGTH);
            commandStringBuilder.append("m:").append(String.format("%02d", i)).append(",").append(partString)
                    .append('\r').append('\n');
        }

        return commandStringBuilder.toString();
    }

    @Override
    public String getReturnStrings() {
        return "A:";
    }

}