A Dreamer's Lair

eQ-3 Max Cube message protocol decrypted: Part 3, the ‘M’ word

In this part of the series of articles about the Cube Message Protocol, I’m going to discuss the Metadata message, the ‘M’ message. It is one of the messages that the cubes sends when connecting to it for the first time. Also the message can be requested by using the m: command.

The metadata contains, as the name already tells us, metadata about our collection of eQ-3 devices.

Like the H message, the M message contains a comma separated list of strings in the form of


The first two parameters are (yet) unknown. The third and last string is a Base64 encoded string. It contains the definitions for all rooms (or groups if you will) and devices. The decoded bytes will look something like this

0000: 56 02 06 02 0a 4c 69 76   V....Liv
0008: 69 6e 67 52 6f 6f 6d 0c   ingRoom.
0010: c0 1e 03 04 48 61 6c 6c   ....Hall
0018: 0b ae 0f 05 08 42 61 74   .....Bat
0020: 68 52 6f 6f 6d 06 c9 22   hRoom...
0028: 04 07 42 65 64 52 6f 6f   ..BedRoo
0030: 6d 0b aa e9 01 09 48 6f   m.....Ho
0038: 62 62 79 52 6f 6f 6d 06   bbyRoom.
0040: c9 41 06 09 53 70 61 72   .A..Spar
0048: 65 52 6f 6f 6d 0c c0 51   eRoom..Q
0050: 0f 03 0a 12 bd 4b 45 51   .....KEQ
0058: 30 37 30 34 37 35 32 13   0704752.
0060: 54 68 65 72 6d 6f 73 74   Thermost
0068: 61 74 48 6f 62 62 79 52   atHobbyR
0070: 6f 6f 6d 01 01 06 c9 41   oom....A
0078: 4b 45 51 30 33 35 32 32   KEQ03522
0080: 37 36 15 52 61 64 69 61   76.Radia
0088: 74 6f 72 48 6f 62 62 79   torHobby
0090: 52 6f 6f 6d 52 65 61 72   RoomRear
0098: 01 01 06 c8 0c 4b 45 51   .....KEQ

The metadata contains the following information

Position   Information
00:        Meta Data Magic. Should always be 0x56
01:        Meta data version. Should always be 0x02
02:        Number of Rooms
xx-(yy-1): Meta Data for each room.
yy:        Number of Devices
(yy+1)-zz: Meta Data for each device

The magic number and meta data version always seem a fixed number. Perhaps the meta data version will be increased when a new meta data version is composed by eQ-3. So perhaps it’s best to check in your code that both numbers are 0x56 and 0x02 and log a warning if they ever change.

After the first two bytes, the next byte indicates the number of rooms (or groups) as defined in the Cube followed by a sequence of blocks of data, one for each room. The metadata for each room looks something like this

0000:          02 0a 4c 69 76   V....Liv
0008: 69 6e 67 52 6f 6f 6d 0c   ingRoom.
0010: c0 1e                     ..

Position    Information
00:         Room ID (1 byte)
01:         Length of Room Name (1 byte)
02-(xx-1):  Room Name
xx:         Room Master Address (3 bytes)

In the above example, the Room has an ID of 2, contains a name of 10 (0x0a) characters which is LivingRoom and has an address of 0x0cc01e which translates as decimal 835614.

After the sequence of rooms, the next byte contains the number of devices followed by a sequence of blocks of data, one for each device. The metadata for each device looks something like this

0050:    03 0a 12 bd 4b 45 51   .....KEQ
0058: 30 37 30 34 37 35 32 13   0704752.
0060: 54 68 65 72 6d 6f 73 74   Thermost
0068: 61 74 48 6f 62 62 79 52   atHobbyR
0070: 6f 6f 6d 01               oom.

Position    Information
00:         Device Type (1 byte)
01:         RF Address (3 byte)
04:         Serial Number (10 bytes)
0E:         Length of Device Name (1 byte)
0F-(xx-1):  Device Name
xx:         Room ID

In the above example the device type is 3, the address is 0x0a12bd which translates as decimal 660157. The serial number for this device is KEQ0704752. The name is 19 (0x13) bytes long with the value of ThermostatHobbyRoom. Lastly, the device is part of room with ID 1.

I have defined the device type, in C#, as an enumeration with the following definition

/// <summary>
/// Enumeration of possible Max Device Types.
/// The int value of the enumeration is important since it links
/// to the device type number in the MAX device.
/// </summary>
public enum MaxDeviceType
    Cube = 0,
    RadiatorThermostat = 1,
    RadiatorThermostatPlus = 2,
    WallThermostat = 3,
    ShutterContact = 4,
    EcoButton = 5

So in the above example the device (type 3) would be a Wall Thermostat Device.

And that’s it for the M message!

eQ-3 Max Cube message protocol decrypted: Part 2, the ‘H’ word

Last time I explained how to find the available Cubes on the network and get their IP-addresses.

This time we will say Hello to the Cube. And polite as it is, it will always reply with a nice Hello back.

When we connect to the Cube for the first time (with the correct IP-address on port 62910, or port 80 for older firm wares) we get a bunch of welcoming messages, the H, M, C and L responses.

Furthermore, when we send an h: message (by simply sending h:\r\n) we also get the H response. The H response is a comma separated list of fields starting with H: (like all Cube messages start with a character and a colon) An example of the H response with all fields:


00: Serial Number                    : JEQ0544923
01: RF Address, hexadecimal          : 03f25d
02: Firmware version                 : 0113
03: Unknown                          : 00000000
04: HTTP Connection ID, hexadecimal  : 299ca43f
05: Duty Cycle                       : 00
06: Free Memory slots                : 32
07: Encoded Cube Date                : 0d0c1d
08: Encoded Cube Time                : 1013
09: Clock Set (not sure what it is)  : 03
10: unknown                          : 0000

The address and firmware should look familiar because they are also present in the UDP answer when finding a cube. I have yet to familiarise myself with the duty cycle and free memory slot fields. For the time being, I store them and ignore them. Same goes for the Clock Set field.

Lastly, the date and time (which the cube uses internally) are a bit encoded. You have to split the date into its bytes, so 0d, 0c and 1d. These (hexadecimal) figures represent year, month and day. In this case it would be 13, 12, 29 which is the 29th of December, 2013.

Same goes for time. Split it in bytes, so 10 and 13. These represent hour and minutes. In this case it would be 16, 19 which would be 16:19.

The cube date and time can be important to keep watch of because, obviously, the cube uses this time for its own weekly program.

Next time I shall talk about the ‘M’ (Meta Data) Response message which will tell us which rooms (or groups as they are called internally in the Cube) and devices are present.

eQ-3 Max Cube message protocol decrypted (Part 1)

In my quest to write a gateway for the eQ-3 Max Cube I came across several sources of information. For those who are interested and for myself to keep a future reference at one place, I will try to write the info for as many messages as I can find on this blog. Perhaps needless to say that the messages also apply to the ELV version of the Cube (since the devices are equal, besides the accompanying software).

I shall start with how we get to know which Cube devices are available on the network and at what IP-Address (or addresses since there can be more than one Cube present).

When a certain UDP broadcast ‘Hello’ message is sent on port 23272, any cube in the network will respond to this message with an answer. On receiving this answer, we can check the originators IP-Address and thus know at what IP-Address the Cube is available. In the received message we can find the Cube’s serial number and firmware version. The latter of which is of importance because the TCP port at which to communicate with the Cube differs depending on the firmware version.

To send the broadcast message we can use the following code.

private const int CubeBroadcastPort = 23272;
private static byte[] _helloMessage = new byte[] { 0x65, 0x51, 0x33, 0x4d, 0x61, 0x78, 0x2a, 0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x49 };

// Broadcast hello message to find available cubes.
UdpClient sender = new UdpClient();
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, CubeBroadcastPort);
sender.Send(_helloMessage, _helloMessage.Length, ip);

ip = new IPEndPoint(IPAddress.Parse(""), CubeBroadcastPort);
sender.Send(_helloMessage, _helloMessage.Length, ip);

This will broadcast the ‘Hello’ message on the network. The Hello message looks like this:

00: 65 51 33 4d 61 78 2a 00    eQ3Max..
08: 2a 2a 2a 2a 2a 2a 2a 2a    ........
10: 2a 2a 49                   ..I

I don’t know the meaning of all bytes in the message. Suffice it to say that it works 🙂

When the above message is broadcasted, the Max! Cube device will respond with the following answer (of 26 bytes):

00: 65 51 33 4d 61 78 41 70    eQ3MaxAp
08: 4a 45 51 30 35 34 34 39    JEQ05449
10: 32 33 3e 49 00 03 f2 5d    23.I....
18: 01 13                      ..

Important in this are the following fields:

Description        Startpos    Length      Example Value
Response           00          8           eQ3MaxAp
Serial Number      08          10          JEQ0544923
Unknown            12          3           3e 49 00
Address            15          3           03 f2 5d
Firmware Version   18          2           01 13

The response is always eQ3MaxAp. You can check for the presence of this code to validate that it is indeed a hello broadcast response message.

The Serial number is a string of 10 characters containing the serial number of the Cube (which in this case would be JEQ0544923).

The address field is the 3 byte address of the Cube. In the Cube software itself all addresses seem to be displayed in decimal notation so the address for this cube would be 258653.

The last bit of info is the firmware version. This info is BCD encoded. So the firmware in this case, in decimal, would be 113. The firmware version is important for us to know at which port the Cube device listens. Prior to firmware version 109, the Cube listens at TCP port 80. Starting from firmware version 109, the TCP port will be 62910.

Next time, we will connect to the Cube device and deal with the hello message to and from the device (the so called h: and H: messages).