Spec with pseudocode and test vectors, APK disassembly, analysis tools, shelved reference Python and the macOS BLE probe. Findings are not yet validated against a real tag. The vendor XAPK and nested lib clone are excluded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EinWd3UT2Xw7UakFtTp6hn
59 lines
2.1 KiB
YAML
59 lines
2.1 KiB
YAML
# ANCEL BM200: live voltage only. History needs bm2.bm200 (reassembly across frames).
|
|
# The writes are AES-encrypted D15501, D1550200, D15507; without the last one the tag sends no live frames.
|
|
esp32_ble_tracker:
|
|
|
|
ble_client:
|
|
- mac_address: !secret bm2_mac
|
|
id: bm2_battery_meter
|
|
on_connect:
|
|
then:
|
|
- delay: 1s
|
|
- ble_client.ble_write:
|
|
id: bm2_battery_meter
|
|
service_uuid: 'fff0'
|
|
characteristic_uuid: 'fff3'
|
|
value: [0x1a, 0xd6, 0xf0, 0x5e, 0x49, 0x90, 0xab, 0x24, 0xb8, 0x4d, 0x57, 0xdf, 0x81, 0xd8, 0x76, 0x6e]
|
|
- delay: 500ms
|
|
- ble_client.ble_write:
|
|
id: bm2_battery_meter
|
|
service_uuid: 'fff0'
|
|
characteristic_uuid: 'fff3'
|
|
value: [0x9c, 0xb1, 0x80, 0x29, 0x77, 0x4c, 0x5c, 0xfc, 0x57, 0xc9, 0xf1, 0x14, 0xd4, 0x0d, 0xb4, 0xe8]
|
|
- delay: 500ms
|
|
- ble_client.ble_write:
|
|
id: bm2_battery_meter
|
|
service_uuid: 'fff0'
|
|
characteristic_uuid: 'fff3'
|
|
value: [0x69, 0x7e, 0xa0, 0xb5, 0xd5, 0x4c, 0xf0, 0x24, 0xe7, 0x94, 0x77, 0x23, 0x55, 0x55, 0x41, 0x14]
|
|
|
|
sensor:
|
|
- platform: ble_client
|
|
type: characteristic
|
|
ble_client_id: bm2_battery_meter
|
|
name: Voltage
|
|
service_uuid: 'fff0'
|
|
characteristic_uuid: 'fff4'
|
|
unit_of_measurement: 'V'
|
|
accuracy_decimals: 2
|
|
state_class: measurement
|
|
device_class: voltage
|
|
force_update: true
|
|
expire_after: 5min
|
|
notify: true
|
|
lambda: |-
|
|
if (x.size() != 16) return NAN;
|
|
mbedtls_aes_context aes;
|
|
mbedtls_aes_init(&aes);
|
|
unsigned char output[16];
|
|
unsigned char key[16] = { 108, 101, 97, 103, 101, 110, 100, 255, 254, 48, 49, 48, 48, 48, 48, 57 };
|
|
unsigned char iv[16] = {};
|
|
mbedtls_aes_setkey_dec(&aes, key, 128);
|
|
mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, 16, iv, (uint8_t*)&x[0], output);
|
|
mbedtls_aes_free(&aes);
|
|
|
|
// D1 55 07 only; 0xFF in byte 3 is the command ack
|
|
if (output[0] != 0xD1 || output[1] != 0x55 || output[2] != 0x07 || output[3] == 0xFF) return NAN;
|
|
return ((output[7] << 8) | output[8]) / 100.0f;
|
|
filters:
|
|
- filter_out: nan
|