mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 11:07:33 +00:00
[rp2040_ble] Add BLE component for RP2040/RP2350 (#14603)
This commit is contained in:
@@ -410,6 +410,7 @@ esphome/components/restart/* @esphome/core
|
||||
esphome/components/rf_bridge/* @jesserockz
|
||||
esphome/components/rgbct/* @jesserockz
|
||||
esphome/components/rp2040/* @jesserockz
|
||||
esphome/components/rp2040_ble/* @bdraco
|
||||
esphome/components/rp2040_pio_led_strip/* @Papa-DMan
|
||||
esphome/components/rp2040_pwm/* @jesserockz
|
||||
esphome/components/rpi_dpi_rgb/* @clydebarrow
|
||||
|
||||
31
esphome/components/rp2040_ble/__init__.py
Normal file
31
esphome/components/rp2040_ble/__init__.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID
|
||||
from esphome.types import ConfigType
|
||||
|
||||
DEPENDENCIES = ["rp2040"]
|
||||
CODEOWNERS = ["@bdraco"]
|
||||
|
||||
rp2040_ble_ns = cg.esphome_ns.namespace("rp2040_ble")
|
||||
RP2040BLE = rp2040_ble_ns.class_("RP2040BLE", cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(RP2040BLE),
|
||||
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
|
||||
|
||||
# Enable Bluetooth in the arduino-pico build
|
||||
# This switches linking from liblwip.a to liblwip-bt.a and defines
|
||||
# ENABLE_CLASSIC, ENABLE_BLE, CYW43_ENABLE_BLUETOOTH
|
||||
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_BLUETOOTH")
|
||||
|
||||
cg.add_define("USE_RP2040_BLE")
|
||||
124
esphome/components/rp2040_ble/rp2040_ble.cpp
Normal file
124
esphome/components/rp2040_ble/rp2040_ble.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include "rp2040_ble.h"
|
||||
|
||||
#ifdef USE_RP2040_BLE
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::rp2040_ble {
|
||||
|
||||
static const char *const TAG = "rp2040_ble";
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
RP2040BLE *global_ble = nullptr;
|
||||
|
||||
void RP2040BLE::setup() {
|
||||
global_ble = this;
|
||||
|
||||
if (this->enable_on_boot_) {
|
||||
this->enable();
|
||||
} else {
|
||||
this->state_ = BLEComponentState::DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
void RP2040BLE::enable() {
|
||||
if (this->state_ == BLEComponentState::ACTIVE || this->state_ == BLEComponentState::ENABLING) {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Enabling BLE...");
|
||||
this->state_ = BLEComponentState::ENABLING;
|
||||
this->active_logged_ = false;
|
||||
|
||||
if (!this->btstack_initialized_) {
|
||||
// BTstack init functions are not idempotent — only call once
|
||||
l2cap_init();
|
||||
sm_init();
|
||||
|
||||
this->hci_event_callback_registration_.callback = &RP2040BLE::packet_handler_;
|
||||
hci_add_event_handler(&this->hci_event_callback_registration_);
|
||||
|
||||
this->sm_event_callback_registration_.callback = &RP2040BLE::packet_handler_;
|
||||
sm_add_event_handler(&this->sm_event_callback_registration_);
|
||||
|
||||
this->btstack_initialized_ = true;
|
||||
}
|
||||
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
}
|
||||
|
||||
void RP2040BLE::disable() {
|
||||
if (this->state_ == BLEComponentState::DISABLED || this->state_ == BLEComponentState::OFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Disabling BLE...");
|
||||
this->state_ = BLEComponentState::DISABLING;
|
||||
|
||||
hci_power_control(HCI_POWER_OFF);
|
||||
|
||||
this->state_ = BLEComponentState::DISABLED;
|
||||
ESP_LOGD(TAG, "BLE disabled");
|
||||
}
|
||||
|
||||
void RP2040BLE::loop() {
|
||||
if (this->state_ == BLEComponentState::ACTIVE && !this->active_logged_) {
|
||||
this->active_logged_ = true;
|
||||
ESP_LOGI(TAG, "BLE active");
|
||||
}
|
||||
}
|
||||
|
||||
static const char *state_to_str(BLEComponentState state) {
|
||||
switch (state) {
|
||||
case BLEComponentState::OFF:
|
||||
return "OFF";
|
||||
case BLEComponentState::ENABLING:
|
||||
return "ENABLING";
|
||||
case BLEComponentState::ACTIVE:
|
||||
return "ACTIVE";
|
||||
case BLEComponentState::DISABLING:
|
||||
return "DISABLING";
|
||||
case BLEComponentState::DISABLED:
|
||||
return "DISABLED";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void RP2040BLE::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"RP2040 BLE:\n"
|
||||
" Enable on boot: %s\n"
|
||||
" State: %s",
|
||||
YESNO(this->enable_on_boot_), state_to_str(this->state_));
|
||||
}
|
||||
|
||||
float RP2040BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; }
|
||||
|
||||
void RP2040BLE::packet_handler_(uint8_t type, uint16_t channel, uint8_t *packet, uint16_t size) {
|
||||
if (global_ble == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != HCI_EVENT_PACKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t event_type = hci_event_packet_get_type(packet);
|
||||
|
||||
switch (event_type) {
|
||||
case BTSTACK_EVENT_STATE: {
|
||||
uint8_t state = btstack_event_state_get_state(packet);
|
||||
if (state == HCI_STATE_WORKING && global_ble->state_ == BLEComponentState::ENABLING) {
|
||||
global_ble->state_ = BLEComponentState::ACTIVE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::rp2040_ble
|
||||
|
||||
#endif // USE_RP2040_BLE
|
||||
51
esphome/components/rp2040_ble/rp2040_ble.h
Normal file
51
esphome/components/rp2040_ble/rp2040_ble.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h" // Must be included before conditional includes
|
||||
|
||||
#ifdef USE_RP2040_BLE
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
#include <btstack.h>
|
||||
|
||||
namespace esphome::rp2040_ble {
|
||||
|
||||
enum class BLEComponentState : uint8_t {
|
||||
OFF = 0,
|
||||
ENABLING,
|
||||
ACTIVE,
|
||||
DISABLING,
|
||||
DISABLED,
|
||||
};
|
||||
|
||||
class RP2040BLE : public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
bool is_active() const { return this->state_ == BLEComponentState::ACTIVE; }
|
||||
|
||||
void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
|
||||
|
||||
protected:
|
||||
static void packet_handler_(uint8_t type, uint16_t channel, uint8_t *packet, uint16_t size);
|
||||
|
||||
btstack_packet_callback_registration_t hci_event_callback_registration_{};
|
||||
btstack_packet_callback_registration_t sm_event_callback_registration_{};
|
||||
|
||||
BLEComponentState state_{BLEComponentState::OFF};
|
||||
bool enable_on_boot_{true};
|
||||
bool btstack_initialized_{false};
|
||||
bool active_logged_{false};
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern RP2040BLE *global_ble;
|
||||
|
||||
} // namespace esphome::rp2040_ble
|
||||
|
||||
#endif // USE_RP2040_BLE
|
||||
@@ -339,6 +339,7 @@
|
||||
#define USE_I2C
|
||||
#define USE_LOGGER_USB_CDC
|
||||
#define USE_SOCKET_IMPL_LWIP_TCP
|
||||
#define USE_RP2040_BLE
|
||||
#define USE_SPI
|
||||
#endif
|
||||
|
||||
|
||||
1
tests/components/rp2040_ble/common.yaml
Normal file
1
tests/components/rp2040_ble/common.yaml
Normal file
@@ -0,0 +1 @@
|
||||
rp2040_ble:
|
||||
@@ -0,0 +1,2 @@
|
||||
rp2040_ble:
|
||||
enable_on_boot: false
|
||||
1
tests/components/rp2040_ble/test.rp2040-ard.yaml
Normal file
1
tests/components/rp2040_ble/test.rp2040-ard.yaml
Normal file
@@ -0,0 +1 @@
|
||||
<<: !include common.yaml
|
||||
Reference in New Issue
Block a user