From a9ad6e9245aa9c1284f318b9bab51f6148355712 Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Fri, 8 Mar 2024 14:04:37 +0100 Subject: [PATCH] ble device decoding on device (will move to server) last commit that has it --- gartenhaus_taster_input.yaml | 29 ++++++++ m5stackfire.yaml | 125 ++++++++++++++++------------------- m5stackfire_partition.csv | 7 ++ my_btmonitor.h | 69 +++++++++++++++++++ wohnzimmer_ble_tracker.yaml | 49 ++++++++++++++ 5 files changed, 212 insertions(+), 67 deletions(-) create mode 100644 m5stackfire_partition.csv create mode 100644 my_btmonitor.h create mode 100644 wohnzimmer_ble_tracker.yaml diff --git a/gartenhaus_taster_input.yaml b/gartenhaus_taster_input.yaml index 428b702..75a7e26 100644 --- a/gartenhaus_taster_input.yaml +++ b/gartenhaus_taster_input.yaml @@ -1,6 +1,10 @@ esphome: name: gartenhaus-taster-input + includes: + - my_btmonitor.h + libraries: + - mbedtls esp32: board: esp32-poe @@ -156,8 +160,33 @@ binary_sensor: +mqtt: + broker: homeassistant.fritz.box + username: !secret mqtt_ble_username + password: !secret mqtt_ble_password + discovery: false +esp32_ble_tracker: + scan_parameters: + interval: 1.2s + window: 500ms + active: false + on_ble_advertise: + - then: + - lambda: |- + const char * detected_device_name = ble_device_name(x.address()); + if(detected_device_name != nullptr) { + auto build_json = [&](JsonObject obj) { + obj["id"] = detected_device_name; + obj["rssi"] = x.get_rssi(); + if(x.get_tx_powers().size() > 0) + obj["tx_power"] = x.get_tx_powers()[0]; + }; + global_mqtt_client->publish_json(std::string("my_btmonitor/devices/") + detected_device_name + "/garten", + build_json); + } + #on_multi_click: # - timing: diff --git a/m5stackfire.yaml b/m5stackfire.yaml index 0fe5ef8..2341357 100644 --- a/m5stackfire.yaml +++ b/m5stackfire.yaml @@ -1,8 +1,17 @@ - esphome: name: m5stackfire - platform: ESP32 + includes: + - my_btmonitor.h + libraries: + - mbedtls + platformio_options: + board_upload.flash_size: 16MB + board_build.partitions: "../../../m5stackfire_partition.csv" + +esp32: board: m5stack-fire + framework: + type: arduino substitutions: friendly_name: "M5StackFire" @@ -22,8 +31,6 @@ ota: password: !secret ota_password logger: - hardware_uart: UART2 - baud_rate: 0 # Power Management external_components: @@ -111,35 +118,22 @@ i2c: scan: True # Display -spi: - clk_pin: 18 - mosi_pin: 23 - miso_pin: 19 - -font: - - file: "gfonts://Roboto" - id: roboto - size: 18 - -image: - - file: m5stack_display.png - id: img_background - type: RGB24 - - -display: - - platform: ili9xxx - model: M5STACK - cs_pin: 14 - dc_pin: 27 - reset_pin: 33 - id: my_display - lambda: |- - it.image(0, 0, id(img_background)); - it.printf(240, 67, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.0f ppm", id(co2value).state ); - it.printf(240, 125, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.1f °C", id(co2temp).state ); - it.printf(240, 184, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.1f %%", id(m5stackfire_dht22_humidity).state ); - +#spi: +# clk_pin: 18 +# mosi_pin: 23 +# miso_pin: 19 +# +#font: +# - file: "gfonts://Roboto" +# id: roboto +# size: 18 +# +#image: +# - file: m5stack_display.png +# id: img_background +# type: RGB24 +# +# #display: # - platform: ili9xxx # model: M5STACK @@ -148,40 +142,12 @@ display: # reset_pin: 33 # id: my_display # lambda: |- -# Color RED(1,0,0); -# Color BLUE(0,0,1); -# Color WHITE(1,1,1); -# -# it.rectangle(0, 0, it.get_width(), it.get_height(), BLUE); -# it.rectangle(0, 22, it.get_width(), it.get_height(), BLUE); // header bar -# it.print(it.get_width() / 2, 11, id(font_roboto_medium22), RED, TextAlign::CENTER, "Particulate matter"); -# -# it.print(11, 33, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "PM1"); -# it.print(11, 55, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "PM2.5"); -# it.print(11, 77, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "PM10"); -# -# ////it.printf(it.get_width() - 11, 33, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f µg/m³", 0.0); -# ////it.printf(it.get_width() - 11, 55, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f µg/m³", 0.0); -# ////it.printf(it.get_width() - 11, 77, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f µg/m³", 0.0); -# -# //it.rectangle(0, 110, it.get_width(), 22, BLUE); // header bar -# //it.print(it.get_width() / 2, 121, id(font_roboto_medium22), RED, TextAlign::CENTER, "Environment"); -# -# //it.print(11, 143, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "T"); -# //it.print(11, 165, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "H"); -# //it.print(11, 187, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "VPD"); -# //it.print(11, 209, id(font_roboto_medium22), WHITE, TextAlign::LEFT, "Tdp"); -# -# ////it.printf(it.get_width() - 77, 143, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f", 0.0); -# ////it.printf(it.get_width() - 77, 165, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f", 0.0); -# ////it.printf(it.get_width() - 77, 187, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f", 0.0); -# ////it.printf(it.get_width() - 77, 209, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%.0f", 0.0); -# -# //it.printf(it.get_width() - 11, 143, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "°C"); -# //it.printf(it.get_width() - 11, 165, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "%%"); -# //it.printf(it.get_width() - 11, 187, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "kPa"); -# //it.printf(it.get_width() - 11, 209, id(font_roboto_medium22), WHITE, TextAlign::RIGHT, "°C"); +# it.image(0, 0, id(img_background)); +# it.printf(240, 67, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.0f ppm", id(co2value).state ); +# it.printf(240, 125, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.1f °C", id(co2temp).state ); +# it.printf(240, 184, id(roboto), Color(255, 255, 255), TextAlign::TOP_CENTER, "%.1f %%", id(m5stackfire_dht22_humidity).state ); # + uart: id: uart_co2 tx_pin: GPIO17 @@ -209,5 +175,30 @@ sensor: id: m5stackfire_dht22_humidity name: "DHT22 humidity" +mqtt: + broker: homeassistant.fritz.box + username: !secret mqtt_ble_username + password: !secret mqtt_ble_password + discovery: false + +esp32_ble_tracker: + scan_parameters: + interval: 1.2s + window: 500ms + active: false + on_ble_advertise: + - then: + - lambda: |- + const char * detected_device_name = ble_device_name(x.address()); + if(detected_device_name != nullptr) { + auto build_json = [&](JsonObject obj) { + obj["id"] = detected_device_name; + obj["rssi"] = x.get_rssi(); + if(x.get_tx_powers().size() > 0) + obj["tx_power"] = x.get_tx_powers()[0]; + }; + global_mqtt_client->publish_json(std::string("my_btmonitor/devices/") + detected_device_name + "/az_oben", + build_json); + } + - \ No newline at end of file diff --git a/m5stackfire_partition.csv b/m5stackfire_partition.csv new file mode 100644 index 0000000..67d7737 --- /dev/null +++ b/m5stackfire_partition.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x640000, +app1, app, ota_1, 0x650000,0x640000, +spiffs, data, spiffs, 0xc90000,0x360000, +coredump, data, coredump,0xFF0000,0x10000, diff --git a/my_btmonitor.h b/my_btmonitor.h new file mode 100644 index 0000000..f35ad46 --- /dev/null +++ b/my_btmonitor.h @@ -0,0 +1,69 @@ +#pragma once + +#include "mbedtls/aes.h" + +int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) { + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + + if (mbedtls_aes_setkey_enc(&ctx, key, 128) != 0) { + mbedtls_aes_free(&ctx); + return -1; + } + + if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, plaintext, enc_data) != 0) { + mbedtls_aes_free(&ctx); + return -1; + } + + mbedtls_aes_free(&ctx); + return 0; +} + +struct encryption_block { + uint8_t key[16]; + uint8_t plain_text[16]; + uint8_t cipher_text[16]; +}; + +inline bool ble_ll_resolv_rpa(const uint8_t *rpa, const uint8_t *irk) { + struct encryption_block ecb; + + auto irk32 = (const uint32_t *)irk; + auto key32 = (uint32_t *)&ecb.key[0]; + auto pt32 = (uint32_t *)&ecb.plain_text[0]; + + key32[0] = irk32[0]; + key32[1] = irk32[1]; + key32[2] = irk32[2]; + key32[3] = irk32[3]; + + pt32[0] = 0; + pt32[1] = 0; + pt32[2] = 0; + pt32[3] = 0; + + ecb.plain_text[15] = rpa[5 - 3]; + ecb.plain_text[14] = rpa[5 - 4]; + ecb.plain_text[13] = rpa[5 - 5]; + + bt_encrypt_be(ecb.key, ecb.plain_text, ecb.cipher_text); + + if (ecb.cipher_text[15] != rpa[5 - 0] || ecb.cipher_text[14] != rpa[5 - 1] || ecb.cipher_text[13] != rpa[5 - 2]) return false; + + return true; +} + +static const char * ble_device_name(const uint8_t * rpa) { + static constexpr uint8_t irk_martins_apple_watch[] = {0xaa, 0x67, 0x54, 0x2b, 0x82, 0xc0, 0xe0, 0x5d, 0x65, 0xc2, 0x7f, 0xb7, 0xe3, 0x13, 0xab, 0xa5}; + static constexpr uint8_t irk_martins_iphone[] = {0x84, 0x0e, 0x38, 0x92, 0x64, 0x4c, 0x1e, 0xbd, 0x15, 0x94, 0xa9, 0x06, 0x9c, 0x14, 0xce, 0x0d}; + if(ble_ll_resolv_rpa(rpa, irk_martins_apple_watch)) { + return "martins_apple_watch"; + } + else if(ble_ll_resolv_rpa(rpa, irk_martins_iphone)) { + return "martins_iphone"; + } + else { + return nullptr; + } +} \ No newline at end of file diff --git a/wohnzimmer_ble_tracker.yaml b/wohnzimmer_ble_tracker.yaml new file mode 100644 index 0000000..a15ecd5 --- /dev/null +++ b/wohnzimmer_ble_tracker.yaml @@ -0,0 +1,49 @@ + +esphome: + name: wohnzimmer-ble-tracker + includes: + - my_btmonitor.h + libraries: + - mbedtls + +esp32: + board: m5stack-atom + framework: + type: arduino + +logger: + +ota: + password: !secret ota_password + +wifi: + ssid: WLAN + password: !secret wifi_password + +mqtt: + broker: homeassistant.fritz.box + username: !secret mqtt_ble_username + password: !secret mqtt_ble_password + discovery: false + + +esp32_ble_tracker: + scan_parameters: + interval: 1.2s + window: 500ms + active: false + on_ble_advertise: + - then: + - lambda: |- + const char * detected_device_name = ble_device_name(x.address()); + if(detected_device_name != nullptr) { + auto build_json = [&](JsonObject obj) { + obj["id"] = detected_device_name; + obj["rssi"] = x.get_rssi(); + if(x.get_tx_powers().size() > 0) + obj["tx_power"] = x.get_tx_powers()[0]; + }; + global_mqtt_client->publish_json(std::string("my_btmonitor/devices/") + detected_device_name + "/wohnzimmer", + build_json); + } +