mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +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