mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 09:44:12 +01:00
Inherit esp32_ble_beacon
from esp32_ble
(#6908)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
172a358d01
commit
5d5f3276e9
10 changed files with 176 additions and 151 deletions
|
@ -7,10 +7,10 @@ from esphome.components.esp32 import add_idf_sdkconfig_option, get_esp32_variant
|
||||||
|
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
CODEOWNERS = ["@jesserockz", "@Rapsssito"]
|
CODEOWNERS = ["@jesserockz", "@Rapsssito"]
|
||||||
CONFLICTS_WITH = ["esp32_ble_beacon"]
|
|
||||||
|
|
||||||
CONF_BLE_ID = "ble_id"
|
CONF_BLE_ID = "ble_id"
|
||||||
CONF_IO_CAPABILITY = "io_capability"
|
CONF_IO_CAPABILITY = "io_capability"
|
||||||
|
CONF_ADVERTISING_CYCLE_TIME = "advertising_cycle_time"
|
||||||
|
|
||||||
NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
|
||||||
|
|
||||||
|
@ -34,6 +34,19 @@ IO_CAPABILITY = {
|
||||||
"display_yes_no": IoCapability.IO_CAP_IO,
|
"display_yes_no": IoCapability.IO_CAP_IO,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_power_level_t = cg.global_ns.enum("esp_power_level_t")
|
||||||
|
|
||||||
|
TX_POWER_LEVELS = {
|
||||||
|
-12: esp_power_level_t.ESP_PWR_LVL_N12,
|
||||||
|
-9: esp_power_level_t.ESP_PWR_LVL_N9,
|
||||||
|
-6: esp_power_level_t.ESP_PWR_LVL_N6,
|
||||||
|
-3: esp_power_level_t.ESP_PWR_LVL_N3,
|
||||||
|
0: esp_power_level_t.ESP_PWR_LVL_N0,
|
||||||
|
3: esp_power_level_t.ESP_PWR_LVL_P3,
|
||||||
|
6: esp_power_level_t.ESP_PWR_LVL_P6,
|
||||||
|
9: esp_power_level_t.ESP_PWR_LVL_P9,
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
||||||
|
@ -41,6 +54,9 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
IO_CAPABILITY, lower=True
|
IO_CAPABILITY, lower=True
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
|
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
|
||||||
|
cv.Optional(
|
||||||
|
CONF_ADVERTISING_CYCLE_TIME, default="10s"
|
||||||
|
): cv.positive_time_period_milliseconds,
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA)
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
@ -58,6 +74,7 @@ async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
|
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
|
||||||
cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY]))
|
cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY]))
|
||||||
|
cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME]))
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
|
|
|
@ -78,6 +78,11 @@ void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &dat
|
||||||
this->advertising_start();
|
this->advertising_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
|
||||||
|
this->advertising_init_();
|
||||||
|
this->advertising_->register_raw_advertisement_callback(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
void ESP32BLE::advertising_add_service_uuid(ESPBTUUID uuid) {
|
void ESP32BLE::advertising_add_service_uuid(ESPBTUUID uuid) {
|
||||||
this->advertising_init_();
|
this->advertising_init_();
|
||||||
this->advertising_->add_service_uuid(uuid);
|
this->advertising_->add_service_uuid(uuid);
|
||||||
|
@ -102,7 +107,7 @@ bool ESP32BLE::ble_pre_setup_() {
|
||||||
void ESP32BLE::advertising_init_() {
|
void ESP32BLE::advertising_init_() {
|
||||||
if (this->advertising_ != nullptr)
|
if (this->advertising_ != nullptr)
|
||||||
return;
|
return;
|
||||||
this->advertising_ = new BLEAdvertising(); // NOLINT(cppcoreguidelines-owning-memory)
|
this->advertising_ = new BLEAdvertising(this->advertising_cycle_time_); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
|
|
||||||
this->advertising_->set_scan_response(true);
|
this->advertising_->set_scan_response(true);
|
||||||
this->advertising_->set_min_preferred_interval(0x06);
|
this->advertising_->set_min_preferred_interval(0x06);
|
||||||
|
@ -312,6 +317,9 @@ void ESP32BLE::loop() {
|
||||||
delete ble_event; // NOLINT(cppcoreguidelines-owning-memory)
|
delete ble_event; // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
ble_event = this->ble_events_.pop();
|
ble_event = this->ble_events_.pop();
|
||||||
}
|
}
|
||||||
|
if (this->advertising_ != nullptr) {
|
||||||
|
this->advertising_->loop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "ble_advertising.h"
|
#include "ble_advertising.h"
|
||||||
#include "ble_uuid.h"
|
#include "ble_uuid.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
@ -76,6 +78,11 @@ class ESP32BLE : public Component {
|
||||||
public:
|
public:
|
||||||
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
void set_io_capability(IoCapability io_capability) { this->io_cap_ = (esp_ble_io_cap_t) io_capability; }
|
||||||
|
|
||||||
|
void set_advertising_cycle_time(uint32_t advertising_cycle_time) {
|
||||||
|
this->advertising_cycle_time_ = advertising_cycle_time;
|
||||||
|
}
|
||||||
|
uint32_t get_advertising_cycle_time() const { return this->advertising_cycle_time_; }
|
||||||
|
|
||||||
void enable();
|
void enable();
|
||||||
void disable();
|
void disable();
|
||||||
bool is_active();
|
bool is_active();
|
||||||
|
@ -89,6 +96,7 @@ class ESP32BLE : public Component {
|
||||||
void advertising_set_manufacturer_data(const std::vector<uint8_t> &data);
|
void advertising_set_manufacturer_data(const std::vector<uint8_t> &data);
|
||||||
void advertising_add_service_uuid(ESPBTUUID uuid);
|
void advertising_add_service_uuid(ESPBTUUID uuid);
|
||||||
void advertising_remove_service_uuid(ESPBTUUID uuid);
|
void advertising_remove_service_uuid(ESPBTUUID uuid);
|
||||||
|
void advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback);
|
||||||
|
|
||||||
void register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); }
|
void register_gap_event_handler(GAPEventHandler *handler) { this->gap_event_handlers_.push_back(handler); }
|
||||||
void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); }
|
void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); }
|
||||||
|
@ -121,6 +129,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};
|
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
||||||
|
uint32_t advertising_cycle_time_;
|
||||||
bool enable_on_boot_;
|
bool enable_on_boot_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace esp32_ble {
|
namespace esp32_ble {
|
||||||
|
|
||||||
static const char *const TAG = "esp32_ble";
|
static const char *const TAG = "esp32_ble.advertising";
|
||||||
|
|
||||||
BLEAdvertising::BLEAdvertising() {
|
BLEAdvertising::BLEAdvertising(uint32_t advertising_cycle_time) : advertising_cycle_time_(advertising_cycle_time) {
|
||||||
this->advertising_data_.set_scan_rsp = false;
|
this->advertising_data_.set_scan_rsp = false;
|
||||||
this->advertising_data_.include_name = true;
|
this->advertising_data_.include_name = true;
|
||||||
this->advertising_data_.include_txpower = true;
|
this->advertising_data_.include_txpower = true;
|
||||||
|
@ -64,7 +64,7 @@ void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BLEAdvertising::start() {
|
esp_err_t BLEAdvertising::services_advertisement_() {
|
||||||
int num_services = this->advertising_uuids_.size();
|
int num_services = this->advertising_uuids_.size();
|
||||||
if (num_services == 0) {
|
if (num_services == 0) {
|
||||||
this->advertising_data_.service_uuid_len = 0;
|
this->advertising_data_.service_uuid_len = 0;
|
||||||
|
@ -87,8 +87,8 @@ void BLEAdvertising::start() {
|
||||||
this->advertising_data_.include_txpower = !this->scan_response_;
|
this->advertising_data_.include_txpower = !this->scan_response_;
|
||||||
err = esp_ble_gap_config_adv_data(&this->advertising_data_);
|
err = esp_ble_gap_config_adv_data(&this->advertising_data_);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Advertising): %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->scan_response_) {
|
if (this->scan_response_) {
|
||||||
|
@ -101,8 +101,8 @@ void BLEAdvertising::start() {
|
||||||
this->scan_response_data_.flag = 0;
|
this->scan_response_data_.flag = 0;
|
||||||
err = esp_ble_gap_config_adv_data(&this->scan_response_data_);
|
err = esp_ble_gap_config_adv_data(&this->scan_response_data_);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data failed (Scan response): %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,8 +113,18 @@ void BLEAdvertising::start() {
|
||||||
|
|
||||||
err = esp_ble_gap_start_advertising(&this->advertising_params_);
|
err = esp_ble_gap_start_advertising(&this->advertising_params_);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err));
|
||||||
return;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEAdvertising::start() {
|
||||||
|
if (this->current_adv_index_ == -1) {
|
||||||
|
this->services_advertisement_();
|
||||||
|
} else {
|
||||||
|
this->raw_advertisements_callbacks_[this->current_adv_index_](true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +134,29 @@ void BLEAdvertising::stop() {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_stop_advertising failed: %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_stop_advertising failed: %d", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this->current_adv_index_ != -1) {
|
||||||
|
this->raw_advertisements_callbacks_[this->current_adv_index_](false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEAdvertising::loop() {
|
||||||
|
if (this->raw_advertisements_callbacks_.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uint32_t now = millis();
|
||||||
|
if (now - this->last_advertisement_time_ > this->advertising_cycle_time_) {
|
||||||
|
this->stop();
|
||||||
|
this->current_adv_index_ += 1;
|
||||||
|
if (this->current_adv_index_ >= this->raw_advertisements_callbacks_.size()) {
|
||||||
|
this->current_adv_index_ = -1;
|
||||||
|
}
|
||||||
|
this->start();
|
||||||
|
this->last_advertisement_time_ = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BLEAdvertising::register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
|
||||||
|
this->raw_advertisements_callbacks_.push_back(std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace esp32_ble
|
} // namespace esp32_ble
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
|
#include <esp_bt.h>
|
||||||
#include <esp_gap_ble_api.h>
|
#include <esp_gap_ble_api.h>
|
||||||
#include <esp_gatts_api.h>
|
#include <esp_gatts_api.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace esp32_ble {
|
namespace esp32_ble {
|
||||||
|
|
||||||
|
using raw_adv_data_t = struct {
|
||||||
|
uint8_t *data;
|
||||||
|
size_t length;
|
||||||
|
esp_power_level_t power_level;
|
||||||
|
};
|
||||||
|
|
||||||
class ESPBTUUID;
|
class ESPBTUUID;
|
||||||
|
|
||||||
class BLEAdvertising {
|
class BLEAdvertising {
|
||||||
public:
|
public:
|
||||||
BLEAdvertising();
|
BLEAdvertising(uint32_t advertising_cycle_time);
|
||||||
|
|
||||||
|
void loop();
|
||||||
|
|
||||||
void add_service_uuid(ESPBTUUID uuid);
|
void add_service_uuid(ESPBTUUID uuid);
|
||||||
void remove_service_uuid(ESPBTUUID uuid);
|
void remove_service_uuid(ESPBTUUID uuid);
|
||||||
|
@ -22,16 +33,25 @@ class BLEAdvertising {
|
||||||
void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; }
|
void set_min_preferred_interval(uint16_t interval) { this->advertising_data_.min_interval = interval; }
|
||||||
void set_manufacturer_data(const std::vector<uint8_t> &data);
|
void set_manufacturer_data(const std::vector<uint8_t> &data);
|
||||||
void set_service_data(const std::vector<uint8_t> &data);
|
void set_service_data(const std::vector<uint8_t> &data);
|
||||||
|
void register_raw_advertisement_callback(std::function<void(bool)> &&callback);
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
esp_err_t services_advertisement_();
|
||||||
|
|
||||||
bool scan_response_;
|
bool scan_response_;
|
||||||
esp_ble_adv_data_t advertising_data_;
|
esp_ble_adv_data_t advertising_data_;
|
||||||
esp_ble_adv_data_t scan_response_data_;
|
esp_ble_adv_data_t scan_response_data_;
|
||||||
esp_ble_adv_params_t advertising_params_;
|
esp_ble_adv_params_t advertising_params_;
|
||||||
std::vector<ESPBTUUID> advertising_uuids_;
|
std::vector<ESPBTUUID> advertising_uuids_;
|
||||||
|
|
||||||
|
std::vector<std::function<void(bool)>> raw_advertisements_callbacks_;
|
||||||
|
|
||||||
|
const uint32_t advertising_cycle_time_;
|
||||||
|
uint32_t last_advertisement_time_{0};
|
||||||
|
int8_t current_adv_index_{-1}; // -1 means standard scan response
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace esp32_ble
|
} // namespace esp32_ble
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components.esp32_ble import CONF_BLE_ID
|
||||||
from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER
|
from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER
|
||||||
from esphome.core import CORE, TimePeriod
|
from esphome.core import CORE, TimePeriod
|
||||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||||
from esphome.components import esp32_ble
|
from esphome.components import esp32_ble
|
||||||
|
|
||||||
|
AUTO_LOAD = ["esp32_ble"]
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
CONFLICTS_WITH = ["esp32_ble_tracker"]
|
|
||||||
|
|
||||||
esp32_ble_beacon_ns = cg.esphome_ns.namespace("esp32_ble_beacon")
|
esp32_ble_beacon_ns = cg.esphome_ns.namespace("esp32_ble_beacon")
|
||||||
ESP32BLEBeacon = esp32_ble_beacon_ns.class_("ESP32BLEBeacon", cg.Component)
|
ESP32BLEBeacon = esp32_ble_beacon_ns.class_(
|
||||||
|
"ESP32BLEBeacon",
|
||||||
|
cg.Component,
|
||||||
|
esp32_ble.GAPEventHandler,
|
||||||
|
cg.Parented.template(esp32_ble.ESP32BLE),
|
||||||
|
)
|
||||||
CONF_MAJOR = "major"
|
CONF_MAJOR = "major"
|
||||||
CONF_MINOR = "minor"
|
CONF_MINOR = "minor"
|
||||||
CONF_MIN_INTERVAL = "min_interval"
|
CONF_MIN_INTERVAL = "min_interval"
|
||||||
|
@ -28,6 +33,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ESP32BLEBeacon),
|
cv.GenerateID(): cv.declare_id(ESP32BLEBeacon),
|
||||||
|
cv.GenerateID(CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE),
|
||||||
cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True),
|
cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True),
|
||||||
cv.Required(CONF_UUID): cv.uuid,
|
cv.Required(CONF_UUID): cv.uuid,
|
||||||
cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t,
|
cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t,
|
||||||
|
@ -48,7 +54,7 @@ CONFIG_SCHEMA = cv.All(
|
||||||
min=-128, max=0
|
min=-128, max=0
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_TX_POWER, default="3dBm"): cv.All(
|
cv.Optional(CONF_TX_POWER, default="3dBm"): cv.All(
|
||||||
cv.decibel, cv.one_of(-12, -9, -6, -3, 0, 3, 6, 9, int=True)
|
cv.decibel, cv.enum(esp32_ble.TX_POWER_LEVELS, int=True)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
|
@ -62,6 +68,10 @@ async def to_code(config):
|
||||||
uuid = config[CONF_UUID].hex
|
uuid = config[CONF_UUID].hex
|
||||||
uuid_arr = [cg.RawExpression(f"0x{uuid[i:i + 2]}") for i in range(0, len(uuid), 2)]
|
uuid_arr = [cg.RawExpression(f"0x{uuid[i:i + 2]}") for i in range(0, len(uuid), 2)]
|
||||||
var = cg.new_Pvariable(config[CONF_ID], uuid_arr)
|
var = cg.new_Pvariable(config[CONF_ID], uuid_arr)
|
||||||
|
|
||||||
|
parent = await cg.get_variable(config[esp32_ble.CONF_BLE_ID])
|
||||||
|
cg.add(parent.register_gap_event_handler(var))
|
||||||
|
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
cg.add(var.set_major(config[CONF_MAJOR]))
|
cg.add(var.set_major(config[CONF_MAJOR]))
|
||||||
cg.add(var.set_minor(config[CONF_MINOR]))
|
cg.add(var.set_minor(config[CONF_MINOR]))
|
||||||
|
|
|
@ -3,14 +3,16 @@
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
#include <nvs_flash.h>
|
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include <esp_bt_main.h>
|
|
||||||
#include <esp_bt.h>
|
#include <esp_bt.h>
|
||||||
#include <freertos/task.h>
|
#include <esp_bt_main.h>
|
||||||
#include <esp_gap_ble_api.h>
|
#include <esp_gap_ble_api.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <nvs_flash.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
#ifdef USE_ARDUINO
|
||||||
#include <esp32-hal-bt.h>
|
#include <esp32-hal-bt.h>
|
||||||
|
@ -21,20 +23,6 @@ namespace esp32_ble_beacon {
|
||||||
|
|
||||||
static const char *const TAG = "esp32_ble_beacon";
|
static const char *const TAG = "esp32_ble_beacon";
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
static esp_ble_adv_params_t ble_adv_params = {
|
|
||||||
.adv_int_min = 0x20,
|
|
||||||
.adv_int_max = 0x40,
|
|
||||||
.adv_type = ADV_TYPE_NONCONN_IND,
|
|
||||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
|
||||||
.peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
|
||||||
.peer_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
|
||||||
.channel_map = ADV_CHNL_ALL,
|
|
||||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ENDIAN_CHANGE_U16(x) ((((x) &0xFF00) >> 8) + (((x) &0xFF) << 8))
|
|
||||||
|
|
||||||
static const esp_ble_ibeacon_head_t IBEACON_COMMON_HEAD = {
|
static const esp_ble_ibeacon_head_t IBEACON_COMMON_HEAD = {
|
||||||
.flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = {0x4C, 0x00}, .beacon_type = {0x02, 0x15}};
|
.flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = {0x4C, 0x00}, .beacon_type = {0x02, 0x15}};
|
||||||
|
|
||||||
|
@ -53,117 +41,62 @@ void ESP32BLEBeacon::dump_config() {
|
||||||
" UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d"
|
" UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d"
|
||||||
", TX Power: %ddBm",
|
", TX Power: %ddBm",
|
||||||
uuid, this->major_, this->minor_, this->min_interval_, this->max_interval_, this->measured_power_,
|
uuid, this->major_, this->minor_, this->min_interval_, this->max_interval_, this->measured_power_,
|
||||||
this->tx_power_);
|
(this->tx_power_ * 3) - 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::AFTER_BLUETOOTH; }
|
||||||
|
|
||||||
void ESP32BLEBeacon::setup() {
|
void ESP32BLEBeacon::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up ESP32 BLE beacon...");
|
this->ble_adv_params_ = {
|
||||||
global_esp32_ble_beacon = this;
|
.adv_int_min = static_cast<uint16_t>(this->min_interval_ / 0.625f),
|
||||||
|
.adv_int_max = static_cast<uint16_t>(this->max_interval_ / 0.625f),
|
||||||
|
.adv_type = ADV_TYPE_NONCONN_IND,
|
||||||
|
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||||
|
.peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||||
|
.peer_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||||
|
.channel_map = ADV_CHNL_ALL,
|
||||||
|
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||||
|
};
|
||||||
|
|
||||||
xTaskCreatePinnedToCore(ESP32BLEBeacon::ble_core_task,
|
global_ble->advertising_register_raw_advertisement_callback([this](bool advertise) {
|
||||||
"ble_task", // name
|
this->advertising_ = advertise;
|
||||||
10000, // stack size (in words)
|
if (advertise) {
|
||||||
nullptr, // input params
|
this->on_advertise_();
|
||||||
1, // priority
|
}
|
||||||
nullptr, // Handle, not needed
|
});
|
||||||
0 // core
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float ESP32BLEBeacon::get_setup_priority() const { return setup_priority::BLUETOOTH; }
|
void ESP32BLEBeacon::on_advertise_() {
|
||||||
void ESP32BLEBeacon::ble_core_task(void *params) {
|
|
||||||
ble_setup();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
delay(1000); // NOLINT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESP32BLEBeacon::ble_setup() {
|
|
||||||
ble_adv_params.adv_int_min = static_cast<uint16_t>(global_esp32_ble_beacon->min_interval_ / 0.625f);
|
|
||||||
ble_adv_params.adv_int_max = static_cast<uint16_t>(global_esp32_ble_beacon->max_interval_ / 0.625f);
|
|
||||||
|
|
||||||
// Initialize non-volatile storage for the bluetooth controller
|
|
||||||
esp_err_t err = nvs_flash_init();
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "nvs_flash_init failed: %d", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_ARDUINO
|
|
||||||
if (!btStart()) {
|
|
||||||
ESP_LOGE(TAG, "btStart failed: %d", esp_bt_controller_get_status());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
|
|
||||||
// start bt controller
|
|
||||||
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
|
|
||||||
esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
||||||
err = esp_bt_controller_init(&cfg);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_INITED) {
|
|
||||||
err = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_bt_controller_enable failed: %s", esp_err_to_name(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
|
|
||||||
ESP_LOGE(TAG, "esp bt controller enable failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
|
||||||
|
|
||||||
err = esp_bluedroid_init();
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_bluedroid_init failed: %d", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
err = esp_bluedroid_enable();
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV,
|
|
||||||
static_cast<esp_power_level_t>((global_esp32_ble_beacon->tx_power_ + 12) / 3));
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
err = esp_ble_gap_register_callback(ESP32BLEBeacon::gap_event_handler);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_register_callback failed: %d", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_ble_ibeacon_t ibeacon_adv_data;
|
esp_ble_ibeacon_t ibeacon_adv_data;
|
||||||
memcpy(&ibeacon_adv_data.ibeacon_head, &IBEACON_COMMON_HEAD, sizeof(esp_ble_ibeacon_head_t));
|
memcpy(&ibeacon_adv_data.ibeacon_head, &IBEACON_COMMON_HEAD, sizeof(esp_ble_ibeacon_head_t));
|
||||||
memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, global_esp32_ble_beacon->uuid_.data(),
|
memcpy(&ibeacon_adv_data.ibeacon_vendor.proximity_uuid, this->uuid_.data(),
|
||||||
sizeof(ibeacon_adv_data.ibeacon_vendor.proximity_uuid));
|
sizeof(ibeacon_adv_data.ibeacon_vendor.proximity_uuid));
|
||||||
ibeacon_adv_data.ibeacon_vendor.minor = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->minor_);
|
ibeacon_adv_data.ibeacon_vendor.minor = byteswap(this->minor_);
|
||||||
ibeacon_adv_data.ibeacon_vendor.major = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->major_);
|
ibeacon_adv_data.ibeacon_vendor.major = byteswap(this->major_);
|
||||||
ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast<uint8_t>(global_esp32_ble_beacon->measured_power_);
|
ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast<uint8_t>(this->measured_power_);
|
||||||
|
|
||||||
esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data));
|
ESP_LOGD(TAG, "Setting BLE TX power");
|
||||||
|
esp_err_t err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, this->tx_power_);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "esp_ble_tx_power_set failed: %s", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
err = esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data));
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw failed: %s", esp_err_to_name(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
||||||
|
if (!this->advertising_)
|
||||||
|
return;
|
||||||
|
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: {
|
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: {
|
||||||
err = esp_ble_gap_start_advertising(&ble_adv_params);
|
err = esp_ble_gap_start_advertising(&this->ble_adv_params_);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %d", err);
|
ESP_LOGE(TAG, "esp_ble_gap_start_advertising failed: %s", esp_err_to_name(err));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -181,6 +114,7 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "BLE stopped advertising successfully");
|
ESP_LOGD(TAG, "BLE stopped advertising successfully");
|
||||||
}
|
}
|
||||||
|
// this->advertising_ = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -188,8 +122,6 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP32BLEBeacon *global_esp32_ble_beacon = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
|
|
||||||
} // namespace esp32_ble_beacon
|
} // namespace esp32_ble_beacon
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/esp32_ble/ble.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|
||||||
#include <esp_gap_ble_api.h>
|
|
||||||
#include <esp_bt.h>
|
#include <esp_bt.h>
|
||||||
|
#include <esp_gap_ble_api.h>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace esp32_ble_beacon {
|
namespace esp32_ble_beacon {
|
||||||
|
|
||||||
// NOLINTNEXTLINE(modernize-use-using)
|
using esp_ble_ibeacon_head_t = struct {
|
||||||
typedef struct {
|
|
||||||
uint8_t flags[3];
|
uint8_t flags[3];
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint8_t company_id[2];
|
uint8_t company_id[2];
|
||||||
uint8_t beacon_type[2];
|
uint8_t beacon_type[2];
|
||||||
} __attribute__((packed)) esp_ble_ibeacon_head_t;
|
} __attribute__((packed));
|
||||||
|
|
||||||
// NOLINTNEXTLINE(modernize-use-using)
|
using esp_ble_ibeacon_vendor_t = struct {
|
||||||
typedef struct {
|
|
||||||
uint8_t proximity_uuid[16];
|
uint8_t proximity_uuid[16];
|
||||||
uint16_t major;
|
uint16_t major;
|
||||||
uint16_t minor;
|
uint16_t minor;
|
||||||
uint8_t measured_power;
|
uint8_t measured_power;
|
||||||
} __attribute__((packed)) esp_ble_ibeacon_vendor_t;
|
} __attribute__((packed));
|
||||||
|
|
||||||
// NOLINTNEXTLINE(modernize-use-using)
|
using esp_ble_ibeacon_t = struct {
|
||||||
typedef struct {
|
|
||||||
esp_ble_ibeacon_head_t ibeacon_head;
|
esp_ble_ibeacon_head_t ibeacon_head;
|
||||||
esp_ble_ibeacon_vendor_t ibeacon_vendor;
|
esp_ble_ibeacon_vendor_t ibeacon_vendor;
|
||||||
} __attribute__((packed)) esp_ble_ibeacon_t;
|
} __attribute__((packed));
|
||||||
|
|
||||||
class ESP32BLEBeacon : public Component {
|
using namespace esp32_ble;
|
||||||
|
|
||||||
|
class ESP32BLEBeacon : public Component, public GAPEventHandler, public Parented<ESP32BLE> {
|
||||||
public:
|
public:
|
||||||
explicit ESP32BLEBeacon(const std::array<uint8_t, 16> &uuid) : uuid_(uuid) {}
|
explicit ESP32BLEBeacon(const std::array<uint8_t, 16> &uuid) : uuid_(uuid) {}
|
||||||
|
|
||||||
|
@ -46,12 +46,11 @@ class ESP32BLEBeacon : public Component {
|
||||||
void set_min_interval(uint16_t val) { this->min_interval_ = val; }
|
void set_min_interval(uint16_t val) { this->min_interval_ = val; }
|
||||||
void set_max_interval(uint16_t val) { this->max_interval_ = val; }
|
void set_max_interval(uint16_t val) { this->max_interval_ = val; }
|
||||||
void set_measured_power(int8_t val) { this->measured_power_ = val; }
|
void set_measured_power(int8_t val) { this->measured_power_ = val; }
|
||||||
void set_tx_power(int8_t val) { this->tx_power_ = val; }
|
void set_tx_power(esp_power_level_t val) { this->tx_power_ = val; }
|
||||||
|
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
void on_advertise_();
|
||||||
static void ble_core_task(void *params);
|
|
||||||
static void ble_setup();
|
|
||||||
|
|
||||||
std::array<uint8_t, 16> uuid_;
|
std::array<uint8_t, 16> uuid_;
|
||||||
uint16_t major_{};
|
uint16_t major_{};
|
||||||
|
@ -59,12 +58,11 @@ class ESP32BLEBeacon : public Component {
|
||||||
uint16_t min_interval_{};
|
uint16_t min_interval_{};
|
||||||
uint16_t max_interval_{};
|
uint16_t max_interval_{};
|
||||||
int8_t measured_power_{};
|
int8_t measured_power_{};
|
||||||
int8_t tx_power_{};
|
esp_power_level_t tx_power_{};
|
||||||
|
esp_ble_adv_params_t ble_adv_params_;
|
||||||
|
bool advertising_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
extern ESP32BLEBeacon *global_esp32_ble_beacon;
|
|
||||||
|
|
||||||
} // namespace esp32_ble_beacon
|
} // namespace esp32_ble_beacon
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||||
|
|
||||||
AUTO_LOAD = ["esp32_ble"]
|
AUTO_LOAD = ["esp32_ble"]
|
||||||
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
|
CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
|
||||||
CONFLICTS_WITH = ["esp32_ble_beacon"]
|
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
|
|
||||||
CONF_MANUFACTURER = "manufacturer"
|
CONF_MANUFACTURER = "manufacturer"
|
||||||
|
|
|
@ -6,7 +6,6 @@ from esphome.const import CONF_ID
|
||||||
|
|
||||||
AUTO_LOAD = ["esp32_ble_server"]
|
AUTO_LOAD = ["esp32_ble_server"]
|
||||||
CODEOWNERS = ["@jesserockz"]
|
CODEOWNERS = ["@jesserockz"]
|
||||||
CONFLICTS_WITH = ["esp32_ble_beacon"]
|
|
||||||
DEPENDENCIES = ["wifi", "esp32"]
|
DEPENDENCIES = ["wifi", "esp32"]
|
||||||
|
|
||||||
CONF_AUTHORIZED_DURATION = "authorized_duration"
|
CONF_AUTHORIZED_DURATION = "authorized_duration"
|
||||||
|
|
Loading…
Reference in a new issue