Skip to content
David Bonnes edited this page Mar 7, 2020 · 60 revisions

The basic packet structure is:

aaa XX bbb DEVICE_ID DEVICE_ID DEVICE_ID CODE nnn PAYLOAD.....

It is a number of fixed-length ascii fields, separated by spaces, with a variable length payload at the end. See here for specific detail how to check that a packet is valid, before decoding the payload.

aaa: RSSI Value and bbb: Sequence Number

In short, these can usually be ignored; Evohome does not use sequence numbers.

WIP: The text aaa is the RSSI strength number field but it is not considered to be used by Evohome devices. WIP: The text bbb is a legacy message number field and this is not usually used in messages between Evohome devices.

These fields will have a 3-digit decimal number, with leading zeros, or --- if they are not used.

XX: Packet Verb and CODE: Packet Code (WIP)

Packet type will be one of the following:

  • ' I' information (note the space before the I)
  • 'RQ' request
  • 'RP' response (to a request)
  • ' W' write (note the space before the W)

Documentation on each code is available separately. Beware that, for historical reasons, the name commonly used for packet codes may - strictly speaking - be misleading, for example Zone Temperature (0x30C9) can contain a temperature that is the temperature of a device rather than a zone.

PAYLOAD: Packet Payload and nnn: Length

The payload is a sequence of (8-bit) bytes represented in hexadecimal (i.e. 00 to FF) and with a maximum length of 48 (minimum length 1). If the message will not fit into the payload, then additional packets are sent (or can be requested) with the remaining portion of the message (e.g. codes 0x000A, 0x0404).

Payload length is interpreted as a decimal number with leading zeros.

Beware: the payload length field is the length of the payload in pairs of hexadecimal characters. Thus, a PAYLOAD of 001234 would have nnn equal to 003, which is 6 characters; 034 is 68 characters.

The payload for a given code will not always be a particular length (this is true even for payloads that are not arrays):

095  I ---  --:------  --:------ THM:227486 1100 005 0018040400
095  I --- BDR:171587  --:------ BDR:171587 1100 008 00180404007FFF01

Each payload is decoded according to its packet type, code, and the sending device_type to provide a message (e.g. 'set the system to away mode'). For example, a temperature packet (0x30C9) from:

  • a device: is the temperature recorded by that device, and is always of length 6 bytes
  • the controller: is an array of temperatures (one for each zone), and in thus a multiple of 6 bytes

The first byte of a payload may contain an index value, such as a zone_idx (00 to 0B), a domain_id (F9, FA, FC), or some other value. Beware, a value of 00 is not always for zone 0.

For some packets, usually from the controller, the payload may be an array of payloads, each with its own index value (see code 0x30C9), for example:

045  I --- 01:145038 --:------ 01:145038 2309 018 00076C0107D002079E03073A0406D60506D6

where the payload, 00076C0107D00..., can be shown as and array of 6 zone entries:

00-076C 01-07D0 02-079E 03-073A 04-06D6 05-06D6

CHECK: Beware, the zone_idx numbers to not have to be an ascending sequence, for example, if zone 3 is deleted, the devices in zone 4 will continue to believe themselves to be in zone_idx == 04 (even if, ultimately, that is the only zone).

What's in a Payload

The encoding of the payload varies greatly, according to the packet code. Notably, it can contain device numbers, command codes, and ASCII characters. Numbers (integers and floats) may be stored as hexadecimal, integers, or even a sequence of bits.

Many packets have no functional payload, those will be 00, with a length of 001.

DEVICE_ID: Device Identifiers

Valid packets have three address fields that may contain a device ID and have a structure of their own, for example: 12:123456 and 18:105324.

Packets are invariably from (sent by) the device that is in the first address field (the only known exception to this is for non-evohome devices).

Packets are usually to (sent to) the device in the third address field. For announcements, the 3rd address will match the 1st, for example, here are the packets send by a controller every sync interval:

045  I --- 01:145038 --:------ 01:145038 1F09 003 FF073F
045  I --- 01:145038 --:------ 01:145038 2309 024 0007D00107D002079E03073A04079E0506D606073A0801F4
045  I --- 01:145038 --:------ 01:145038 30C9 021 0007DF01080B0207D10307660407550508100608AB

There are special device ids, such as --:------ (no device) and 63:262142 (aka 7FFFFF).

049  I --- 30:082155 63:262142 --:------ 10E0 038 000001C90011006CFEFFFFFFFFFF090907E0425244472D30324A415330310000000000000000
053  I --- 04:189082 63:262142 --:------ 1FC9 006 0030C912E29A

Device identifiers may also appear in payloads, although they will appear in a completely different format, for example: 3C6FA9 and 06368E. An evohome controller's id can be obtained through its user interface and will be in this format.

There are known algorithms for converting between the two types of device id (see below).

WIP: HGI and CTL are examples of labels used to represent specific types of device IDs and "--:------" denotes a blank device ID. All messages must contain 3 device IDs and at most, two of these may be blank depending on the specific message. For your specific system these labels must be replaced by actual device IDs.

Device Types

In the standard device id format, the two digits before the colon (:) represent the device type.

DEVICE_MAP = {
    "01": "CTL",  # Controller
    "02": "UFH",  # Underfloor heating (HCC80, HCE80)
    "03": "HCW",  # Thermostat with manual setpoint control (HCW82)
    "04": "TRV",  # Thermostatic radiator valve (HR80, HR91, HR92)
    "07": "DHW",  # DHW sensor (CS92)
    "10": "OTB",  # OpenTherm bridge (R8810)
    "12": "THm",  # Thermostat with setpoint schedule control (DTS92E)
    "13": "BDR",  # Wireless relay box (BDR91)
    "18": "HGI",  # Honeywell Gateway Interface (HGI80, HGS80)
    "22": "THM",  # Thermostat with setpoint schedule control (DTS92E)
    "30": "GWY",  # Internet Gateway (RFG100)
    "34": "STA",  # Thermostat with/without setpoint control (T87RF)
    "63": "NUL",  # Null/Broadcast devices
}

Other device types have been seen (32), but are not yet well understood.

Device Number to ID

def dev_hex_to_id(device_hex: str, friendly_id=False) -> str:
    """Convert (say) '06368E' to '01:145038' (or 'CTL:145038')."""
    if device_hex == "FFFFFF":  # aka '63:262143'
        return f"{'':10}" if friendly_id else f"{'':9}"
    if not device_hex.strip():    # aka '--:------'
        return f"{'':10}" if friendly_id else "--:------"
    _tmp = int(device_hex, 16)
    dev_type = f"{(_tmp & 0xFC0000) >> 18:02d}"
    if friendly_id:
        dev_type = DEVICE_MAP.get(dev_type, f"{dev_type:<3}")
    return f"{dev_type}:{_tmp & 0x03FFFF:06d}"

Device ID to Number

def dev_id_to_hex(device_id: str) -> str:
    """Convert (say) '01:145038' (or 'CTL:145038') to '06368E'."""
    if len(device_id) == 9:  # e.g. '01:123456'
        dev_type = device_id[:2]
    else:  # len(device_id) == 10, e.g. 'CTL:123456', or ' 63:262143'
        dev_type = DEVICE_LOOKUP.get(device_id[:3], device_id[1:3])
    return f"{(int(dev_type) << 18) + int(device_id[-6:]):0>6X}"  # sans preceding 0x

WIP: The payload decode information shown in each command uses the Python slices syntax i.e. [start:stop] where the first nibble (4 bits) is numbered 0.

Clone this wiki locally