mirror of
https://github.com/esphome/esphome.git
synced 2025-10-17 07:57:13 +02:00
Merge branch 'integration' into memory_api
This commit is contained in:
commit
96dd348f9a
@ -1519,7 +1519,7 @@ message BluetoothGATTCharacteristic {
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true];
|
||||
uint32 handle = 2;
|
||||
uint32 properties = 3;
|
||||
repeated BluetoothGATTDescriptor descriptors = 4;
|
||||
repeated BluetoothGATTDescriptor descriptors = 4 [(fixed_vector) = true];
|
||||
|
||||
// New field for efficient UUID (v1.12+)
|
||||
// Only one of uuid or short_uuid will be set.
|
||||
@ -1531,7 +1531,7 @@ message BluetoothGATTCharacteristic {
|
||||
message BluetoothGATTService {
|
||||
repeated uint64 uuid = 1 [(fixed_array_size) = 2, (fixed_array_skip_zero) = true];
|
||||
uint32 handle = 2;
|
||||
repeated BluetoothGATTCharacteristic characteristics = 3;
|
||||
repeated BluetoothGATTCharacteristic characteristics = 3 [(fixed_vector) = true];
|
||||
|
||||
// New field for efficient UUID (v1.12+)
|
||||
// Only one of uuid or short_uuid will be set.
|
||||
|
@ -64,4 +64,10 @@ extend google.protobuf.FieldOptions {
|
||||
// This is typically done through methods returning const T& or special accessor
|
||||
// methods like get_options() or supported_modes_for_api_().
|
||||
optional string container_pointer = 50001;
|
||||
|
||||
// fixed_vector: Use FixedVector instead of std::vector for repeated fields
|
||||
// When set, the repeated field will use FixedVector<T> which requires calling
|
||||
// init(size) before adding elements. This eliminates std::vector template overhead
|
||||
// and is ideal when the exact size is known before populating the array.
|
||||
optional bool fixed_vector = 50013 [default=false];
|
||||
}
|
||||
|
@ -1923,7 +1923,7 @@ class BluetoothGATTCharacteristic final : public ProtoMessage {
|
||||
std::array<uint64_t, 2> uuid{};
|
||||
uint32_t handle{0};
|
||||
uint32_t properties{0};
|
||||
std::vector<BluetoothGATTDescriptor> descriptors{};
|
||||
FixedVector<BluetoothGATTDescriptor> descriptors{};
|
||||
uint32_t short_uuid{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
@ -1937,7 +1937,7 @@ class BluetoothGATTService final : public ProtoMessage {
|
||||
public:
|
||||
std::array<uint64_t, 2> uuid{};
|
||||
uint32_t handle{0};
|
||||
std::vector<BluetoothGATTCharacteristic> characteristics{};
|
||||
FixedVector<BluetoothGATTCharacteristic> characteristics{};
|
||||
uint32_t short_uuid{0};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
|
@ -749,13 +749,29 @@ class ProtoSize {
|
||||
template<typename MessageType>
|
||||
inline void add_repeated_message(uint32_t field_id_size, const std::vector<MessageType> &messages) {
|
||||
// Skip if the vector is empty
|
||||
if (messages.empty()) {
|
||||
return;
|
||||
if (!messages.empty()) {
|
||||
// Use the force version for all messages in the repeated field
|
||||
for (const auto &message : messages) {
|
||||
add_message_object_force(field_id_size, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the force version for all messages in the repeated field
|
||||
for (const auto &message : messages) {
|
||||
add_message_object_force(field_id_size, message);
|
||||
/**
|
||||
* @brief Calculates and adds the sizes of all messages in a repeated field to the total message size (FixedVector
|
||||
* version)
|
||||
*
|
||||
* @tparam MessageType The type of the nested messages in the FixedVector
|
||||
* @param messages FixedVector of message objects
|
||||
*/
|
||||
template<typename MessageType>
|
||||
inline void add_repeated_message(uint32_t field_id_size, const FixedVector<MessageType> &messages) {
|
||||
// Skip if the fixed vector is empty
|
||||
if (!messages.empty()) {
|
||||
// Use the force version for all messages in the repeated field
|
||||
for (const auto &message : messages) {
|
||||
add_message_object_force(field_id_size, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -230,8 +230,8 @@ void BluetoothConnection::send_service_for_discovery_() {
|
||||
service_resp.handle = service_result.start_handle;
|
||||
|
||||
if (total_char_count > 0) {
|
||||
// Reserve space and process characteristics
|
||||
service_resp.characteristics.reserve(total_char_count);
|
||||
// Initialize FixedVector with exact count and process characteristics
|
||||
service_resp.characteristics.init(total_char_count);
|
||||
uint16_t char_offset = 0;
|
||||
esp_gattc_char_elem_t char_result;
|
||||
while (true) { // characteristics
|
||||
@ -253,9 +253,7 @@ void BluetoothConnection::send_service_for_discovery_() {
|
||||
|
||||
service_resp.characteristics.emplace_back();
|
||||
auto &characteristic_resp = service_resp.characteristics.back();
|
||||
|
||||
fill_gatt_uuid(characteristic_resp.uuid, characteristic_resp.short_uuid, char_result.uuid, use_efficient_uuids);
|
||||
|
||||
characteristic_resp.handle = char_result.char_handle;
|
||||
characteristic_resp.properties = char_result.properties;
|
||||
char_offset++;
|
||||
@ -271,12 +269,11 @@ void BluetoothConnection::send_service_for_discovery_() {
|
||||
return;
|
||||
}
|
||||
if (total_desc_count == 0) {
|
||||
// No descriptors, continue to next characteristic
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reserve space and process descriptors
|
||||
characteristic_resp.descriptors.reserve(total_desc_count);
|
||||
// Initialize FixedVector with exact count and process descriptors
|
||||
characteristic_resp.descriptors.init(total_desc_count);
|
||||
uint16_t desc_offset = 0;
|
||||
esp_gattc_descr_elem_t desc_result;
|
||||
while (true) { // descriptors
|
||||
@ -297,9 +294,7 @@ void BluetoothConnection::send_service_for_discovery_() {
|
||||
|
||||
characteristic_resp.descriptors.emplace_back();
|
||||
auto &descriptor_resp = characteristic_resp.descriptors.back();
|
||||
|
||||
fill_gatt_uuid(descriptor_resp.uuid, descriptor_resp.short_uuid, desc_result.uuid, use_efficient_uuids);
|
||||
|
||||
descriptor_resp.handle = desc_result.handle;
|
||||
desc_offset++;
|
||||
}
|
||||
|
@ -108,8 +108,13 @@ class BTLoggers(Enum):
|
||||
"""ESP32 WiFi provisioning over Bluetooth"""
|
||||
|
||||
|
||||
# Set to track which loggers are needed by components
|
||||
_required_loggers: set[BTLoggers] = set()
|
||||
# Key for storing required loggers in CORE.data
|
||||
ESP32_BLE_REQUIRED_LOGGERS_KEY = "esp32_ble_required_loggers"
|
||||
|
||||
|
||||
def _get_required_loggers() -> set[BTLoggers]:
|
||||
"""Get the set of required Bluetooth loggers from CORE.data."""
|
||||
return CORE.data.setdefault(ESP32_BLE_REQUIRED_LOGGERS_KEY, set())
|
||||
|
||||
|
||||
# Dataclass for handler registration counts
|
||||
@ -170,12 +175,13 @@ def register_bt_logger(*loggers: BTLoggers) -> None:
|
||||
Args:
|
||||
*loggers: One or more BTLoggers enum members
|
||||
"""
|
||||
required_loggers = _get_required_loggers()
|
||||
for logger in loggers:
|
||||
if not isinstance(logger, BTLoggers):
|
||||
raise TypeError(
|
||||
f"Logger must be a BTLoggers enum member, got {type(logger)}"
|
||||
)
|
||||
_required_loggers.add(logger)
|
||||
required_loggers.add(logger)
|
||||
|
||||
|
||||
CONF_BLE_ID = "ble_id"
|
||||
@ -427,7 +433,7 @@ def final_validation(config):
|
||||
FINAL_VALIDATE_SCHEMA = final_validation
|
||||
|
||||
|
||||
# This needs to be run as a job with very low priority so that all components have
|
||||
# This needs to be run as a job with CoroPriority.FINAL priority so that all components have
|
||||
# a chance to register their handlers before the counts are added to defines.
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _add_ble_handler_defines():
|
||||
@ -479,8 +485,9 @@ async def to_code(config):
|
||||
# Apply logger settings if log disabling is enabled
|
||||
if config.get(CONF_DISABLE_BT_LOGS, False):
|
||||
# Disable all Bluetooth loggers that are not required
|
||||
required_loggers = _get_required_loggers()
|
||||
for logger in BTLoggers:
|
||||
if logger not in _required_loggers:
|
||||
if logger not in required_loggers:
|
||||
add_idf_sdkconfig_option(f"{logger.value}_NONE", True)
|
||||
|
||||
# Set BLE connection establishment timeout to match aioesphomeapi/bleak-retry-connector
|
||||
|
@ -60,11 +60,21 @@ class RegistrationCounts:
|
||||
clients: int = 0
|
||||
|
||||
|
||||
# Set to track which features are needed by components
|
||||
_required_features: set[BLEFeatures] = set()
|
||||
# CORE.data keys for state management
|
||||
ESP32_BLE_TRACKER_REQUIRED_FEATURES_KEY = "esp32_ble_tracker_required_features"
|
||||
ESP32_BLE_TRACKER_REGISTRATION_COUNTS_KEY = "esp32_ble_tracker_registration_counts"
|
||||
|
||||
# Track registration counts for StaticVector sizing
|
||||
_registration_counts = RegistrationCounts()
|
||||
|
||||
def _get_required_features() -> set[BLEFeatures]:
|
||||
"""Get the set of required BLE features from CORE.data."""
|
||||
return CORE.data.setdefault(ESP32_BLE_TRACKER_REQUIRED_FEATURES_KEY, set())
|
||||
|
||||
|
||||
def _get_registration_counts() -> RegistrationCounts:
|
||||
"""Get the registration counts from CORE.data."""
|
||||
return CORE.data.setdefault(
|
||||
ESP32_BLE_TRACKER_REGISTRATION_COUNTS_KEY, RegistrationCounts()
|
||||
)
|
||||
|
||||
|
||||
def register_ble_features(features: set[BLEFeatures]) -> None:
|
||||
@ -73,7 +83,7 @@ def register_ble_features(features: set[BLEFeatures]) -> None:
|
||||
Args:
|
||||
features: Set of BLEFeatures enum members
|
||||
"""
|
||||
_required_features.update(features)
|
||||
_get_required_features().update(features)
|
||||
|
||||
|
||||
esp32_ble_tracker_ns = cg.esphome_ns.namespace("esp32_ble_tracker")
|
||||
@ -267,15 +277,17 @@ async def to_code(config):
|
||||
):
|
||||
register_ble_features({BLEFeatures.ESP_BT_DEVICE})
|
||||
|
||||
registration_counts = _get_registration_counts()
|
||||
|
||||
for conf in config.get(CONF_ON_BLE_ADVERTISE, []):
|
||||
_registration_counts.listeners += 1
|
||||
registration_counts.listeners += 1
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
if CONF_MAC_ADDRESS in conf:
|
||||
addr_list = [it.as_hex for it in conf[CONF_MAC_ADDRESS]]
|
||||
cg.add(trigger.set_addresses(addr_list))
|
||||
await automation.build_automation(trigger, [(ESPBTDeviceConstRef, "x")], conf)
|
||||
for conf in config.get(CONF_ON_BLE_SERVICE_DATA_ADVERTISE, []):
|
||||
_registration_counts.listeners += 1
|
||||
registration_counts.listeners += 1
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
if len(conf[CONF_SERVICE_UUID]) == len(bt_uuid16_format):
|
||||
cg.add(trigger.set_service_uuid16(as_hex(conf[CONF_SERVICE_UUID])))
|
||||
@ -288,7 +300,7 @@ async def to_code(config):
|
||||
cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex))
|
||||
await automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf)
|
||||
for conf in config.get(CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE, []):
|
||||
_registration_counts.listeners += 1
|
||||
registration_counts.listeners += 1
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
if len(conf[CONF_MANUFACTURER_ID]) == len(bt_uuid16_format):
|
||||
cg.add(trigger.set_manufacturer_uuid16(as_hex(conf[CONF_MANUFACTURER_ID])))
|
||||
@ -301,7 +313,7 @@ async def to_code(config):
|
||||
cg.add(trigger.set_address(conf[CONF_MAC_ADDRESS].as_hex))
|
||||
await automation.build_automation(trigger, [(adv_data_t_const_ref, "x")], conf)
|
||||
for conf in config.get(CONF_ON_SCAN_END, []):
|
||||
_registration_counts.listeners += 1
|
||||
registration_counts.listeners += 1
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
@ -331,19 +343,21 @@ async def to_code(config):
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _add_ble_features():
|
||||
# Add feature-specific defines based on what's needed
|
||||
if BLEFeatures.ESP_BT_DEVICE in _required_features:
|
||||
required_features = _get_required_features()
|
||||
if BLEFeatures.ESP_BT_DEVICE in required_features:
|
||||
cg.add_define("USE_ESP32_BLE_DEVICE")
|
||||
cg.add_define("USE_ESP32_BLE_UUID")
|
||||
|
||||
# Add defines for StaticVector sizing based on registration counts
|
||||
# Only define if count > 0 to avoid allocating unnecessary memory
|
||||
if _registration_counts.listeners > 0:
|
||||
registration_counts = _get_registration_counts()
|
||||
if registration_counts.listeners > 0:
|
||||
cg.add_define(
|
||||
"ESPHOME_ESP32_BLE_TRACKER_LISTENER_COUNT", _registration_counts.listeners
|
||||
"ESPHOME_ESP32_BLE_TRACKER_LISTENER_COUNT", registration_counts.listeners
|
||||
)
|
||||
if _registration_counts.clients > 0:
|
||||
if registration_counts.clients > 0:
|
||||
cg.add_define(
|
||||
"ESPHOME_ESP32_BLE_TRACKER_CLIENT_COUNT", _registration_counts.clients
|
||||
"ESPHOME_ESP32_BLE_TRACKER_CLIENT_COUNT", registration_counts.clients
|
||||
)
|
||||
|
||||
|
||||
@ -395,7 +409,7 @@ async def register_ble_device(
|
||||
var: cg.SafeExpType, config: ConfigType
|
||||
) -> cg.SafeExpType:
|
||||
register_ble_features({BLEFeatures.ESP_BT_DEVICE})
|
||||
_registration_counts.listeners += 1
|
||||
_get_registration_counts().listeners += 1
|
||||
paren = await cg.get_variable(config[CONF_ESP32_BLE_ID])
|
||||
cg.add(paren.register_listener(var))
|
||||
return var
|
||||
@ -403,7 +417,7 @@ async def register_ble_device(
|
||||
|
||||
async def register_client(var: cg.SafeExpType, config: ConfigType) -> cg.SafeExpType:
|
||||
register_ble_features({BLEFeatures.ESP_BT_DEVICE})
|
||||
_registration_counts.clients += 1
|
||||
_get_registration_counts().clients += 1
|
||||
paren = await cg.get_variable(config[CONF_ESP32_BLE_ID])
|
||||
cg.add(paren.register_client(var))
|
||||
return var
|
||||
@ -417,7 +431,7 @@ async def register_raw_ble_device(
|
||||
This does NOT register the ESP_BT_DEVICE feature, meaning ESPBTDevice
|
||||
will not be compiled in if this is the only registration method used.
|
||||
"""
|
||||
_registration_counts.listeners += 1
|
||||
_get_registration_counts().listeners += 1
|
||||
paren = await cg.get_variable(config[CONF_ESP32_BLE_ID])
|
||||
cg.add(paren.register_listener(var))
|
||||
return var
|
||||
@ -431,7 +445,7 @@ async def register_raw_client(
|
||||
This does NOT register the ESP_BT_DEVICE feature, meaning ESPBTDevice
|
||||
will not be compiled in if this is the only registration method used.
|
||||
"""
|
||||
_registration_counts.clients += 1
|
||||
_get_registration_counts().clients += 1
|
||||
paren = await cg.get_variable(config[CONF_ESP32_BLE_ID])
|
||||
cg.add(paren.register_client(var))
|
||||
return var
|
||||
|
@ -143,7 +143,18 @@ def validate_mclk_divisible_by_3(config):
|
||||
return config
|
||||
|
||||
|
||||
_use_legacy_driver = None
|
||||
# Key for storing legacy driver setting in CORE.data
|
||||
I2S_USE_LEGACY_DRIVER_KEY = "i2s_use_legacy_driver"
|
||||
|
||||
|
||||
def _get_use_legacy_driver():
|
||||
"""Get the legacy driver setting from CORE.data."""
|
||||
return CORE.data.get(I2S_USE_LEGACY_DRIVER_KEY)
|
||||
|
||||
|
||||
def _set_use_legacy_driver(value: bool) -> None:
|
||||
"""Set the legacy driver setting in CORE.data."""
|
||||
CORE.data[I2S_USE_LEGACY_DRIVER_KEY] = value
|
||||
|
||||
|
||||
def i2s_audio_component_schema(
|
||||
@ -209,17 +220,15 @@ async def register_i2s_audio_component(var, config):
|
||||
|
||||
|
||||
def validate_use_legacy(value):
|
||||
global _use_legacy_driver # noqa: PLW0603
|
||||
if CONF_USE_LEGACY in value:
|
||||
if (_use_legacy_driver is not None) and (
|
||||
_use_legacy_driver != value[CONF_USE_LEGACY]
|
||||
):
|
||||
existing_value = _get_use_legacy_driver()
|
||||
if (existing_value is not None) and (existing_value != value[CONF_USE_LEGACY]):
|
||||
raise cv.Invalid(
|
||||
f"All i2s_audio components must set {CONF_USE_LEGACY} to the same value."
|
||||
)
|
||||
if (not value[CONF_USE_LEGACY]) and (CORE.using_arduino):
|
||||
raise cv.Invalid("Arduino supports only the legacy i2s driver")
|
||||
_use_legacy_driver = value[CONF_USE_LEGACY]
|
||||
_set_use_legacy_driver(value[CONF_USE_LEGACY])
|
||||
return value
|
||||
|
||||
|
||||
@ -249,7 +258,8 @@ def _final_validate(_):
|
||||
|
||||
|
||||
def use_legacy():
|
||||
return not (CORE.using_esp_idf and not _use_legacy_driver)
|
||||
legacy_driver = _get_use_legacy_driver()
|
||||
return not (CORE.using_esp_idf and not legacy_driver)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
|
@ -202,7 +202,11 @@ template<typename T> class FixedVector {
|
||||
|
||||
~FixedVector() { cleanup_(); }
|
||||
|
||||
// Enable move semantics for use in containers
|
||||
// Disable copy operations (avoid accidental expensive copies)
|
||||
FixedVector(const FixedVector &) = delete;
|
||||
FixedVector &operator=(const FixedVector &) = delete;
|
||||
|
||||
// Enable move semantics (allows use in move-only containers like std::vector)
|
||||
FixedVector(FixedVector &&other) noexcept : data_(other.data_), size_(other.size_), capacity_(other.capacity_) {
|
||||
other.reset_();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
||||
esptool==5.1.0
|
||||
click==8.1.7
|
||||
esphome-dashboard==20251013.0
|
||||
aioesphomeapi==41.16.0
|
||||
aioesphomeapi==41.16.1
|
||||
zeroconf==0.148.0
|
||||
puremagic==1.30
|
||||
ruamel.yaml==0.18.15 # dashboard_import
|
||||
|
@ -1415,6 +1415,8 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
# Check if this is a pointer field by looking for container_pointer option
|
||||
self._container_type = get_field_opt(field, pb.container_pointer, "")
|
||||
self._use_pointer = bool(self._container_type)
|
||||
# Check if this should use FixedVector instead of std::vector
|
||||
self._use_fixed_vector = get_field_opt(field, pb.fixed_vector, False)
|
||||
|
||||
# For repeated fields, we need to get the base type info
|
||||
# but we can't call create_field_type_info as it would cause recursion
|
||||
@ -1438,6 +1440,8 @@ class RepeatedTypeInfo(TypeInfo):
|
||||
if "<" in self._container_type and ">" in self._container_type:
|
||||
return f"const {self._container_type}*"
|
||||
return f"const {self._container_type}<{self._ti.cpp_type}>*"
|
||||
if self._use_fixed_vector:
|
||||
return f"FixedVector<{self._ti.cpp_type}>"
|
||||
return f"std::vector<{self._ti.cpp_type}>"
|
||||
|
||||
@property
|
||||
|
Loading…
x
Reference in New Issue
Block a user