[canbus] Optimize canbus.send memory usage - store static data in flash (#11788)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
J. Nick Koston
2025-11-09 22:22:15 +00:00
committed by GitHub
co-authored by Jesse Hills
parent 870b2c4f84
commit 3bcbfe8d97
2 changed files with 26 additions and 15 deletions
+5 -2
View File
@@ -4,7 +4,7 @@ from esphome import automation
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_DATA, CONF_ID, CONF_TRIGGER_ID from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID
from esphome.core import CORE from esphome.core import CORE, ID
CODEOWNERS = ["@mvturnho", "@danielschramm"] CODEOWNERS = ["@mvturnho", "@danielschramm"]
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -176,5 +176,8 @@ async def canbus_action_to_code(config, action_id, template_arg, args):
else: else:
if isinstance(data, bytes): if isinstance(data, bytes):
data = [int(x) for x in data] data = [int(x) for x in data]
cg.add(var.set_data_static(data)) # Generate static array in flash to avoid RAM copy
arr_id = ID(f"{action_id}_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)))
return var return var
+21 -13
View File
@@ -112,13 +112,16 @@ class Canbus : public Component {
template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> { template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public Parented<Canbus> {
public: public:
void set_data_template(const std::function<std::vector<uint8_t>(Ts...)> func) { void set_data_template(std::vector<uint8_t> (*func)(Ts...)) {
this->data_func_ = func; // Stateless lambdas (generated by ESPHome) implicitly convert to function pointers
this->static_ = false; this->data_.func = func;
this->len_ = -1; // Sentinel value indicates template mode
} }
void set_data_static(const std::vector<uint8_t> &data) {
this->data_static_ = data; // Store pointer to static data in flash (no RAM copy)
this->static_ = true; void set_data_static(const uint8_t *data, size_t len) {
this->data_.data = data;
this->len_ = len; // Length >= 0 indicates static mode
} }
void set_can_id(uint32_t can_id) { this->can_id_ = can_id; } void set_can_id(uint32_t can_id) { this->can_id_ = can_id; }
@@ -133,21 +136,26 @@ template<typename... Ts> class CanbusSendAction : public Action<Ts...>, public P
auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_; auto can_id = this->can_id_.has_value() ? *this->can_id_ : this->parent_->can_id_;
auto use_extended_id = auto use_extended_id =
this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_; this->use_extended_id_.has_value() ? *this->use_extended_id_ : this->parent_->use_extended_id_;
if (this->static_) { std::vector<uint8_t> data;
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, this->data_static_); if (this->len_ >= 0) {
// Static mode: copy from flash to vector
data.assign(this->data_.data, this->data_.data + this->len_);
} else { } else {
auto val = this->data_func_(x...); // Template mode: call function
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, val); data = this->data_.func(x...);
} }
this->parent_->send_data(can_id, use_extended_id, this->remote_transmission_request_, data);
} }
protected: protected:
optional<uint32_t> can_id_{}; optional<uint32_t> can_id_{};
optional<bool> use_extended_id_{}; optional<bool> use_extended_id_{};
bool remote_transmission_request_{false}; bool remote_transmission_request_{false};
bool static_{false}; ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length
std::function<std::vector<uint8_t>(Ts...)> data_func_{}; union Data {
std::vector<uint8_t> data_static_{}; std::vector<uint8_t> (*func)(Ts...); // Function pointer (stateless lambdas)
const uint8_t *data; // Pointer to static data in flash
} data_;
}; };
class CanbusTrigger : public Trigger<std::vector<uint8_t>, uint32_t, bool>, public Component { class CanbusTrigger : public Trigger<std::vector<uint8_t>, uint32_t, bool>, public Component {