Add BLE scan parameters (#769)

* Add BLE parameters

Fixes https://github.com/esphome/issues/issues/735

* Fix
This commit is contained in:
Otto Winter 2019-10-18 18:15:53 +02:00 committed by GitHub
parent aebb6d2fcc
commit 4310c14497
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 19 deletions

View File

@ -1,19 +1,48 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_SCAN_INTERVAL, ESP_PLATFORM_ESP32 from esphome.const import CONF_ID, ESP_PLATFORM_ESP32, CONF_INTERVAL, \
CONF_DURATION
from esphome.core import coroutine from esphome.core import coroutine
ESP_PLATFORMS = [ESP_PLATFORM_ESP32] ESP_PLATFORMS = [ESP_PLATFORM_ESP32]
AUTO_LOAD = ['xiaomi_ble'] AUTO_LOAD = ['xiaomi_ble']
CONF_ESP32_BLE_ID = 'esp32_ble_id' CONF_ESP32_BLE_ID = 'esp32_ble_id'
CONF_SCAN_PARAMETERS = 'scan_parameters'
CONF_WINDOW = 'window'
CONF_ACTIVE = 'active'
esp32_ble_tracker_ns = cg.esphome_ns.namespace('esp32_ble_tracker') esp32_ble_tracker_ns = cg.esphome_ns.namespace('esp32_ble_tracker')
ESP32BLETracker = esp32_ble_tracker_ns.class_('ESP32BLETracker', cg.Component) ESP32BLETracker = esp32_ble_tracker_ns.class_('ESP32BLETracker', cg.Component)
ESPBTDeviceListener = esp32_ble_tracker_ns.class_('ESPBTDeviceListener') ESPBTDeviceListener = esp32_ble_tracker_ns.class_('ESPBTDeviceListener')
def validate_scan_parameters(config):
duration = config[CONF_DURATION]
interval = config[CONF_INTERVAL]
window = config[CONF_WINDOW]
if window > interval:
raise cv.Invalid("Scan window ({}) needs to be smaller than scan interval ({})"
"".format(window, interval))
if interval.total_milliseconds * 3 > duration.total_milliseconds:
raise cv.Invalid("Scan duration needs to be at least three times the scan interval to"
"cover all BLE channels.")
return config
CONFIG_SCHEMA = cv.Schema({ CONFIG_SCHEMA = cv.Schema({
cv.GenerateID(): cv.declare_id(ESP32BLETracker), cv.GenerateID(): cv.declare_id(ESP32BLETracker),
cv.Optional(CONF_SCAN_INTERVAL, default='300s'): cv.positive_time_period_seconds, cv.Optional(CONF_SCAN_PARAMETERS, default={}): cv.All(cv.Schema({
cv.Optional(CONF_DURATION, default='5min'): cv.positive_time_period_seconds,
cv.Optional(CONF_INTERVAL, default='320ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_WINDOW, default='200ms'): cv.positive_time_period_milliseconds,
cv.Optional(CONF_ACTIVE, default=True): cv.boolean,
}), validate_scan_parameters),
cv.Optional('scan_interval'): cv.invalid("This option has been removed in 1.14 (Reason: "
"it never had an effect)"),
}).extend(cv.COMPONENT_SCHEMA) }).extend(cv.COMPONENT_SCHEMA)
ESP_BLE_DEVICE_SCHEMA = cv.Schema({ ESP_BLE_DEVICE_SCHEMA = cv.Schema({
@ -24,7 +53,11 @@ ESP_BLE_DEVICE_SCHEMA = cv.Schema({
def to_code(config): def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
yield cg.register_component(var, config) yield cg.register_component(var, config)
cg.add(var.set_scan_interval(config[CONF_SCAN_INTERVAL])) params = config[CONF_SCAN_PARAMETERS]
cg.add(var.set_scan_duration(params[CONF_DURATION]))
cg.add(var.set_scan_interval(int(params[CONF_INTERVAL].total_milliseconds / 0.625)))
cg.add(var.set_scan_window(int(params[CONF_WINDOW].total_milliseconds / 0.625)))
cg.add(var.set_scan_active(params[CONF_ACTIVE]))
@coroutine @coroutine

View File

@ -150,21 +150,16 @@ void ESP32BLETracker::start_scan(bool first) {
listener->on_scan_end(); listener->on_scan_end();
} }
this->already_discovered_.clear(); this->already_discovered_.clear();
this->scan_params_.scan_type = BLE_SCAN_TYPE_ACTIVE; this->scan_params_.scan_type = this->scan_active_ ? BLE_SCAN_TYPE_ACTIVE : BLE_SCAN_TYPE_PASSIVE;
this->scan_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC; this->scan_params_.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
this->scan_params_.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL; this->scan_params_.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL;
// Values determined empirically, higher scan intervals and lower scan windows make the ESP more stable this->scan_params_.scan_interval = this->scan_interval_;
// Ideally, these values should both be quite low, especially scan window. 0x10/0x10 is the esp-idf this->scan_params_.scan_window = this->scan_window_;
// default and works quite well. 0x100/0x50 discovers a few less BLE broadcast packets but is a lot
// more stable (order of several hours). The old ESPHome default (1600/1600) was terrible with
// crashes every few minutes
this->scan_params_.scan_interval = 0x200;
this->scan_params_.scan_window = 0x30;
esp_ble_gap_set_scan_params(&this->scan_params_); esp_ble_gap_set_scan_params(&this->scan_params_);
esp_ble_gap_start_scanning(this->scan_interval_); esp_ble_gap_start_scanning(this->scan_duration_);
this->set_timeout("scan", this->scan_interval_ * 2000, []() { this->set_timeout("scan", this->scan_duration_ * 2000, []() {
ESP_LOGW(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack..."); ESP_LOGW(TAG, "ESP-IDF BLE scan never terminated, rebooting to restore BLE stack...");
App.reboot(); App.reboot();
}); });
@ -454,10 +449,12 @@ const std::string &ESPBTDevice::get_manufacturer_data() const { return this->man
const std::string &ESPBTDevice::get_service_data() const { return this->service_data_; } const std::string &ESPBTDevice::get_service_data() const { return this->service_data_; }
const optional<ESPBTUUID> &ESPBTDevice::get_service_data_uuid() const { return this->service_data_uuid_; } const optional<ESPBTUUID> &ESPBTDevice::get_service_data_uuid() const { return this->service_data_uuid_; }
void ESP32BLETracker::set_scan_interval(uint32_t scan_interval) { this->scan_interval_ = scan_interval; }
void ESP32BLETracker::dump_config() { void ESP32BLETracker::dump_config() {
ESP_LOGCONFIG(TAG, "BLE Tracker:"); ESP_LOGCONFIG(TAG, "BLE Tracker:");
ESP_LOGCONFIG(TAG, " Scan Interval: %u s", this->scan_interval_); ESP_LOGCONFIG(TAG, " Scan Duration: %u s", this->scan_duration_);
ESP_LOGCONFIG(TAG, " Scan Interval: %u ms", this->scan_interval_);
ESP_LOGCONFIG(TAG, " Scan Window: %u ms", this->scan_window_);
ESP_LOGCONFIG(TAG, " Scan Type: %s", this->scan_active_ ? "ACTIVE" : "PASSIVE");
} }
void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) { void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {
const uint64_t address = device.address_uint64(); const uint64_t address = device.address_uint64();

View File

@ -107,7 +107,10 @@ class ESPBTDeviceListener {
class ESP32BLETracker : public Component { class ESP32BLETracker : public Component {
public: public:
void set_scan_interval(uint32_t scan_interval); void set_scan_duration(uint32_t scan_duration) { scan_duration_ = scan_duration; }
void set_scan_interval(uint32_t scan_interval) { scan_interval_ = scan_interval; }
void set_scan_window(uint32_t scan_window) { scan_window_ = scan_window; }
void set_scan_active(bool scan_active) { scan_active_ = scan_active; }
/// Setup the FreeRTOS task and the Bluetooth stack. /// Setup the FreeRTOS task and the Bluetooth stack.
void setup() override; void setup() override;
@ -142,7 +145,10 @@ class ESP32BLETracker : public Component {
/// A structure holding the ESP BLE scan parameters. /// A structure holding the ESP BLE scan parameters.
esp_ble_scan_params_t scan_params_; esp_ble_scan_params_t scan_params_;
/// The interval in seconds to perform scans. /// The interval in seconds to perform scans.
uint32_t scan_interval_{300}; uint32_t scan_duration_;
uint32_t scan_interval_;
uint32_t scan_window_;
bool scan_active_;
SemaphoreHandle_t scan_result_lock_; SemaphoreHandle_t scan_result_lock_;
SemaphoreHandle_t scan_end_lock_; SemaphoreHandle_t scan_end_lock_;
size_t scan_result_index_{0}; size_t scan_result_index_{0};

View File

@ -364,7 +364,6 @@ CONF_RX_PIN = 'rx_pin'
CONF_SAFE_MODE = 'safe_mode' CONF_SAFE_MODE = 'safe_mode'
CONF_SAMSUNG = 'samsung' CONF_SAMSUNG = 'samsung'
CONF_SCAN = 'scan' CONF_SCAN = 'scan'
CONF_SCAN_INTERVAL = 'scan_interval'
CONF_SCL = 'scl' CONF_SCL = 'scl'
CONF_SCL_PIN = 'scl_pin' CONF_SCL_PIN = 'scl_pin'
CONF_SDA = 'sda' CONF_SDA = 'sda'

View File

@ -197,7 +197,6 @@ remote_receiver:
dump: [] dump: []
esp32_ble_tracker: esp32_ble_tracker:
scan_interval: 300s
#esp32_ble_beacon: #esp32_ble_beacon:
# type: iBeacon # type: iBeacon