ESPHome  2024.4.0
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->set_found_(true);
77  return true;
78  }
79  break;
81  for (auto uuid : device.get_service_uuids()) {
82  if (this->uuid_ == uuid) {
83  this->set_found_(true);
84  return true;
85  }
86  }
87  break;
89  if (!device.get_ibeacon().has_value()) {
90  return false;
91  }
92 
93  auto ibeacon = device.get_ibeacon().value();
94 
95  if (this->ibeacon_uuid_ != ibeacon.get_uuid()) {
96  return false;
97  }
98 
99  if (this->check_ibeacon_major_ && this->ibeacon_major_ != ibeacon.get_major()) {
100  return false;
101  }
102 
103  if (this->check_ibeacon_minor_ && this->ibeacon_minor_ != ibeacon.get_minor()) {
104  return false;
105  }
106 
107  this->set_found_(true);
108  return true;
109  }
110  return false;
111  }
112 
113  void loop() override {
114  if (this->found_ && this->last_seen_ + this->timeout_ < millis())
115  this->set_found_(false);
116  }
117  void dump_config() override;
118  float get_setup_priority() const override { return setup_priority::DATA; }
119 
120  protected:
121  void set_found_(bool state) {
122  this->found_ = state;
123  if (state)
124  this->last_seen_ = millis();
125  this->publish_state(state);
126  }
129 
130  uint64_t address_;
131  uint8_t *irk_;
132 
134 
136  uint16_t ibeacon_major_{0};
137  uint16_t ibeacon_minor_{0};
138 
140 
141  bool check_ibeacon_major_{false};
142  bool check_ibeacon_minor_{false};
143  bool check_minimum_rssi_{false};
144 
145  bool resolve_irk_(uint64_t addr64, const uint8_t *irk) {
146  uint8_t ecb_key[16];
147  uint8_t ecb_plaintext[16];
148  uint8_t ecb_ciphertext[16];
149 
150  memcpy(&ecb_key, irk, 16);
151  memset(&ecb_plaintext, 0, 16);
152 
153  ecb_plaintext[13] = (addr64 >> 40) & 0xff;
154  ecb_plaintext[14] = (addr64 >> 32) & 0xff;
155  ecb_plaintext[15] = (addr64 >> 24) & 0xff;
156 
157  mbedtls_aes_context ctx = {0, 0, {0}};
158  mbedtls_aes_init(&ctx);
159 
160  if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
161  mbedtls_aes_free(&ctx);
162  return false;
163  }
164 
165  if (mbedtls_aes_crypt_ecb(&ctx,
166 #ifdef USE_ARDUINO
167  MBEDTLS_AES_ENCRYPT,
168 #elif defined(USE_ESP_IDF)
169  ESP_AES_ENCRYPT,
170 #endif
171  ecb_plaintext, ecb_ciphertext) != 0) {
172  mbedtls_aes_free(&ctx);
173  return false;
174  }
175 
176  mbedtls_aes_free(&ctx);
177 
178  return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
179  ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
180  }
181 
182  bool found_{false};
183  uint32_t last_seen_{};
184  uint32_t timeout_{};
185 };
186 
187 } // namespace ble_presence
188 } // namespace esphome
189 
190 #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