Skip to content

Commit ffadeb8

Browse files
Create reference.md
1 parent f30b41e commit ffadeb8

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

reference.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# BTHome v2 Advertising Payload for MicroPython
2+
3+
The BTHome v2 format reference is published at https://bthome.io/format/. This document will distill the format into a blueprint for MicroPython code.
4+
5+
Given the following sample BTHome advertising payload:
6+
7+
```
8+
020106 0B094449592D73656E736F72 0A16D2FC4002C40903BF13
9+
```
10+
11+
The advertisement is one continuous string of hex digits, but is separated into three distint parts using spaces for ease of reading. These parts are:
12+
13+
1. Flags
14+
2. Local Name
15+
3. Service Data
16+
17+
## Advertisement Flags
18+
19+
The first part contains Bluetooth flags. It is always the same for any BTHome advertisements.
20+
21+
```
22+
020106
23+
```
24+
25+
* 02 is the length byte
26+
* 01 is an indicator for flags
27+
* 06 is flag data (0b00000110)
28+
* bit 1: LE General Discoverable Mode
29+
* bit 2: BR/EDR Not Supported
30+
31+
Because it never changes, flags can be represented as a static bytestring.
32+
33+
```
34+
BTHOME_FLAGS = bytes.fromhex('020106')
35+
```
36+
37+
## Device Name
38+
39+
The second part contains the name of the device encoded as ASCII with bytes prepended to indicate name length and type.
40+
41+
```
42+
0B094449592D73656E736F72
43+
```
44+
45+
* 0B is the length byte (does not include the length byte itself in calculations, but does inslude the type indicator for complete or shortened)
46+
* 09 is an indicator for complete name (as opposed to shortened name being 0x08)
47+
* 4449592D73656E736F72 ASCII encoded hex string reading "DIY-sensor"
48+
49+
The device name should be user defined and flexible in length. But, it is competing for the small space available for advertising data. Ten bytes (the same as used by the example name "DIY-sensor" seems to be a reasonable limit.
50+
51+
See https://stackoverflow.com/questions/65568893/how-to-know-the-maximum-length-of-bt-name#65577574 for a good discussion of this limit.
52+
53+
Because the name is user definded and may vary in length, it will be provided as a string and:
54+
* The string length must be non-zero and not exceeding maximum length
55+
* The string must be converted to ASCII-encoded bytes
56+
* The length of the string must be calculated
57+
* The complete name indicator (0x09) must be prepended to the byte string.
58+
* The length of the string (including the "complete name" indicator) must be calculated and prepended to the final byte string.
59+
60+
61+
## Service Data
62+
63+
The third part is service data. It contains the information to indicate a BTHome advertisement as well as values gathered from various sensors.
64+
65+
```
66+
0A16D2FC4002C40903BF13
67+
```
68+
69+
* 0A is the length byte
70+
* 16 indicates a service data type of UUID16 follows
71+
* D2FC is the UUID16 indicating BTHome data follows (little endian format for FCD2, the UUID16 reserved for BTHome)
72+
* 40 is flag data
73+
* bit 0: encrypted
74+
* bit 1: reserved
75+
* bit 2: trigger based (irregular advertisement triggered by some user interaction)
76+
* bit 3: reserved
77+
* bit 4: reserved
78+
* bits 5..7: BTHome version (010 for version 2)
79+
* 02C40903BF13 represents sensor data
80+
* 02 indicates temperature measurement
81+
* C409 is 25 C temperature in little endian format with a two-place fixed-point decimal (similar to GATT characteristic)
82+
* 03 indicates humidity measurement
83+
* BF13 is 50.55% humidity in little endian with a two-place fixed-point decimal (similar to GATT characteristic)
84+
85+
Additional sensor types and value may be found under the heading of "sensor data" on https://bthome.io/format/
86+
87+
Because an arbitrary number of zero or more sensors can be configured, the byte string should start as 16D2FC (UUID16 indicator and BTHome UUID.)
88+
* Flag data should be 0x00 for regular interval devices or 0x40 for triggered devices.
89+
* Encryption will remain unimplemented at this time, so the bit 0 will be 0.
90+
* Sensors configured to send updates at regular intervals should have a bit 2 of 0, triggered advertisements have a bit 2 of 1.
91+
* Sensor readings should be put into proper format and appended.
92+
* Each reading starts with a one-byte object ID to indicate the type
93+
* Reading values are always little endian
94+
* Non-integer values used fix-point decimal (often two decimal places)
95+
* Length of values can vary between one to three bytes depending on object ID
96+
97+
`struct.pack()` is helpful in converting object ID and value to little endian bytes. 24-bit values pose a challenge because there is no format string for a 3-byte value available to `struct.pack()`. This can be overcome by using a 32-bit long int (L) format and removing the final 0x00 byte.
98+
99+
Examples for encoding environmental data include the following:
100+
101+
```
102+
temperature_bytes = pack('<Bh', BTHOME_TEMPERATURE_SINT16, temperature_celsius * 100)
103+
humidity_bytes = pack('<Bh', BTHOME_HUMIDITY_UINT16, round(humidity_percent * 100))
104+
illuminance_bytes = pack('<BL', BTHOME_ILLUMINANCE_UINT24, illuminance_lux)[:-1]
105+
```

0 commit comments

Comments
 (0)