ESPHome  2024.3.2
ble_presence_device.h
Go to the documentation of this file.
1 #pragma once
2 
6 
7 #ifdef USE_ESP32
8 
9 #ifdef USE_ARDUINO
10 #include "mbedtls/aes.h"
11 #include "mbedtls/base64.h"
12 #endif
13 
14 #ifdef USE_ESP_IDF
15 #define MBEDTLS_AES_ALT
16 #include <aes_alt.h>
17 #endif
18 
19 namespace esphome {
20 namespace ble_presence {
21 
24  public Component {
25  public:
26  void set_address(uint64_t address) {
28  this->address_ = address;
29  }
30  void set_irk(uint8_t *irk) {
31  this->match_by_ = MATCH_BY_IRK;
32  this->irk_ = irk;
33  }
34  void set_service_uuid16(uint16_t uuid) {
37  }
38  void set_service_uuid32(uint32_t uuid) {
41  }
42  void set_service_uuid128(uint8_t *uuid) {
45  }
46  void set_ibeacon_uuid(uint8_t *uuid) {
49  }
50  void set_ibeacon_major(uint16_t major) {
51  this->check_ibeacon_major_ = true;
52  this->ibeacon_major_ = major;
53  }
54  void set_ibeacon_minor(uint16_t minor) {
55  this->check_ibeacon_minor_ = true;
56  this->ibeacon_minor_ = minor;
57  }
58  void set_minimum_rssi(int rssi) {
59  this->check_minimum_rssi_ = true;
60  this->minimum_rssi_ = rssi;
61  }
62  void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
63  bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
64  if (this->check_minimum_rssi_ && this->minimum_rssi_ > device.get_rssi()) {
65  return false;
66  }
67  switch (this->match_by_) {
69  if (device.address_uint64() == this->address_) {
70  this->set_found_(true);
71  return true;
72  }
73  break;
74  case MATCH_BY_IRK:
75  if (resolve_irk_(device.address_uint64(), this->irk_)) {
76  this->publish_state(true);
77  this->found_ = true;
78  return true;
79  }
80  break;
82  for (auto uuid : device.get_service_uuids()) {
83  if (this->uuid_ == uuid) {
84  this->set_found_(true);
85  return true;
86  }
87  }
88  break;
90  if (!device.get_ibeacon().has_value()) {
91  return false;
92  }
93 
94  auto ibeacon = device.get_ibeacon().value();
95 
96  if (this->ibeacon_uuid_ != ibeacon.get_uuid()) {
97  return false;
98  }
99 
100  if (this->check_ibeacon_major_ && this->ibeacon_major_ != ibeacon.get_major()) {
101  return false;
102  }
103 
104  if (this->check_ibeacon_minor_ && this->ibeacon_minor_ != ibeacon.get_minor()) {
105  return false;
106  }
107 
108  this->set_found_(true);
109  return true;
110  }
111  return false;
112  }
113 
114  void loop() override {
115  if (this->found_ && this->last_seen_ + this->timeout_ < millis())
116  this->set_found_(false);
117  }
118  void dump_config() override;
119  float get_setup_priority() const override { return setup_priority::DATA; }
120 
121  protected:
122  void set_found_(bool state) {
123  this->found_ = state;
124  if (state)
125  this->last_seen_ = millis();
126  this->publish_state(state);
127  }
130 
131  uint64_t address_;
132  uint8_t *irk_;
133 
135 
137  uint16_t ibeacon_major_{0};
138  uint16_t ibeacon_minor_{0};
139 
141 
142  bool check_ibeacon_major_{false};
143  bool check_ibeacon_minor_{false};
144  bool check_minimum_rssi_{false};
145 
146  bool resolve_irk_(uint64_t addr64, const uint8_t *irk) {
147  uint8_t ecb_key[16];
148  uint8_t ecb_plaintext[16];
149  uint8_t ecb_ciphertext[16];
150 
151  memcpy(&ecb_key, irk, 16);
152  memset(&ecb_plaintext, 0, 16);
153 
154  ecb_plaintext[13] = (addr64 >> 40) & 0xff;
155  ecb_plaintext[14] = (addr64 >> 32) & 0xff;
156  ecb_plaintext[15] = (addr64 >> 24) & 0xff;
157 
158  mbedtls_aes_context ctx = {0, 0, {0}};
159  mbedtls_aes_init(&ctx);
160 
161  if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
162  mbedtls_aes_free(&ctx);
163  return false;
164  }
165 
166  if (mbedtls_aes_crypt_ecb(&ctx,
167 #ifdef USE_ARDUINO
168  MBEDTLS_AES_ENCRYPT,
169 #elif defined(USE_ESP_IDF)
170  ESP_AES_ENCRYPT,
171 #endif
172  ecb_plaintext, ecb_ciphertext) != 0) {
173  mbedtls_aes_free(&ctx);
174  return false;
175  }
176 
177  mbedtls_aes_free(&ctx);
178 
179  return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
180  ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
181  }
182 
183  bool found_{false};
184  uint32_t last_seen_{};
185  uint32_t timeout_{};
186 };
187 
188 } // namespace ble_presence
189 } // namespace esphome
190 
191 #endif
optional< ESPBLEiBeacon > get_ibeacon() const
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:19
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override
const std::vector< ESPBTUUID > & get_service_uuids() const
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:25
bool resolve_irk_(uint64_t addr64, const uint8_t *irk)
static ESPBTUUID from_uint32(uint32_t uuid)
Definition: ble_uuid.cpp:22
static ESPBTUUID from_uint16(uint16_t uuid)
Definition: ble_uuid.cpp:16
bool state
The current reported state of the binary sensor.
Definition: binary_sensor.h:61
void publish_state(bool state)
Publish a new state to the front-end.
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
esp32_ble_tracker::ESPBTUUID ibeacon_uuid_
static ESPBTUUID from_raw(const uint8_t *data)
Definition: ble_uuid.cpp:28
esp_bt_uuid_t get_uuid() const
Definition: ble_uuid.cpp:164