Merge remote-tracking branch 'origin/pack-entity-strings' into integration

This commit is contained in:
J. Nick Koston
2026-03-02 09:31:46 -10:00
10 changed files with 86 additions and 31 deletions
+1 -1
View File
@@ -48,8 +48,8 @@ void arch_init() {
void HOT arch_feed_wdt() { esp_task_wdt_reset(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
const char *progmem_read_ptr(const char *const *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); }
uint32_t arch_get_cpu_freq_hz() {
uint32_t freq = 0;
+1 -6
View File
@@ -368,16 +368,11 @@ SETTERS = {
}
@setup_entity("camera")
async def _setup_esp32_camera(var, config):
pass
async def to_code(config):
cg.add_define("USE_CAMERA")
socket.require_wake_loop_threadsafe()
var = cg.new_Pvariable(config[CONF_ID])
await _setup_esp32_camera(var, config)
await setup_entity(var, config, "camera")
await cg.register_component(var, config)
for key, setter in SETTERS.items():
+3 -3
View File
@@ -34,12 +34,12 @@ void HOT arch_feed_wdt() { system_soft_wdt_feed(); }
uint8_t progmem_read_byte(const uint8_t *addr) {
return pgm_read_byte(addr); // NOLINT
}
uint16_t progmem_read_uint16(const uint16_t *addr) {
return pgm_read_word(addr); // NOLINT
}
const char *progmem_read_ptr(const char *const *addr) {
return reinterpret_cast<const char *>(pgm_read_ptr(addr)); // NOLINT
}
uint16_t progmem_read_uint16(const uint16_t *addr) {
return pgm_read_word(addr); // NOLINT
}
uint32_t IRAM_ATTR HOT arch_get_cpu_cycle_count() { return esp_get_cycle_count(); }
uint32_t arch_get_cpu_freq_hz() { return F_CPU; }
+1 -1
View File
@@ -59,8 +59,8 @@ void HOT arch_feed_wdt() {
}
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
const char *progmem_read_ptr(const char *const *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
uint32_t arch_get_cpu_cycle_count() {
struct timespec spec;
clock_gettime(CLOCK_MONOTONIC, &spec);
+1 -1
View File
@@ -36,8 +36,8 @@ void HOT arch_feed_wdt() { lt_wdt_feed(); }
uint32_t arch_get_cpu_cycle_count() { return lt_cpu_get_cycle_count(); }
uint32_t arch_get_cpu_freq_hz() { return lt_cpu_get_freq(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
const char *progmem_read_ptr(const char *const *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
} // namespace esphome
+1 -1
View File
@@ -34,10 +34,10 @@ void HOT arch_feed_wdt() { watchdog_update(); }
uint8_t progmem_read_byte(const uint8_t *addr) {
return pgm_read_byte(addr); // NOLINT
}
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
const char *progmem_read_ptr(const char *const *addr) {
return reinterpret_cast<const char *>(pgm_read_ptr(addr)); // NOLINT
}
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
uint32_t HOT arch_get_cpu_cycle_count() { return ulMainGetRunTimeCounterValue(); }
uint32_t arch_get_cpu_freq_hz() { return RP2040::f_cpu(); }
+1 -1
View File
@@ -60,8 +60,8 @@ void arch_restart() { sys_reboot(SYS_REBOOT_COLD); }
uint32_t arch_get_cpu_cycle_count() { return k_cycle_get_32(); }
uint32_t arch_get_cpu_freq_hz() { return sys_clock_hw_cycles_per_sec(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
const char *progmem_read_ptr(const char *const *addr) { return *addr; }
uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; }
Mutex::Mutex() {
auto *mutex = new k_mutex();
+27 -16
View File
@@ -236,33 +236,44 @@ def get_base_entity_object_id(
return sanitize(snake_case(base_str))
def setup_entity(platform: str) -> Callable:
"""Decorator for component setup functions.
def setup_entity(var_or_platform, config=None, platform=None):
"""Set up entity properties — works as both decorator and direct call.
Wraps the function to:
1. Set up common entity properties (name, icon, etc.)
2. Run the wrapped function (which may call setup_device_class, etc.)
3. Finalize entity strings (pack dc/uom/icon indices into uint32_t)
Usage::
Decorator mode::
@setup_entity("sensor")
async def setup_sensor_core_(var, config):
setup_device_class(config)
setup_unit_of_measurement(config)
...
Direct call mode (for entities with no extra string properties)::
await setup_entity(var, config, "camera")
"""
if isinstance(var_or_platform, str) and config is None:
# Decorator mode: @setup_entity("sensor")
platform = var_or_platform
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def wrapper(var: MockObj, config: ConfigType, *args, **kwargs) -> None:
await _setup_entity_impl(var, config, platform)
await func(var, config, *args, **kwargs)
finalize_entity_strings(var, config)
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def wrapper(
var: MockObj, config: ConfigType, *args, **kwargs
) -> None:
await _setup_entity_impl(var, config, platform)
await func(var, config, *args, **kwargs)
finalize_entity_strings(var, config)
return wrapper
return wrapper
return decorator
return decorator
# Direct call mode: await setup_entity(var, config, "camera")
async def _do() -> None:
await _setup_entity_impl(var_or_platform, config, platform)
finalize_entity_strings(var_or_platform, config)
return _do()
async def _setup_entity_impl(var: MockObj, config: ConfigType, platform: str) -> None:
+1 -1
View File
@@ -42,7 +42,7 @@ void arch_feed_wdt();
uint32_t arch_get_cpu_cycle_count();
uint32_t arch_get_cpu_freq_hz();
uint8_t progmem_read_byte(const uint8_t *addr);
uint16_t progmem_read_uint16(const uint16_t *addr);
const char *progmem_read_ptr(const char *const *addr);
uint16_t progmem_read_uint16(const uint16_t *addr);
} // namespace esphome
@@ -23,6 +23,7 @@ from esphome.core.entity_helpers import (
_setup_entity_impl,
entity_duplicate_validator,
get_base_entity_object_id,
setup_entity,
)
from esphome.cpp_generator import MockObj
from esphome.helpers import sanitize, snake_case
@@ -924,3 +925,51 @@ async def test_setup_entity_with_entity_category(
assert any(
'set_entity_category("diagnostic")' in expr for expr in added_expressions
)
@pytest.mark.asyncio
async def test_setup_entity_direct_call(setup_test_environment: list[str]) -> None:
"""Test setup_entity in direct call mode (legacy / backward compat)."""
added_expressions = setup_test_environment
var = MockObj("camera1")
config = {
CONF_NAME: "My Camera",
CONF_DISABLED_BY_DEFAULT: False,
CONF_ICON: "mdi:camera",
}
# Direct call mode: await setup_entity(var, config, "camera")
await setup_entity(var, config, "camera")
# Should have called set_name
object_id = extract_object_id_from_expressions(added_expressions)
assert object_id == "my_camera"
# Icon index should have been stored and finalized
assert config.get("_entity_icon_idx", 0) > 0
@pytest.mark.asyncio
async def test_setup_entity_decorator_mode(setup_test_environment: list[str]) -> None:
"""Test setup_entity in decorator mode."""
added_expressions = setup_test_environment
body_called = False
@setup_entity("sensor")
async def my_setup(var, config):
nonlocal body_called
body_called = True
var = MockObj("sensor1")
config = {
CONF_NAME: "Temperature",
CONF_DISABLED_BY_DEFAULT: False,
}
await my_setup(var, config)
assert body_called
object_id = extract_object_id_from_expressions(added_expressions)
assert object_id == "temperature"