1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-01 15:41:52 +00:00

[ble_client] Use function pointers for lambda actions and sensors (#11564)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
J. Nick Koston
2025-10-28 14:10:32 -05:00
committed by GitHub
parent 0119e17f04
commit 08b8454555
3 changed files with 57 additions and 32 deletions

View File

@@ -96,8 +96,11 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
BLEClientWriteAction(BLEClient *ble_client) { BLEClientWriteAction(BLEClient *ble_client) {
ble_client->register_ble_node(this); ble_client->register_ble_node(this);
ble_client_ = ble_client; ble_client_ = ble_client;
this->construct_simple_value_();
} }
~BLEClientWriteAction() { this->destroy_simple_value_(); }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
@@ -106,14 +109,18 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
void set_char_uuid32(uint32_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_char_uuid32(uint32_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
void set_value_template(std::function<std::vector<uint8_t>(Ts...)> func) { void set_value_template(std::vector<uint8_t> (*func)(Ts...)) {
this->value_template_ = std::move(func); this->destroy_simple_value_();
has_simple_value_ = false; this->value_.template_func = func;
this->has_simple_value_ = false;
} }
void set_value_simple(const std::vector<uint8_t> &value) { void set_value_simple(const std::vector<uint8_t> &value) {
this->value_simple_ = value; if (!this->has_simple_value_) {
has_simple_value_ = true; this->construct_simple_value_();
}
this->value_.simple = value;
this->has_simple_value_ = true;
} }
void play(Ts... x) override {} void play(Ts... x) override {}
@@ -121,7 +128,7 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
void play_complex(Ts... x) override { void play_complex(Ts... x) override {
this->num_running_++; this->num_running_++;
this->var_ = std::make_tuple(x...); this->var_ = std::make_tuple(x...);
auto value = this->has_simple_value_ ? this->value_simple_ : this->value_template_(x...); auto value = this->has_simple_value_ ? this->value_.simple : this->value_.template_func(x...);
// on write failure, continue the automation chain rather than stopping so that e.g. disconnect can work. // on write failure, continue the automation chain rather than stopping so that e.g. disconnect can work.
if (!write(value)) if (!write(value))
this->play_next_(x...); this->play_next_(x...);
@@ -194,10 +201,22 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
} }
private: private:
void construct_simple_value_() { new (&this->value_.simple) std::vector<uint8_t>(); }
void destroy_simple_value_() {
if (this->has_simple_value_) {
this->value_.simple.~vector();
}
}
BLEClient *ble_client_; BLEClient *ble_client_;
bool has_simple_value_ = true; bool has_simple_value_ = true;
std::vector<uint8_t> value_simple_; union Value {
std::function<std::vector<uint8_t>(Ts...)> value_template_{}; std::vector<uint8_t> simple;
std::vector<uint8_t> (*template_func)(Ts...);
Value() {} // trivial constructor
~Value() {} // trivial destructor - we manage lifetime via discriminator
} value_;
espbt::ESPBTUUID service_uuid_; espbt::ESPBTUUID service_uuid_;
espbt::ESPBTUUID char_uuid_; espbt::ESPBTUUID char_uuid_;
std::tuple<Ts...> var_{}; std::tuple<Ts...> var_{};
@@ -213,9 +232,9 @@ template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...
void play(Ts... x) override { void play(Ts... x) override {
uint32_t passkey; uint32_t passkey;
if (has_simple_value_) { if (has_simple_value_) {
passkey = this->value_simple_; passkey = this->value_.simple;
} else { } else {
passkey = this->value_template_(x...); passkey = this->value_.template_func(x...);
} }
if (passkey > 999999) if (passkey > 999999)
return; return;
@@ -224,21 +243,23 @@ template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...
esp_ble_passkey_reply(remote_bda, true, passkey); esp_ble_passkey_reply(remote_bda, true, passkey);
} }
void set_value_template(std::function<uint32_t(Ts...)> func) { void set_value_template(uint32_t (*func)(Ts...)) {
this->value_template_ = std::move(func); this->value_.template_func = func;
has_simple_value_ = false; this->has_simple_value_ = false;
} }
void set_value_simple(const uint32_t &value) { void set_value_simple(const uint32_t &value) {
this->value_simple_ = value; this->value_.simple = value;
has_simple_value_ = true; this->has_simple_value_ = true;
} }
private: private:
BLEClient *parent_{nullptr}; BLEClient *parent_{nullptr};
bool has_simple_value_ = true; bool has_simple_value_ = true;
uint32_t value_simple_{0}; union {
std::function<uint32_t(Ts...)> value_template_{}; uint32_t simple;
uint32_t (*template_func)(Ts...);
} value_{.simple = 0};
}; };
template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Action<Ts...> { template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Action<Ts...> {
@@ -249,27 +270,29 @@ template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Ac
esp_bd_addr_t remote_bda; esp_bd_addr_t remote_bda;
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t)); memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
if (has_simple_value_) { if (has_simple_value_) {
esp_ble_confirm_reply(remote_bda, this->value_simple_); esp_ble_confirm_reply(remote_bda, this->value_.simple);
} else { } else {
esp_ble_confirm_reply(remote_bda, this->value_template_(x...)); esp_ble_confirm_reply(remote_bda, this->value_.template_func(x...));
} }
} }
void set_value_template(std::function<bool(Ts...)> func) { void set_value_template(bool (*func)(Ts...)) {
this->value_template_ = std::move(func); this->value_.template_func = func;
has_simple_value_ = false; this->has_simple_value_ = false;
} }
void set_value_simple(const bool &value) { void set_value_simple(const bool &value) {
this->value_simple_ = value; this->value_.simple = value;
has_simple_value_ = true; this->has_simple_value_ = true;
} }
private: private:
BLEClient *parent_{nullptr}; BLEClient *parent_{nullptr};
bool has_simple_value_ = true; bool has_simple_value_ = true;
bool value_simple_{false}; union {
std::function<bool(Ts...)> value_template_{}; bool simple;
bool (*template_func)(Ts...);
} value_{.simple = false};
}; };
template<typename... Ts> class BLEClientRemoveBondAction : public Action<Ts...> { template<typename... Ts> class BLEClientRemoveBondAction : public Action<Ts...> {

View File

@@ -117,9 +117,9 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
} }
float BLESensor::parse_data_(uint8_t *value, uint16_t value_len) { float BLESensor::parse_data_(uint8_t *value, uint16_t value_len) {
if (this->data_to_value_func_.has_value()) { if (this->has_data_to_value_) {
std::vector<uint8_t> data(value, value + value_len); std::vector<uint8_t> data(value, value + value_len);
return (*this->data_to_value_func_)(data); return this->data_to_value_func_(data);
} else { } else {
return value[0]; return value[0];
} }

View File

@@ -15,8 +15,6 @@ namespace ble_client {
namespace espbt = esphome::esp32_ble_tracker; namespace espbt = esphome::esp32_ble_tracker;
using data_to_value_t = std::function<float(std::vector<uint8_t>)>;
class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClientNode { class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClientNode {
public: public:
void loop() override; void loop() override;
@@ -33,13 +31,17 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie
void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); } void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); } void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); } void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
void set_data_to_value(data_to_value_t &&lambda) { this->data_to_value_func_ = lambda; } void set_data_to_value(float (*lambda)(const std::vector<uint8_t> &)) {
this->data_to_value_func_ = lambda;
this->has_data_to_value_ = true;
}
void set_enable_notify(bool notify) { this->notify_ = notify; } void set_enable_notify(bool notify) { this->notify_ = notify; }
uint16_t handle; uint16_t handle;
protected: protected:
float parse_data_(uint8_t *value, uint16_t value_len); float parse_data_(uint8_t *value, uint16_t value_len);
optional<data_to_value_t> data_to_value_func_{}; bool has_data_to_value_{false};
float (*data_to_value_func_)(const std::vector<uint8_t> &){};
bool notify_; bool notify_;
espbt::ESPBTUUID service_uuid_; espbt::ESPBTUUID service_uuid_;
espbt::ESPBTUUID char_uuid_; espbt::ESPBTUUID char_uuid_;