mirror of
https://github.com/esphome/esphome.git
synced 2026-02-20 16:35:37 -07:00
Merge branch 'dev' into source_both_zero_copy
This commit is contained in:
@@ -30,7 +30,9 @@ void A01nyubComponent::check_buffer_() {
|
||||
ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters);
|
||||
this->publish_state(meters);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str());
|
||||
char hex_buf[format_hex_pretty_size(4)];
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s",
|
||||
format_hex_pretty_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);
|
||||
|
||||
@@ -29,7 +29,9 @@ void A02yyuwComponent::check_buffer_() {
|
||||
ESP_LOGV(TAG, "Distance from sensor: %f mm", distance);
|
||||
this->publish_state(distance);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str());
|
||||
char hex_buf[format_hex_pretty_size(4)];
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s",
|
||||
format_hex_pretty_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);
|
||||
|
||||
@@ -25,11 +25,13 @@ class AddressableLightDisplay : public display::DisplayBuffer {
|
||||
if (enabled_ && !enabled) { // enabled -> disabled
|
||||
// - Tell the parent light to refresh, effectively wiping the display. Also
|
||||
// restores the previous effect (if any).
|
||||
light_state_->make_call().set_effect(this->last_effect_).perform();
|
||||
if (this->last_effect_index_.has_value()) {
|
||||
light_state_->make_call().set_effect(*this->last_effect_index_).perform();
|
||||
}
|
||||
|
||||
} else if (!enabled_ && enabled) { // disabled -> enabled
|
||||
// - Save the current effect.
|
||||
this->last_effect_ = light_state_->get_effect_name();
|
||||
// - Save the current effect index.
|
||||
this->last_effect_index_ = light_state_->get_current_effect_index();
|
||||
// - Disable any current effect.
|
||||
light_state_->make_call().set_effect(0).perform();
|
||||
}
|
||||
@@ -56,7 +58,7 @@ class AddressableLightDisplay : public display::DisplayBuffer {
|
||||
int32_t width_;
|
||||
int32_t height_;
|
||||
std::vector<Color> addressable_light_buffer_;
|
||||
optional<std::string> last_effect_;
|
||||
optional<uint32_t> last_effect_index_;
|
||||
optional<std::function<int(int, int)>> pixel_mapper_f_;
|
||||
};
|
||||
} // namespace addressable_light
|
||||
|
||||
@@ -1530,7 +1530,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
||||
|
||||
HelloResponse resp;
|
||||
resp.api_version_major = 1;
|
||||
resp.api_version_minor = 13;
|
||||
resp.api_version_minor = 14;
|
||||
// Send only the version string - the client only logs this for debugging and doesn't use it otherwise
|
||||
resp.set_server_info(ESPHOME_VERSION_REF);
|
||||
resp.set_name(StringRef(App.get_name()));
|
||||
@@ -1749,20 +1749,20 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
||||
// the action list. This ensures async actions (delays, waits) complete first.
|
||||
}
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message) {
|
||||
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, StringRef error_message) {
|
||||
ExecuteServiceResponse resp;
|
||||
resp.call_id = call_id;
|
||||
resp.success = success;
|
||||
resp.set_error_message(StringRef(error_message));
|
||||
resp.set_error_message(error_message);
|
||||
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
|
||||
}
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message,
|
||||
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, StringRef error_message,
|
||||
const uint8_t *response_data, size_t response_data_len) {
|
||||
ExecuteServiceResponse resp;
|
||||
resp.call_id = call_id;
|
||||
resp.success = success;
|
||||
resp.set_error_message(StringRef(error_message));
|
||||
resp.set_error_message(error_message);
|
||||
resp.response_data = response_data;
|
||||
resp.response_data_len = response_data_len;
|
||||
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
|
||||
|
||||
@@ -24,9 +24,10 @@ struct ClientInfo {
|
||||
// Keepalive timeout in milliseconds
|
||||
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
|
||||
// Maximum number of entities to process in a single batch during initial state/info sending
|
||||
// This was increased from 20 to 24 after removing the unique_id field from entity info messages,
|
||||
// which reduced message sizes allowing more entities per batch without exceeding packet limits
|
||||
static constexpr size_t MAX_INITIAL_PER_BATCH = 24;
|
||||
// API 1.14+ clients compute object_id client-side, so messages are smaller and we can fit more per batch
|
||||
// TODO: Remove MAX_INITIAL_PER_BATCH_LEGACY before 2026.7.0 - all clients should support API 1.14 by then
|
||||
static constexpr size_t MAX_INITIAL_PER_BATCH_LEGACY = 24; // For clients < API 1.14 (includes object_id)
|
||||
static constexpr size_t MAX_INITIAL_PER_BATCH = 34; // For clients >= API 1.14 (no object_id)
|
||||
// Maximum number of packets to process in a single batch (platform-dependent)
|
||||
// This limit exists to prevent stack overflow from the PacketInfo array in process_batch_
|
||||
// Each PacketInfo is 8 bytes, so 64 * 8 = 512 bytes, 32 * 8 = 256 bytes
|
||||
@@ -233,9 +234,9 @@ class APIConnection final : public APIServerConnection {
|
||||
#ifdef USE_API_USER_DEFINED_ACTIONS
|
||||
void execute_service(const ExecuteServiceRequest &msg) override;
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message);
|
||||
void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message);
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message,
|
||||
void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message,
|
||||
const uint8_t *response_data, size_t response_data_len);
|
||||
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
@@ -323,10 +324,16 @@ class APIConnection final : public APIServerConnection {
|
||||
APIConnection *conn, uint32_t remaining_size, bool is_single) {
|
||||
// Set common fields that are shared by all entity types
|
||||
msg.key = entity->get_object_id_hash();
|
||||
// Get object_id with zero heap allocation
|
||||
// Static case returns direct reference, dynamic case uses buffer
|
||||
|
||||
// API 1.14+ clients compute object_id client-side from the entity name
|
||||
// For older clients, we must send object_id for backward compatibility
|
||||
// See: https://github.com/esphome/backlog/issues/76
|
||||
// TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then
|
||||
// Buffer must remain in scope until encode_message_to_buffer is called
|
||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
||||
msg.set_object_id(entity->get_object_id_to(object_id_buf));
|
||||
if (!conn->client_supports_api_version(1, 14)) {
|
||||
msg.set_object_id(entity->get_object_id_to(object_id_buf));
|
||||
}
|
||||
|
||||
if (entity->has_own_name()) {
|
||||
msg.set_name(entity->get_name());
|
||||
@@ -349,16 +356,24 @@ class APIConnection final : public APIServerConnection {
|
||||
inline bool check_voice_assistant_api_connection_() const;
|
||||
#endif
|
||||
|
||||
// Get the max batch size based on client API version
|
||||
// API 1.14+ clients don't receive object_id, so messages are smaller and more fit per batch
|
||||
// TODO: Remove this method before 2026.7.0 and use MAX_INITIAL_PER_BATCH directly
|
||||
size_t get_max_batch_size_() const {
|
||||
return this->client_supports_api_version(1, 14) ? MAX_INITIAL_PER_BATCH : MAX_INITIAL_PER_BATCH_LEGACY;
|
||||
}
|
||||
|
||||
// Helper method to process multiple entities from an iterator in a batch
|
||||
template<typename Iterator> void process_iterator_batch_(Iterator &iterator) {
|
||||
size_t initial_size = this->deferred_batch_.size();
|
||||
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < MAX_INITIAL_PER_BATCH) {
|
||||
size_t max_batch = this->get_max_batch_size_();
|
||||
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < max_batch) {
|
||||
iterator.advance();
|
||||
}
|
||||
|
||||
// If the batch is full, process it immediately
|
||||
// Note: iterator.advance() already calls schedule_batch_() via schedule_message_()
|
||||
if (this->deferred_batch_.size() >= MAX_INITIAL_PER_BATCH) {
|
||||
if (this->deferred_batch_.size() >= max_batch) {
|
||||
this->process_batch_();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,12 +13,26 @@ namespace esphome::api {
|
||||
|
||||
static const char *const TAG = "api.frame_helper";
|
||||
|
||||
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
|
||||
static constexpr size_t API_MAX_LOG_BYTES = 168;
|
||||
|
||||
#define HELPER_LOG(msg, ...) \
|
||||
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
|
||||
|
||||
#ifdef HELPER_LOG_PACKETS
|
||||
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
|
||||
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
|
||||
#define LOG_PACKET_RECEIVED(buffer) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Received frame: %s", \
|
||||
format_hex_pretty_to(hex_buf_, (buffer).data(), \
|
||||
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#define LOG_PACKET_SENDING(data, len) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Sending raw: %s", \
|
||||
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
|
||||
#define LOG_PACKET_SENDING(data, len) ((void) 0)
|
||||
|
||||
@@ -24,12 +24,26 @@ static const char *const PROLOGUE_INIT = "NoiseAPIInit";
|
||||
#endif
|
||||
static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
|
||||
|
||||
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
|
||||
static constexpr size_t API_MAX_LOG_BYTES = 168;
|
||||
|
||||
#define HELPER_LOG(msg, ...) \
|
||||
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
|
||||
|
||||
#ifdef HELPER_LOG_PACKETS
|
||||
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
|
||||
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
|
||||
#define LOG_PACKET_RECEIVED(buffer) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Received frame: %s", \
|
||||
format_hex_pretty_to(hex_buf_, (buffer).data(), \
|
||||
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#define LOG_PACKET_SENDING(data, len) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Sending raw: %s", \
|
||||
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
|
||||
#define LOG_PACKET_SENDING(data, len) ((void) 0)
|
||||
|
||||
@@ -18,12 +18,26 @@ namespace esphome::api {
|
||||
|
||||
static const char *const TAG = "api.plaintext";
|
||||
|
||||
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
|
||||
static constexpr size_t API_MAX_LOG_BYTES = 168;
|
||||
|
||||
#define HELPER_LOG(msg, ...) \
|
||||
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
|
||||
|
||||
#ifdef HELPER_LOG_PACKETS
|
||||
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
|
||||
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
|
||||
#define LOG_PACKET_RECEIVED(buffer) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Received frame: %s", \
|
||||
format_hex_pretty_to(hex_buf_, (buffer).data(), \
|
||||
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#define LOG_PACKET_SENDING(data, len) \
|
||||
do { \
|
||||
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
|
||||
ESP_LOGVV(TAG, "Sending raw: %s", \
|
||||
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
|
||||
#define LOG_PACKET_SENDING(data, len) ((void) 0)
|
||||
|
||||
@@ -678,7 +678,7 @@ void APIServer::unregister_active_action_calls_for_connection(APIConnection *con
|
||||
}
|
||||
}
|
||||
|
||||
void APIServer::send_action_response(uint32_t action_call_id, bool success, const std::string &error_message) {
|
||||
void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message) {
|
||||
for (auto &call : this->active_action_calls_) {
|
||||
if (call.action_call_id == action_call_id) {
|
||||
call.connection->send_execute_service_response(call.client_call_id, success, error_message);
|
||||
@@ -688,7 +688,7 @@ void APIServer::send_action_response(uint32_t action_call_id, bool success, cons
|
||||
ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id);
|
||||
}
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
void APIServer::send_action_response(uint32_t action_call_id, bool success, const std::string &error_message,
|
||||
void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
|
||||
const uint8_t *response_data, size_t response_data_len) {
|
||||
for (auto &call : this->active_action_calls_) {
|
||||
if (call.action_call_id == action_call_id) {
|
||||
|
||||
@@ -165,9 +165,9 @@ class APIServer : public Component,
|
||||
void unregister_active_action_call(uint32_t action_call_id);
|
||||
void unregister_active_action_calls_for_connection(APIConnection *conn);
|
||||
// Send response for a specific action call (uses action_call_id, sends client_call_id in response)
|
||||
void send_action_response(uint32_t action_call_id, bool success, const std::string &error_message);
|
||||
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message);
|
||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
void send_action_response(uint32_t action_call_id, bool success, const std::string &error_message,
|
||||
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
|
||||
const uint8_t *response_data, size_t response_data_len);
|
||||
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
|
||||
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||
|
||||
@@ -255,7 +255,7 @@ template<typename... Ts> class APIRespondAction : public Action<Ts...> {
|
||||
bool return_response = std::get<1>(args);
|
||||
if (!return_response) {
|
||||
// Client doesn't want response data, just send success/error
|
||||
this->parent_->send_action_response(call_id, success, error_message);
|
||||
this->parent_->send_action_response(call_id, success, StringRef(error_message));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -265,12 +265,12 @@ template<typename... Ts> class APIRespondAction : public Action<Ts...> {
|
||||
json::JsonBuilder builder;
|
||||
this->json_builder_(x..., builder.root());
|
||||
std::string json_str = builder.serialize();
|
||||
this->parent_->send_action_response(call_id, success, error_message,
|
||||
this->parent_->send_action_response(call_id, success, StringRef(error_message),
|
||||
reinterpret_cast<const uint8_t *>(json_str.data()), json_str.size());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
this->parent_->send_action_response(call_id, success, error_message);
|
||||
this->parent_->send_action_response(call_id, success, StringRef(error_message));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -47,7 +47,10 @@ struct DNSAnswer {
|
||||
|
||||
void DNSServer::start(const network::IPAddress &ip) {
|
||||
this->server_ip_ = ip;
|
||||
ESP_LOGV(TAG, "Starting DNS server on %s", ip.str().c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGV(TAG, "Starting DNS server on %s", ip.str_to(ip_buf));
|
||||
#endif
|
||||
|
||||
// Create loop-monitored UDP socket
|
||||
this->socket_ = socket::socket_ip_loop_monitored(SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
@@ -128,7 +128,9 @@ void CH422GGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->
|
||||
bool CH422GGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) ^ this->inverted_; }
|
||||
|
||||
void CH422GGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value ^ this->inverted_); }
|
||||
std::string CH422GGPIOPin::dump_summary() const { return str_sprintf("EXIO%u via CH422G", pin_); }
|
||||
size_t CH422GGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "EXIO%u via CH422G", this->pin_);
|
||||
}
|
||||
void CH422GGPIOPin::set_flags(gpio::Flags flags) {
|
||||
flags_ = flags;
|
||||
this->parent_->pin_mode(this->pin_, flags);
|
||||
|
||||
@@ -50,7 +50,7 @@ class CH422GGPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(CH422GComponent *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "cse7766.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace cse7766 {
|
||||
|
||||
static const char *const TAG = "cse7766";
|
||||
static constexpr size_t CSE7766_RAW_DATA_SIZE = 24;
|
||||
|
||||
void CSE7766Component::loop() {
|
||||
const uint32_t now = App.get_loop_component_start_time();
|
||||
@@ -70,8 +72,8 @@ bool CSE7766Component::check_byte_() {
|
||||
void CSE7766Component::parse_data_() {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
{
|
||||
std::string s = format_hex_pretty(this->raw_data_, sizeof(this->raw_data_));
|
||||
ESP_LOGVV(TAG, "Raw data: %s", s.c_str());
|
||||
char hex_buf[format_hex_pretty_size(CSE7766_RAW_DATA_SIZE)];
|
||||
ESP_LOGVV(TAG, "Raw data: %s", format_hex_pretty_to(hex_buf, this->raw_data_, sizeof(this->raw_data_)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
static const char *const TAG = "epaper_spi";
|
||||
static constexpr size_t EPAPER_MAX_CMD_LOG_BYTES = 128;
|
||||
|
||||
static constexpr const char *const EPAPER_STATE_STRINGS[] = {
|
||||
"IDLE", "UPDATE", "RESET", "RESET_END", "SHOULD_WAIT", "INITIALISE",
|
||||
@@ -68,8 +69,11 @@ void EPaperBase::data(uint8_t value) {
|
||||
// The command is the first byte, length is the length of data only in the second byte, followed by the data.
|
||||
// [COMMAND, LENGTH, DATA...]
|
||||
void EPaperBase::cmd_data(uint8_t command, const uint8_t *ptr, size_t length) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(EPAPER_MAX_CMD_LOG_BYTES)];
|
||||
ESP_LOGV(TAG, "Command: 0x%02X, Length: %d, Data: %s", command, length,
|
||||
format_hex_pretty(ptr, length, '.', false).c_str());
|
||||
format_hex_pretty_to(hex_buf, ptr, length, '.'));
|
||||
#endif
|
||||
|
||||
this->dc_pin_->digital_write(false);
|
||||
this->enable();
|
||||
|
||||
@@ -85,6 +85,7 @@ CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES = "enable_idf_experimental_features"
|
||||
CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert"
|
||||
CONF_ENABLE_OTA_ROLLBACK = "enable_ota_rollback"
|
||||
CONF_EXECUTE_FROM_PSRAM = "execute_from_psram"
|
||||
CONF_MINIMUM_CHIP_REVISION = "minimum_chip_revision"
|
||||
CONF_RELEASE = "release"
|
||||
|
||||
LOG_LEVELS_IDF = [
|
||||
@@ -109,6 +110,21 @@ COMPILER_OPTIMIZATIONS = {
|
||||
"SIZE": "CONFIG_COMPILER_OPTIMIZATION_SIZE",
|
||||
}
|
||||
|
||||
# ESP32 (original) chip revision options
|
||||
# Setting minimum revision to 3.0 or higher:
|
||||
# - Reduces flash size by excluding workaround code for older chip bugs
|
||||
# - For PSRAM users: disables CONFIG_SPIRAM_CACHE_WORKAROUND, which saves significant
|
||||
# IRAM by keeping C library functions in ROM instead of recompiling them
|
||||
# See: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/chip_revision.html
|
||||
ESP32_CHIP_REVISIONS = {
|
||||
"0.0": "CONFIG_ESP32_REV_MIN_0",
|
||||
"1.0": "CONFIG_ESP32_REV_MIN_1",
|
||||
"1.1": "CONFIG_ESP32_REV_MIN_1_1",
|
||||
"2.0": "CONFIG_ESP32_REV_MIN_2",
|
||||
"3.0": "CONFIG_ESP32_REV_MIN_3",
|
||||
"3.1": "CONFIG_ESP32_REV_MIN_3_1",
|
||||
}
|
||||
|
||||
# Socket limit configuration for ESP-IDF
|
||||
# ESP-IDF CONFIG_LWIP_MAX_SOCKETS has range 1-253, default 10
|
||||
DEFAULT_MAX_SOCKETS = 10 # ESP-IDF default
|
||||
@@ -566,6 +582,16 @@ def final_validate(config):
|
||||
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_IGNORE_EFUSE_MAC_CRC],
|
||||
)
|
||||
)
|
||||
if (
|
||||
config[CONF_VARIANT] != VARIANT_ESP32
|
||||
and advanced.get(CONF_MINIMUM_CHIP_REVISION) is not None
|
||||
):
|
||||
errs.append(
|
||||
cv.Invalid(
|
||||
f"'{CONF_MINIMUM_CHIP_REVISION}' is only supported on {VARIANT_ESP32}",
|
||||
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_MINIMUM_CHIP_REVISION],
|
||||
)
|
||||
)
|
||||
if advanced[CONF_EXECUTE_FROM_PSRAM]:
|
||||
if config[CONF_VARIANT] != VARIANT_ESP32S3:
|
||||
errs.append(
|
||||
@@ -694,6 +720,9 @@ FRAMEWORK_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_ENABLE_LWIP_ASSERT, default=True): cv.boolean,
|
||||
cv.Optional(CONF_IGNORE_EFUSE_CUSTOM_MAC, default=False): cv.boolean,
|
||||
cv.Optional(CONF_IGNORE_EFUSE_MAC_CRC, default=False): cv.boolean,
|
||||
cv.Optional(CONF_MINIMUM_CHIP_REVISION): cv.one_of(
|
||||
*ESP32_CHIP_REVISIONS
|
||||
),
|
||||
# DHCP server is needed for WiFi AP mode. When WiFi component is used,
|
||||
# it will handle disabling DHCP server when AP is not configured.
|
||||
# Default to false (disabled) when WiFi is not used.
|
||||
@@ -1017,6 +1046,16 @@ async def to_code(config):
|
||||
add_idf_sdkconfig_option(
|
||||
f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True
|
||||
)
|
||||
|
||||
# Set minimum chip revision for ESP32 variant
|
||||
# Setting this to 3.0 or higher reduces flash size by excluding workaround code,
|
||||
# and for PSRAM users saves significant IRAM by keeping C library functions in ROM.
|
||||
if variant == VARIANT_ESP32:
|
||||
min_rev = conf[CONF_ADVANCED].get(CONF_MINIMUM_CHIP_REVISION)
|
||||
if min_rev is not None:
|
||||
for rev, flag in ESP32_CHIP_REVISIONS.items():
|
||||
add_idf_sdkconfig_option(flag, rev == min_rev)
|
||||
cg.add_define("USE_ESP32_MIN_CHIP_REVISION_SET")
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_SINGLE_APP", False)
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM", True)
|
||||
add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM_FILENAME", "partitions.csv")
|
||||
|
||||
@@ -97,10 +97,8 @@ void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpi
|
||||
gpio_isr_handler_add(this->get_pin_num(), func, arg);
|
||||
}
|
||||
|
||||
std::string ESP32InternalGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "GPIO%" PRIu32, static_cast<uint32_t>(this->pin_));
|
||||
return buffer;
|
||||
size_t ESP32InternalGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "GPIO%" PRIu32, static_cast<uint32_t>(this->pin_));
|
||||
}
|
||||
|
||||
void ESP32InternalGPIOPin::setup() {
|
||||
|
||||
@@ -24,7 +24,7 @@ class ESP32InternalGPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return this->pin_; }
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "esphome/components/esp32_ble/ble.h"
|
||||
#include "esphome/components/esp32_ble_server/ble_2902.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
@@ -14,6 +15,7 @@ namespace esp32_improv {
|
||||
using namespace bytebuffer;
|
||||
|
||||
static const char *const TAG = "esp32_improv.component";
|
||||
static constexpr size_t IMPROV_MAX_LOG_BYTES = 128;
|
||||
static const char *const ESPHOME_MY_LINK = "https://my.home-assistant.io/redirect/config_flow_start?domain=esphome";
|
||||
static constexpr uint16_t STOP_ADVERTISING_DELAY =
|
||||
10000; // Delay (ms) before stopping service to allow BLE clients to read the final state
|
||||
@@ -314,7 +316,11 @@ void ESP32ImprovComponent::dump_config() {
|
||||
void ESP32ImprovComponent::process_incoming_data_() {
|
||||
uint8_t length = this->incoming_data_[1];
|
||||
|
||||
ESP_LOGV(TAG, "Processing bytes - %s", format_hex_pretty(this->incoming_data_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(IMPROV_MAX_LOG_BYTES)];
|
||||
ESP_LOGV(TAG, "Processing bytes - %s",
|
||||
format_hex_pretty_to(hex_buf, this->incoming_data_.data(), this->incoming_data_.size()));
|
||||
#endif
|
||||
if (this->incoming_data_.size() - 3 == length) {
|
||||
this->set_error_(improv::ERROR_NONE);
|
||||
improv::ImprovCommand command = improv::parse_improv_data(this->incoming_data_);
|
||||
@@ -403,8 +409,12 @@ void ESP32ImprovComponent::check_wifi_connection_() {
|
||||
#ifdef USE_WEBSERVER
|
||||
for (auto &ip : wifi::global_wifi_component->wifi_sta_ip_addresses()) {
|
||||
if (ip.is_ip4()) {
|
||||
char url_buffer[64];
|
||||
snprintf(url_buffer, sizeof(url_buffer), "http://%s:%d", ip.str().c_str(), USE_WEBSERVER_PORT);
|
||||
// "http://" (7) + IPv4 max (15) + ":" (1) + port max (5) + null = 29
|
||||
char url_buffer[32];
|
||||
memcpy(url_buffer, "http://", 7); // NOLINT(bugprone-not-null-terminated-result) - str_to null-terminates
|
||||
ip.str_to(url_buffer + 7);
|
||||
size_t len = strlen(url_buffer);
|
||||
snprintf(url_buffer + len, sizeof(url_buffer) - len, ":%d", USE_WEBSERVER_PORT);
|
||||
url_strings[url_count++] = url_buffer;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -98,10 +98,8 @@ void ESP8266GPIOPin::pin_mode(gpio::Flags flags) {
|
||||
pinMode(pin_, flags_to_mode(flags, pin_)); // NOLINT
|
||||
}
|
||||
|
||||
std::string ESP8266GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "GPIO%u", pin_);
|
||||
return buffer;
|
||||
size_t ESP8266GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "GPIO%u", this->pin_);
|
||||
}
|
||||
|
||||
bool ESP8266GPIOPin::digital_read() {
|
||||
|
||||
@@ -17,7 +17,7 @@ class ESP8266GPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return pin_; }
|
||||
|
||||
@@ -11,6 +11,7 @@ from esphome.const import (
|
||||
CONF_SPEED,
|
||||
DEVICE_CLASS_SPEED,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
STATE_CLASS_MEASUREMENT_ANGLE,
|
||||
UNIT_DEGREES,
|
||||
UNIT_KILOMETER_PER_HOUR,
|
||||
UNIT_METER,
|
||||
@@ -21,6 +22,7 @@ CONF_HDOP = "hdop"
|
||||
|
||||
ICON_ALTIMETER = "mdi:altimeter"
|
||||
ICON_COMPASS = "mdi:compass"
|
||||
ICON_CIRCLE_DOUBLE = "mdi:circle-double"
|
||||
ICON_LATITUDE = "mdi:latitude"
|
||||
ICON_LONGITUDE = "mdi:longitude"
|
||||
ICON_SATELLITE = "mdi:satellite-variant"
|
||||
@@ -50,7 +52,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
unit_of_measurement=UNIT_DEGREES,
|
||||
icon=ICON_LONGITUDE,
|
||||
accuracy_decimals=6,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT_ANGLE,
|
||||
),
|
||||
cv.Optional(CONF_SPEED): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_KILOMETER_PER_HOUR,
|
||||
@@ -63,7 +65,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
unit_of_measurement=UNIT_DEGREES,
|
||||
icon=ICON_COMPASS,
|
||||
accuracy_decimals=2,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
state_class=STATE_CLASS_MEASUREMENT_ANGLE,
|
||||
),
|
||||
cv.Optional(CONF_ALTITUDE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_METER,
|
||||
@@ -72,11 +74,14 @@ CONFIG_SCHEMA = cv.All(
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_SATELLITES): sensor.sensor_schema(
|
||||
# no unit_of_measurement
|
||||
icon=ICON_SATELLITE,
|
||||
accuracy_decimals=0,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_HDOP): sensor.sensor_schema(
|
||||
# no unit_of_measurement
|
||||
icon=ICON_CIRCLE_DOUBLE,
|
||||
accuracy_decimals=3,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
|
||||
@@ -34,9 +34,9 @@ void HLW8012Component::setup() {
|
||||
}
|
||||
void HLW8012Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "HLW8012:");
|
||||
LOG_PIN(" SEL Pin: ", this->sel_pin_)
|
||||
LOG_PIN(" CF Pin: ", this->cf_pin_)
|
||||
LOG_PIN(" CF1 Pin: ", this->cf1_pin_)
|
||||
LOG_PIN(" SEL Pin: ", this->sel_pin_);
|
||||
LOG_PIN(" CF Pin: ", this->cf_pin_);
|
||||
LOG_PIN(" CF1 Pin: ", this->cf1_pin_);
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" Change measurement mode every %" PRIu32 "\n"
|
||||
" Current resistor: %.1f mΩ\n"
|
||||
|
||||
@@ -25,11 +25,7 @@ void HostGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpio::Interr
|
||||
}
|
||||
void HostGPIOPin::pin_mode(gpio::Flags flags) { ESP_LOGD(TAG, "Setting pin %d mode to %02X", pin_, (uint32_t) flags); }
|
||||
|
||||
std::string HostGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "GPIO%u", pin_);
|
||||
return buffer;
|
||||
}
|
||||
size_t HostGPIOPin::dump_summary(char *buffer, size_t len) const { return snprintf(buffer, len, "GPIO%u", this->pin_); }
|
||||
|
||||
bool HostGPIOPin::digital_read() { return inverted_; }
|
||||
void HostGPIOPin::digital_write(bool value) {
|
||||
|
||||
@@ -17,7 +17,7 @@ class HostGPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return pin_; }
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace hte501 {
|
||||
|
||||
static const char *const TAG = "hte501";
|
||||
|
||||
static constexpr size_t HTE501_SERIAL_NUMBER_SIZE = 7;
|
||||
|
||||
void HTE501Component::setup() {
|
||||
uint8_t address[] = {0x70, 0x29};
|
||||
uint8_t identification[9];
|
||||
@@ -16,7 +18,10 @@ void HTE501Component::setup() {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex(identification + 0, 7).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char serial_hex[format_hex_size(HTE501_SERIAL_NUMBER_SIZE)];
|
||||
#endif
|
||||
ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex_to(serial_hex, identification, HTE501_SERIAL_NUMBER_SIZE));
|
||||
}
|
||||
|
||||
void HTE501Component::dump_config() {
|
||||
|
||||
@@ -39,7 +39,9 @@ void Jsnsr04tComponent::check_buffer_() {
|
||||
ESP_LOGV(TAG, "Distance from sensor: %umm, %.3fm", distance, meters);
|
||||
this->publish_state(meters);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str());
|
||||
char hex_buf[format_hex_pretty_size(4)];
|
||||
ESP_LOGW(TAG, "Invalid data read from sensor: %s",
|
||||
format_hex_pretty_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
|
||||
}
|
||||
} else {
|
||||
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "kuntze.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
@@ -10,11 +11,17 @@ static const char *const TAG = "kuntze";
|
||||
static const uint8_t CMD_READ_REG = 0x03;
|
||||
static const uint16_t REGISTER[] = {4136, 4160, 4680, 6000, 4688, 4728, 5832};
|
||||
|
||||
// Maximum bytes to log for Modbus responses (2 registers = 4, plus count = 5)
|
||||
static constexpr size_t KUNTZE_MAX_LOG_BYTES = 8;
|
||||
|
||||
void Kuntze::on_modbus_data(const std::vector<uint8_t> &data) {
|
||||
auto get_16bit = [&](int i) -> uint16_t { return (uint16_t(data[i * 2]) << 8) | uint16_t(data[i * 2 + 1]); };
|
||||
|
||||
this->waiting_ = false;
|
||||
ESP_LOGV(TAG, "Data: %s", format_hex_pretty(data).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(KUNTZE_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGV(TAG, "Data: %s", format_hex_pretty_to(hex_buf, data.data(), data.size()));
|
||||
|
||||
float value = (float) get_16bit(0);
|
||||
for (int i = 0; i < data[3]; i++)
|
||||
|
||||
@@ -413,7 +413,8 @@ bool LD2410Component::handle_ack_data_() {
|
||||
return true;
|
||||
}
|
||||
if (!ld2410::validate_header_footer(CMD_FRAME_HEADER, this->buffer_data_)) {
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty(this->buffer_data_, HEADER_FOOTER_SIZE).c_str());
|
||||
char hex_buf[format_hex_pretty_size(HEADER_FOOTER_SIZE)];
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, HEADER_FOOTER_SIZE));
|
||||
return true;
|
||||
}
|
||||
if (this->buffer_data_[COMMAND_STATUS] != 0x01) {
|
||||
@@ -597,11 +598,17 @@ void LD2410Component::readline_(int readch) {
|
||||
return; // Not enough data to process yet
|
||||
}
|
||||
if (ld2410::validate_header_footer(DATA_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
this->handle_periodic_data_();
|
||||
this->buffer_pos_ = 0; // Reset position index for next message
|
||||
} else if (ld2410::validate_header_footer(CMD_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
if (this->handle_ack_data_()) {
|
||||
this->buffer_pos_ = 0; // Reset position index for next message
|
||||
} else {
|
||||
|
||||
@@ -457,7 +457,8 @@ bool LD2412Component::handle_ack_data_() {
|
||||
return true;
|
||||
}
|
||||
if (!ld2412::validate_header_footer(CMD_FRAME_HEADER, this->buffer_data_)) {
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty(this->buffer_data_, HEADER_FOOTER_SIZE).c_str());
|
||||
char hex_buf[format_hex_pretty_size(HEADER_FOOTER_SIZE)];
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, HEADER_FOOTER_SIZE));
|
||||
return true;
|
||||
}
|
||||
if (this->buffer_data_[COMMAND_STATUS] != 0x01) {
|
||||
@@ -670,11 +671,17 @@ void LD2412Component::readline_(int readch) {
|
||||
return; // Not enough data to process yet
|
||||
}
|
||||
if (ld2412::validate_header_footer(DATA_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
this->handle_periodic_data_();
|
||||
this->buffer_pos_ = 0; // Reset position index for next message
|
||||
} else if (ld2412::validate_header_footer(CMD_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
if (this->handle_ack_data_()) {
|
||||
this->buffer_pos_ = 0; // Reset position index for next message
|
||||
} else {
|
||||
|
||||
@@ -607,7 +607,8 @@ bool LD2450Component::handle_ack_data_() {
|
||||
return true;
|
||||
}
|
||||
if (!ld2450::validate_header_footer(CMD_FRAME_HEADER, this->buffer_data_)) {
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty(this->buffer_data_, HEADER_FOOTER_SIZE).c_str());
|
||||
char hex_buf[format_hex_pretty_size(HEADER_FOOTER_SIZE)];
|
||||
ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, HEADER_FOOTER_SIZE));
|
||||
return true;
|
||||
}
|
||||
if (this->buffer_data_[COMMAND_STATUS] != 0x01) {
|
||||
@@ -758,11 +759,17 @@ void LD2450Component::readline_(int readch) {
|
||||
}
|
||||
if (this->buffer_data_[this->buffer_pos_ - 2] == DATA_FRAME_FOOTER[0] &&
|
||||
this->buffer_data_[this->buffer_pos_ - 1] == DATA_FRAME_FOOTER[1]) {
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
this->handle_periodic_data_();
|
||||
this->buffer_pos_ = 0; // Reset position index for next frame
|
||||
} else if (ld2450::validate_header_footer(CMD_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_LINE_LENGTH)];
|
||||
ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty_to(hex_buf, this->buffer_data_, this->buffer_pos_));
|
||||
#endif
|
||||
if (this->handle_ack_data_()) {
|
||||
this->buffer_pos_ = 0; // Reset position index for next message
|
||||
} else {
|
||||
|
||||
@@ -63,10 +63,8 @@ void ArduinoInternalGPIOPin::pin_mode(gpio::Flags flags) {
|
||||
pinMode(pin_, flags_to_mode(flags)); // NOLINT
|
||||
}
|
||||
|
||||
std::string ArduinoInternalGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u", pin_);
|
||||
return buffer;
|
||||
size_t ArduinoInternalGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u", this->pin_);
|
||||
}
|
||||
|
||||
bool ArduinoInternalGPIOPin::digital_read() {
|
||||
|
||||
@@ -16,7 +16,7 @@ class ArduinoInternalGPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return pin_; }
|
||||
|
||||
@@ -161,10 +161,8 @@ void MAX6956GPIOPin::setup() { pin_mode(flags_); }
|
||||
void MAX6956GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool MAX6956GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void MAX6956GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string MAX6956GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via Max6956", pin_);
|
||||
return buffer;
|
||||
size_t MAX6956GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via Max6956", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace max6956
|
||||
|
||||
@@ -76,7 +76,7 @@ class MAX6956GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(MAX6956 *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -99,10 +99,8 @@ void MCP23016GPIOPin::setup() { pin_mode(flags_); }
|
||||
void MCP23016GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool MCP23016GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void MCP23016GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string MCP23016GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via MCP23016", pin_);
|
||||
return buffer;
|
||||
size_t MCP23016GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via MCP23016", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace mcp23016
|
||||
|
||||
@@ -60,7 +60,7 @@ class MCP23016GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(MCP23016 *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -16,8 +16,8 @@ template<uint8_t N> bool MCP23XXXGPIOPin<N>::digital_read() {
|
||||
template<uint8_t N> void MCP23XXXGPIOPin<N>::digital_write(bool value) {
|
||||
this->parent_->digital_write(this->pin_, value != this->inverted_);
|
||||
}
|
||||
template<uint8_t N> std::string MCP23XXXGPIOPin<N>::dump_summary() const {
|
||||
return str_snprintf("%u via MCP23XXX", 15, pin_);
|
||||
template<uint8_t N> size_t MCP23XXXGPIOPin<N>::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via MCP23XXX", this->pin_);
|
||||
}
|
||||
|
||||
template class MCP23XXXGPIOPin<8>;
|
||||
|
||||
@@ -36,7 +36,7 @@ template<uint8_t N> class MCP23XXXGPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(MCP23XXXBase<N> *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -153,10 +153,8 @@ void MPR121GPIOPin::digital_write(bool value) {
|
||||
this->parent_->digital_write(this->pin_ - 4, value != this->inverted_);
|
||||
}
|
||||
|
||||
std::string MPR121GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "ELE%u on MPR121", this->pin_);
|
||||
return buffer;
|
||||
size_t MPR121GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "ELE%u on MPR121", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace mpr121
|
||||
|
||||
@@ -109,7 +109,7 @@ class MPR121GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(MPR121Component *parent) { this->parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
|
||||
@@ -153,13 +153,14 @@ void MQTTClientComponent::on_log(uint8_t level, const char *tag, const char *mes
|
||||
#endif
|
||||
|
||||
void MQTTClientComponent::dump_config() {
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"MQTT:\n"
|
||||
" Server Address: %s:%u (%s)\n"
|
||||
" Username: " LOG_SECRET("'%s'") "\n"
|
||||
" Client ID: " LOG_SECRET("'%s'") "\n"
|
||||
" Clean Session: %s",
|
||||
this->credentials_.address.c_str(), this->credentials_.port, this->ip_.str().c_str(),
|
||||
this->credentials_.address.c_str(), this->credentials_.port, this->ip_.str_to(ip_buf),
|
||||
this->credentials_.username.c_str(), this->credentials_.client_id.c_str(),
|
||||
YESNO(this->credentials_.clean_session));
|
||||
if (this->is_discovery_ip_enabled()) {
|
||||
@@ -246,7 +247,8 @@ void MQTTClientComponent::check_dnslookup_() {
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Resolved broker IP address to %s", this->ip_.str().c_str());
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGD(TAG, "Resolved broker IP address to %s", this->ip_.str_to(ip_buf));
|
||||
this->start_connect_();
|
||||
}
|
||||
#if defined(USE_ESP8266) && LWIP_VERSION_MAJOR == 1
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace nextion {
|
||||
static const char *const TAG = "nextion.upload.arduino";
|
||||
static constexpr size_t NEXTION_MAX_RESPONSE_LOG_BYTES = 16;
|
||||
|
||||
// Followed guide
|
||||
// https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
|
||||
@@ -89,8 +91,10 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) {
|
||||
EspClass::getFreeHeap());
|
||||
upload_first_chunk_sent_ = true;
|
||||
if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request
|
||||
ESP_LOGD(TAG, "Recv: [%s]",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGD(
|
||||
TAG, "Recv: [%s]",
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()));
|
||||
uint32_t result = 0;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
|
||||
@@ -107,8 +111,10 @@ int Nextion::upload_by_chunks_(HTTPClient &http_client, uint32_t &range_start) {
|
||||
buffer = nullptr;
|
||||
return range_end + 1;
|
||||
} else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok"
|
||||
ESP_LOGE(TAG, "Invalid response: [%s]",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGE(
|
||||
TAG, "Invalid response: [%s]",
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()));
|
||||
// Deallocate buffer
|
||||
allocator.deallocate(buffer, 4096);
|
||||
buffer = nullptr;
|
||||
@@ -274,8 +280,9 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
this->recv_ret_string_(response, 5000, true); // This can take some time to return
|
||||
|
||||
// The Nextion display will, if it's ready to accept data, send a 0x05 byte.
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGD(TAG, "Upload resp: [%s] %zu B",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(response.data()), response.size()),
|
||||
response.length());
|
||||
ESP_LOGV(TAG, "Heap: %" PRIu32, EspClass::getFreeHeap());
|
||||
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
#include "esphome/components/network/util.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/util.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace nextion {
|
||||
static const char *const TAG = "nextion.upload.esp32";
|
||||
static constexpr size_t NEXTION_MAX_RESPONSE_LOG_BYTES = 16;
|
||||
|
||||
// Followed guide
|
||||
// https://unofficialnextion.com/t/nextion-upload-protocol-v1-2-the-fast-one/1044/2
|
||||
@@ -110,8 +112,10 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
|
||||
#endif
|
||||
upload_first_chunk_sent_ = true;
|
||||
if (recv_string[0] == 0x08 && recv_string.size() == 5) { // handle partial upload request
|
||||
ESP_LOGD(TAG, "Recv: [%s]",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGD(
|
||||
TAG, "Recv: [%s]",
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()));
|
||||
uint32_t result = 0;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
result += static_cast<uint8_t>(recv_string[j + 1]) << (8 * j);
|
||||
@@ -128,8 +132,10 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
|
||||
buffer = nullptr;
|
||||
return range_end + 1;
|
||||
} else if (recv_string[0] != 0x05 and recv_string[0] != 0x08) { // 0x05 == "ok"
|
||||
ESP_LOGE(TAG, "Invalid response: [%s]",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()).c_str());
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGE(
|
||||
TAG, "Invalid response: [%s]",
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(recv_string.data()), recv_string.size()));
|
||||
// Deallocate buffer
|
||||
allocator.deallocate(buffer, 4096);
|
||||
buffer = nullptr;
|
||||
@@ -287,8 +293,9 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
this->recv_ret_string_(response, 5000, true); // This can take some time to return
|
||||
|
||||
// The Nextion display will, if it's ready to accept data, send a 0x05 byte.
|
||||
char hex_buf[format_hex_pretty_size(NEXTION_MAX_RESPONSE_LOG_BYTES)];
|
||||
ESP_LOGD(TAG, "Upload resp: [%s] %zu B",
|
||||
format_hex_pretty(reinterpret_cast<const uint8_t *>(response.data()), response.size()).c_str(),
|
||||
format_hex_pretty_to(hex_buf, reinterpret_cast<const uint8_t *>(response.data()), response.size()),
|
||||
response.length());
|
||||
ESP_LOGV(TAG, "Heap: %" PRIu32, esp_get_free_heap_size());
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "opentherm.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <cinttypes>
|
||||
#ifdef USE_ESP32
|
||||
#include "driver/timer.h"
|
||||
#include "esp_err.h"
|
||||
@@ -569,8 +570,8 @@ void OpenTherm::debug_data(OpenthermData &data) {
|
||||
to_string(data.f88()).c_str());
|
||||
}
|
||||
void OpenTherm::debug_error(OpenThermError &error) const {
|
||||
ESP_LOGD(TAG, "data: %s; clock: %s; capture: %s; bit_pos: %s", format_hex(error.data).c_str(),
|
||||
to_string(clock_).c_str(), format_bin(error.capture).c_str(), to_string(error.bit_pos).c_str());
|
||||
ESP_LOGD(TAG, "data: 0x%08" PRIx32 "; clock: %u; capture: 0x%08" PRIx32 "; bit_pos: %u", error.data, this->clock_,
|
||||
error.capture, error.bit_pos);
|
||||
}
|
||||
|
||||
float OpenthermData::f88() { return ((float) this->s16()) / 256.0; }
|
||||
|
||||
@@ -180,10 +180,8 @@ void PCA6416AGPIOPin::setup() { pin_mode(flags_); }
|
||||
void PCA6416AGPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool PCA6416AGPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void PCA6416AGPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string PCA6416AGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via PCA6416A", pin_);
|
||||
return buffer;
|
||||
size_t PCA6416AGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via PCA6416A", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace pca6416a
|
||||
|
||||
@@ -52,7 +52,7 @@ class PCA6416AGPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(PCA6416AComponent *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -129,10 +129,8 @@ void PCA9554GPIOPin::setup() { pin_mode(flags_); }
|
||||
void PCA9554GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool PCA9554GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void PCA9554GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string PCA9554GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via PCA9554", pin_);
|
||||
return buffer;
|
||||
size_t PCA9554GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via PCA9554", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace pca9554
|
||||
|
||||
@@ -59,7 +59,7 @@ class PCA9554GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(PCA9554Component *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -104,10 +104,8 @@ void PCF8574GPIOPin::setup() { pin_mode(flags_); }
|
||||
void PCF8574GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool PCF8574GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void PCF8574GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string PCF8574GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via PCF8574", pin_);
|
||||
return buffer;
|
||||
size_t PCF8574GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via PCF8574", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace pcf8574
|
||||
|
||||
@@ -54,7 +54,7 @@ class PCF8574GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(PCF8574Component *parent) { parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
|
||||
@@ -164,7 +164,9 @@ bool PI4IOE5V6408GPIOPin::digital_read() { return this->parent_->digital_read(th
|
||||
void PI4IOE5V6408GPIOPin::digital_write(bool value) {
|
||||
this->parent_->digital_write(this->pin_, value != this->inverted_);
|
||||
}
|
||||
std::string PI4IOE5V6408GPIOPin::dump_summary() const { return str_sprintf("%u via PI4IOE5V6408", this->pin_); }
|
||||
size_t PI4IOE5V6408GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via PI4IOE5V6408", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace pi4ioe5v6408
|
||||
} // namespace esphome
|
||||
|
||||
@@ -52,7 +52,7 @@ class PI4IOE5V6408GPIOPin : public GPIOPin, public Parented<PI4IOE5V6408Componen
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_inverted(bool inverted) { this->inverted_ = inverted; }
|
||||
|
||||
@@ -12,6 +12,9 @@ static const uint8_t WAIT_I_RQ = 0x30; // RxIRq and IdleIRq
|
||||
|
||||
static const char *const TAG = "rc522";
|
||||
|
||||
// Max UID size for RFID tags (4, 7, or 10 bytes)
|
||||
static constexpr size_t RC522_MAX_UID_SIZE = 10;
|
||||
|
||||
static const uint8_t RESET_COUNT = 5;
|
||||
|
||||
void RC522::setup() {
|
||||
@@ -191,8 +194,9 @@ void RC522::loop() {
|
||||
if (status == STATUS_TIMEOUT) {
|
||||
ESP_LOGV(TAG, "STATE_READ_SERIAL_DONE -> TIMEOUT (no tag present) %d", status);
|
||||
} else {
|
||||
char hex_buf[format_hex_pretty_size(RC522_MAX_UID_SIZE)];
|
||||
ESP_LOGW(TAG, "Unexpected response. Read status is %d. Read bytes: %d (%s)", status, back_length_,
|
||||
format_hex_pretty(buffer_, back_length_, '-', false).c_str());
|
||||
format_hex_pretty_to(hex_buf, buffer_, back_length_, '-'));
|
||||
}
|
||||
|
||||
state_ = STATE_DONE;
|
||||
@@ -237,13 +241,18 @@ void RC522::loop() {
|
||||
trigger->process(rfid_uid);
|
||||
|
||||
if (report) {
|
||||
ESP_LOGD(TAG, "Found new tag '%s'", format_hex_pretty(rfid_uid, '-', false).c_str());
|
||||
char uid_buf[format_hex_pretty_size(RC522_MAX_UID_SIZE)];
|
||||
ESP_LOGD(TAG, "Found new tag '%s'", format_hex_pretty_to(uid_buf, rfid_uid.data(), rfid_uid.size(), '-'));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (!this->current_uid_.empty()) {
|
||||
ESP_LOGV(TAG, "Tag '%s' removed", format_hex_pretty(this->current_uid_, '-', false).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char uid_buf[format_hex_pretty_size(RC522_MAX_UID_SIZE)];
|
||||
ESP_LOGV(TAG, "Tag '%s' removed",
|
||||
format_hex_pretty_to(uid_buf, this->current_uid_.data(), this->current_uid_.size(), '-'));
|
||||
#endif
|
||||
for (auto *trigger : this->triggers_ontagremoved_)
|
||||
trigger->process(this->current_uid_);
|
||||
}
|
||||
@@ -338,7 +347,10 @@ void RC522::pcd_clear_register_bit_mask_(PcdRegister reg, ///< The register to
|
||||
* @return STATUS_OK on success, STATUS_??? otherwise.
|
||||
*/
|
||||
void RC522::pcd_transceive_data_(uint8_t send_len) {
|
||||
ESP_LOGV(TAG, "PCD TRANSCEIVE: RX: %s", format_hex_pretty(buffer_, send_len, '-', false).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(RC522_MAX_UID_SIZE)];
|
||||
ESP_LOGV(TAG, "PCD TRANSCEIVE: RX: %s", format_hex_pretty_to(hex_buf, buffer_, send_len, '-'));
|
||||
#endif
|
||||
delayMicroseconds(1000); // we need 1 ms delay between antenna on and those communication commands
|
||||
send_len_ = send_len;
|
||||
// Prepare values for BitFramingReg
|
||||
@@ -412,8 +424,11 @@ RC522::StatusCode RC522::await_transceive_() {
|
||||
error_reg_value); // TODO: is this always due to collissions?
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(RC522_MAX_UID_SIZE)];
|
||||
ESP_LOGV(TAG, "received %d bytes: %s", back_length_,
|
||||
format_hex_pretty(buffer_ + send_len_, back_length_, '-', false).c_str());
|
||||
format_hex_pretty_to(hex_buf, buffer_ + send_len_, back_length_, '-'));
|
||||
#endif
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "haier_protocol.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -12,6 +13,8 @@ constexpr uint32_t BIT_MARK_US = 540;
|
||||
constexpr uint32_t BIT_ONE_SPACE_US = 1650;
|
||||
constexpr uint32_t BIT_ZERO_SPACE_US = 580;
|
||||
constexpr unsigned int HAIER_IR_PACKET_BIT_SIZE = 112;
|
||||
// Max data bytes in packet (excluding checksum)
|
||||
constexpr size_t HAIER_MAX_DATA_BYTES = (HAIER_IR_PACKET_BIT_SIZE / 8);
|
||||
|
||||
void HaierProtocol::encode_byte_(RemoteTransmitData *dst, uint8_t item) {
|
||||
for (uint8_t mask = 1 << 7; mask != 0; mask >>= 1) {
|
||||
@@ -77,7 +80,8 @@ optional<HaierData> HaierProtocol::decode(RemoteReceiveData src) {
|
||||
}
|
||||
|
||||
void HaierProtocol::dump(const HaierData &data) {
|
||||
ESP_LOGI(TAG, "Received Haier: %s", format_hex_pretty(data.data).c_str());
|
||||
char hex_buf[format_hex_pretty_size(HAIER_MAX_DATA_BYTES)];
|
||||
ESP_LOGI(TAG, "Received Haier: %s", format_hex_pretty_to(hex_buf, data.data.data(), data.data.size()));
|
||||
}
|
||||
|
||||
} // namespace remote_base
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "mirage_protocol.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -13,9 +14,12 @@ constexpr uint32_t BIT_ONE_SPACE_US = 1592;
|
||||
constexpr uint32_t BIT_ZERO_SPACE_US = 545;
|
||||
|
||||
constexpr unsigned int MIRAGE_IR_PACKET_BIT_SIZE = 120;
|
||||
// Max data bytes in packet (excluding checksum)
|
||||
constexpr size_t MIRAGE_MAX_DATA_BYTES = (MIRAGE_IR_PACKET_BIT_SIZE / 8);
|
||||
|
||||
void MirageProtocol::encode(RemoteTransmitData *dst, const MirageData &data) {
|
||||
ESP_LOGI(TAG, "Transive Mirage: %s", format_hex_pretty(data.data).c_str());
|
||||
char hex_buf[format_hex_pretty_size(MIRAGE_MAX_DATA_BYTES)];
|
||||
ESP_LOGI(TAG, "Transmit Mirage: %s", format_hex_pretty_to(hex_buf, data.data.data(), data.data.size()));
|
||||
dst->set_carrier_frequency(38000);
|
||||
dst->reserve(5 + ((data.data.size() + 1) * 2));
|
||||
dst->mark(HEADER_MARK_US);
|
||||
@@ -77,7 +81,8 @@ optional<MirageData> MirageProtocol::decode(RemoteReceiveData src) {
|
||||
}
|
||||
|
||||
void MirageProtocol::dump(const MirageData &data) {
|
||||
ESP_LOGI(TAG, "Received Mirage: %s", format_hex_pretty(data.data).c_str());
|
||||
char hex_buf[format_hex_pretty_size(MIRAGE_MAX_DATA_BYTES)];
|
||||
ESP_LOGI(TAG, "Received Mirage: %s", format_hex_pretty_to(hex_buf, data.data.data(), data.data.size()));
|
||||
}
|
||||
|
||||
} // namespace remote_base
|
||||
|
||||
@@ -64,10 +64,8 @@ void RP2040GPIOPin::pin_mode(gpio::Flags flags) {
|
||||
pinMode(pin_, flags_to_mode(flags, pin_)); // NOLINT
|
||||
}
|
||||
|
||||
std::string RP2040GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "GPIO%u", pin_);
|
||||
return buffer;
|
||||
size_t RP2040GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "GPIO%u", this->pin_);
|
||||
}
|
||||
|
||||
bool RP2040GPIOPin::digital_read() {
|
||||
|
||||
@@ -18,7 +18,7 @@ class RP2040GPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return pin_; }
|
||||
|
||||
@@ -270,7 +270,10 @@ void ShellyDimmer::send_settings_() {
|
||||
}
|
||||
|
||||
bool ShellyDimmer::send_command_(uint8_t cmd, const uint8_t *const payload, uint8_t len) {
|
||||
ESP_LOGD(TAG, "Sending command: 0x%02x (%d bytes) payload 0x%s", cmd, len, format_hex(payload, len).c_str());
|
||||
// Buffer for hex formatting: max frame size * 2 + null (covers any payload)
|
||||
char hex_buf[SHELLY_DIMMER_PROTO_MAX_FRAME_SIZE * 2 + 1];
|
||||
ESP_LOGD(TAG, "Sending command: 0x%02x (%d bytes) payload 0x%s", cmd, len,
|
||||
format_hex_to(hex_buf, sizeof(hex_buf), payload, len));
|
||||
|
||||
// Prepare a command frame.
|
||||
uint8_t frame[SHELLY_DIMMER_PROTO_MAX_FRAME_SIZE];
|
||||
|
||||
@@ -64,7 +64,9 @@ float SN74HC165Component::get_setup_priority() const { return setup_priority::IO
|
||||
|
||||
bool SN74HC165GPIOPin::digital_read() { return this->parent_->digital_read_(this->pin_) != this->inverted_; }
|
||||
|
||||
std::string SN74HC165GPIOPin::dump_summary() const { return str_snprintf("%u via SN74HC165", 18, pin_); }
|
||||
size_t SN74HC165GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via SN74HC165", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace sn74hc165
|
||||
} // namespace esphome
|
||||
|
||||
@@ -47,7 +47,7 @@ class SN74HC165GPIOPin : public GPIOPin, public Parented<SN74HC165Component> {
|
||||
void pin_mode(gpio::Flags flags) override {}
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override{};
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_pin(uint16_t pin) { pin_ = pin; }
|
||||
void set_inverted(bool inverted) { inverted_ = inverted; }
|
||||
|
||||
@@ -93,7 +93,9 @@ float SN74HC595Component::get_setup_priority() const { return setup_priority::IO
|
||||
void SN74HC595GPIOPin::digital_write(bool value) {
|
||||
this->parent_->digital_write_(this->pin_, value != this->inverted_);
|
||||
}
|
||||
std::string SN74HC595GPIOPin::dump_summary() const { return str_snprintf("%u via SN74HC595", 18, pin_); }
|
||||
size_t SN74HC595GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via SN74HC595", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace sn74hc595
|
||||
} // namespace esphome
|
||||
|
||||
@@ -54,7 +54,7 @@ class SN74HC595GPIOPin : public GPIOPin, public Parented<SN74HC595Component> {
|
||||
void pin_mode(gpio::Flags flags) override {}
|
||||
bool digital_read() override { return false; }
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_pin(uint16_t pin) { pin_ = pin; }
|
||||
void set_inverted(bool inverted) { inverted_ = inverted; }
|
||||
|
||||
@@ -42,12 +42,17 @@
|
||||
* M 6C - CRC over bytes 2 to F (Addition)
|
||||
\*********************************************************************************************/
|
||||
#include "sonoff_d1.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace sonoff_d1 {
|
||||
|
||||
static const char *const TAG = "sonoff_d1";
|
||||
|
||||
// Protocol constants
|
||||
static constexpr size_t SONOFF_D1_ACK_SIZE = 7;
|
||||
static constexpr size_t SONOFF_D1_MAX_CMD_SIZE = 17;
|
||||
|
||||
uint8_t SonoffD1Output::calc_checksum_(const uint8_t *cmd, const size_t len) {
|
||||
uint8_t crc = 0;
|
||||
for (size_t i = 2; i < len - 1; i++) {
|
||||
@@ -86,8 +91,11 @@ bool SonoffD1Output::read_command_(uint8_t *cmd, size_t &len) {
|
||||
|
||||
// Read a minimal packet
|
||||
if (this->read_array(cmd, 6)) {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(6)];
|
||||
ESP_LOGV(TAG, "[%04d] Reading from dimmer:", this->write_count_);
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty(cmd, 6).c_str());
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty_to(hex_buf, cmd, 6));
|
||||
#endif
|
||||
|
||||
if (cmd[0] != 0xAA || cmd[1] != 0x55) {
|
||||
ESP_LOGW(TAG, "[%04d] RX: wrong header (%x%x, must be AA55)", this->write_count_, cmd[0], cmd[1]);
|
||||
@@ -101,7 +109,10 @@ bool SonoffD1Output::read_command_(uint8_t *cmd, size_t &len) {
|
||||
return false;
|
||||
}
|
||||
if (this->read_array(&cmd[6], cmd[5] + 1 /*checksum suffix*/)) {
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty(&cmd[6], cmd[5] + 1).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf2[format_hex_pretty_size(SONOFF_D1_MAX_CMD_SIZE)];
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty_to(hex_buf2, &cmd[6], cmd[5] + 1));
|
||||
#endif
|
||||
|
||||
// Check the checksum
|
||||
uint8_t valid_checksum = this->calc_checksum_(cmd, cmd[5] + 7);
|
||||
@@ -145,9 +156,10 @@ bool SonoffD1Output::read_ack_(const uint8_t *cmd, const size_t len) {
|
||||
ESP_LOGD(TAG, "[%04d] Acknowledge received", this->write_count_);
|
||||
return true;
|
||||
} else {
|
||||
char hex_buf[format_hex_pretty_size(SONOFF_D1_ACK_SIZE)];
|
||||
ESP_LOGW(TAG, "[%04d] Unexpected acknowledge received (possible clash of RF/HA commands), expected ack was:",
|
||||
this->write_count_);
|
||||
ESP_LOGW(TAG, "[%04d] %s", this->write_count_, format_hex_pretty(ref_buffer, sizeof(ref_buffer)).c_str());
|
||||
ESP_LOGW(TAG, "[%04d] %s", this->write_count_, format_hex_pretty_to(hex_buf, ref_buffer, sizeof(ref_buffer)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -174,8 +186,11 @@ bool SonoffD1Output::write_command_(uint8_t *cmd, const size_t len, bool needs_a
|
||||
// 2. UART command initiated by this component can clash with a command initiated by RF
|
||||
uint32_t retries = 10;
|
||||
do {
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(SONOFF_D1_MAX_CMD_SIZE)];
|
||||
ESP_LOGV(TAG, "[%04d] Writing to the dimmer:", this->write_count_);
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty(cmd, len).c_str());
|
||||
ESP_LOGV(TAG, "[%04d] %s", this->write_count_, format_hex_pretty_to(hex_buf, cmd, len));
|
||||
#endif
|
||||
this->write_array(cmd, len);
|
||||
this->write_count_++;
|
||||
if (!needs_ack)
|
||||
|
||||
@@ -64,9 +64,9 @@ void SPIComponent::setup() {
|
||||
|
||||
void SPIComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "SPI bus:");
|
||||
LOG_PIN(" CLK Pin: ", this->clk_pin_)
|
||||
LOG_PIN(" SDI Pin: ", this->sdi_pin_)
|
||||
LOG_PIN(" SDO Pin: ", this->sdo_pin_)
|
||||
LOG_PIN(" CLK Pin: ", this->clk_pin_);
|
||||
LOG_PIN(" SDI Pin: ", this->sdi_pin_);
|
||||
LOG_PIN(" SDO Pin: ", this->sdo_pin_);
|
||||
for (size_t i = 0; i != this->data_pins_.size(); i++) {
|
||||
ESP_LOGCONFIG(TAG, " Data pin %u: GPIO%d", i, this->data_pins_[i]);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,11 @@ class NullPin : public GPIOPin {
|
||||
|
||||
void digital_write(bool value) override {}
|
||||
|
||||
std::string dump_summary() const override { return std::string(); }
|
||||
size_t dump_summary(char *buffer, size_t len) const override {
|
||||
if (len > 0)
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
static GPIOPin *const NULL_PIN; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
@@ -12,10 +12,8 @@ void SX1509GPIOPin::setup() { pin_mode(flags_); }
|
||||
void SX1509GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool SX1509GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void SX1509GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string SX1509GPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via sx1509", this->pin_);
|
||||
return buffer;
|
||||
size_t SX1509GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via sx1509", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace sx1509
|
||||
|
||||
@@ -13,7 +13,7 @@ class SX1509GPIOPin : public GPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_parent(SX1509Component *parent) { this->parent_ = parent; }
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
|
||||
@@ -138,7 +138,9 @@ void TCA9555GPIOPin::setup() { this->pin_mode(this->flags_); }
|
||||
void TCA9555GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool TCA9555GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
void TCA9555GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); }
|
||||
std::string TCA9555GPIOPin::dump_summary() const { return str_sprintf("%u via TCA9555", this->pin_); }
|
||||
size_t TCA9555GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via TCA9555", this->pin_);
|
||||
}
|
||||
|
||||
} // namespace tca9555
|
||||
} // namespace esphome
|
||||
|
||||
@@ -48,7 +48,7 @@ class TCA9555GPIOPin : public GPIOPin, public Parented<TCA9555Component> {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
|
||||
void set_pin(uint8_t pin) { this->pin_ = pin; }
|
||||
void set_inverted(bool inverted) { this->inverted_ = inverted; }
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace tee501 {
|
||||
|
||||
static const char *const TAG = "tee501";
|
||||
|
||||
static constexpr size_t TEE501_SERIAL_NUMBER_SIZE = 7;
|
||||
|
||||
void TEE501Component::setup() {
|
||||
uint8_t address[] = {0x70, 0x29};
|
||||
uint8_t identification[9];
|
||||
@@ -17,7 +19,10 @@ void TEE501Component::setup() {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex(identification + 0, 7).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char serial_hex[format_hex_size(TEE501_SERIAL_NUMBER_SIZE)];
|
||||
#endif
|
||||
ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex_to(serial_hex, identification, TEE501_SERIAL_NUMBER_SIZE));
|
||||
}
|
||||
|
||||
void TEE501Component::dump_config() {
|
||||
|
||||
@@ -20,6 +20,8 @@ static const char *const TAG = "tuya";
|
||||
static const int COMMAND_DELAY = 10;
|
||||
static const int RECEIVE_TIMEOUT = 300;
|
||||
static const int MAX_RETRIES = 5;
|
||||
// Max bytes to log for datapoint values (larger values are truncated)
|
||||
static constexpr size_t MAX_DATAPOINT_LOG_BYTES = 16;
|
||||
|
||||
void Tuya::setup() {
|
||||
this->set_interval("heartbeat", 15000, [this] { this->send_empty_command_(TuyaCommandType::HEARTBEAT); });
|
||||
@@ -51,7 +53,9 @@ void Tuya::dump_config() {
|
||||
}
|
||||
for (auto &info : this->datapoints_) {
|
||||
if (info.type == TuyaDatapointType::RAW) {
|
||||
ESP_LOGCONFIG(TAG, " Datapoint %u: raw (value: %s)", info.id, format_hex_pretty(info.value_raw).c_str());
|
||||
char hex_buf[format_hex_pretty_size(MAX_DATAPOINT_LOG_BYTES)];
|
||||
ESP_LOGCONFIG(TAG, " Datapoint %u: raw (value: %s)", info.id,
|
||||
format_hex_pretty_to(hex_buf, info.value_raw.data(), info.value_raw.size()));
|
||||
} else if (info.type == TuyaDatapointType::BOOLEAN) {
|
||||
ESP_LOGCONFIG(TAG, " Datapoint %u: switch (value: %s)", info.id, ONOFF(info.value_bool));
|
||||
} else if (info.type == TuyaDatapointType::INTEGER) {
|
||||
@@ -122,8 +126,11 @@ bool Tuya::validate_message_() {
|
||||
|
||||
// valid message
|
||||
const uint8_t *message_data = data + 6;
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_DATAPOINT_LOG_BYTES)];
|
||||
ESP_LOGV(TAG, "Received Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", command, version,
|
||||
format_hex_pretty(message_data, length).c_str(), static_cast<uint8_t>(this->init_state_));
|
||||
format_hex_pretty_to(hex_buf, message_data, length), static_cast<uint8_t>(this->init_state_));
|
||||
#endif
|
||||
this->handle_command_(command, version, message_data, length);
|
||||
|
||||
// return false to reset rx buffer
|
||||
@@ -349,7 +356,11 @@ void Tuya::handle_datapoints_(const uint8_t *buffer, size_t len) {
|
||||
switch (datapoint.type) {
|
||||
case TuyaDatapointType::RAW:
|
||||
datapoint.value_raw = std::vector<uint8_t>(data, data + data_size);
|
||||
ESP_LOGD(TAG, "Datapoint %u update to %s", datapoint.id, format_hex_pretty(datapoint.value_raw).c_str());
|
||||
{
|
||||
char hex_buf[format_hex_pretty_size(MAX_DATAPOINT_LOG_BYTES)];
|
||||
ESP_LOGD(TAG, "Datapoint %u update to %s", datapoint.id,
|
||||
format_hex_pretty_to(hex_buf, datapoint.value_raw.data(), datapoint.value_raw.size()));
|
||||
}
|
||||
break;
|
||||
case TuyaDatapointType::BOOLEAN:
|
||||
if (data_size != 1) {
|
||||
@@ -460,8 +471,12 @@ void Tuya::send_raw_command_(TuyaCommand command) {
|
||||
break;
|
||||
}
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(MAX_DATAPOINT_LOG_BYTES)];
|
||||
ESP_LOGV(TAG, "Sending Tuya: CMD=0x%02X VERSION=%u DATA=[%s] INIT_STATE=%u", static_cast<uint8_t>(command.cmd),
|
||||
version, format_hex_pretty(command.payload).c_str(), static_cast<uint8_t>(this->init_state_));
|
||||
version, format_hex_pretty_to(hex_buf, command.payload.data(), command.payload.size()),
|
||||
static_cast<uint8_t>(this->init_state_));
|
||||
#endif
|
||||
|
||||
this->write_array({0x55, 0xAA, version, (uint8_t) command.cmd, len_hi, len_lo});
|
||||
if (!command.payload.empty())
|
||||
@@ -675,7 +690,8 @@ void Tuya::set_numeric_datapoint_value_(uint8_t datapoint_id, TuyaDatapointType
|
||||
}
|
||||
|
||||
void Tuya::set_raw_datapoint_value_(uint8_t datapoint_id, const std::vector<uint8_t> &value, bool forced) {
|
||||
ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, format_hex_pretty(value).c_str());
|
||||
char hex_buf[format_hex_pretty_size(MAX_DATAPOINT_LOG_BYTES)];
|
||||
ESP_LOGD(TAG, "Setting datapoint %u to %s", datapoint_id, format_hex_pretty_to(hex_buf, value.data(), value.size()));
|
||||
optional<TuyaDatapoint> datapoint = this->get_datapoint_(datapoint_id);
|
||||
if (!datapoint.has_value()) {
|
||||
ESP_LOGW(TAG, "Setting unknown datapoint %u", datapoint_id);
|
||||
|
||||
@@ -65,11 +65,14 @@ void UDPComponent::setup() {
|
||||
server.sin_port = htons(this->listen_port_);
|
||||
|
||||
if (this->listen_address_.has_value()) {
|
||||
// Only 16 bytes needed for IPv4, but use standard size for consistency
|
||||
char addr_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
this->listen_address_.value().str_to(addr_buf);
|
||||
struct ip_mreq imreq = {};
|
||||
imreq.imr_interface.s_addr = ESPHOME_INADDR_ANY;
|
||||
inet_aton(this->listen_address_.value().str().c_str(), &imreq.imr_multiaddr);
|
||||
inet_aton(addr_buf, &imreq.imr_multiaddr);
|
||||
server.sin_addr.s_addr = imreq.imr_multiaddr.s_addr;
|
||||
ESP_LOGD(TAG, "Join multicast %s", this->listen_address_.value().str().c_str());
|
||||
ESP_LOGD(TAG, "Join multicast %s", addr_buf);
|
||||
err = this->listen_socket_->setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
|
||||
|
||||
@@ -8,6 +8,9 @@ namespace uponor_smatrix {
|
||||
|
||||
static const char *const TAG = "uponor_smatrix";
|
||||
|
||||
// Maximum bytes to log in verbose hex output
|
||||
static constexpr size_t UPONOR_MAX_LOG_BYTES = 36;
|
||||
|
||||
void UponorSmatrixComponent::setup() {
|
||||
#ifdef USE_TIME
|
||||
if (this->time_id_ != nullptr) {
|
||||
@@ -97,8 +100,11 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_size(UPONOR_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGV(TAG, "Received packet: addr=%08X, data=%s, crc=%04X", device_address,
|
||||
format_hex(&packet[4], packet_len - 6).c_str(), crc);
|
||||
format_hex_to(hex_buf, &packet[4], packet_len - 6), crc);
|
||||
|
||||
// Handle packet
|
||||
size_t data_len = (packet_len - 6) / 3;
|
||||
|
||||
@@ -8,6 +8,9 @@ namespace vbus {
|
||||
|
||||
static const char *const TAG = "vbus";
|
||||
|
||||
// Maximum bytes to log in verbose hex output (16 frames * 4 bytes = 64 bytes typical)
|
||||
static constexpr size_t VBUS_MAX_LOG_BYTES = 64;
|
||||
|
||||
void VBus::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "VBus:");
|
||||
check_uart_settings(9600);
|
||||
@@ -101,8 +104,11 @@ void VBus::loop() {
|
||||
this->buffer_.push_back(this->fbytes_[i]);
|
||||
if (++this->cframe_ < this->frames_)
|
||||
continue;
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char hex_buf[format_hex_size(VBUS_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGV(TAG, "P2 C%04x %04x->%04x: %s", this->command_, this->source_, this->dest_,
|
||||
format_hex(this->buffer_).c_str());
|
||||
format_hex_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->on_message(this->command_, this->source_, this->dest_, this->buffer_);
|
||||
this->state_ = 0;
|
||||
|
||||
@@ -177,10 +177,10 @@ uint32_t WaveshareEPaper2P13InV3::idle_timeout_() { return 5000; }
|
||||
void WaveshareEPaper2P13InV3::dump_config() {
|
||||
LOG_DISPLAY("", "Waveshare E-Paper", this)
|
||||
ESP_LOGCONFIG(TAG, " Model: 2.13inV3");
|
||||
LOG_PIN(" CS Pin: ", this->cs_)
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_)
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_)
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_)
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
||||
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
||||
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -245,10 +245,8 @@ void WeikaiGPIOPin::setup() {
|
||||
this->pin_mode(this->flags_);
|
||||
}
|
||||
|
||||
std::string WeikaiGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%u via WeiKai %s", this->pin_, this->parent_->get_name());
|
||||
return buffer;
|
||||
size_t WeikaiGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via WeiKai %s", this->pin_, this->parent_->get_name());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -278,7 +278,7 @@ class WeikaiGPIOPin : public GPIOPin {
|
||||
gpio::Flags get_flags() const override { return this->flags_; }
|
||||
|
||||
void setup() override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void pin_mode(gpio::Flags flags) override { this->parent_->set_pin_direction_(this->pin_, flags); }
|
||||
bool digital_read() override { return this->parent_->read_pin_val_(this->pin_) != this->inverted_; }
|
||||
void digital_write(bool value) override { this->parent_->write_pin_val_(this->pin_, value != this->inverted_); }
|
||||
|
||||
@@ -45,7 +45,8 @@ template<typename... Ts> class WiFiConfigureAction : public Action<Ts...>, publi
|
||||
if (this->connecting_)
|
||||
return;
|
||||
// If already connected to the same AP, do nothing
|
||||
if (global_wifi_component->wifi_ssid() == ssid) {
|
||||
char ssid_buf[SSID_BUFFER_SIZE];
|
||||
if (strcmp(global_wifi_component->wifi_ssid_to(ssid_buf), ssid.c_str()) == 0) {
|
||||
// Callback to notify the user that the connection was successful
|
||||
this->connect_trigger_->trigger();
|
||||
return;
|
||||
@@ -94,7 +95,8 @@ template<typename... Ts> class WiFiConfigureAction : public Action<Ts...>, publi
|
||||
this->cancel_timeout("wifi-connect-timeout");
|
||||
this->cancel_timeout("wifi-fallback-timeout");
|
||||
this->connecting_ = false;
|
||||
if (global_wifi_component->wifi_ssid() == this->new_sta_.get_ssid()) {
|
||||
char ssid_buf[SSID_BUFFER_SIZE];
|
||||
if (strcmp(global_wifi_component->wifi_ssid_to(ssid_buf), this->new_sta_.get_ssid().c_str()) == 0) {
|
||||
// Callback to notify the user that the connection was successful
|
||||
this->connect_trigger_->trigger();
|
||||
} else {
|
||||
|
||||
@@ -655,12 +655,15 @@ void WiFiComponent::setup_ap_config_() {
|
||||
#ifdef USE_WIFI_MANUAL_IP
|
||||
auto manual_ip = this->ap_.get_manual_ip();
|
||||
if (manual_ip.has_value()) {
|
||||
char static_ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char gateway_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char subnet_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" AP Static IP: '%s'\n"
|
||||
" AP Gateway: '%s'\n"
|
||||
" AP Subnet: '%s'",
|
||||
manual_ip->static_ip.str().c_str(), manual_ip->gateway.str().c_str(),
|
||||
manual_ip->subnet.str().c_str());
|
||||
manual_ip->static_ip.str_to(static_ip_buf), manual_ip->gateway.str_to(gateway_buf),
|
||||
manual_ip->subnet.str_to(subnet_buf));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -816,8 +819,14 @@ void WiFiComponent::start_connecting(const WiFiAP &ap) {
|
||||
#ifdef USE_WIFI_MANUAL_IP
|
||||
if (ap.get_manual_ip().has_value()) {
|
||||
ManualIP m = *ap.get_manual_ip();
|
||||
ESP_LOGV(TAG, " Manual IP: Static IP=%s Gateway=%s Subnet=%s DNS1=%s DNS2=%s", m.static_ip.str().c_str(),
|
||||
m.gateway.str().c_str(), m.subnet.str().c_str(), m.dns1.str().c_str(), m.dns2.str().c_str());
|
||||
char static_ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char gateway_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char subnet_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char dns1_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char dns2_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
ESP_LOGV(TAG, " Manual IP: Static IP=%s Gateway=%s Subnet=%s DNS1=%s DNS2=%s", m.static_ip.str_to(static_ip_buf),
|
||||
m.gateway.str_to(gateway_buf), m.subnet.str_to(subnet_buf), m.dns1.str_to(dns1_buf),
|
||||
m.dns2.str_to(dns2_buf));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -1167,7 +1176,8 @@ void WiFiComponent::check_connecting_finished() {
|
||||
auto status = this->wifi_sta_connect_status_();
|
||||
|
||||
if (status == WiFiSTAConnectStatus::CONNECTED) {
|
||||
if (wifi_ssid().empty()) {
|
||||
char ssid_buf[SSID_BUFFER_SIZE];
|
||||
if (wifi_ssid_to(ssid_buf)[0] == '\0') {
|
||||
ESP_LOGW(TAG, "Connection incomplete");
|
||||
this->retry_connect();
|
||||
return;
|
||||
|
||||
@@ -518,15 +518,12 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
switch (event->event) {
|
||||
case EVENT_STAMODE_CONNECTED: {
|
||||
auto it = event->event_info.connected;
|
||||
char buf[33];
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_address_pretty(it.bssid).c_str(),
|
||||
it.channel);
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=%s channel=%u", it.ssid_len, (const char *) it.ssid,
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel);
|
||||
s_sta_connected = true;
|
||||
#ifdef USE_WIFI_LISTENERS
|
||||
for (auto *listener : global_wifi_component->connect_state_listeners_) {
|
||||
listener->on_wifi_connect_state(StringRef(buf, it.ssid_len), it.bssid);
|
||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
||||
}
|
||||
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||
#ifdef USE_WIFI_MANUAL_IP
|
||||
@@ -543,17 +540,15 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
||||
}
|
||||
case EVENT_STAMODE_DISCONNECTED: {
|
||||
auto it = event->event_info.disconnected;
|
||||
char buf[33];
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
if (it.reason == REASON_NO_AP_FOUND) {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' reason='Probe Request Unsuccessful'", it.ssid_len,
|
||||
(const char *) it.ssid);
|
||||
s_sta_connect_not_found = true;
|
||||
} else {
|
||||
char bssid_s[18];
|
||||
format_mac_addr_upper(it.bssid, bssid_s);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, bssid_s,
|
||||
LOG_STR_ARG(get_disconnect_reason_str(it.reason)));
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' bssid=" LOG_SECRET("%s") " reason='%s'", it.ssid_len,
|
||||
(const char *) it.ssid, bssid_s, LOG_STR_ARG(get_disconnect_reason_str(it.reason)));
|
||||
s_sta_connect_error = true;
|
||||
}
|
||||
s_sta_connected = false;
|
||||
@@ -810,10 +805,13 @@ bool WiFiComponent::wifi_ap_ip_config_(const optional<ManualIP> &manual_ip) {
|
||||
network::IPAddress start_address = network::IPAddress(&info.ip);
|
||||
start_address += 99;
|
||||
lease.start_ip = start_address;
|
||||
ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
#endif
|
||||
ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str_to(ip_buf));
|
||||
start_address += 10;
|
||||
lease.end_ip = start_address;
|
||||
ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str());
|
||||
ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str_to(ip_buf));
|
||||
if (!wifi_softap_set_dhcps_lease(&lease)) {
|
||||
ESP_LOGE(TAG, "Set SoftAP DHCP lease failed");
|
||||
return false;
|
||||
|
||||
@@ -734,16 +734,13 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_CONNECTED) {
|
||||
const auto &it = data->data.sta_connected;
|
||||
char buf[33];
|
||||
assert(it.ssid_len <= 32);
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", it.ssid_len,
|
||||
(const char *) it.ssid, format_mac_address_pretty(it.bssid).c_str(), it.channel,
|
||||
get_auth_mode_str(it.authmode));
|
||||
s_sta_connected = true;
|
||||
#ifdef USE_WIFI_LISTENERS
|
||||
for (auto *listener : this->connect_state_listeners_) {
|
||||
listener->on_wifi_connect_state(StringRef(buf, it.ssid_len), it.bssid);
|
||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
||||
}
|
||||
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||
#ifdef USE_WIFI_MANUAL_IP
|
||||
@@ -757,21 +754,18 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
||||
|
||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
const auto &it = data->data.sta_disconnected;
|
||||
char buf[33];
|
||||
assert(it.ssid_len <= 32);
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
if (it.reason == WIFI_REASON_NO_AP_FOUND) {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' reason='Probe Request Unsuccessful'", it.ssid_len,
|
||||
(const char *) it.ssid);
|
||||
s_sta_connect_not_found = true;
|
||||
} else if (it.reason == WIFI_REASON_ROAMING) {
|
||||
ESP_LOGI(TAG, "Disconnected ssid='%s' reason='Station Roaming'", buf);
|
||||
ESP_LOGI(TAG, "Disconnected ssid='%.*s' reason='Station Roaming'", it.ssid_len, (const char *) it.ssid);
|
||||
return;
|
||||
} else {
|
||||
char bssid_s[18];
|
||||
format_mac_addr_upper(it.bssid, bssid_s);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, bssid_s,
|
||||
get_disconnect_reason_str(it.reason));
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' bssid=" LOG_SECRET("%s") " reason='%s'", it.ssid_len,
|
||||
(const char *) it.ssid, bssid_s, get_disconnect_reason_str(it.reason));
|
||||
s_sta_connect_error = true;
|
||||
}
|
||||
s_sta_connected = false;
|
||||
@@ -969,10 +963,13 @@ bool WiFiComponent::wifi_ap_ip_config_(const optional<ManualIP> &manual_ip) {
|
||||
network::IPAddress start_address = network::IPAddress(&info.ip);
|
||||
start_address += 99;
|
||||
lease.start_ip = start_address;
|
||||
ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str().c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
#endif
|
||||
ESP_LOGV(TAG, "DHCP server IP lease start: %s", start_address.str_to(ip_buf));
|
||||
start_address += 10;
|
||||
lease.end_ip = start_address;
|
||||
ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str().c_str());
|
||||
ESP_LOGV(TAG, "DHCP server IP lease end: %s", start_address.str_to(ip_buf));
|
||||
err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, &lease, sizeof(lease));
|
||||
|
||||
if (err != ESP_OK) {
|
||||
@@ -984,8 +981,10 @@ bool WiFiComponent::wifi_ap_ip_config_(const optional<ManualIP> &manual_ip) {
|
||||
// Configure DHCP Option 114 (Captive Portal URI) if captive portal is enabled
|
||||
// This provides a standards-compliant way for clients to discover the captive portal
|
||||
if (captive_portal::global_captive_portal != nullptr) {
|
||||
static char captive_portal_uri[32];
|
||||
snprintf(captive_portal_uri, sizeof(captive_portal_uri), "http://%s", network::IPAddress(&info.ip).str().c_str());
|
||||
// Buffer must be static - dhcps_set_option_info stores pointer, doesn't copy
|
||||
static char captive_portal_uri[24]; // "http://" (7) + IPv4 max (15) + null
|
||||
memcpy(captive_portal_uri, "http://", 7); // NOLINT(bugprone-not-null-terminated-result) - str_to null-terminates
|
||||
network::IPAddress(&info.ip).str_to(captive_portal_uri + 7);
|
||||
err = esp_netif_dhcps_option(s_ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captive_portal_uri,
|
||||
strlen(captive_portal_uri));
|
||||
if (err != ESP_OK) {
|
||||
|
||||
@@ -296,14 +296,12 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_STA_CONNECTED: {
|
||||
auto it = info.wifi_sta_connected;
|
||||
char buf[33];
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||
ESP_LOGV(TAG, "Connected ssid='%.*s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", it.ssid_len,
|
||||
(const char *) it.ssid, format_mac_address_pretty(it.bssid).c_str(), it.channel,
|
||||
get_auth_mode_str(it.authmode));
|
||||
#ifdef USE_WIFI_LISTENERS
|
||||
for (auto *listener : this->connect_state_listeners_) {
|
||||
listener->on_wifi_connect_state(StringRef(buf, it.ssid_len), it.bssid);
|
||||
listener->on_wifi_connect_state(StringRef(it.ssid, it.ssid_len), it.bssid);
|
||||
}
|
||||
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||
#ifdef USE_WIFI_MANUAL_IP
|
||||
@@ -318,9 +316,6 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
}
|
||||
case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: {
|
||||
auto it = info.wifi_sta_disconnected;
|
||||
char buf[33];
|
||||
memcpy(buf, it.ssid, it.ssid_len);
|
||||
buf[it.ssid_len] = '\0';
|
||||
|
||||
// LibreTiny can send spurious disconnect events with empty ssid/bssid during connection.
|
||||
// These are typically "Association Leave" events that don't indicate actual failures:
|
||||
@@ -339,12 +334,13 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
||||
}
|
||||
|
||||
if (it.reason == WIFI_REASON_NO_AP_FOUND) {
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' reason='Probe Request Unsuccessful'", buf);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' reason='Probe Request Unsuccessful'", it.ssid_len,
|
||||
(const char *) it.ssid);
|
||||
} else {
|
||||
char bssid_s[18];
|
||||
format_mac_addr_upper(it.bssid, bssid_s);
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%s' bssid=" LOG_SECRET("%s") " reason='%s'", buf, bssid_s,
|
||||
get_disconnect_reason_str(it.reason));
|
||||
ESP_LOGW(TAG, "Disconnected ssid='%.*s' bssid=" LOG_SECRET("%s") " reason='%s'", it.ssid_len,
|
||||
(const char *) it.ssid, bssid_s, get_disconnect_reason_str(it.reason));
|
||||
}
|
||||
|
||||
uint8_t reason = it.reason;
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace xiaomi_ble {
|
||||
|
||||
static const char *const TAG = "xiaomi_ble";
|
||||
|
||||
// Maximum bytes to log in very verbose hex output (covers largest packet of ~24 bytes)
|
||||
static constexpr size_t XIAOMI_MAX_LOG_BYTES = 32;
|
||||
|
||||
bool parse_xiaomi_value(uint16_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result) {
|
||||
// button pressed, 3 bytes, only byte 3 is used for supported devices so far
|
||||
if ((value_type == 0x1001) && (value_length == 3)) {
|
||||
@@ -263,7 +266,10 @@ optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::Service
|
||||
bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, const uint64_t &address) {
|
||||
if ((raw.size() != 19) && ((raw.size() < 22) || (raw.size() > 24))) {
|
||||
ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): data packet has wrong size (%d)!", raw.size());
|
||||
ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty_to(hex_buf, raw.data(), raw.size()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -320,12 +326,17 @@ bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, c
|
||||
memcpy(mac_address + 4, mac_reverse + 1, 1);
|
||||
memcpy(mac_address + 5, mac_reverse, 1);
|
||||
ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption failed.");
|
||||
ESP_LOGVV(TAG, " MAC address : %s", format_mac_address_pretty(mac_address).c_str());
|
||||
ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty(raw.data(), raw.size()).c_str());
|
||||
ESP_LOGVV(TAG, " Key : %s", format_hex_pretty(vector.key, vector.keysize).c_str());
|
||||
ESP_LOGVV(TAG, " Iv : %s", format_hex_pretty(vector.iv, vector.ivsize).c_str());
|
||||
ESP_LOGVV(TAG, " Cipher : %s", format_hex_pretty(vector.ciphertext, vector.datasize).c_str());
|
||||
ESP_LOGVV(TAG, " Tag : %s", format_hex_pretty(vector.tag, vector.tagsize).c_str());
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
format_mac_addr_upper(mac_address, mac_buf);
|
||||
char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGVV(TAG, " MAC address : %s", mac_buf);
|
||||
ESP_LOGVV(TAG, " Packet : %s", format_hex_pretty_to(hex_buf, raw.data(), raw.size()));
|
||||
ESP_LOGVV(TAG, " Key : %s", format_hex_pretty_to(hex_buf, vector.key, vector.keysize));
|
||||
ESP_LOGVV(TAG, " Iv : %s", format_hex_pretty_to(hex_buf, vector.iv, vector.ivsize));
|
||||
ESP_LOGVV(TAG, " Cipher : %s", format_hex_pretty_to(hex_buf, vector.ciphertext, vector.datasize));
|
||||
ESP_LOGVV(TAG, " Tag : %s", format_hex_pretty_to(hex_buf, vector.tag, vector.tagsize));
|
||||
mbedtls_ccm_free(&ctx);
|
||||
return false;
|
||||
}
|
||||
@@ -341,8 +352,11 @@ bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, c
|
||||
raw[0] &= ~0x08;
|
||||
|
||||
ESP_LOGVV(TAG, "decrypt_xiaomi_payload(): authenticated decryption passed.");
|
||||
ESP_LOGVV(TAG, " Plaintext : %s, Packet : %d", format_hex_pretty(raw.data() + cipher_pos, vector.datasize).c_str(),
|
||||
static_cast<int>(raw[4]));
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
char hex_buf[format_hex_pretty_size(XIAOMI_MAX_LOG_BYTES)];
|
||||
#endif
|
||||
ESP_LOGVV(TAG, " Plaintext : %s, Packet : %d",
|
||||
format_hex_pretty_to(hex_buf, raw.data() + cipher_pos, vector.datasize), static_cast<int>(raw[4]));
|
||||
|
||||
mbedtls_ccm_free(&ctx);
|
||||
return true;
|
||||
|
||||
@@ -110,7 +110,9 @@ void XL9535Component::pin_mode(uint8_t pin, gpio::Flags mode) {
|
||||
|
||||
void XL9535GPIOPin::setup() { this->pin_mode(this->flags_); }
|
||||
|
||||
std::string XL9535GPIOPin::dump_summary() const { return str_snprintf("%u via XL9535", 15, this->pin_); }
|
||||
size_t XL9535GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "%u via XL9535", this->pin_);
|
||||
}
|
||||
|
||||
void XL9535GPIOPin::pin_mode(gpio::Flags flags) { this->parent_->pin_mode(this->pin_, flags); }
|
||||
bool XL9535GPIOPin::digital_read() { return this->parent_->digital_read(this->pin_) != this->inverted_; }
|
||||
|
||||
@@ -39,7 +39,7 @@ class XL9535GPIOPin : public GPIOPin {
|
||||
gpio::Flags get_flags() const override { return this->flags_; }
|
||||
|
||||
void setup() override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
|
||||
@@ -85,10 +85,8 @@ void ZephyrGPIOPin::pin_mode(gpio::Flags flags) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string ZephyrGPIOPin::dump_summary() const {
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "GPIO%u, P%u.%u", this->pin_, this->pin_ / 32, this->pin_ % 32);
|
||||
return buffer;
|
||||
size_t ZephyrGPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
return snprintf(buffer, len, "GPIO%u, P%u.%u", this->pin_, this->pin_ / 32, this->pin_ % 32);
|
||||
}
|
||||
|
||||
bool ZephyrGPIOPin::digital_read() {
|
||||
|
||||
@@ -16,7 +16,7 @@ class ZephyrGPIOPin : public InternalGPIOPin {
|
||||
void pin_mode(gpio::Flags flags) override;
|
||||
bool digital_read() override;
|
||||
void digital_write(bool value) override;
|
||||
std::string dump_summary() const override;
|
||||
size_t dump_summary(char *buffer, size_t len) const override;
|
||||
void detach_interrupt() const override;
|
||||
ISRInternalGPIOPin to_isr() const override;
|
||||
uint8_t get_pin() const override { return this->pin_; }
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#ifdef USE_ESP8266
|
||||
#include <pgmspace.h>
|
||||
#endif
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_chip_info.h>
|
||||
#endif
|
||||
#include "esphome/core/version.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include <algorithm>
|
||||
@@ -203,6 +206,19 @@ void Application::loop() {
|
||||
ESP_LOGI(TAG, "ESPHome version " ESPHOME_VERSION " compiled on %s", build_time_str);
|
||||
#ifdef ESPHOME_PROJECT_NAME
|
||||
ESP_LOGI(TAG, "Project " ESPHOME_PROJECT_NAME " version " ESPHOME_PROJECT_VERSION);
|
||||
#endif
|
||||
#ifdef USE_ESP32
|
||||
esp_chip_info_t chip_info;
|
||||
esp_chip_info(&chip_info);
|
||||
ESP_LOGI(TAG, "ESP32 Chip: %s r%d.%d, %d core(s)", ESPHOME_VARIANT, chip_info.revision / 100,
|
||||
chip_info.revision % 100, chip_info.cores);
|
||||
#if defined(USE_ESP32_VARIANT_ESP32) && !defined(USE_ESP32_MIN_CHIP_REVISION_SET)
|
||||
// Suggest optimization for chips that don't need the PSRAM cache workaround
|
||||
if (chip_info.revision >= 300) {
|
||||
ESP_LOGW(TAG, "Set minimum_chip_revision: \"%d.%d\" to reduce binary size", chip_info.revision / 100,
|
||||
chip_info.revision % 100);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,7 @@
|
||||
#define USE_MQTT_IDF_ENQUEUE
|
||||
#define USE_ESPHOME_TASK_LOG_BUFFER
|
||||
#define USE_OTA_ROLLBACK
|
||||
#define USE_ESP32_MIN_CHIP_REVISION_SET
|
||||
|
||||
#define USE_BLUETOOTH_PROXY
|
||||
#define BLUETOOTH_PROXY_MAX_CONNECTIONS 3
|
||||
|
||||
@@ -9,7 +9,8 @@ static const char *const TAG = "entity_base";
|
||||
|
||||
// Entity Name
|
||||
const StringRef &EntityBase::get_name() const { return this->name_; }
|
||||
void EntityBase::set_name(const char *name) {
|
||||
void EntityBase::set_name(const char *name) { this->set_name(name, 0); }
|
||||
void EntityBase::set_name(const char *name, uint32_t object_id_hash) {
|
||||
this->name_ = StringRef(name);
|
||||
if (this->name_.empty()) {
|
||||
#ifdef USE_DEVICES
|
||||
@@ -18,11 +19,29 @@ void EntityBase::set_name(const char *name) {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
this->name_ = StringRef(App.get_friendly_name());
|
||||
// Bug-for-bug compatibility with OLD behavior:
|
||||
// - With MAC suffix: OLD code used App.get_friendly_name() directly (no fallback)
|
||||
// - Without MAC suffix: OLD code used pre-computed object_id with fallback to device name
|
||||
const std::string &friendly = App.get_friendly_name();
|
||||
if (App.is_name_add_mac_suffix_enabled()) {
|
||||
// MAC suffix enabled - use friendly_name directly (even if empty) for compatibility
|
||||
this->name_ = StringRef(friendly);
|
||||
} else {
|
||||
// No MAC suffix - fallback to device name if friendly_name is empty
|
||||
this->name_ = StringRef(!friendly.empty() ? friendly : App.get_name());
|
||||
}
|
||||
}
|
||||
this->flags_.has_own_name = false;
|
||||
// Dynamic name - must calculate hash at runtime
|
||||
this->calc_object_id_();
|
||||
} else {
|
||||
this->flags_.has_own_name = true;
|
||||
// Static name - use pre-computed hash if provided
|
||||
if (object_id_hash != 0) {
|
||||
this->object_id_hash_ = object_id_hash;
|
||||
} else {
|
||||
this->calc_object_id_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,69 +64,30 @@ void EntityBase::set_icon(const char *icon) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check if the object_id is dynamic (changes with MAC suffix)
|
||||
bool EntityBase::is_object_id_dynamic_() const {
|
||||
return !this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled();
|
||||
}
|
||||
|
||||
// Entity Object ID
|
||||
// Entity Object ID - computed on-demand from name
|
||||
std::string EntityBase::get_object_id() const {
|
||||
// Check if `App.get_friendly_name()` is constant or dynamic.
|
||||
if (this->is_object_id_dynamic_()) {
|
||||
// `App.get_friendly_name()` is dynamic.
|
||||
return str_sanitize(str_snake_case(App.get_friendly_name()));
|
||||
}
|
||||
// `App.get_friendly_name()` is constant.
|
||||
return this->object_id_c_str_ == nullptr ? "" : this->object_id_c_str_;
|
||||
}
|
||||
void EntityBase::set_object_id(const char *object_id) {
|
||||
this->object_id_c_str_ = object_id;
|
||||
this->calc_object_id_();
|
||||
}
|
||||
|
||||
void EntityBase::set_name_and_object_id(const char *name, const char *object_id) {
|
||||
this->set_name(name);
|
||||
this->object_id_c_str_ = object_id;
|
||||
this->calc_object_id_();
|
||||
}
|
||||
|
||||
// Calculate Object ID Hash from Entity Name
|
||||
void EntityBase::calc_object_id_() {
|
||||
char buf[OBJECT_ID_MAX_LEN];
|
||||
StringRef object_id = this->get_object_id_to(buf);
|
||||
this->object_id_hash_ = fnv1_hash(object_id.c_str());
|
||||
size_t len = this->write_object_id_to(buf, sizeof(buf));
|
||||
return std::string(buf, len);
|
||||
}
|
||||
|
||||
// Format dynamic object_id: sanitized snake_case of friendly_name
|
||||
static size_t format_dynamic_object_id(char *buf, size_t buf_size) {
|
||||
const std::string &name = App.get_friendly_name();
|
||||
size_t len = std::min(name.size(), buf_size - 1);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
buf[i] = to_sanitized_char(to_snake_case_char(name[i]));
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
// Calculate Object ID Hash directly from name using snake_case + sanitize
|
||||
void EntityBase::calc_object_id_() {
|
||||
this->object_id_hash_ = fnv1_hash_object_id(this->name_.c_str(), this->name_.size());
|
||||
}
|
||||
|
||||
size_t EntityBase::write_object_id_to(char *buf, size_t buf_size) const {
|
||||
if (this->is_object_id_dynamic_()) {
|
||||
return format_dynamic_object_id(buf, buf_size);
|
||||
size_t len = std::min(this->name_.size(), buf_size - 1);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
buf[i] = to_sanitized_char(to_snake_case_char(this->name_[i]));
|
||||
}
|
||||
const char *src = this->object_id_c_str_ == nullptr ? "" : this->object_id_c_str_;
|
||||
size_t len = strlen(src);
|
||||
if (len >= buf_size)
|
||||
len = buf_size - 1;
|
||||
memcpy(buf, src, len);
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
StringRef EntityBase::get_object_id_to(std::span<char, OBJECT_ID_MAX_LEN> buf) const {
|
||||
if (this->is_object_id_dynamic_()) {
|
||||
size_t len = format_dynamic_object_id(buf.data(), buf.size());
|
||||
return StringRef(buf.data(), len);
|
||||
}
|
||||
return this->object_id_c_str_ == nullptr ? StringRef() : StringRef(this->object_id_c_str_);
|
||||
size_t len = this->write_object_id_to(buf.data(), buf.size());
|
||||
return StringRef(buf.data(), len);
|
||||
}
|
||||
|
||||
uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; }
|
||||
|
||||
@@ -28,6 +28,9 @@ class EntityBase {
|
||||
// Get/set the name of this Entity
|
||||
const StringRef &get_name() const;
|
||||
void set_name(const char *name);
|
||||
/// Set name with pre-computed object_id hash (avoids runtime hash calculation)
|
||||
/// Use hash=0 for dynamic names that need runtime calculation
|
||||
void set_name(const char *name, uint32_t object_id_hash);
|
||||
|
||||
// Get whether this Entity has its own name or it should use the device friendly_name.
|
||||
bool has_own_name() const { return this->flags_.has_own_name; }
|
||||
@@ -43,10 +46,6 @@ class EntityBase {
|
||||
"which will remain available longer. get_object_id() will be removed in 2026.7.0",
|
||||
"2025.12.0")
|
||||
std::string get_object_id() const;
|
||||
void set_object_id(const char *object_id);
|
||||
|
||||
// Set both name and object_id in one call (reduces generated code size)
|
||||
void set_name_and_object_id(const char *name, const char *object_id);
|
||||
|
||||
// Get the unique Object ID of this Entity
|
||||
uint32_t get_object_id_hash();
|
||||
@@ -142,11 +141,7 @@ class EntityBase {
|
||||
protected:
|
||||
void calc_object_id_();
|
||||
|
||||
/// Check if the object_id is dynamic (changes with MAC suffix)
|
||||
bool is_object_id_dynamic_() const;
|
||||
|
||||
StringRef name_;
|
||||
const char *object_id_c_str_{nullptr};
|
||||
#ifdef USE_ENTITY_ICON
|
||||
const char *icon_c_str_{nullptr};
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ from esphome.const import (
|
||||
from esphome.core import CORE, ID
|
||||
from esphome.cpp_generator import MockObj, add, get_variable
|
||||
import esphome.final_validate as fv
|
||||
from esphome.helpers import sanitize, snake_case
|
||||
from esphome.helpers import fnv1_hash_object_id, sanitize, snake_case
|
||||
from esphome.types import ConfigType, EntityMetadata
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -75,34 +75,18 @@ async def setup_entity(var: MockObj, config: ConfigType, platform: str) -> None:
|
||||
config: Configuration dictionary containing entity settings
|
||||
platform: The platform name (e.g., "sensor", "binary_sensor")
|
||||
"""
|
||||
# Get device info
|
||||
device_name: str | None = None
|
||||
device_id_obj: ID | None
|
||||
# Get device info if configured
|
||||
if device_id_obj := config.get(CONF_DEVICE_ID):
|
||||
device: MockObj = await get_variable(device_id_obj)
|
||||
add(var.set_device(device))
|
||||
# Get device name for object ID calculation
|
||||
device_name = device_id_obj.id
|
||||
|
||||
# Calculate base object_id using the same logic as C++
|
||||
# This must match the C++ behavior in esphome/core/entity_base.cpp
|
||||
base_object_id = get_base_entity_object_id(
|
||||
config[CONF_NAME], CORE.friendly_name, device_name
|
||||
)
|
||||
|
||||
if not config[CONF_NAME]:
|
||||
_LOGGER.debug(
|
||||
"Entity has empty name, using '%s' as object_id base", base_object_id
|
||||
)
|
||||
|
||||
# Set both name and object_id in one call to reduce generated code size
|
||||
add(var.set_name_and_object_id(config[CONF_NAME], base_object_id))
|
||||
_LOGGER.debug(
|
||||
"Setting object_id '%s' for entity '%s' on platform '%s'",
|
||||
base_object_id,
|
||||
config[CONF_NAME],
|
||||
platform,
|
||||
)
|
||||
# Set the entity name with pre-computed object_id hash
|
||||
# For named entities: pre-compute hash from entity name
|
||||
# For empty-name entities: pass 0, C++ calculates hash at runtime from
|
||||
# device name, friendly_name, or app name (bug-for-bug compatibility)
|
||||
entity_name = config[CONF_NAME]
|
||||
object_id_hash = fnv1_hash_object_id(entity_name) if entity_name else 0
|
||||
add(var.set_name(entity_name, object_id_hash))
|
||||
# Only set disabled_by_default if True (default is False)
|
||||
if config[CONF_DISABLED_BY_DEFAULT]:
|
||||
add(var.set_disabled_by_default(True))
|
||||
|
||||
24
esphome/core/gpio.cpp
Normal file
24
esphome/core/gpio.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "esphome/core/gpio.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
void log_pin(const char *tag, const __FlashStringHelper *prefix, GPIOPin *pin) {
|
||||
if (pin == nullptr)
|
||||
return;
|
||||
static constexpr size_t LOG_PIN_PREFIX_MAX_LEN = 32;
|
||||
char prefix_buf[LOG_PIN_PREFIX_MAX_LEN];
|
||||
strncpy_P(prefix_buf, reinterpret_cast<const char *>(prefix), sizeof(prefix_buf) - 1);
|
||||
prefix_buf[sizeof(prefix_buf) - 1] = '\0';
|
||||
log_pin_with_prefix(tag, prefix_buf, pin);
|
||||
}
|
||||
#else
|
||||
void log_pin(const char *tag, const char *prefix, GPIOPin *pin) {
|
||||
if (pin == nullptr)
|
||||
return;
|
||||
log_pin_with_prefix(tag, prefix, pin);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace esphome
|
||||
@@ -1,13 +1,22 @@
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
#define LOG_PIN(prefix, pin) \
|
||||
if ((pin) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, prefix "%s", (pin)->dump_summary().c_str()); \
|
||||
}
|
||||
/// Maximum buffer size for dump_summary output
|
||||
inline constexpr size_t GPIO_SUMMARY_MAX_LEN = 48;
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
#define LOG_PIN(prefix, pin) log_pin(TAG, F(prefix), pin)
|
||||
#else
|
||||
#define LOG_PIN(prefix, pin) log_pin(TAG, prefix, pin)
|
||||
#endif
|
||||
|
||||
// put GPIO flags in a namespace to not pollute esphome namespace
|
||||
namespace gpio {
|
||||
@@ -64,7 +73,17 @@ class GPIOPin {
|
||||
|
||||
virtual void digital_write(bool value) = 0;
|
||||
|
||||
virtual std::string dump_summary() const = 0;
|
||||
/// Write a summary of this pin to the provided buffer.
|
||||
/// @param buffer The buffer to write to
|
||||
/// @param len The size of the buffer (must be > 0)
|
||||
/// @return The number of characters that would be written (excluding null terminator),
|
||||
/// which may exceed len-1 if truncation occurred (snprintf semantics)
|
||||
virtual size_t dump_summary(char *buffer, size_t len) const;
|
||||
|
||||
/// Get a summary of this pin as a string.
|
||||
/// @deprecated Use dump_summary(char*, size_t) instead. Will be removed in 2026.7.0.
|
||||
ESPDEPRECATED("Override dump_summary(char*, size_t) instead. Will be removed in 2026.7.0.", "2026.1.0")
|
||||
virtual std::string dump_summary() const;
|
||||
|
||||
virtual bool is_internal() { return false; }
|
||||
};
|
||||
@@ -103,4 +122,41 @@ class InternalGPIOPin : public GPIOPin {
|
||||
virtual void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const = 0;
|
||||
};
|
||||
|
||||
// Inline default implementations for GPIOPin virtual methods.
|
||||
// These provide bridge functionality for backwards compatibility with external components.
|
||||
|
||||
// Default implementation bridges to old std::string method for backwards compatibility.
|
||||
inline size_t GPIOPin::dump_summary(char *buffer, size_t len) const {
|
||||
if (len == 0)
|
||||
return 0;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
std::string s = this->dump_summary();
|
||||
#pragma GCC diagnostic pop
|
||||
size_t copy_len = std::min(s.size(), len - 1);
|
||||
memcpy(buffer, s.c_str(), copy_len);
|
||||
buffer[copy_len] = '\0';
|
||||
return s.size(); // Return would-be length (snprintf semantics)
|
||||
}
|
||||
|
||||
// Default implementation returns empty string.
|
||||
// External components should override this if they haven't migrated to buffer-based version.
|
||||
// Remove before 2026.7.0
|
||||
inline std::string GPIOPin::dump_summary() const { return {}; }
|
||||
|
||||
// Inline helper for log_pin - allows compiler to inline into log_pin in gpio.cpp
|
||||
inline void log_pin_with_prefix(const char *tag, const char *prefix, GPIOPin *pin) {
|
||||
char buffer[GPIO_SUMMARY_MAX_LEN];
|
||||
size_t len = pin->dump_summary(buffer, sizeof(buffer));
|
||||
len = std::min(len, sizeof(buffer) - 1);
|
||||
esp_log_printf_(ESPHOME_LOG_LEVEL_CONFIG, tag, __LINE__, "%s%.*s", prefix, (int) len, buffer);
|
||||
}
|
||||
|
||||
// log_pin function declarations - implementation in gpio.cpp
|
||||
#ifdef USE_ESP8266
|
||||
void log_pin(const char *tag, const __FlashStringHelper *prefix, GPIOPin *pin);
|
||||
#else
|
||||
void log_pin(const char *tag, const char *prefix, GPIOPin *pin);
|
||||
#endif
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
@@ -529,6 +529,20 @@ constexpr char to_sanitized_char(char c) {
|
||||
/// Sanitizes the input string by removing all characters but alphanumerics, dashes and underscores.
|
||||
std::string str_sanitize(const std::string &str);
|
||||
|
||||
/// Calculate FNV-1 hash of a string while applying snake_case + sanitize transformations.
|
||||
/// This computes object_id hashes directly from names without creating an intermediate buffer.
|
||||
/// IMPORTANT: Must match Python fnv1_hash_object_id() in esphome/helpers.py.
|
||||
/// If you modify this function, update the Python version and tests in both places.
|
||||
inline uint32_t fnv1_hash_object_id(const char *str, size_t len) {
|
||||
uint32_t hash = FNV1_OFFSET_BASIS;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
hash *= FNV1_PRIME;
|
||||
// Apply snake_case (space->underscore, uppercase->lowercase) then sanitize
|
||||
hash ^= static_cast<uint8_t>(to_sanitized_char(to_snake_case_char(str[i])));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// snprintf-like function returning std::string of maximum length \p len (excluding null terminator).
|
||||
std::string __attribute__((format(printf, 1, 3))) str_snprintf(const char *fmt, size_t len, ...);
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ IS_MACOS = platform.system() == "Darwin"
|
||||
IS_WINDOWS = platform.system() == "Windows"
|
||||
IS_LINUX = platform.system() == "Linux"
|
||||
|
||||
# FNV-1 hash constants (must match C++ in esphome/core/helpers.h)
|
||||
FNV1_OFFSET_BASIS = 2166136261
|
||||
FNV1_PRIME = 16777619
|
||||
|
||||
|
||||
def ensure_unique_string(preferred_string, current_strings):
|
||||
test_string = preferred_string
|
||||
@@ -49,8 +53,17 @@ def ensure_unique_string(preferred_string, current_strings):
|
||||
return test_string
|
||||
|
||||
|
||||
def fnv1_hash(string: str) -> int:
|
||||
"""FNV-1 32-bit hash function (multiply then XOR)."""
|
||||
hash_value = FNV1_OFFSET_BASIS
|
||||
for char in string:
|
||||
hash_value = (hash_value * FNV1_PRIME) & 0xFFFFFFFF
|
||||
hash_value ^= ord(char)
|
||||
return hash_value
|
||||
|
||||
|
||||
def fnv1a_32bit_hash(string: str) -> int:
|
||||
"""FNV-1a 32-bit hash function.
|
||||
"""FNV-1a 32-bit hash function (XOR then multiply).
|
||||
|
||||
Note: This uses 32-bit hash instead of 64-bit for several reasons:
|
||||
1. ESPHome targets 32-bit microcontrollers with limited RAM (often <320KB)
|
||||
@@ -63,13 +76,22 @@ def fnv1a_32bit_hash(string: str) -> int:
|
||||
a handful of area_ids and device_ids (typically <10 areas and <100
|
||||
devices), making collisions virtually impossible.
|
||||
"""
|
||||
hash_value = 2166136261
|
||||
hash_value = FNV1_OFFSET_BASIS
|
||||
for char in string:
|
||||
hash_value ^= ord(char)
|
||||
hash_value = (hash_value * 16777619) & 0xFFFFFFFF
|
||||
hash_value = (hash_value * FNV1_PRIME) & 0xFFFFFFFF
|
||||
return hash_value
|
||||
|
||||
|
||||
def fnv1_hash_object_id(name: str) -> int:
|
||||
"""Compute FNV-1 hash of name with snake_case + sanitize transformations.
|
||||
|
||||
IMPORTANT: Must produce same result as C++ fnv1_hash_object_id() in helpers.h.
|
||||
Used for pre-computing entity object_id hashes at code generation time.
|
||||
"""
|
||||
return fnv1_hash(sanitize(snake_case(name)))
|
||||
|
||||
|
||||
def strip_accents(value: str) -> str:
|
||||
"""Remove accents from a string."""
|
||||
import unicodedata
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_binary_sensor_sets_mandatory_fields(generate_main):
|
||||
)
|
||||
|
||||
# Then
|
||||
assert 'bs_1->set_name_and_object_id("test bs1", "test_bs1");' in main_cpp
|
||||
assert 'bs_1->set_name("test bs1",' in main_cpp
|
||||
assert "bs_1->set_pin(" in main_cpp
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ def test_button_sets_mandatory_fields(generate_main):
|
||||
main_cpp = generate_main("tests/component_tests/button/test_button.yaml")
|
||||
|
||||
# Then
|
||||
assert 'wol_1->set_name_and_object_id("wol_test_1", "wol_test_1");' in main_cpp
|
||||
assert 'wol_1->set_name("wol_test_1",' in main_cpp
|
||||
assert "wol_2->set_macaddr(18, 52, 86, 120, 144, 171);" in main_cpp
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user