2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.max.internal.message;
15 import java.nio.charset.StandardCharsets;
16 import java.util.ArrayList;
17 import java.util.Base64;
18 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.openhab.binding.max.internal.Utils;
22 import org.openhab.binding.max.internal.device.DeviceInformation;
23 import org.openhab.binding.max.internal.device.DeviceType;
24 import org.openhab.binding.max.internal.device.RoomInformation;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * The M message contains metadata about the MAX! Cube setup.
31 * @author Andreas Heil - Initial contribution
32 * @author Marcel Verpaalen - Room details parse
35 public final class MMessage extends Message {
36 private final Logger logger = LoggerFactory.getLogger(MMessage.class);
38 public List<RoomInformation> rooms = new ArrayList<>();
39 public List<DeviceInformation> devices = new ArrayList<>();
40 private Boolean hasConfiguration;
42 public MMessage(String raw) {
44 hasConfiguration = false;
46 String[] tokens = this.getPayload().split(Message.DELIMETER);
48 if (tokens.length <= 1) {
49 logger.debug("No rooms defined. Configure your Max! Cube");
50 hasConfiguration = false;
54 byte[] bytes = Base64.getDecoder().decode(tokens[2].trim().getBytes(StandardCharsets.UTF_8));
56 hasConfiguration = true;
57 logger.trace("*** M Message trace**** ");
58 logger.trace("\tMagic? (expect 86) : {}", (int) bytes[0]);
59 logger.trace("\tVersion? (expect 2): {}", (int) bytes[1]);
60 logger.trace("\t#defined rooms in M: {}", (int) bytes[2]);
62 rooms = new ArrayList<>();
63 devices = new ArrayList<>();
65 int roomCount = bytes[2];
67 int byteOffset = 3; // start of rooms
71 for (int i = 0; i < roomCount; i++) {
73 int position = bytes[byteOffset++];
75 int nameLength = bytes[byteOffset++] & 0xff;
76 byte[] data = new byte[nameLength];
77 System.arraycopy(bytes, byteOffset, data, 0, nameLength);
78 byteOffset += nameLength;
79 String name = new String(data, StandardCharsets.UTF_8);
81 String rfAddress = Utils.toHex((bytes[byteOffset] & 0xff), (bytes[byteOffset + 1] & 0xff),
82 (bytes[byteOffset + 2] & 0xff));
85 rooms.add(new RoomInformation(position, name, rfAddress));
90 int deviceCount = bytes[byteOffset++];
92 for (int deviceId = 0; deviceId < deviceCount; deviceId++) {
93 DeviceType deviceType = DeviceType.create(bytes[byteOffset++]);
95 String rfAddress = Utils.toHex((bytes[byteOffset] & 0xff), (bytes[byteOffset + 1] & 0xff),
96 (bytes[byteOffset + 2] & 0xff));
99 final StringBuilder serialNumberBuilder = new StringBuilder(10);
101 for (int i = 0; i < 10; i++) {
102 serialNumberBuilder.append((char) bytes[byteOffset++]);
105 int nameLength = bytes[byteOffset++] & 0xff;
106 byte[] data = new byte[nameLength];
107 System.arraycopy(bytes, byteOffset, data, 0, nameLength);
108 byteOffset += nameLength;
109 String deviceName = new String(data, StandardCharsets.UTF_8);
111 int roomId = bytes[byteOffset++] & 0xff;
112 devices.add(new DeviceInformation(deviceType, serialNumberBuilder.toString(), rfAddress, deviceName,
115 } catch (Exception e) {
116 logger.debug("Unknown error parsing the M Message: {}", e.getMessage(), e);
117 logger.debug("\tRAW : {}", this.getPayload());
122 public void debug(Logger logger) {
123 logger.debug("=== M Message === ");
124 if (hasConfiguration) {
125 logger.trace("\tRAW : {}", this.getPayload());
126 for (RoomInformation room : rooms) {
127 logger.debug("\t=== Rooms ===");
128 logger.debug("\tRoom Pos : {}", room.getPosition());
129 logger.debug("\tRoom Name : {}", room.getName());
130 logger.debug("\tRoom RF Adr: {}", room.getRFAddress());
131 for (DeviceInformation device : devices) {
132 if (room.getPosition() == device.getRoomId()) {
133 logger.debug("\t=== Devices ===");
134 logger.debug("\tDevice Type : {}", device.getDeviceType());
135 logger.debug("\tDevice Name : {}", device.getName());
136 logger.debug("\tDevice Serialnr: {}", device.getSerialNumber());
137 logger.debug("\tDevice RF Adr : {}", device.getRFAddress());
138 logger.debug("\tRoom Id : {}", device.getRoomId());
143 logger.debug("M Message empty. No Configuration");
148 public MessageType getType() {
149 return MessageType.M;