15static const char *
const TAG =
"zwave_proxy";
18static constexpr size_t ZWAVE_MAX_LOG_BYTES = 168;
20static constexpr uint8_t ZWAVE_COMMAND_GET_NETWORK_IDS = 0x20;
22static constexpr uint8_t ZWAVE_COMMAND_TYPE_RESPONSE = 0x01;
23static constexpr uint8_t ZWAVE_MIN_GET_NETWORK_IDS_LENGTH = 9;
24static constexpr uint32_t HOME_ID_TIMEOUT_MS = 100;
25static constexpr uint32_t RECONNECT_DELAY_MS = 500;
26static constexpr uint8_t MAX_QUERY_RETRIES = 5;
28static uint8_t calculate_frame_checksum(
const uint8_t *data, uint8_t
length) {
33 for (uint8_t i = 1; i <
length - 1; i++) {
62 ESP_LOGV(TAG,
"Handled response during setup");
76 ESP_LOGW(TAG,
"Timeout reading Home ID during setup");
85 ESP_LOGV(TAG,
"Handled late response");
88 ESP_LOGW(TAG,
"Subscriber disconnected");
119 if (this->
buffer_[3] == ZWAVE_COMMAND_GET_NETWORK_IDS && this->
buffer_[2] == ZWAVE_COMMAND_TYPE_RESPONSE &&
127 ESP_LOGV(TAG,
"Sending to client: %s", YESNO(this->
api_connection_ !=
nullptr));
162 ESP_LOGE(TAG,
"Only one API subscription is allowed at a time");
166 ESP_LOGV(TAG,
"API connection is now subscribed");
171 ESP_LOGV(TAG,
"API connection is not subscribed");
178 ESP_LOGW(TAG,
"Unknown request type: %" PRIu32,
static_cast<uint32_t>(
type));
186 ESP_LOGD(TAG,
"Modem reconnected");
195 ESP_LOGW(TAG,
"Modem disconnected");
212 ESP_LOGD(TAG,
"Querying Home ID (attempt %u)", this->
query_retries_);
215 ESP_LOGW(TAG,
"Failed to read Home ID after %u attempts", MAX_QUERY_RETRIES);
221 static constexpr uint8_t ZERO_HOME_ID[ZWAVE_HOME_ID_SIZE] = {};
233 if (std::memcmp(this->
home_id_.data(), new_home_id, this->home_id_.size()) == 0) {
234 ESP_LOGV(TAG,
"Home ID unchanged");
237 std::memcpy(this->
home_id_.data(), new_home_id, this->home_id_.size());
246 if (data ==
nullptr) {
247 ESP_LOGE(TAG,
"Null data pointer");
251 ESP_LOGE(TAG,
"Length 0");
257 ESP_LOGV(TAG,
"Response already sent: 0x%02X", data[0]);
261#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
274 if (conn !=
nullptr) {
288 uint8_t cmd[] = {0x01, 0x03, 0x00, command_id, 0x00};
289 cmd[4] = calculate_frame_checksum(cmd,
sizeof(cmd));
294 bool frame_completed =
false;
302 ESP_LOGW(TAG,
"Invalid LENGTH: %u",
byte);
306 ESP_LOGVV(TAG,
"Received LENGTH: %u",
byte);
314 ESP_LOGVV(TAG,
"Received TYPE: 0x%02X",
byte);
319 ESP_LOGVV(TAG,
"Received COMMAND ID: 0x%02X",
byte);
324 ESP_LOGVV(TAG,
"Received PAYLOAD: 0x%02X",
byte);
331 auto checksum = calculate_frame_checksum(this->
buffer_.data(), this->buffer_index_);
332 ESP_LOGVV(TAG,
"CHECKSUM Received: 0x%02X - Calculated: 0x%02X",
byte,
checksum);
334 ESP_LOGW(TAG,
"Bad checksum: expected 0x%02X, got 0x%02X",
checksum,
byte);
338#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
342 frame_completed =
true;
355 frame_completed =
true;
362 ESP_LOGW(TAG,
"Bad parsing state; resetting");
366 return frame_completed;
374 ESP_LOGV(TAG,
"Received START");
376 ESP_LOGD(TAG,
"Exited bootloader mode");
383 ESP_LOGV(TAG,
"Received BL_MENU");
385 ESP_LOGD(TAG,
"Entered bootloader mode");
392 ESP_LOGV(TAG,
"Received BL_BEGIN_UPLOAD");
395 ESP_LOGV(TAG,
"Received ACK");
398 ESP_LOGV(TAG,
"Received NAK");
401 ESP_LOGV(TAG,
"Received CAN");
404 ESP_LOGW(TAG,
"Unrecognized START: 0x%02X",
byte);
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void status_set_warning()
void status_clear_warning()
bool is_connection_setup()
bool send_message(const T &msg)
void on_zwave_proxy_request(const ZWaveProxyRequest &msg)
enums::ZWaveProxyRequestType type
virtual bool is_connected()
bool read_byte(uint8_t *data)
void write_byte(uint8_t data)
void write_array(const uint8_t *data, size_t len)
void zwave_proxy_request(api::APIConnection *api_connection, api::enums::ZWaveProxyRequestType type)
api::ZWaveProxyFrame outgoing_proto_msg_
void send_frame(const uint8_t *data, size_t length)
bool parse_byte_(uint8_t byte)
void parse_start_(uint8_t byte)
void send_homeid_changed_msg_(api::APIConnection *conn=nullptr)
uint16_t end_frame_after_
bool set_home_id_(const uint8_t *new_home_id)
void send_simple_command_(uint8_t command_id)
void retry_home_id_query_()
void api_connection_authenticated(api::APIConnection *conn)
bool can_proceed() override
ZWaveParsingState parsing_state_
std::array< uint8_t, MAX_ZWAVE_FRAME_SIZE > buffer_
void dump_config() override
api::APIConnection * api_connection_
float get_setup_priority() const override
void on_connection_changed_(bool connected)
std::array< uint8_t, ZWAVE_HOME_ID_SIZE > home_id_
@ ZWAVE_PROXY_REQUEST_TYPE_SUBSCRIBE
@ ZWAVE_PROXY_REQUEST_TYPE_UNSUBSCRIBE
@ ZWAVE_PROXY_REQUEST_TYPE_HOME_ID_CHANGE
APIServer * global_api_server
constexpr float BEFORE_CONNECTION
For components that should be initialized after WiFi and before API is connected.
@ ZWAVE_FRAME_TYPE_BL_MENU
@ ZWAVE_FRAME_TYPE_BL_BEGIN_UPLOAD
@ ZWAVE_PARSING_STATE_WAIT_COMMAND_ID
@ ZWAVE_PARSING_STATE_WAIT_LENGTH
@ ZWAVE_PARSING_STATE_WAIT_CHECKSUM
@ ZWAVE_PARSING_STATE_WAIT_PAYLOAD
@ ZWAVE_PARSING_STATE_SEND_ACK
@ ZWAVE_PARSING_STATE_SEND_NAK
@ ZWAVE_PARSING_STATE_READ_BL_MENU
@ ZWAVE_PARSING_STATE_WAIT_TYPE
@ ZWAVE_PARSING_STATE_SEND_CAN
@ ZWAVE_PARSING_STATE_WAIT_START
ZWaveProxy * global_zwave_proxy
bool api_is_connected()
Return whether the node has at least one client connected to the native API.
char * format_hex_pretty_to(char *buffer, size_t buffer_size, const uint8_t *data, size_t length, char separator)
Format byte array as uppercase hex to buffer (base implementation).
constexpr size_t format_hex_pretty_size(size_t byte_count)
Calculate buffer size needed for format_hex_pretty_to with separator: "XX:XX:...:XX\0".
Application App
Global storage of Application pointer - only one Application can exist.