mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 16:38:16 +01:00
Add support for BLE passkey authentication (#4258)
Co-authored-by: Branden Cash <203336+ammmze@users.noreply.github.com>
This commit is contained in:
parent
c97d361b6c
commit
1c4af08ed3
7 changed files with 312 additions and 5 deletions
|
@ -29,8 +29,35 @@ BLEClientConnectTrigger = ble_client_ns.class_(
|
||||||
BLEClientDisconnectTrigger = ble_client_ns.class_(
|
BLEClientDisconnectTrigger = ble_client_ns.class_(
|
||||||
"BLEClientDisconnectTrigger", automation.Trigger.template(BLEClientNodeConstRef)
|
"BLEClientDisconnectTrigger", automation.Trigger.template(BLEClientNodeConstRef)
|
||||||
)
|
)
|
||||||
|
BLEClientPasskeyRequestTrigger = ble_client_ns.class_(
|
||||||
|
"BLEClientPasskeyRequestTrigger", automation.Trigger.template(BLEClientNodeConstRef)
|
||||||
|
)
|
||||||
|
BLEClientPasskeyNotificationTrigger = ble_client_ns.class_(
|
||||||
|
"BLEClientPasskeyNotificationTrigger",
|
||||||
|
automation.Trigger.template(BLEClientNodeConstRef, cg.uint32),
|
||||||
|
)
|
||||||
|
BLEClientNumericComparisonRequestTrigger = ble_client_ns.class_(
|
||||||
|
"BLEClientNumericComparisonRequestTrigger",
|
||||||
|
automation.Trigger.template(BLEClientNodeConstRef, cg.uint32),
|
||||||
|
)
|
||||||
|
|
||||||
# Actions
|
# Actions
|
||||||
BLEWriteAction = ble_client_ns.class_("BLEClientWriteAction", automation.Action)
|
BLEWriteAction = ble_client_ns.class_("BLEClientWriteAction", automation.Action)
|
||||||
|
BLEPasskeyReplyAction = ble_client_ns.class_(
|
||||||
|
"BLEClientPasskeyReplyAction", automation.Action
|
||||||
|
)
|
||||||
|
BLENumericComparisonReplyAction = ble_client_ns.class_(
|
||||||
|
"BLEClientNumericComparisonReplyAction", automation.Action
|
||||||
|
)
|
||||||
|
BLERemoveBondAction = ble_client_ns.class_(
|
||||||
|
"BLEClientRemoveBondAction", automation.Action
|
||||||
|
)
|
||||||
|
|
||||||
|
CONF_PASSKEY = "passkey"
|
||||||
|
CONF_ACCEPT = "accept"
|
||||||
|
CONF_ON_PASSKEY_REQUEST = "on_passkey_request"
|
||||||
|
CONF_ON_PASSKEY_NOTIFICATION = "on_passkey_notification"
|
||||||
|
CONF_ON_NUMERIC_COMPARISON_REQUEST = "on_numeric_comparison_request"
|
||||||
|
|
||||||
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so
|
# Espressif platformio framework is built with MAX_BLE_CONN to 3, so
|
||||||
# enforce this in yaml checks.
|
# enforce this in yaml checks.
|
||||||
|
@ -56,6 +83,29 @@ CONFIG_SCHEMA = (
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_ON_PASSKEY_REQUEST): automation.validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||||
|
BLEClientPasskeyRequestTrigger
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_ON_PASSKEY_NOTIFICATION): automation.validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||||
|
BLEClientPasskeyNotificationTrigger
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
cv.Optional(
|
||||||
|
CONF_ON_NUMERIC_COMPARISON_REQUEST
|
||||||
|
): automation.validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||||
|
BLEClientNumericComparisonRequestTrigger
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.COMPONENT_SCHEMA)
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
@ -85,13 +135,34 @@ BLE_WRITE_ACTION_SCHEMA = cv.Schema(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
BLE_NUMERIC_COMPARISON_REPLY_ACTION_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
|
||||||
|
cv.Required(CONF_ACCEPT): cv.templatable(cv.boolean),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
BLE_PASSKEY_REPLY_ACTION_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
|
||||||
|
cv.Required(CONF_PASSKEY): cv.templatable(cv.int_range(min=0, max=999999)),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
"ble_client.ble_write", BLEWriteAction, BLE_WRITE_ACTION_SCHEMA
|
"ble_client.ble_write", BLEWriteAction, BLE_WRITE_ACTION_SCHEMA
|
||||||
)
|
)
|
||||||
async def ble_write_to_code(config, action_id, template_arg, args):
|
async def ble_write_to_code(config, action_id, template_arg, args):
|
||||||
paren = await cg.get_variable(config[CONF_ID])
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||||
|
|
||||||
value = config[CONF_VALUE]
|
value = config[CONF_VALUE]
|
||||||
if cg.is_template(value):
|
if cg.is_template(value):
|
||||||
|
@ -137,6 +208,54 @@ async def ble_write_to_code(config, action_id, template_arg, args):
|
||||||
return var
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"ble_client.numeric_comparison_reply",
|
||||||
|
BLENumericComparisonReplyAction,
|
||||||
|
BLE_NUMERIC_COMPARISON_REPLY_ACTION_SCHEMA,
|
||||||
|
)
|
||||||
|
async def numeric_comparison_reply_to_code(config, action_id, template_arg, args):
|
||||||
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||||
|
|
||||||
|
accept = config[CONF_ACCEPT]
|
||||||
|
if cg.is_template(accept):
|
||||||
|
templ = await cg.templatable(accept, args, cg.bool_)
|
||||||
|
cg.add(var.set_value_template(templ))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_value_simple(accept))
|
||||||
|
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"ble_client.passkey_reply", BLEPasskeyReplyAction, BLE_PASSKEY_REPLY_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
async def passkey_reply_to_code(config, action_id, template_arg, args):
|
||||||
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||||
|
|
||||||
|
passkey = config[CONF_PASSKEY]
|
||||||
|
if cg.is_template(passkey):
|
||||||
|
templ = await cg.templatable(passkey, args, cg.uint32)
|
||||||
|
cg.add(var.set_value_template(templ))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_value_simple(passkey))
|
||||||
|
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"ble_client.remove_bond",
|
||||||
|
BLERemoveBondAction,
|
||||||
|
BLE_REMOVE_BOND_ACTION_SCHEMA,
|
||||||
|
)
|
||||||
|
async def remove_bond_to_code(config, action_id, template_arg, args):
|
||||||
|
parent = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, parent)
|
||||||
|
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
@ -148,3 +267,12 @@ async def to_code(config):
|
||||||
for conf in config.get(CONF_ON_DISCONNECT, []):
|
for conf in config.get(CONF_ON_DISCONNECT, []):
|
||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
await automation.build_automation(trigger, [], conf)
|
await automation.build_automation(trigger, [], conf)
|
||||||
|
for conf in config.get(CONF_ON_PASSKEY_REQUEST, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [], conf)
|
||||||
|
for conf in config.get(CONF_ON_PASSKEY_NOTIFICATION, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [(cg.uint32, "passkey")], conf)
|
||||||
|
for conf in config.get(CONF_ON_NUMERIC_COMPARISON_REQUEST, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(trigger, [(cg.uint32, "passkey")], conf)
|
||||||
|
|
|
@ -37,6 +37,44 @@ class BLEClientDisconnectTrigger : public Trigger<>, public BLEClientNode {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BLEClientPasskeyRequestTrigger : public Trigger<>, public BLEClientNode {
|
||||||
|
public:
|
||||||
|
explicit BLEClientPasskeyRequestTrigger(BLEClient *parent) { parent->register_ble_node(this); }
|
||||||
|
void loop() override {}
|
||||||
|
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
|
||||||
|
if (event == ESP_GAP_BLE_PASSKEY_REQ_EVT &&
|
||||||
|
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
|
||||||
|
this->trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BLEClientPasskeyNotificationTrigger : public Trigger<uint32_t>, public BLEClientNode {
|
||||||
|
public:
|
||||||
|
explicit BLEClientPasskeyNotificationTrigger(BLEClient *parent) { parent->register_ble_node(this); }
|
||||||
|
void loop() override {}
|
||||||
|
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
|
||||||
|
if (event == ESP_GAP_BLE_PASSKEY_NOTIF_EVT &&
|
||||||
|
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
|
||||||
|
uint32_t passkey = param->ble_security.key_notif.passkey;
|
||||||
|
this->trigger(passkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BLEClientNumericComparisonRequestTrigger : public Trigger<uint32_t>, public BLEClientNode {
|
||||||
|
public:
|
||||||
|
explicit BLEClientNumericComparisonRequestTrigger(BLEClient *parent) { parent->register_ble_node(this); }
|
||||||
|
void loop() override {}
|
||||||
|
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override {
|
||||||
|
if (event == ESP_GAP_BLE_NC_REQ_EVT &&
|
||||||
|
memcmp(param->ble_security.auth_cmpl.bd_addr, this->parent_->get_remote_bda(), 6) == 0) {
|
||||||
|
uint32_t passkey = param->ble_security.key_notif.passkey;
|
||||||
|
this->trigger(passkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class BLEWriterClientNode : public BLEClientNode {
|
class BLEWriterClientNode : public BLEClientNode {
|
||||||
public:
|
public:
|
||||||
BLEWriterClientNode(BLEClient *ble_client) {
|
BLEWriterClientNode(BLEClient *ble_client) {
|
||||||
|
@ -94,6 +132,86 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
||||||
std::function<std::vector<uint8_t>(Ts...)> value_template_{};
|
std::function<std::vector<uint8_t>(Ts...)> value_template_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
BLEClientPasskeyReplyAction(BLEClient *ble_client) { parent_ = ble_client; }
|
||||||
|
|
||||||
|
void play(Ts... x) override {
|
||||||
|
uint32_t passkey;
|
||||||
|
if (has_simple_value_) {
|
||||||
|
passkey = this->value_simple_;
|
||||||
|
} else {
|
||||||
|
passkey = this->value_template_(x...);
|
||||||
|
}
|
||||||
|
if (passkey > 999999)
|
||||||
|
return;
|
||||||
|
esp_bd_addr_t remote_bda;
|
||||||
|
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
|
||||||
|
esp_ble_passkey_reply(remote_bda, true, passkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value_template(std::function<uint32_t(Ts...)> func) {
|
||||||
|
this->value_template_ = std::move(func);
|
||||||
|
has_simple_value_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value_simple(const uint32_t &value) {
|
||||||
|
this->value_simple_ = value;
|
||||||
|
has_simple_value_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLEClient *parent_{nullptr};
|
||||||
|
bool has_simple_value_ = true;
|
||||||
|
uint32_t value_simple_{0};
|
||||||
|
std::function<uint32_t(Ts...)> value_template_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
BLEClientNumericComparisonReplyAction(BLEClient *ble_client) { parent_ = ble_client; }
|
||||||
|
|
||||||
|
void play(Ts... x) override {
|
||||||
|
esp_bd_addr_t remote_bda;
|
||||||
|
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
|
||||||
|
if (has_simple_value_) {
|
||||||
|
esp_ble_confirm_reply(remote_bda, this->value_simple_);
|
||||||
|
} else {
|
||||||
|
esp_ble_confirm_reply(remote_bda, this->value_template_(x...));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value_template(std::function<bool(Ts...)> func) {
|
||||||
|
this->value_template_ = std::move(func);
|
||||||
|
has_simple_value_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_value_simple(const bool &value) {
|
||||||
|
this->value_simple_ = value;
|
||||||
|
has_simple_value_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLEClient *parent_{nullptr};
|
||||||
|
bool has_simple_value_ = true;
|
||||||
|
bool value_simple_{false};
|
||||||
|
std::function<bool(Ts...)> value_template_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class BLEClientRemoveBondAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
BLEClientRemoveBondAction(BLEClient *ble_client) { parent_ = ble_client; }
|
||||||
|
|
||||||
|
void play(Ts... x) override {
|
||||||
|
esp_bd_addr_t remote_bda;
|
||||||
|
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
|
||||||
|
esp_ble_remove_bond_device(remote_bda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLEClient *parent_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ble_client
|
} // namespace ble_client
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ class BLEClient;
|
||||||
class BLEClientNode {
|
class BLEClientNode {
|
||||||
public:
|
public:
|
||||||
virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
||||||
esp_ble_gattc_cb_param_t *param) = 0;
|
esp_ble_gattc_cb_param_t *param){};
|
||||||
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {}
|
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {}
|
||||||
virtual void loop() {}
|
virtual void loop() {}
|
||||||
void set_address(uint64_t address) { address_ = address; }
|
void set_address(uint64_t address) { address_ = address; }
|
||||||
|
|
|
@ -9,6 +9,7 @@ CODEOWNERS = ["@jesserockz"]
|
||||||
CONFLICTS_WITH = ["esp32_ble_beacon"]
|
CONFLICTS_WITH = ["esp32_ble_beacon"]
|
||||||
|
|
||||||
CONF_BLE_ID = "ble_id"
|
CONF_BLE_ID = "ble_id"
|
||||||
|
CONF_IO_CAPABILITY = "io_capability"
|
||||||
|
|
||||||
NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
||||||
|
|
||||||
|
@ -19,10 +20,21 @@ GAPEventHandler = esp32_ble_ns.class_("GAPEventHandler")
|
||||||
GATTcEventHandler = esp32_ble_ns.class_("GATTcEventHandler")
|
GATTcEventHandler = esp32_ble_ns.class_("GATTcEventHandler")
|
||||||
GATTsEventHandler = esp32_ble_ns.class_("GATTsEventHandler")
|
GATTsEventHandler = esp32_ble_ns.class_("GATTsEventHandler")
|
||||||
|
|
||||||
|
IoCapability = esp32_ble_ns.enum("IoCapability")
|
||||||
|
IO_CAPABILITY = {
|
||||||
|
"none": IoCapability.IO_CAP_NONE,
|
||||||
|
"keyboard_only": IoCapability.IO_CAP_IN,
|
||||||
|
"keyboard_display": IoCapability.IO_CAP_KBDISP,
|
||||||
|
"display_only": IoCapability.IO_CAP_OUT,
|
||||||
|
"display_yes_no": IoCapability.IO_CAP_IO,
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
||||||
|
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
||||||
|
IO_CAPABILITY, lower=True
|
||||||
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
@ -39,6 +51,7 @@ FINAL_VALIDATE_SCHEMA = validate_variant
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY]))
|
||||||
|
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||||
|
|
|
@ -134,8 +134,7 @@ bool ESP32BLE::ble_setup_() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE;
|
err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &(this->io_cap_), sizeof(uint8_t));
|
||||||
err = esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_set_security_param failed: %d", err);
|
||||||
return false;
|
return false;
|
||||||
|
@ -215,9 +214,31 @@ float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; }
|
||||||
void ESP32BLE::dump_config() {
|
void ESP32BLE::dump_config() {
|
||||||
const uint8_t *mac_address = esp_bt_dev_get_address();
|
const uint8_t *mac_address = esp_bt_dev_get_address();
|
||||||
if (mac_address) {
|
if (mac_address) {
|
||||||
|
const char *io_capability_s;
|
||||||
|
switch (this->io_cap_) {
|
||||||
|
case ESP_IO_CAP_OUT:
|
||||||
|
io_capability_s = "display_only";
|
||||||
|
break;
|
||||||
|
case ESP_IO_CAP_IO:
|
||||||
|
io_capability_s = "display_yes_no";
|
||||||
|
break;
|
||||||
|
case ESP_IO_CAP_IN:
|
||||||
|
io_capability_s = "keyboard_only";
|
||||||
|
break;
|
||||||
|
case ESP_IO_CAP_NONE:
|
||||||
|
io_capability_s = "none";
|
||||||
|
break;
|
||||||
|
case ESP_IO_CAP_KBDISP:
|
||||||
|
io_capability_s = "keyboard_display";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
io_capability_s = "invalid";
|
||||||
|
break;
|
||||||
|
}
|
||||||
ESP_LOGCONFIG(TAG, "ESP32 BLE:");
|
ESP_LOGCONFIG(TAG, "ESP32 BLE:");
|
||||||
ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
|
ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2],
|
||||||
mac_address[3], mac_address[4], mac_address[5]);
|
mac_address[3], mac_address[4], mac_address[5]);
|
||||||
|
ESP_LOGCONFIG(TAG, " IO Capability: %s", io_capability_s);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
|
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,14 @@ typedef struct {
|
||||||
uint16_t mtu;
|
uint16_t mtu;
|
||||||
} conn_status_t;
|
} conn_status_t;
|
||||||
|
|
||||||
|
enum IoCapability {
|
||||||
|
IO_CAP_OUT = ESP_IO_CAP_OUT,
|
||||||
|
IO_CAP_IO = ESP_IO_CAP_IO,
|
||||||
|
IO_CAP_IN = ESP_IO_CAP_IN,
|
||||||
|
IO_CAP_NONE = ESP_IO_CAP_NONE,
|
||||||
|
IO_CAP_KBDISP = ESP_IO_CAP_KBDISP,
|
||||||
|
};
|
||||||
|
|
||||||
class GAPEventHandler {
|
class GAPEventHandler {
|
||||||
public:
|
public:
|
||||||
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
|
virtual void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) = 0;
|
||||||
|
@ -44,6 +52,8 @@ class GATTsEventHandler {
|
||||||
|
|
||||||
class ESP32BLE : public Component {
|
class ESP32BLE : public Component {
|
||||||
public:
|
public:
|
||||||
|
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
||||||
|
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
@ -72,6 +82,7 @@ class ESP32BLE : public Component {
|
||||||
|
|
||||||
Queue<BLEEvent> ble_events_;
|
Queue<BLEEvent> ble_events_;
|
||||||
BLEAdvertising *advertising_;
|
BLEAdvertising *advertising_;
|
||||||
|
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
|
@ -294,6 +294,9 @@ wled:
|
||||||
|
|
||||||
adalight:
|
adalight:
|
||||||
|
|
||||||
|
esp32_ble:
|
||||||
|
io_capability: keyboard_only
|
||||||
|
|
||||||
esp32_ble_tracker:
|
esp32_ble_tracker:
|
||||||
|
|
||||||
ble_client:
|
ble_client:
|
||||||
|
@ -307,6 +310,19 @@ ble_client:
|
||||||
on_disconnect:
|
on_disconnect:
|
||||||
then:
|
then:
|
||||||
- switch.turn_on: ble1_status
|
- switch.turn_on: ble1_status
|
||||||
|
on_passkey_request:
|
||||||
|
then:
|
||||||
|
- ble_client.passkey_reply:
|
||||||
|
id: ble_blah
|
||||||
|
passkey: 123456
|
||||||
|
on_passkey_notification:
|
||||||
|
then:
|
||||||
|
- logger.log: "Passkey notification received"
|
||||||
|
on_numeric_comparison_request:
|
||||||
|
then:
|
||||||
|
- ble_client.numeric_comparison_reply:
|
||||||
|
id: ble_blah
|
||||||
|
accept: True
|
||||||
- mac_address: C4:4F:33:11:22:33
|
- mac_address: C4:4F:33:11:22:33
|
||||||
id: my_bedjet_ble_client
|
id: my_bedjet_ble_client
|
||||||
bedjet:
|
bedjet:
|
||||||
|
|
Loading…
Reference in a new issue