mirror of
https://github.com/esphome/esphome.git
synced 2025-10-30 06:33:51 +00:00
[zwave_proxy] Fix race condition sending zero home ID on reboot (#10848)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "zwave_proxy.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
@@ -12,6 +13,7 @@ static constexpr uint8_t ZWAVE_COMMAND_GET_NETWORK_IDS = 0x20;
|
||||
// GET_NETWORK_IDS response: [SOF][LENGTH][TYPE][CMD][HOME_ID(4)][NODE_ID][...]
|
||||
static constexpr uint8_t ZWAVE_COMMAND_TYPE_RESPONSE = 0x01; // Response type field value
|
||||
static constexpr uint8_t ZWAVE_MIN_GET_NETWORK_IDS_LENGTH = 9; // TYPE + CMD + HOME_ID(4) + NODE_ID + checksum
|
||||
static constexpr uint32_t HOME_ID_TIMEOUT_MS = 100; // Timeout for waiting for home ID during setup
|
||||
|
||||
static uint8_t calculate_frame_checksum(const uint8_t *data, uint8_t length) {
|
||||
// Calculate Z-Wave frame checksum
|
||||
@@ -26,7 +28,44 @@ static uint8_t calculate_frame_checksum(const uint8_t *data, uint8_t length) {
|
||||
|
||||
ZWaveProxy::ZWaveProxy() { global_zwave_proxy = this; }
|
||||
|
||||
void ZWaveProxy::setup() { this->send_simple_command_(ZWAVE_COMMAND_GET_NETWORK_IDS); }
|
||||
void ZWaveProxy::setup() {
|
||||
this->setup_time_ = App.get_loop_component_start_time();
|
||||
this->send_simple_command_(ZWAVE_COMMAND_GET_NETWORK_IDS);
|
||||
}
|
||||
|
||||
float ZWaveProxy::get_setup_priority() const {
|
||||
// Set up before API so home ID is ready when API starts
|
||||
return setup_priority::BEFORE_CONNECTION;
|
||||
}
|
||||
|
||||
bool ZWaveProxy::can_proceed() {
|
||||
// If we already have the home ID, we can proceed
|
||||
if (this->home_id_ready_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle any pending responses
|
||||
if (this->response_handler_()) {
|
||||
ESP_LOGV(TAG, "Handled response during setup");
|
||||
}
|
||||
|
||||
// Process UART data to check for home ID
|
||||
this->process_uart_();
|
||||
|
||||
// Check if we got the home ID after processing
|
||||
if (this->home_id_ready_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait up to HOME_ID_TIMEOUT_MS for home ID response
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
if (now - this->setup_time_ > HOME_ID_TIMEOUT_MS) {
|
||||
ESP_LOGW(TAG, "Timeout reading Home ID during setup");
|
||||
return true; // Proceed anyway after timeout
|
||||
}
|
||||
|
||||
return false; // Keep waiting
|
||||
}
|
||||
|
||||
void ZWaveProxy::loop() {
|
||||
if (this->response_handler_()) {
|
||||
@@ -37,6 +76,11 @@ void ZWaveProxy::loop() {
|
||||
this->api_connection_ = nullptr; // Unsubscribe if disconnected
|
||||
}
|
||||
|
||||
this->process_uart_();
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
void ZWaveProxy::process_uart_() {
|
||||
while (this->available()) {
|
||||
uint8_t byte;
|
||||
if (!this->read_byte(&byte)) {
|
||||
@@ -56,6 +100,7 @@ void ZWaveProxy::loop() {
|
||||
// Extract the 4-byte Home ID starting at offset 4
|
||||
// The frame parser has already validated the checksum and ensured all bytes are present
|
||||
std::memcpy(this->home_id_.data(), this->buffer_.data() + 4, this->home_id_.size());
|
||||
this->home_id_ready_ = true;
|
||||
ESP_LOGI(TAG, "Home ID: %s",
|
||||
format_hex_pretty(this->home_id_.data(), this->home_id_.size(), ':', false).c_str());
|
||||
}
|
||||
@@ -73,7 +118,6 @@ void ZWaveProxy::loop() {
|
||||
}
|
||||
}
|
||||
}
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
void ZWaveProxy::dump_config() { ESP_LOGCONFIG(TAG, "Z-Wave Proxy"); }
|
||||
|
||||
@@ -44,6 +44,8 @@ class ZWaveProxy : public uart::UARTDevice, public Component {
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
bool can_proceed() override;
|
||||
|
||||
void zwave_proxy_request(api::APIConnection *api_connection, api::enums::ZWaveProxyRequestType type);
|
||||
api::APIConnection *get_api_connection() { return this->api_connection_; }
|
||||
@@ -60,19 +62,24 @@ class ZWaveProxy : public uart::UARTDevice, public Component {
|
||||
bool parse_byte_(uint8_t byte); // Returns true if frame parsing was completed (a frame is ready in the buffer)
|
||||
void parse_start_(uint8_t byte);
|
||||
bool response_handler_();
|
||||
|
||||
api::APIConnection *api_connection_{nullptr}; // Current subscribed client
|
||||
|
||||
std::array<uint8_t, 4> home_id_{0, 0, 0, 0}; // Fixed buffer for home ID
|
||||
std::array<uint8_t, sizeof(api::ZWaveProxyFrame::data)> buffer_; // Fixed buffer for incoming data
|
||||
uint8_t buffer_index_{0}; // Index for populating the data buffer
|
||||
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};
|
||||
bool in_bootloader_{false}; // True if the device is detected to be in bootloader mode
|
||||
void process_uart_(); // Process all available UART data
|
||||
|
||||
// Pre-allocated message - always ready to send
|
||||
api::ZWaveProxyFrame outgoing_proto_msg_;
|
||||
std::array<uint8_t, sizeof(api::ZWaveProxyFrame::data)> buffer_; // Fixed buffer for incoming data
|
||||
std::array<uint8_t, 4> home_id_{0, 0, 0, 0}; // Fixed buffer for home ID
|
||||
|
||||
// Pointers and 32-bit values (aligned together)
|
||||
api::APIConnection *api_connection_{nullptr}; // Current subscribed client
|
||||
uint32_t setup_time_{0}; // Time when setup() was called
|
||||
|
||||
// 8-bit values (grouped together to minimize padding)
|
||||
uint8_t buffer_index_{0}; // Index for populating the data buffer
|
||||
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};
|
||||
bool in_bootloader_{false}; // True if the device is detected to be in bootloader mode
|
||||
bool home_id_ready_{false}; // True when home ID has been received from Z-Wave module
|
||||
};
|
||||
|
||||
extern ZWaveProxy *global_zwave_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
Reference in New Issue
Block a user