BTHome logo

This is the documentation for BTHome v1. This API is considered legacy and should not be used for new projects.

Example Data

The BTHome v1 format can best be explained with an example. First, the basics:
Bluetooth defines a single packet format for both advertising and data transmissions. This packet consist of four components: preamble (1 octet), access address (4 octets), Protocol Data Unit – PDU (2-257 octets), and Cyclic Redundancy Check – CRC (3 octets). If you want to learn more about the BLE format, you can read this).

BLE packet

Advertising payload

The actual data is being sent as part of the PDU, as the Payload, as indicated in green. The advertising payload is a long message with bytes (bytestring). An example of a BTHome payload is: 020106 0B094449592D73656E736F72 0B161C182302C4090303BF13

The advertising payload can consist of one or more Advertising Data (AD) elements. Each element contains the following:

The advertising payload should contain the following three AD elements:

In the example, we have:

BTHome Data format

The BTHome data can contain multiple measurements. We continue with the example from above.

BTHome data = 0x1C18 2302C409 0303BF13

Lets explain how the last two data packets work. The temperature packet is used as example. The first byte 0x23 (in bits 00100 011) is giving information about:

Type Bit 5-7 Format Data Type
0 000 uint unsigned integer
1 001 int signed integer
2 010 float float
3 011 string string
4 100 MAC MAC address (reversed)

Supported data

Full example payloads for each data type.

Sensor data

Object id Property Preferred data type Factor Example Result Unit
0x01 battery uint8 (1 byte) 1 020161 97 %
0x02 temperature sint16 (2 bytes) 0.01 2302CA09 25.06 °C
0x03 humidity uint16 (2 bytes) 0.01 0303BF13 50.55 %
0x2E humidity uint1 (1 byte) 1 022E23 35 %
0x04 pressure uint24 (3 bytes) 0.01 0404138A01 1008.83 hPa
0x05 illuminance uint24 (3 bytes) 0.01 0405138A14 13460.67 lux
0x06 mass (kg) uint16 (2 byte) 0.01 03065E1F 80.3 kg
0x07 mass (lb) uint16 (2 byte) 0.01 03073E1D 74.86 lb
0x08 dewpoint sint16 (2 bytes) 0.01 2308CA06 17.38 °C
0x09 count uint (4 bytes) 1 020960 96
0X0A energy uint24 (3 bytes) 0.001 040A138A14 1346.067 kWh
0x0B power uint24 (3 bytes) 0.01 040B021B00 69.14 W
0x0C voltage uint16 (2 bytes) 0.001 030C020C 3.074 V
0x0D pm2.5 uint16 (2 bytes) 1 030D120C 3090 ug/m3
0x0E pm10 uint16 (2 bytes) 1 030E021C 7170 ug/m3
0x12 co2 uint16 (2 bytes) 1 0312E204 1250 ppm
0x13 tvoc uint16 (2 bytes) 1 03133301 307 ug/m3
0x14 moisture uint16 (2 bytes) 0.01 0314020C 30.74 %
0x2F moisture uint8 (1 byte) 1 022F23 35 %
0x50 timestamp uint48 (4 bytes) - 05505396164 see below
0x51 acceleration uint16 (2 bytes) 0.001 03518756 22.151 m/s²
0x52 gyroscope uint16 (2 bytes) 0.001 03528756 22.151 °/s
0x53 text see below - 0D5348656C6C6F20576F726C6421 Hello World!
0x54 raw see below - 0D5448656C6C6F20576F726C6421 48656c6c6f20576f726c6421
Timestamp

The timestamp sensor needs a little more explanation. The timestamp sensor is defined as number of seconds since 1970-1-1, 00:00:00, UTC, (also called epoch time), and is returning a datetime object with timezone UTC. 0x5D396164 is, after converting from bytes (little endian) to an integer, 1684093277 seconds, which corresponds to 2023-5-14, 19:41:17. The corresponding datetime object that is returned is: datetime(2023, 5, 14, 19, 41, 17, tzinfo=timezone.utc)

Text and Raw sensors

Text has to be encoded in UTF-8, while the raw sensor is reported back as hexadecimal string. The byte string 0x48656C6C6F20576F726C6421 in text is Hello World!, while in raw sensor will give 48656c6c6f20576f726c6421 as result.

Multiple measurements of the same type

If you want to send multiple measurements of the same type, e.g. three temperatures, you can just add multiple measurements of the same type to the payload. A postfix will be added to the measurement name (e.g. temperature_2) in the order of which you define the measurements. Note that this implies that you will need to use the same order in each advertisement, to prevent measurements being assigned to the wrong entity. If only one measurement of a certain type is sent, no postfix will be used.

Binary Sensor data

Binary sensor data should always be an uint8 of a single byte. Its value should be 1 for on, and 0 for off. Note: Binary sensors will be supported in Home Assistant 2022.10.

Object id Property Data type Example Result
0x0F generic boolean uint8 (1 byte) 020F01 1 (True = On)
0x10 power uint8 (1 byte) 021001 1 (True = On)
0x11 opening uint8 (1 byte) 021100 0 (False = Closed)
0x15 battery uint8 (1 byte) 021501 1 (True = Low)
0x16 battery charging uint8 (1 byte) 021601 1 (True = Charging)
0x17 carbon monoxide uint8 (1 byte) 021700 0 (False = Not detected)
0x18 cold uint8 (1 byte) 021801 1 (True = Cold)
0x19 connectivity uint8 (1 byte) 021900 0 (False = Disconnected)
0x1A door uint8 (1 byte) 021A00 0 (False = Closed)
0x1B garage door uint8 (1 byte) 021B01 0 (False = Closed)
0x1C gas uint8 (1 byte) 021C01 1 (True = Detected)
0x1D heat uint8 (1 byte) 021D00 0 (False = Normal)
0x1E light uint8 (1 byte) 021E01 1 (True = Light detected)
0x1F lock uint8 (1 byte) 021F01 1 (True = Unlocked)
0x20 moisture uint8 (1 byte) 022001 1 (True = Wet)
0x21 motion uint8 (1 byte) 022100 0 (False = Clear)
0x22 moving uint8 (1 byte) 022201 1 (True = Moving)
0x23 occupancy uint8 (1 byte) 022301 1 (True = Detected)
0x24 plug uint8 (1 byte) 022400 0 (False = Unplugged)
0x25 presence uint8 (1 byte) 022500 0 (False = Away)
0x26 problem uint8 (1 byte) 022601 1 (True = Problem)
0x27 running uint8 (1 byte) 022701 1 (True = Running)
0x28 safety uint8 (1 byte) 022800 0 (False = Unsafe)
0x29 smoke uint8 (1 byte) 022901 1 (True = Detected)
0x2A sound uint8 (1 byte) 022A00 0 (False = Clear)
0x2B tamper uint8 (1 byte) 022B00 0 (False = Off)
0x2C vibration uint8 (1 byte) 022C01 1 (True = Detected)
0x2D window uint8 (1 byte) 022D01 0 (False = Closed)

Events

Devices can also send events. Events are a combination of a device type (like a button or dimmer) and an event (like "press" or "long press" or "rotate left 3 steps"). Note: Events will be supported in Home Assistant 2023.5 and higher.

Object id Device type Event id Event type Event property Example Result
0x3A button 0x00 None 023A00
0x01 press 023A01 press
0x02 double_press 023A02 double_press
0x03 triple_press 023A03 triple_press
0x04 long_press 023A04 long_press
0x05 long_double_press 023A05 long_double_press
0x06 long_triple_press 023A06 long_triple_press
0x3C dimmer 0x00 None 023C00
0x01 rotate left # steps 033C0103 rotate left 3 steps
0x02 rotate right # steps 033C020A rotate right 10 steps
Multiple events of the same type

Similar as for sensors and binary sensors, you can also send multiple events of the same type, by just adding them behind each other. The event `0x00` (None) is a special event that can be used in case you e.g. have a device with two buttons, and you only want to send an event for the 2nd button. An event 023A00203A01 will send no event for the first button, and an event "press" for the second button.

Misc data

Packet id

The packet id is optional and can be used to filter duplicate data. This allows you to send multiple advertisements that are exactly the same, to improve the chance that the advertisement arrives. BTHome receivers should only process the advertisement if the packet id is different compared to the previous one. The packet id is a value between 0 (0x00) and 255 (0xFF), and should be increased on every change in data. Note that the packet id is not used in the Home Assistant integration, as Home Assistant has its own deduplication mechanism.

Object id Property Data Type Example Result
0x00 packet id uint8 (1 byte) 020009 9

Encryption

Unencrypted BLE advertisements can be read by anyone nearby listening for Bluetooth packets. BTHome supports AES encryption (CCM mode) which works with a pre-shared key. When encrypted, the data can only be read by knowing the encryption key. The encryption key should be a 16 bytes long key (32 characters).

More information on how to encrypt your messages is demonstrated in this script.

Scope & Constraints

The goal of the BTHome standard is to share sensor data efficiently via Bluetooth LE discovery packets. It is not the goal to offer a way for devices to share control.