mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 02:02:51 +00:00
[remote_base] Keep constant abbwelcome payloads in shared flash tables (#20311)
This commit is contained in:
@@ -44,7 +44,7 @@ from esphome.const import (
|
||||
CONF_WAND_ID,
|
||||
CONF_ZERO,
|
||||
)
|
||||
from esphome.core import ID, coroutine
|
||||
from esphome.core import coroutine
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
from esphome.types import ConfigType, TemplateArgsType
|
||||
@@ -2393,17 +2393,14 @@ async def abbwelcome_action(var, config, args):
|
||||
await cg.templatable(config[CONF_MESSAGE_ID], args, cg.uint8)
|
||||
)
|
||||
)
|
||||
if CONF_DATA in config:
|
||||
data_ = config[CONF_DATA]
|
||||
if cg.is_template(data_):
|
||||
template_ = await cg.templatable(
|
||||
data_, args, cg.std_vector.template(cg.uint8)
|
||||
)
|
||||
cg.add(var.set_data_template(template_))
|
||||
else:
|
||||
arr_id = ID(f"{var.base}_data", is_declaration=True, type=cg.uint8)
|
||||
arr = cg.static_const_array(arr_id, cg.ArrayInitializer(*data_))
|
||||
cg.add(var.set_data_static(arr, len(data_)))
|
||||
# TemplatableBytes starts in lambda mode with no function, so a transmit without data sets an empty payload
|
||||
await automation.templatable_bytes(
|
||||
config.get(CONF_DATA, []),
|
||||
args,
|
||||
var.set_data_template,
|
||||
var.set_data_static,
|
||||
"abbwelcome_data",
|
||||
)
|
||||
|
||||
|
||||
# Mirage
|
||||
|
||||
@@ -112,13 +112,14 @@ class ABBWelcomeData {
|
||||
}
|
||||
void set_message_id(uint8_t message_id) { this->data_[4 + 2 * this->get_address_length()] = message_id; }
|
||||
uint8_t get_message_id() const { return this->data_[4 + 2 * this->get_address_length()]; }
|
||||
void set_data(std::vector<uint8_t> data) {
|
||||
uint8_t size = std::min(MAX_DATA_LENGTH, static_cast<uint8_t>(data.size()));
|
||||
void set_data(const uint8_t *data, size_t len) {
|
||||
uint8_t size = static_cast<uint8_t>(std::min<size_t>(MAX_DATA_LENGTH, len));
|
||||
this->data_[2] &= (0xff ^ DATA_LENGTH_MASK);
|
||||
this->data_[2] |= (size & DATA_LENGTH_MASK);
|
||||
if (size)
|
||||
std::copy_n(data.begin(), size, this->data_.begin() + 5 + 2 * this->get_address_length());
|
||||
std::copy_n(data, size, this->data_.begin() + 5 + 2 * this->get_address_length());
|
||||
}
|
||||
void set_data(const std::vector<uint8_t> &data) { this->set_data(data.data(), data.size()); }
|
||||
std::vector<uint8_t> get_data() const {
|
||||
std::vector<uint8_t> data(this->data_.begin() + 5 + 2 * this->get_address_length(),
|
||||
this->data_.begin() + 5 + 2 * this->get_address_length() + this->get_data_size());
|
||||
@@ -233,14 +234,8 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
|
||||
TEMPLATABLE_VALUE(uint8_t, message_type)
|
||||
TEMPLATABLE_VALUE(uint8_t, message_id)
|
||||
TEMPLATABLE_VALUE(bool, auto_message_id)
|
||||
void set_data_template(std::vector<uint8_t> (*func)(Ts...)) {
|
||||
this->data_.func = func;
|
||||
this->len_ = -1; // Sentinel value indicates template mode
|
||||
}
|
||||
void set_data_static(const uint8_t *data, size_t len) {
|
||||
this->data_.data = data;
|
||||
this->len_ = len; // Length >= 0 indicates static mode
|
||||
}
|
||||
TEMPLATABLE_BYTES(data)
|
||||
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
ABBWelcomeData data;
|
||||
data.set_three_byte_address(this->three_byte_address_.value(x...));
|
||||
@@ -250,25 +245,11 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
|
||||
data.set_message_type(this->message_type_.value(x...));
|
||||
data.set_message_id(this->message_id_.value(x...));
|
||||
data.auto_message_id = this->auto_message_id_.value(x...);
|
||||
std::vector<uint8_t> data_vec;
|
||||
if (this->len_ > 0) {
|
||||
// Static mode: copy from flash to vector
|
||||
data_vec.assign(this->data_.data, this->data_.data + this->len_);
|
||||
} else if (this->len_ < 0) {
|
||||
// Template mode: call function
|
||||
data_vec = this->data_.func(x...);
|
||||
}
|
||||
data.set_data(data_vec);
|
||||
this->data_.template visit<MAX_DATA_LENGTH>(
|
||||
[&data](const uint8_t *bytes, size_t len) { data.set_data(bytes, len); }, x...);
|
||||
data.finalize();
|
||||
ABBWelcomeProtocol().encode(dst, data);
|
||||
}
|
||||
|
||||
protected:
|
||||
ssize_t len_{0}; // <0 = template mode, >=0 = static mode with length
|
||||
union Data {
|
||||
std::vector<uint8_t> (*func)(Ts...); // Function pointer (stateless lambdas)
|
||||
const uint8_t *data; // Pointer to static data in flash
|
||||
} data_;
|
||||
};
|
||||
|
||||
} // namespace esphome::remote_base
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
esphome:
|
||||
name: test
|
||||
on_boot:
|
||||
then:
|
||||
- remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x01
|
||||
data: [0x10, 0x20, 0x30]
|
||||
- remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x02
|
||||
data: [0x10, 0x20, 0x30]
|
||||
- remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x03
|
||||
data: []
|
||||
- remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x04
|
||||
- remote_transmitter.transmit_abbwelcome:
|
||||
source_address: 0x1234
|
||||
destination_address: 0x5678
|
||||
message_type: 0x05
|
||||
data: !lambda return {0x09};
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
|
||||
remote_transmitter:
|
||||
pin: 4
|
||||
carrier_duty_percent: 100%
|
||||
@@ -0,0 +1,21 @@
|
||||
"""Tests for abbwelcome constant data in shared PROGMEM tables."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
|
||||
def test_constant_data_shares_progmem_tables(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""Equal data shares one table, empty or missing data is an empty table, lambdas stay templates."""
|
||||
main_cpp = generate_main(component_config_path("abbwelcome_payload_tables.yaml"))
|
||||
|
||||
tables = re.findall(
|
||||
r"static constexpr uint8_t (\w+)\[\] PROGMEM = (\{[^}]*\});", main_cpp
|
||||
)
|
||||
assert [v for _, v in tables] == ["{0x10, 0x20, 0x30}"]
|
||||
assert main_cpp.count(f"set_data_static({tables[0][0]}, 3);") == 2
|
||||
assert main_cpp.count("set_data_static(nullptr, 0);") == 2
|
||||
assert main_cpp.count("set_data_template(") == 1
|
||||
Reference in New Issue
Block a user