From 5ec158811025db6932bbbd999ce6cf322cd89287 Mon Sep 17 00:00:00 2001 From: Frank Riley Date: Wed, 12 Oct 2022 16:59:07 -0700 Subject: [PATCH] Update the ibeacon code (#3859) --- .../components/esp32_ble_beacon/__init__.py | 57 +++++++++++++++---- .../esp32_ble_beacon/esp32_ble_beacon.cpp | 30 ++++++++-- .../esp32_ble_beacon/esp32_ble_beacon.h | 13 ++++- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/esphome/components/esp32_ble_beacon/__init__.py b/esphome/components/esp32_ble_beacon/__init__.py index d6cbb15dd2..c3bd4ee418 100644 --- a/esphome/components/esp32_ble_beacon/__init__.py +++ b/esphome/components/esp32_ble_beacon/__init__.py @@ -1,7 +1,7 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID -from esphome.core import CORE +from esphome.const import CONF_ID, CONF_TYPE, CONF_UUID, CONF_TX_POWER +from esphome.core import CORE, TimePeriod from esphome.components.esp32 import add_idf_sdkconfig_option DEPENDENCIES = ["esp32"] @@ -12,16 +12,47 @@ ESP32BLEBeacon = esp32_ble_beacon_ns.class_("ESP32BLEBeacon", cg.Component) CONF_MAJOR = "major" CONF_MINOR = "minor" +CONF_MIN_INTERVAL = "min_interval" +CONF_MAX_INTERVAL = "max_interval" +CONF_MEASURED_POWER = "measured_power" -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(ESP32BLEBeacon), - cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True), - cv.Required(CONF_UUID): cv.uuid, - cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t, - cv.Optional(CONF_MINOR, default=61958): cv.uint16_t, - } -).extend(cv.COMPONENT_SCHEMA) + +def validate_config(config): + if config[CONF_MIN_INTERVAL] > config.get(CONF_MAX_INTERVAL): + raise cv.Invalid("min_interval must be <= max_interval") + return config + + +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ESP32BLEBeacon), + cv.Required(CONF_TYPE): cv.one_of("IBEACON", upper=True), + cv.Required(CONF_UUID): cv.uuid, + cv.Optional(CONF_MAJOR, default=10167): cv.uint16_t, + cv.Optional(CONF_MINOR, default=61958): cv.uint16_t, + cv.Optional(CONF_MIN_INTERVAL, default="100ms"): cv.All( + cv.positive_time_period_milliseconds, + cv.Range( + min=TimePeriod(milliseconds=20), max=TimePeriod(milliseconds=10240) + ), + ), + cv.Optional(CONF_MAX_INTERVAL, default="100ms"): cv.All( + cv.positive_time_period_milliseconds, + cv.Range( + min=TimePeriod(milliseconds=20), max=TimePeriod(milliseconds=10240) + ), + ), + cv.Optional(CONF_MEASURED_POWER, default=-59): cv.int_range( + min=-128, max=0 + ), + cv.Optional(CONF_TX_POWER, default="3dBm"): cv.All( + cv.decibel, cv.one_of(-12, -9, -6, -3, 0, 3, 6, 9, int=True) + ), + } + ).extend(cv.COMPONENT_SCHEMA), + validate_config, +) async def to_code(config): @@ -31,6 +62,10 @@ async def to_code(config): await cg.register_component(var, config) cg.add(var.set_major(config[CONF_MAJOR])) cg.add(var.set_minor(config[CONF_MINOR])) + cg.add(var.set_min_interval(config[CONF_MIN_INTERVAL])) + cg.add(var.set_max_interval(config[CONF_MAX_INTERVAL])) + cg.add(var.set_measured_power(config[CONF_MEASURED_POWER])) + cg.add(var.set_tx_power(config[CONF_TX_POWER])) if CORE.using_esp_idf: add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True) diff --git a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp index 955bc8595f..589fcc1e82 100644 --- a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +++ b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp @@ -36,11 +36,24 @@ static esp_ble_adv_params_t ble_adv_params = { #define ENDIAN_CHANGE_U16(x) ((((x) &0xFF00) >> 8) + (((x) &0xFF) << 8)) static const esp_ble_ibeacon_head_t IBEACON_COMMON_HEAD = { - .flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = 0x004C, .beacon_type = 0x1502}; + .flags = {0x02, 0x01, 0x06}, .length = 0x1A, .type = 0xFF, .company_id = {0x4C, 0x00}, .beacon_type = {0x02, 0x15}}; void ESP32BLEBeacon::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE Beacon:"); - ESP_LOGCONFIG(TAG, " Major: %u, Minor: %u", this->major_, this->minor_); + char uuid[37]; + char *bpos = uuid; + for (int8_t ii = 0; ii < 16; ++ii) { + bpos += sprintf(bpos, "%02X", this->uuid_[ii]); + if (ii == 3 || ii == 5 || ii == 7 || ii == 9) { + bpos += sprintf(bpos, "-"); + } + } + uuid[36] = '\0'; + ESP_LOGCONFIG(TAG, + " UUID: %s, Major: %u, Minor: %u, Min Interval: %ums, Max Interval: %ums, Measured Power: %d" + ", TX Power: %ddBm", + uuid, this->major_, this->minor_, this->min_interval_, this->max_interval_, this->measured_power_, + this->tx_power_); } void ESP32BLEBeacon::setup() { @@ -67,6 +80,9 @@ void ESP32BLEBeacon::ble_core_task(void *params) { } void ESP32BLEBeacon::ble_setup() { + ble_adv_params.adv_int_min = static_cast(global_esp32_ble_beacon->min_interval_ / 0.625f); + ble_adv_params.adv_int_max = static_cast(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) { @@ -118,6 +134,12 @@ void ESP32BLEBeacon::ble_setup() { ESP_LOGE(TAG, "esp_bluedroid_enable failed: %d", err); return; } + err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, + static_cast((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); @@ -130,7 +152,7 @@ void ESP32BLEBeacon::ble_setup() { 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.major = ENDIAN_CHANGE_U16(global_esp32_ble_beacon->major_); - ibeacon_adv_data.ibeacon_vendor.measured_power = 0xC5; + ibeacon_adv_data.ibeacon_vendor.measured_power = static_cast(global_esp32_ble_beacon->measured_power_); esp_ble_gap_config_adv_data_raw((uint8_t *) &ibeacon_adv_data, sizeof(ibeacon_adv_data)); } @@ -153,7 +175,7 @@ void ESP32BLEBeacon::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap break; } case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: { - err = param->adv_start_cmpl.status; + err = param->adv_stop_cmpl.status; if (err != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(TAG, "BLE adv stop failed: %s", esp_err_to_name(err)); } else { diff --git a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h index 80ad2041f2..5208b67ea3 100644 --- a/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h +++ b/esphome/components/esp32_ble_beacon/esp32_ble_beacon.h @@ -5,6 +5,7 @@ #ifdef USE_ESP32 #include +#include namespace esphome { namespace esp32_ble_beacon { @@ -14,8 +15,8 @@ typedef struct { uint8_t flags[3]; uint8_t length; uint8_t type; - uint16_t company_id; - uint16_t beacon_type; + uint8_t company_id[2]; + uint8_t beacon_type[2]; } __attribute__((packed)) esp_ble_ibeacon_head_t; // NOLINTNEXTLINE(modernize-use-using) @@ -42,6 +43,10 @@ class ESP32BLEBeacon : public Component { void set_major(uint16_t major) { this->major_ = major; } void set_minor(uint16_t minor) { this->minor_ = minor; } + void set_min_interval(uint16_t val) { this->min_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_tx_power(int8_t val) { this->tx_power_ = val; } protected: static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); @@ -51,6 +56,10 @@ class ESP32BLEBeacon : public Component { std::array uuid_; uint16_t major_{}; uint16_t minor_{}; + uint16_t min_interval_{}; + uint16_t max_interval_{}; + int8_t measured_power_{}; + int8_t tx_power_{}; }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)