1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-15 17:52:19 +01:00

Update API messages

This commit is contained in:
kbx81
2025-09-11 22:49:30 -05:00
parent 77cf7a3423
commit bb516ed5cc
10 changed files with 76 additions and 81 deletions

View File

@@ -70,7 +70,7 @@ service APIConnection {
rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {} rpc alarm_control_panel_command (AlarmControlPanelCommandRequest) returns (void) {}
rpc zwave_proxy_frame_to_device(ZWaveProxyFrameToDevice) returns (void) {} rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {}
rpc zwave_proxy_subscribe(ZWaveProxySubscribeRequest) returns (void) {} rpc zwave_proxy_subscribe(ZWaveProxySubscribeRequest) returns (void) {}
rpc zwave_proxy_unsubscribe(ZWaveProxyUnsubscribeRequest) returns (void) {} rpc zwave_proxy_unsubscribe(ZWaveProxyUnsubscribeRequest) returns (void) {}
} }
@@ -2287,26 +2287,17 @@ message UpdateCommandRequest {
// ==================== Z-WAVE ==================== // ==================== Z-WAVE ====================
message ZWaveProxyFrameFromDevice { message ZWaveProxyFrame {
option (id) = 128; option (id) = 128;
option (source) = SOURCE_SERVER; option (source) = SOURCE_BOTH;
option (ifdef) = "USE_ZWAVE_PROXY"; option (ifdef) = "USE_ZWAVE_PROXY";
option (no_delay) = true; option (no_delay) = true;
string data = 1; bytes data = 1 [(fixed_array_size) = 257];
}
message ZWaveProxyFrameToDevice {
option (id) = 129;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_ZWAVE_PROXY";
option (no_delay) = true;
string data = 1;
} }
message ZWaveProxySubscribeRequest { message ZWaveProxySubscribeRequest {
option (id) = 130; option (id) = 129;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_ZWAVE_PROXY"; option (ifdef) = "USE_ZWAVE_PROXY";
@@ -2314,7 +2305,7 @@ message ZWaveProxySubscribeRequest {
} }
message ZWaveProxyUnsubscribeRequest { message ZWaveProxyUnsubscribeRequest {
option (id) = 131; option (id) = 130;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_ZWAVE_PROXY"; option (ifdef) = "USE_ZWAVE_PROXY";
} }

View File

@@ -1213,7 +1213,7 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void APIConnection::zwave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &msg) { void APIConnection::zwave_proxy_frame(const ZWaveProxyFrame &msg) {
zwave_proxy::global_zwave_proxy->send_frame(msg.data); zwave_proxy::global_zwave_proxy->send_frame(msg.data);
} }

View File

@@ -172,7 +172,7 @@ class APIConnection final : public APIServerConnection {
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void zwave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &msg) override; void zwave_proxy_frame(const ZWaveProxyFrame &msg) override;
void zwave_proxy_subscribe(const ZWaveProxySubscribeRequest &msg) override; void zwave_proxy_subscribe(const ZWaveProxySubscribeRequest &msg) override;
void zwave_proxy_unsubscribe(const ZWaveProxyUnsubscribeRequest &msg) override; void zwave_proxy_unsubscribe(const ZWaveProxyUnsubscribeRequest &msg) override;
#endif #endif

View File

@@ -3026,18 +3026,24 @@ bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
} }
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void ZWaveProxyFrameFromDevice::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->data_ref_); } bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
void ZWaveProxyFrameFromDevice::calculate_size(ProtoSize &size) const { size.add_length(1, this->data_ref_.size()); }
bool ZWaveProxyFrameToDevice::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) { switch (field_id) {
case 1: case 1: {
this->data = value.as_string(); const std::string &data_str = value.as_string();
this->data_len = data_str.size();
if (this->data_len > 257) {
this->data_len = 257;
}
memcpy(this->data, data_str.data(), this->data_len);
break; break;
}
default: default:
return false; return false;
} }
return true; return true;
} }
void ZWaveProxyFrame::encode(ProtoWriteBuffer buffer) const { buffer.encode_bytes(1, this->data, this->data_len); }
void ZWaveProxyFrame::calculate_size(ProtoSize &size) const { size.add_length(1, this->data_len); }
bool ZWaveProxySubscribeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { bool ZWaveProxySubscribeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) { switch (field_id) {
case 1: case 1:

View File

@@ -2919,41 +2919,27 @@ class UpdateCommandRequest final : public CommandProtoMessage {
}; };
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
class ZWaveProxyFrameFromDevice final : public ProtoMessage { class ZWaveProxyFrame final : public ProtoDecodableMessage {
public: public:
static constexpr uint8_t MESSAGE_TYPE = 128; static constexpr uint8_t MESSAGE_TYPE = 128;
static constexpr uint8_t ESTIMATED_SIZE = 9; static constexpr uint8_t ESTIMATED_SIZE = 33;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "z_wave_proxy_frame_from_device"; } const char *message_name() const override { return "z_wave_proxy_frame"; }
#endif #endif
StringRef data_ref_{}; uint8_t data[257]{};
void set_data(const StringRef &ref) { this->data_ref_ = ref; } uint16_t data_len{0};
void encode(ProtoWriteBuffer buffer) const override; void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override; void calculate_size(ProtoSize &size) const override;
#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
protected:
};
class ZWaveProxyFrameToDevice final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 129;
static constexpr uint8_t ESTIMATED_SIZE = 9;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "z_wave_proxy_frame_to_device"; }
#endif
std::string data{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected: protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
}; };
class ZWaveProxySubscribeRequest final : public ProtoDecodableMessage { class ZWaveProxySubscribeRequest final : public ProtoDecodableMessage {
public: public:
static constexpr uint8_t MESSAGE_TYPE = 130; static constexpr uint8_t MESSAGE_TYPE = 129;
static constexpr uint8_t ESTIMATED_SIZE = 4; static constexpr uint8_t ESTIMATED_SIZE = 4;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "z_wave_proxy_subscribe_request"; } const char *message_name() const override { return "z_wave_proxy_subscribe_request"; }
@@ -2968,7 +2954,7 @@ class ZWaveProxySubscribeRequest final : public ProtoDecodableMessage {
}; };
class ZWaveProxyUnsubscribeRequest final : public ProtoMessage { class ZWaveProxyUnsubscribeRequest final : public ProtoMessage {
public: public:
static constexpr uint8_t MESSAGE_TYPE = 131; static constexpr uint8_t MESSAGE_TYPE = 130;
static constexpr uint8_t ESTIMATED_SIZE = 0; static constexpr uint8_t ESTIMATED_SIZE = 0;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "z_wave_proxy_unsubscribe_request"; } const char *message_name() const override { return "z_wave_proxy_unsubscribe_request"; }

View File

@@ -2112,8 +2112,12 @@ void UpdateCommandRequest::dump_to(std::string &out) const {
} }
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void ZWaveProxyFrameFromDevice::dump_to(std::string &out) const { dump_field(out, "data", this->data_ref_); } void ZWaveProxyFrame::dump_to(std::string &out) const {
void ZWaveProxyFrameToDevice::dump_to(std::string &out) const { dump_field(out, "data", this->data); } MessageDumpHelper helper(out, "ZWaveProxyFrame");
out.append(" data: ");
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
}
void ZWaveProxySubscribeRequest::dump_to(std::string &out) const { dump_field(out, "flags", this->flags); } void ZWaveProxySubscribeRequest::dump_to(std::string &out) const { dump_field(out, "flags", this->flags); }
void ZWaveProxyUnsubscribeRequest::dump_to(std::string &out) const { out.append("ZWaveProxyUnsubscribeRequest {}"); } void ZWaveProxyUnsubscribeRequest::dump_to(std::string &out) const { out.append("ZWaveProxyUnsubscribeRequest {}"); }
#endif #endif

View File

@@ -597,13 +597,13 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
} }
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
case ZWaveProxyFrameToDevice::MESSAGE_TYPE: { case ZWaveProxyFrame::MESSAGE_TYPE: {
ZWaveProxyFrameToDevice msg; ZWaveProxyFrame msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_z_wave_proxy_frame_to_device: %s", msg.dump().c_str()); ESP_LOGVV(TAG, "on_z_wave_proxy_frame: %s", msg.dump().c_str());
#endif #endif
this->on_z_wave_proxy_frame_to_device(msg); this->on_z_wave_proxy_frame(msg);
break; break;
} }
#endif #endif
@@ -943,9 +943,9 @@ void APIServerConnection::on_alarm_control_panel_command_request(const AlarmCont
} }
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void APIServerConnection::on_z_wave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &msg) { void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) {
if (this->check_authenticated_()) { if (this->check_authenticated_()) {
this->zwave_proxy_frame_to_device(msg); this->zwave_proxy_frame(msg);
} }
} }
#endif #endif

View File

@@ -206,9 +206,8 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_UPDATE #ifdef USE_UPDATE
virtual void on_update_command_request(const UpdateCommandRequest &value){}; virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void on_z_wave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &value){}; virtual void on_z_wave_proxy_frame(const ZWaveProxyFrame &value){};
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void on_z_wave_proxy_subscribe_request(const ZWaveProxySubscribeRequest &value){}; virtual void on_z_wave_proxy_subscribe_request(const ZWaveProxySubscribeRequest &value){};
@@ -344,7 +343,7 @@ class APIServerConnection : public APIServerConnectionBase {
virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0; virtual void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) = 0;
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void zwave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &msg) = 0; virtual void zwave_proxy_frame(const ZWaveProxyFrame &msg) = 0;
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void zwave_proxy_subscribe(const ZWaveProxySubscribeRequest &msg) = 0; virtual void zwave_proxy_subscribe(const ZWaveProxySubscribeRequest &msg) = 0;
@@ -475,7 +474,7 @@ class APIServerConnection : public APIServerConnectionBase {
void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override; void on_alarm_control_panel_command_request(const AlarmControlPanelCommandRequest &msg) override;
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void on_z_wave_proxy_frame_to_device(const ZWaveProxyFrameToDevice &msg) override; void on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) override;
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void on_z_wave_proxy_subscribe_request(const ZWaveProxySubscribeRequest &msg) override; void on_z_wave_proxy_subscribe_request(const ZWaveProxySubscribeRequest &msg) override;

View File

@@ -25,10 +25,12 @@ void ZWaveProxy::loop() {
return; return;
} }
if (this->parse_byte_(byte)) { if (this->parse_byte_(byte)) {
ESP_LOGD(TAG, "Sending frame: %s", YESNO(this->api_connection_ != nullptr)); ESP_LOGD(TAG, "Sending to client: %s", YESNO(this->api_connection_ != nullptr));
if (this->api_connection_ != nullptr) { if (this->api_connection_ != nullptr) {
this->outgoing_proto_msg_.set_data(StringRef((const char *) this->buffer_, this->buffer_index_)); // minimize copying to reduce CPU overhead
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrameFromDevice::MESSAGE_TYPE); this->outgoing_proto_msg_.data_len = this->buffer_[0] == ZWAVE_FRAME_TYPE_START ? this->buffer_[1] + 2 : 1;
std::memcpy(this->outgoing_proto_msg_.data, this->buffer_, this->outgoing_proto_msg_.data_len);
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE);
} }
} }
} }
@@ -53,14 +55,20 @@ void ZWaveProxy::unsubscribe_api_connection(api::APIConnection *api_connection)
this->api_connection_ = nullptr; this->api_connection_ = nullptr;
} }
void ZWaveProxy::send_frame(const std::string &data) { void ZWaveProxy::send_frame(const uint8_t *data, size_t length) {
ESP_LOGD(TAG, "Sending: %s", format_hex_pretty(data).c_str()); if (!length) {
this->write_array((uint8_t *) data.data(), data.size()); if (data[0] == ZWAVE_FRAME_TYPE_START) {
length = data[1] + 2; // data[1] is payload length, not including SoF + checksum
} else {
length = 1; // assume ACK/NAK/CAN
} }
}
void ZWaveProxy::send_frame(const std::vector<uint8_t> &data) { if (length == 1 && data[0] == this->last_response_) {
ESP_LOGD(TAG, "Sending: %s", format_hex_pretty(data).c_str()); ESP_LOGW(TAG, "Skipping sending duplicate response: 0x%02X", data[0]);
this->write_array(data); return;
}
ESP_LOGD(TAG, "Sending: %s", format_hex_pretty(data, length).c_str());
this->write_array(data, length);
} }
bool ZWaveProxy::parse_byte_(uint8_t byte) { bool ZWaveProxy::parse_byte_(uint8_t byte) {
@@ -152,29 +160,30 @@ void ZWaveProxy::parse_start_(uint8_t byte) {
} }
// Forward response (ACK/NAK/CAN) back to client for processing // Forward response (ACK/NAK/CAN) back to client for processing
if (this->api_connection_ != nullptr) { if (this->api_connection_ != nullptr) {
this->outgoing_proto_msg_.set_data(StringRef(&byte, 1)); this->outgoing_proto_msg_.data[0] = byte;
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrameFromDevice::MESSAGE_TYPE); this->outgoing_proto_msg_.data_len = 1;
this->api_connection_->send_message(this->outgoing_proto_msg_, api::ZWaveProxyFrame::MESSAGE_TYPE);
} }
} }
bool ZWaveProxy::response_handler_() { bool ZWaveProxy::response_handler_() {
uint8_t response_byte = 0;
switch (this->parsing_state_) { switch (this->parsing_state_) {
case ZWAVE_PARSING_STATE_SEND_ACK: case ZWAVE_PARSING_STATE_SEND_ACK:
response_byte = ZWAVE_FRAME_TYPE_ACK; this->last_response_ = ZWAVE_FRAME_TYPE_ACK;
break; break;
case ZWAVE_PARSING_STATE_SEND_CAN: case ZWAVE_PARSING_STATE_SEND_CAN:
response_byte = ZWAVE_FRAME_TYPE_CAN; this->last_response_ = ZWAVE_FRAME_TYPE_CAN;
break; break;
case ZWAVE_PARSING_STATE_SEND_NAK: case ZWAVE_PARSING_STATE_SEND_NAK:
response_byte = ZWAVE_FRAME_TYPE_NAK; this->last_response_ = ZWAVE_FRAME_TYPE_NAK;
break; break;
default: default:
return false; // No response handled return false; // No response handled
} }
ESP_LOGD(TAG, "Sending %s (0x%02X)", response_byte == ZWAVE_FRAME_TYPE_ACK ? "ACK" : "NAK/CAN", response_byte); ESP_LOGD(TAG, "Sending %s (0x%02X)", this->last_response_ == ZWAVE_FRAME_TYPE_ACK ? "ACK" : "NAK/CAN",
this->write_byte(response_byte); this->last_response_);
this->write_byte(this->last_response_);
this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START; this->parsing_state_ = ZWAVE_PARSING_STATE_WAIT_START;
return true; return true;
} }

View File

@@ -44,8 +44,7 @@ class ZWaveProxy : public uart::UARTDevice, public Component {
uint32_t get_feature_flags() const { return ZWaveProxyFeature::FEATURE_ZWAVE_PROXY_ENABLED; } uint32_t get_feature_flags() const { return ZWaveProxyFeature::FEATURE_ZWAVE_PROXY_ENABLED; }
void send_frame(const std::string &data); void send_frame(const uint8_t *data, size_t length = 0);
void send_frame(const std::vector<uint8_t> &data);
protected: protected:
bool parse_byte_(uint8_t byte); // Returns true if frame parsing was completed (a frame is ready in the buffer) bool parse_byte_(uint8_t byte); // Returns true if frame parsing was completed (a frame is ready in the buffer)
@@ -54,14 +53,15 @@ class ZWaveProxy : public uart::UARTDevice, public Component {
api::APIConnection *api_connection_{nullptr}; // Current subscribed client api::APIConnection *api_connection_{nullptr}; // Current subscribed client
uint8_t buffer_[257]; // Fixed buffer for incoming data: max length = 255 + 2 (start of frame and checksum) uint8_t buffer_[sizeof(api::ZWaveProxyFrame::data)]; // Fixed buffer for incoming data
uint8_t buffer_index_{0}; // Index for populating the data buffer uint8_t buffer_index_{0}; // Index for populating the data buffer
uint8_t checksum_{0}; // Checksum of the frame being parsed uint8_t checksum_{0}; // Checksum of the frame being parsed
uint8_t end_frame_after_{0}; // Payload reception ends after this index uint8_t end_frame_after_{0}; // Payload reception ends after this index
uint8_t last_response_{0}; // Last response type sent
ZWaveParsingState parsing_state_{ZWAVE_PARSING_STATE_WAIT_START}; ZWaveParsingState parsing_state_{ZWAVE_PARSING_STATE_WAIT_START};
// Pre-allocated message - always ready to send // Pre-allocated message - always ready to send
api::ZWaveProxyFrameFromDevice outgoing_proto_msg_; api::ZWaveProxyFrame outgoing_proto_msg_;
}; };
extern ZWaveProxy *global_zwave_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) extern ZWaveProxy *global_zwave_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)