[light] Add zero-copy support for API effect commands (#12384)

This commit is contained in:
J. Nick Koston
2025-12-10 04:19:29 +01:00
committed by GitHub
parent 5601a2b686
commit 03c391bd43
7 changed files with 21 additions and 12 deletions
+1 -1
View File
@@ -579,7 +579,7 @@ message LightCommandRequest {
bool has_flash_length = 16; bool has_flash_length = 16;
uint32 flash_length = 17; uint32 flash_length = 17;
bool has_effect = 18; bool has_effect = 18;
string effect = 19; string effect = 19 [(pointer_to_buffer) = true];
uint32 device_id = 28 [(field_ifdef) = "USE_DEVICES"]; uint32 device_id = 28 [(field_ifdef) = "USE_DEVICES"];
} }
+1 -1
View File
@@ -533,7 +533,7 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
if (msg.has_flash_length) if (msg.has_flash_length)
call.set_flash_length(msg.flash_length); call.set_flash_length(msg.flash_length);
if (msg.has_effect) if (msg.has_effect)
call.set_effect(msg.effect); call.set_effect(reinterpret_cast<const char *>(msg.effect), msg.effect_len);
call.perform(); call.perform();
} }
#endif #endif
+5 -2
View File
@@ -611,9 +611,12 @@ bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
} }
bool LightCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { bool LightCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) { switch (field_id) {
case 19: case 19: {
this->effect = value.as_string(); // Use raw data directly to avoid allocation
this->effect = value.data();
this->effect_len = value.size();
break; break;
}
default: default:
return false; return false;
} }
+3 -2
View File
@@ -840,7 +840,7 @@ class LightStateResponse final : public StateResponseProtoMessage {
class LightCommandRequest final : public CommandProtoMessage { class LightCommandRequest final : public CommandProtoMessage {
public: public:
static constexpr uint8_t MESSAGE_TYPE = 32; static constexpr uint8_t MESSAGE_TYPE = 32;
static constexpr uint8_t ESTIMATED_SIZE = 112; static constexpr uint8_t ESTIMATED_SIZE = 122;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "light_command_request"; } const char *message_name() const override { return "light_command_request"; }
#endif #endif
@@ -869,7 +869,8 @@ class LightCommandRequest final : public CommandProtoMessage {
bool has_flash_length{false}; bool has_flash_length{false};
uint32_t flash_length{0}; uint32_t flash_length{0};
bool has_effect{false}; bool has_effect{false};
std::string effect{}; const uint8_t *effect{nullptr};
uint16_t effect_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override; void dump_to(std::string &out) const override;
#endif #endif
+3 -1
View File
@@ -999,7 +999,9 @@ void LightCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_flash_length", this->has_flash_length); dump_field(out, "has_flash_length", this->has_flash_length);
dump_field(out, "flash_length", this->flash_length); dump_field(out, "flash_length", this->flash_length);
dump_field(out, "has_effect", this->has_effect); dump_field(out, "has_effect", this->has_effect);
dump_field(out, "effect", this->effect); out.append(" effect: ");
out.append(format_hex_pretty(this->effect, this->effect_len));
out.append("\n");
#ifdef USE_DEVICES #ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id); dump_field(out, "device_id", this->device_id);
#endif #endif
+5 -4
View File
@@ -504,8 +504,8 @@ color_mode_bitmask_t LightCall::get_suitable_color_modes_mask_() {
#undef KEY #undef KEY
} }
LightCall &LightCall::set_effect(const std::string &effect) { LightCall &LightCall::set_effect(const char *effect, size_t len) {
if (strcasecmp(effect.c_str(), "none") == 0) { if (len == 4 && strncasecmp(effect, "none", 4) == 0) {
this->set_effect(0); this->set_effect(0);
return *this; return *this;
} }
@@ -513,15 +513,16 @@ LightCall &LightCall::set_effect(const std::string &effect) {
bool found = false; bool found = false;
for (uint32_t i = 0; i < this->parent_->effects_.size(); i++) { for (uint32_t i = 0; i < this->parent_->effects_.size(); i++) {
LightEffect *e = this->parent_->effects_[i]; LightEffect *e = this->parent_->effects_[i];
const char *name = e->get_name();
if (strcasecmp(effect.c_str(), e->get_name()) == 0) { if (strncasecmp(effect, name, len) == 0 && name[len] == '\0') {
this->set_effect(i + 1); this->set_effect(i + 1);
found = true; found = true;
break; break;
} }
} }
if (!found) { if (!found) {
ESP_LOGW(TAG, "'%s': no such effect '%s'", this->parent_->get_name().c_str(), effect.c_str()); ESP_LOGW(TAG, "'%s': no such effect '%.*s'", this->parent_->get_name().c_str(), (int) len, effect);
} }
return *this; return *this;
} }
+3 -1
View File
@@ -129,7 +129,9 @@ class LightCall {
/// Set the effect of the light by its name. /// Set the effect of the light by its name.
LightCall &set_effect(optional<std::string> effect); LightCall &set_effect(optional<std::string> effect);
/// Set the effect of the light by its name. /// Set the effect of the light by its name.
LightCall &set_effect(const std::string &effect); LightCall &set_effect(const std::string &effect) { return this->set_effect(effect.data(), effect.size()); }
/// Set the effect of the light by its name and length (zero-copy from API).
LightCall &set_effect(const char *effect, size_t len);
/// Set the effect of the light by its internal index number (only for internal use). /// Set the effect of the light by its internal index number (only for internal use).
LightCall &set_effect(uint32_t effect_number); LightCall &set_effect(uint32_t effect_number);
LightCall &set_effect(optional<uint32_t> effect_number); LightCall &set_effect(optional<uint32_t> effect_number);