Skip to content

Commit 46aea7c

Browse files
authored
clean up Bluetooth_MI32.md
1 parent 19972e9 commit 46aea7c

File tree

1 file changed

+131
-80
lines changed

1 file changed

+131
-80
lines changed

docs/Bluetooth_MI32.md

+131-80
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,58 @@
1+
---
2+
tags:
3+
- Bluetooth
4+
- BLE
5+
- Berry
6+
- Mijia
7+
- Xiaomi
8+
- ESP32
9+
---
10+
111
# MI32 legacy
212

3-
The MI32-driver focuses on the passive observation of BLE sensors of the Xiaomi/Mijia universe, thus only needing a small memory footprint. Berry can be used to create generic applications.
4-
Currently supported are all members of the ESP32 family with Bluetooth capabilities.
5-
The driver can be built to use Bluetooth version 5.x.
13+
Focus on the passive observation of BLE sensors of the Xiaomi/Mijia universe with a small memory footprint.
14+
Create generic Bluetooth applications with Berry.
15+
616

717
## Usage
818

9-
This driver is not part of any standard build. To self compile it is recommended to add build environments to `platformio_tasmota_cenv.ini`. This file needs to be created first.
10-
Add this section (change accordingly for the other chipsets or use one of the examples in `platformio_tasmota_cenv.ini` with naming scheme `tasmota32xx-mi32`):
11-
```
12-
[env:tasmota32-mi32-legacy]
13-
extends = env:tasmota32_base
14-
build_flags = ${env:tasmota32_base.build_flags}
15-
-DUSE_MI_ESP32
16-
-DUSE_MI_EXT_GUI
17-
-DCONFIG_BT_NIMBLE_NVS_PERSIST=y
18-
lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_div, lib/lib_ssl
19-
```
20-
21-
If you want to try out Bluetooth version 5.x, which consumes a bit more memory and has limited capabilities on the platform itself, a custom build is needed, e.g.:
22-
```
23-
[env:tasmota32c3-mi32]
24-
extends = env:tasmota32_base
25-
board = esp32c3
26-
board_build.flash_mode = qio
27-
lib_ignore = Micro-RTSP
28-
build_flags = ${env:tasmota32_base.build_flags}
29-
-DFIRMWARE_BLUETOOTH
30-
-DUSE_MI_EXT_GUI
31-
-DCONFIG_BT_NIMBLE_EXT_ADV
32-
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=1
33-
-DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3.bin"'
34-
custom_sdkconfig = CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
35-
CONFIG_BT_NIMBLE_EXT_ADV=y
36-
```
37-
38-
It is probably necessary to restart your IDE (i.e. Visual Studio Code) to see the option to build this environment.
19+
Currently supported are all members of the ESP32 family with Bluetooth capabilities.
20+
This driver is not part of any standard build. To self compile it is recommended to use `platformio_tasmota_cenv.ini`, which needs to be created first.
21+
Use or change one of the existing example sections with naming scheme `tasmota32xx-mi32`.
22+
??? example "build environment"
23+
```
24+
[env:tasmota32-mi32-legacy]
25+
extends = env:tasmota32_base
26+
build_flags = ${env:tasmota32_base.build_flags}
27+
-DUSE_MI_ESP32
28+
-DUSE_MI_EXT_GUI
29+
-DCONFIG_BT_NIMBLE_NVS_PERSIST=y
30+
lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_div, lib/lib_ssl
31+
```
32+
33+
### Bluetooth 5
34+
35+
If you want to try out Bluetooth version 5.x, which consumes a bit more memory and has limited capabilities on the ESP platform itself, a custom build is needed, e.g.:
36+
??? example "build environment BLE 5"
37+
```
38+
[env:tasmota32c3-mi32]
39+
extends = env:tasmota32_base
40+
board = esp32c3
41+
board_build.flash_mode = qio
42+
lib_ignore = Micro-RTSP
43+
build_flags = ${env:tasmota32_base.build_flags}
44+
-DFIRMWARE_BLUETOOTH
45+
-DUSE_MI_EXT_GUI
46+
-DCONFIG_BT_NIMBLE_EXT_ADV
47+
-DCONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES=1
48+
-DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3.bin"'
49+
custom_sdkconfig = CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=y
50+
CONFIG_BT_NIMBLE_EXT_ADV=y
51+
;It is probably necessary to restart your IDE (i.e. Visual Studio Code) to see the option to build this environment.
52+
```
53+
Basically every consumer BLE device with "BLE 5" capabilities has only hardware support for Bluetooth 5.x.
54+
At the time of writing there is not a single widely used product out there, that has the software support enabled.
55+
The only known exception is the open source firmware on [pvvx.github.io](https://pvvx.github.io) with possible BLE long range support, but due to hardware limitations the ESP32 platform does not gain much (aka nothing) here.
3956

4057
## Tasmota and BLE-sensors
4158

@@ -54,14 +71,14 @@ Other sensors like the MJYD2S and nearly every newer device are not usable witho
5471

5572
The idea is to provide as many automatic functions as possible. Besides the hardware setup, there are zero or very few things to configure.
5673
The sensor namings are based on the original sensor names and shortened if appropriate (Flower care -> Flora). A part of the MAC will be added to the name as a suffix.
57-
All sensors are treated as if they are physically connected to the ESP32 device. For motion and remote control sensors MQTT-messages will be published in (nearly) real time.
74+
All sensors are treated as if they are physically connected to the ESP32 device. For motion and remote control sensors MQTT-messages will be published in (nearly) real time.
5875

5976
### Supported Devices
6077

6178
!!! note "It can not be ruled out, that changes in the device firmware may break the functionality of this driver completely!"
6279

63-
The naming conventions in the product range of bluetooth sensors in XIAOMI-universe can be a bit confusing. The exact same sensor can be advertised under slightly different names depending on the seller (Mijia, Xiaomi, Cleargrass, ...).
64-
If an unknown "Mijia" sensor is found it will be added with naming scheme `MI_`+`PID` and if the builtin parser of the driver supports the packet type, it will work too.
80+
The naming conventions in the product range of bluetooth sensors in XIAOMI-universe can be a bit confusing. The exact same sensor can be advertised under slightly different names depending on the seller (Mijia, Xiaomi, Cleargrass, ...).
81+
If an unknown "Mijia" sensor is found it will be added with naming scheme `MI_`+`PID` and if the builtin parser of the driver supports the packet type, it will work too.
6582

6683
<table>
6784
<tr>
@@ -161,8 +178,10 @@ If an unknown "Mijia" sensor is found it will be added with naming scheme `MI_`+
161178
<td class="tg-lboi">passive only with decryption (legacy decryption)<br>both versions reported as YLKG08</td>
162179
</tr>
163180
</table>
164-
passive: data is received via BLE advertisements
165-
active: data is received via bidirectional connection to the sensor
181+
182+
[passive]: data is received via BLE advertisements
183+
[active]: data is received via bidirectional connection to the sensor
184+
166185

167186
#### Devices with payload encryption
168187

@@ -180,9 +199,9 @@ rule1 on System#Boot do backlog MI32key 00112233445566778899AABBCCDDEEFF11223344
180199

181200
### Tracking of BLE devices and "iPhone presence detection"
182201

183-
It is possible to track generic BLE devices with `mi32option5 1>`. This includes every device with a public address (aka a fixed MAC address) out of the box.
184-
Additionally it is possible to observe (typically more modern) BLE devices with a *Random Private Resolvable Address* or in short RPA, which includes iPhones and other Apple devices.
185-
For the latter it is necessary to retrieve the Identiy Resolving Key (= IRK), which is supported in directly the driver with the help of a Berry script:
202+
It is possible to track generic BLE devices with `mi32option5 1`. This includes every device with a public address (aka a fixed MAC address) out of the box.
203+
Additionally it is possible to observe (typically more modern) BLE devices with a *Random Private Resolvable Address* or in short RPA, which includes iPhones and other Apple devices.
204+
For the latter it is necessary to retrieve the Identiy Resolving Key (= IRK), which is supported directly by the driver with the help of a Berry script:
186205

187206
??? example " Retrieve IRK from BLE device with RPA"
188207

@@ -421,8 +440,8 @@ MI32Option5|`0` = do not report generic BLE devices (default)<br>`1` = report ev
421440

422441
## Mi Dashboard
423442

424-
The driver provides an extended web GUI to show the observed Xiaomi sensors in a widget style, that features a responsive design to use the screen area as effective as possible. The other advantage is, that only the widget with new data gets redrawn (indicated by a fading circle) and no unnecessary refresh operations will happen. A simple graph shows if valid data for every hour was received in the last 24h, where only one gap for the coming hour is not a sign of an error. Configured sensors with no received packet since boot or key/decryption errors are dimmed.
425-
Own widgets can be added with Berry using the `MI32` module, thus allowing to create small Apps or visualizing the state of arbitrary BLE devices.
443+
The driver provides an extended web GUI to show the observed Xiaomi sensors in a widget style, that features a responsive design to use the screen area as effective as possible. The other advantage is, that only the widget with new data gets redrawn (indicated by a fading circle) and no unnecessary refresh operations will happen. A simple graph shows if valid data for every hour was received in the last 24h, where only one gap for the coming hour is not a sign of an error. Configured sensors with no received packet since boot or key/decryption errors are dimmed.
444+
Own widgets can be added with Berry using the `MI32` module, thus allowing to create small Apps or visualizing the state of arbitrary BLE devices.
426445

427446

428447
## Homeassistant and Tasmota - BLE sensors
@@ -561,6 +580,15 @@ We just have to provide a pointer to a (callback) function and a byte buffer. T
561580
1 byte - length of payload
562581
n bytes - payload data
563582
```
583+
```mermaid
584+
packet-beta
585+
0-5: "MAC"
586+
6: "t"
587+
7: "R"
588+
8: "l"
589+
9-40: "payload data (up to 31 byte)"
590+
41-71: "optional scan response (up to 31 byte)"
591+
```
564592

565593
The advertisement callback function provides 2 arguments, which are indices of the whole buffer that point to optional parts of the payload. A value of 0 means, this type of of element is not in the payload.
566594
1. svc (= service data index) - index of service data in the advertisement buffer
@@ -588,40 +616,55 @@ cbuf = bytes(-64)
588616
def cb(error,op,uuid,handle)
589617
end
590618
591-
cbp = tasmota.gen_cb(cb)
619+
cbp = tasmota.gen_cb(/e,o,u,h->cb)
592620
BLE.conn_cb(cbp,cbuf)
593621
```
594622

595-
#####Return values of the callback function
596-
597-
Error (codes):
598-
599-
- 0 - no error
600-
- 1 - connection error
601-
- 2 - did disconnect
602-
- 3 - did not get service
603-
- 4 - did not get characteristic
604-
- 5 - could not read value
605-
- 6 - characteristic can not notify
606-
- 7 - characteristic not writable
607-
- 8 - did not write value
608-
- 9 - timeout: did not read on notify
609-
610-
Op (codes):
611-
612-
- 1 - read
613-
- 2 - write
614-
- 3 - subscribe - direct response after launching a run command to subscribe
615-
- 5 - disconnect
616-
- 6 - retrieve all *services* of connected device
617-
- 7 - retrieve all *characteristics* and *GATT Characteristic Property Flags* of a service
618-
- 103 - notify read - the notification with data from the BLE server
619-
620-
uuid:
621-
Returns the 16 bit UUID of the characteristic as a number, even if the UUID was 128 bit.
622-
623-
handle:
624-
Returns the 16 bit handle of the characteristic as a number.
623+
```mermaid
624+
---
625+
title: "Return values of the callback function"
626+
---
627+
classDiagram
628+
class cb{
629+
<<function>>
630+
error, operation, uuid, handle
631+
}
632+
class error{
633+
<<int>>
634+
0 - no error
635+
1 - connection error
636+
2 - did disconnect
637+
3 - did not get service
638+
4 - did not get characteristic
639+
5 - could not read value
640+
6 - characteristic can not notify
641+
7 - characteristic not writable
642+
8 - did not write value
643+
9 - timeout: did not read on notify
644+
}
645+
class operation{
646+
<<int>>
647+
1 - read
648+
2 - write
649+
3 - subscribe - response to command to subscribe, not a notification
650+
5 - disconnect
651+
6 - retrieve all services of connected device
652+
7 - retrieve all characteristics and GATT Characteristic Property Flags of a service
653+
103 - notify read - the notification with data from the BLE server
654+
}
655+
class uuid{
656+
<<int>>
657+
16-bit uuid
658+
}
659+
class handle{
660+
<<int>>
661+
16-bit handle
662+
}
663+
cb --|> error
664+
cb --|> operation
665+
cb --|> uuid
666+
cb --|> handle
667+
```
625668

626669
Internally this creates a context, that can be modified with the following methods:
627670

@@ -644,7 +687,7 @@ Finally run the context with the specified properties and (if you want to get da
644687

645688
- 11 - read - then disconnect (returns 1 in the callback)
646689
- 12 - write - then disconnect (returns 2 in the callback)
647-
- 13 - subscribe - then disconnect after waiting for notification(returns 3 in the callback)
690+
- 13 - subscribe - then disconnect after waiting for notification (returns 3 in the callback)
648691

649692
The buffer format for reading and writing is in the format (length - data):
650693
```
@@ -654,7 +697,9 @@ n bytes - data
654697

655698
#### Central role (aka server)
656699

657-
The server is initiated similarly with `BLE.serv_cb(cbp,cbuf)`. After that you have to construct the server by first adding all *characteristics* and finally starting it, by setting the *advertisement* data for the first time. Setting *advertisement* data without adding *characteristics* will not start a BLE server but only a BLE Broadcaster, which is totally fine for some use cases (i.e. Beacons, BTHome).
700+
The server is initiated similarly with `BLE.serv_cb(cbp,cbuf)`.
701+
After that you have to construct the server by first adding all *characteristics* and finally starting it, by setting the *advertisement* data for the first time.
702+
Setting *advertisement* data without adding *characteristics* will not start a BLE server but only a BLE Broadcaster, which is totally fine for some use cases (i.e. Beacons, BTHome).
658703
The BLE server can be stopped with `BLE.serv_cb(nil)`, which will restart the "BLE Scan Task".
659704

660705
The callback functions returns error, operation, 16-bit-uuid and 16-bit-handle.
@@ -674,9 +719,13 @@ BLE.serv_cb(cbp,cbuf)
674719

675720
####Command op codes:
676721

677-
- 201 - add and/or set advertisement data according to the BLE standard, typically chaining small packets in the in the format of `length-type-data`. When called for the first time, will return a bytes buffer, that represents an array of the 16-bit-handles of all characteristics in the order of addition.
722+
- 201 - add and/or set advertisement data according to the BLE standard, typically chaining small packets in the in the format of `length-type-data`.
723+
When called for the first time, will return a bytes buffer, that represents an array of the 16-bit-handles of all characteristics in the order of addition.
678724
- 202 - add and/or set scan response data, according to the BLE standard which is equally to the advertisement data. Should be used sparsely.
679-
- 211 - add and/or set characteristic with value of bytes buffer. For simplicity a `Client Characteristic Configuration Descriptor` (aka 0x2902) will be added on construction of every characteristic and read, write, notification and indication is enabled. You can select write with or without response withe the optional boolean of `BLE.set_chr(string, bool)`, which defaults to "write with no response". The function call will always trigger a *notification*. As every *characteristic* belongs to a *service*, `BLE.set_svc(string)` must have been called before.
725+
- 211 - add and/or set characteristic with value of bytes buffer.
726+
For simplicity a `Client Characteristic Configuration Descriptor` (aka 0x2902) will be added on construction of every characteristic and read, write, notification and indication is enabled.
727+
You can select write with or without response withe the optional boolean of `BLE.set_chr(string, bool)`, which defaults to "write with no response".
728+
The function call will always trigger a *callback*. As every *characteristic* belongs to a *service*, `BLE.set_svc(string)` must have been called before.
680729

681730
####Response op codes (triggered when a client interacts with the server):
682731

@@ -693,15 +742,17 @@ BLE.serv_cb(cbp,cbuf)
693742

694743
!!! tip
695744

696-
By default the synchronization between the BLE framework and Berry happens every 50 milliseconds, which should be enough for the majority of use cases. For very fast BLE devices it can be necessary to use Berrys `fast_loop` to trigger this at maximum speed (of about every 5 milliseconds). This is typically done in an init function of a class like that:
745+
By default the synchronization between the BLE framework and Berry happens every 50 milliseconds, which should be enough for the majority of use cases.
746+
For very fast BLE devices it can be necessary to use Berrys `fast_loop` to trigger this at maximum speed (of about every 5 milliseconds).
747+
This is typically done in an init function of a class like that:
697748
`tasmota.add_fast_loop(/-> BLE.loop())`
698749

699750
####Configuration op codes (return immediately, no callback involved):
700751

701752
- 231 - set own address to random with `BLE.set_MAC(bytes("aabbccddeeff"),1)`
702753
- 232 - set advertising parameters with bytes() descriptor of length 5 [advType:byte, minInterval:uint16_t, max interval: uint16_t]
703754
- 233 - set GAP name with `string` in bytes buffer (must be null terminated)
704-
755+
705756
### Berry examples
706757

707758
Here is an implementation of the "old" MI32 commands:

0 commit comments

Comments
 (0)