Merge branch 'dev' into debug_cleanup

This commit is contained in:
J. Nick Koston
2026-01-06 19:31:49 -10:00
committed by GitHub
142 changed files with 1224 additions and 1320 deletions

View File

@@ -1 +1 @@
97fb425f1d681a5994ed1cc6187910f5d2c37ee577b6dc07eb3f4d8862a011de
191a0e6ab5842d153dd77a2023bc5742f9d4333c334de8d81b57f2b8d4d4b65e

View File

@@ -101,16 +101,14 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
auto &noise_ctx = parent->get_noise_ctx();
if (noise_ctx.has_psk()) {
this->helper_ =
std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx, &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
} else {
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
}
#elif defined(USE_API_PLAINTEXT)
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
#elif defined(USE_API_NOISE)
this->helper_ = std::unique_ptr<APIFrameHelper>{
new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx(), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
#else
#error "No frame helper defined"
#endif
@@ -131,8 +129,9 @@ void APIConnection::start() {
this->fatal_error_with_log_(LOG_STR("Helper init failed"), err);
return;
}
this->client_info_.peername = helper_->getpeername();
this->client_info_.name = this->client_info_.peername;
// Initialize client name with peername (IP address) until Hello message provides actual name
const char *peername = this->helper_->get_client_peername();
this->helper_->set_client_name(peername, strlen(peername));
}
APIConnection::~APIConnection() {
@@ -252,8 +251,7 @@ void APIConnection::loop() {
// Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
on_fatal_error();
ESP_LOGW(TAG, "%s (%s) is unresponsive; disconnecting", this->client_info_.name.c_str(),
this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("is unresponsive; disconnecting"));
}
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
// Only send ping if we're not disconnecting
@@ -287,7 +285,7 @@ bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
// remote initiated disconnect_client
// don't close yet, we still need to send the disconnect response
// close will happen on next loop
ESP_LOGD(TAG, "%s (%s) disconnected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("disconnected"));
this->flags_.next_close = true;
DisconnectResponse resp;
return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
@@ -1504,9 +1502,10 @@ void APIConnection::complete_authentication_() {
}
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
ESP_LOGD(TAG, "%s (%s) connected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("connected"));
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername);
this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()),
std::string(this->helper_->get_client_peername()));
#endif
#ifdef USE_HOMEASSISTANT_TIME
if (homeassistant::global_homeassistant_time != nullptr) {
@@ -1521,12 +1520,12 @@ void APIConnection::complete_authentication_() {
}
bool APIConnection::send_hello_response(const HelloRequest &msg) {
this->client_info_.name.assign(msg.client_info.c_str(), msg.client_info.size());
this->client_info_.peername = this->helper_->getpeername();
// Copy client name with truncation if needed (set_client_name handles truncation)
this->helper_->set_client_name(msg.client_info.c_str(), msg.client_info.size());
this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor;
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.name.c_str(),
this->client_info_.peername.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->helper_->get_client_name(),
this->helper_->get_client_peername(), this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp;
resp.api_version_major = 1;
@@ -1836,7 +1835,7 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
}
void APIConnection::on_no_setup_connection() {
this->on_fatal_error();
ESP_LOGD(TAG, "%s (%s) no connection setup", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("no connection setup"));
}
void APIConnection::on_fatal_error() {
this->helper_->close();
@@ -2084,8 +2083,13 @@ void APIConnection::process_state_subscriptions_() {
}
#endif // USE_API_HOMEASSISTANT_STATES
void APIConnection::log_client_(int level, const LogString *message) {
esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT("%s (%s): %s"), this->helper_->get_client_name(),
this->helper_->get_client_peername(), LOG_STR_ARG(message));
}
void APIConnection::log_warning_(const LogString *message, APIError err) {
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->client_info_.name.c_str(), this->client_info_.peername.c_str(),
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), this->helper_->get_client_peername(),
LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno);
}

View File

@@ -9,18 +9,13 @@
#include "esphome/core/application.h"
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/string_ref.h"
#include <functional>
#include <vector>
namespace esphome::api {
// Client information structure
struct ClientInfo {
std::string name; // Client name from Hello message
std::string peername; // IP:port from socket
};
// 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
@@ -279,8 +274,9 @@ class APIConnection final : public APIServerConnection {
bool try_to_clear_buffer(bool log_out_of_space);
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
const std::string &get_name() const { return this->client_info_.name; }
const std::string &get_peername() const { return this->client_info_.peername; }
const char *get_name() const { return this->helper_->get_client_name(); }
/// Get peer name (IP address) - cached at connection init time
const char *get_peername() const { return this->helper_->get_client_peername(); }
protected:
// Helper function to handle authentication completion
@@ -526,10 +522,7 @@ class APIConnection final : public APIServerConnection {
std::unique_ptr<camera::CameraImageReader> image_reader_;
#endif
// Group 3: Client info struct (24 bytes on 32-bit: 2 strings × 12 bytes each)
ClientInfo client_info_;
// Group 4: 4-byte types
// Group 3: 4-byte types
uint32_t last_traffic_;
#ifdef USE_API_HOMEASSISTANT_STATES
int state_subs_at_ = -1;
@@ -756,6 +749,8 @@ class APIConnection final : public APIServerConnection {
return this->schedule_batch_();
}
// Helper function to log client messages with name and peername
void log_client_(int level, const LogString *message);
// Helper function to log API errors with errno
void log_warning_(const LogString *message, APIError err);
// Helper to handle fatal errors with logging

View File

@@ -1,6 +1,5 @@
#include "api_frame_helper.h"
#ifdef USE_API
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
@@ -16,8 +15,11 @@ 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__)
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) \
@@ -243,6 +245,8 @@ APIError APIFrameHelper::init_common_() {
HELPER_LOG("Bad state for init %d", (int) state_);
return APIError::BAD_STATE;
}
// Cache peername now while socket is valid - needed for error logging after socket failure
this->socket_->getpeername_to(this->client_peername_);
int err = this->socket_->setblocking(false);
if (err != 0) {
state_ = State::FAILED;

View File

@@ -33,11 +33,11 @@ static constexpr uint16_t MAX_MESSAGE_SIZE = 32768; // 32 KiB for ESP32 and oth
// Must be >= MAX_INITIAL_PER_BATCH in api_connection.h (enforced by static_assert there)
static constexpr size_t MAX_MESSAGES_PER_BATCH = 34;
// Forward declaration
struct ClientInfo;
class ProtoWriteBuffer;
// Max client name length (e.g., "Home Assistant 2026.1.0.dev0" = 28 chars)
static constexpr size_t CLIENT_INFO_NAME_MAX_LEN = 32;
struct ReadPacketBuffer {
const uint8_t *data; // Points directly into frame helper's rx_buf_ (valid until next read_packet call)
uint16_t data_len;
@@ -86,14 +86,23 @@ const LogString *api_error_to_logstr(APIError err);
class APIFrameHelper {
public:
APIFrameHelper() = default;
explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info)
: socket_(std::move(socket)), client_info_(client_info) {}
explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket) : socket_(std::move(socket)) {}
// Get client name (null-terminated)
const char *get_client_name() const { return this->client_name_; }
// Get client peername/IP (null-terminated, cached at init time for availability after socket failure)
const char *get_client_peername() const { return this->client_peername_; }
// Set client name from buffer with length (truncates if needed)
void set_client_name(const char *name, size_t len) {
size_t copy_len = std::min(len, sizeof(this->client_name_) - 1);
memcpy(this->client_name_, name, copy_len);
this->client_name_[copy_len] = '\0';
}
virtual ~APIFrameHelper() = default;
virtual APIError init() = 0;
virtual APIError loop();
virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; }
std::string getpeername() { return socket_->getpeername(); }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); }
APIError close() {
state_ = State::CLOSED;
@@ -186,9 +195,10 @@ class APIFrameHelper {
std::array<std::unique_ptr<SendBuffer>, API_MAX_SEND_QUEUE> tx_buf_;
std::vector<uint8_t> rx_buf_;
// Pointer to client info (4 bytes on 32-bit)
// Note: The pointed-to ClientInfo object must outlive this APIFrameHelper instance.
const ClientInfo *client_info_{nullptr};
// Client name buffer - stores name from Hello message or initial peername
char client_name_[CLIENT_INFO_NAME_MAX_LEN]{};
// Cached peername/IP address - captured at init time for availability after socket failure
char client_peername_[socket::SOCKADDR_STR_LEN]{};
// Group smaller types together
uint16_t rx_buf_len_ = 0;

View File

@@ -27,8 +27,11 @@ 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__)
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) \

View File

@@ -9,8 +9,8 @@ namespace esphome::api {
class APINoiseFrameHelper final : public APIFrameHelper {
public:
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, APINoiseContext &ctx, const ClientInfo *client_info)
: APIFrameHelper(std::move(socket), client_info), ctx_(ctx) {
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, APINoiseContext &ctx)
: APIFrameHelper(std::move(socket)), ctx_(ctx) {
// Noise header structure:
// Pos 0: indicator (0x01)
// Pos 1-2: encrypted payload size (16-bit big-endian)

View File

@@ -1,7 +1,6 @@
#include "api_frame_helper_plaintext.h"
#ifdef USE_API
#ifdef USE_API_PLAINTEXT
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
@@ -21,8 +20,11 @@ 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__)
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) \

View File

@@ -7,8 +7,7 @@ namespace esphome::api {
class APIPlaintextFrameHelper final : public APIFrameHelper {
public:
APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info)
: APIFrameHelper(std::move(socket), client_info) {
explicit APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket) : APIFrameHelper(std::move(socket)) {
// Plaintext header structure (worst case):
// Pos 0: indicator (0x00)
// Pos 1-3: payload size varint (up to 3 bytes)

View File

@@ -125,15 +125,18 @@ void APIServer::loop() {
if (!sock)
break;
char peername[socket::SOCKADDR_STR_LEN];
sock->getpeername_to(peername);
// Check if we're at the connection limit
if (this->clients_.size() >= this->max_connections_) {
ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, sock->getpeername().c_str());
ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, peername);
// Immediately close - socket destructor will handle cleanup
sock.reset();
continue;
}
ESP_LOGD(TAG, "Accept %s", sock->getpeername().c_str());
ESP_LOGD(TAG, "Accept %s", peername);
auto *conn = new APIConnection(std::move(sock), this);
this->clients_.emplace_back(conn);
@@ -166,8 +169,7 @@ void APIServer::loop() {
// Network is down - disconnect all clients
for (auto &client : this->clients_) {
client->on_fatal_error();
ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(),
client->client_info_.peername.c_str());
client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("Network down; disconnect"));
}
// Continue to process and clean up the clients below
}
@@ -185,12 +187,12 @@ void APIServer::loop() {
// Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_.name, client->client_info_.peername);
this->client_disconnected_trigger_->trigger(std::string(client->get_name()), std::string(client->get_peername()));
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->unregister_active_action_calls_for_connection(client.get());
#endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.name.c_str());
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
// Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) {

View File

@@ -10,38 +10,37 @@ namespace esphome::aqi {
class AQICalculator : public AbstractAQICalculator {
public:
uint16_t get_aqi(uint16_t pm2_5_value, uint16_t pm10_0_value) override {
int pm2_5_index = calculate_index_(pm2_5_value, pm2_5_calculation_grid_);
int pm10_0_index = calculate_index_(pm10_0_value, pm10_0_calculation_grid_);
int pm2_5_index = calculate_index(pm2_5_value, PM2_5_GRID);
int pm10_0_index = calculate_index(pm10_0_value, PM10_0_GRID);
return (pm2_5_index < pm10_0_index) ? pm10_0_index : pm2_5_index;
}
protected:
static const int AMOUNT_OF_LEVELS = 6;
static constexpr int NUM_LEVELS = 6;
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
static constexpr int INDEX_GRID[NUM_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 9}, {10, 35}, {36, 55},
{56, 125}, {126, 225}, {226, INT_MAX}};
static constexpr int PM2_5_GRID[NUM_LEVELS][2] = {{0, 9}, {10, 35}, {36, 55}, {56, 125}, {126, 225}, {226, INT_MAX}};
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
{255, 354}, {355, 424}, {425, INT_MAX}};
static constexpr int PM10_0_GRID[NUM_LEVELS][2] = {{0, 54}, {55, 154}, {155, 254},
{255, 354}, {355, 424}, {425, INT_MAX}};
int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
int grid_index = get_grid_index_(value, array);
static int calculate_index(uint16_t value, const int array[NUM_LEVELS][2]) {
int grid_index = get_grid_index(value, array);
if (grid_index == -1) {
return -1;
}
int aqi_lo = index_grid_[grid_index][0];
int aqi_hi = index_grid_[grid_index][1];
int aqi_lo = INDEX_GRID[grid_index][0];
int aqi_hi = INDEX_GRID[grid_index][1];
int conc_lo = array[grid_index][0];
int conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
}
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
for (int i = 0; i < AMOUNT_OF_LEVELS; i++) {
static int get_grid_index(uint16_t value, const int array[NUM_LEVELS][2]) {
for (int i = 0; i < NUM_LEVELS; i++) {
if (value >= array[i][0] && value <= array[i][1]) {
return i;
}

View File

@@ -0,0 +1,52 @@
#include "aqi_sensor.h"
#include "esphome/core/log.h"
namespace esphome::aqi {
static const char *const TAG = "aqi";
void AQISensor::setup() {
if (this->pm_2_5_sensor_ != nullptr) {
this->pm_2_5_sensor_->add_on_state_callback([this](float value) {
this->pm_2_5_value_ = value;
// Defer calculation to avoid double-publishing if both sensors update in the same loop
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
if (this->pm_10_0_sensor_ != nullptr) {
this->pm_10_0_sensor_->add_on_state_callback([this](float value) {
this->pm_10_0_value_ = value;
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
}
void AQISensor::dump_config() {
ESP_LOGCONFIG(TAG, "AQI Sensor:");
ESP_LOGCONFIG(TAG, " Calculation Type: %s", this->aqi_calc_type_ == AQI_TYPE ? "AQI" : "CAQI");
if (this->pm_2_5_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " PM2.5 Sensor: '%s'", this->pm_2_5_sensor_->get_name().c_str());
}
if (this->pm_10_0_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " PM10 Sensor: '%s'", this->pm_10_0_sensor_->get_name().c_str());
}
LOG_SENSOR(" ", "AQI", this);
}
void AQISensor::calculate_aqi_() {
if (std::isnan(this->pm_2_5_value_) || std::isnan(this->pm_10_0_value_)) {
return;
}
AbstractAQICalculator *calculator = this->aqi_calculator_factory_.get_calculator(this->aqi_calc_type_);
if (calculator == nullptr) {
ESP_LOGW(TAG, "Unknown AQI calculator type");
return;
}
uint16_t aqi =
calculator->get_aqi(static_cast<uint16_t>(this->pm_2_5_value_), static_cast<uint16_t>(this->pm_10_0_value_));
this->publish_state(aqi);
}
} // namespace esphome::aqi

View File

@@ -0,0 +1,31 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "aqi_calculator_factory.h"
namespace esphome::aqi {
class AQISensor : public sensor::Sensor, public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_pm_2_5_sensor(sensor::Sensor *sensor) { this->pm_2_5_sensor_ = sensor; }
void set_pm_10_0_sensor(sensor::Sensor *sensor) { this->pm_10_0_sensor_ = sensor; }
void set_aqi_calculation_type(AQICalculatorType type) { this->aqi_calc_type_ = type; }
protected:
void calculate_aqi_();
sensor::Sensor *pm_2_5_sensor_{nullptr};
sensor::Sensor *pm_10_0_sensor_{nullptr};
AQICalculatorType aqi_calc_type_{AQI_TYPE};
AQICalculatorFactory aqi_calculator_factory_;
float pm_2_5_value_{NAN};
float pm_10_0_value_{NAN};
};
} // namespace esphome::aqi

View File

@@ -1,6 +1,5 @@
#pragma once
#include "esphome/core/log.h"
#include "abstract_aqi_calculator.h"
namespace esphome::aqi {
@@ -8,37 +7,37 @@ namespace esphome::aqi {
class CAQICalculator : public AbstractAQICalculator {
public:
uint16_t get_aqi(uint16_t pm2_5_value, uint16_t pm10_0_value) override {
int pm2_5_index = calculate_index_(pm2_5_value, pm2_5_calculation_grid_);
int pm10_0_index = calculate_index_(pm10_0_value, pm10_0_calculation_grid_);
int pm2_5_index = calculate_index(pm2_5_value, PM2_5_GRID);
int pm10_0_index = calculate_index(pm10_0_value, PM10_0_GRID);
return (pm2_5_index < pm10_0_index) ? pm10_0_index : pm2_5_index;
}
protected:
static const int AMOUNT_OF_LEVELS = 5;
static constexpr int NUM_LEVELS = 5;
int index_grid_[AMOUNT_OF_LEVELS][2] = {{0, 25}, {26, 50}, {51, 75}, {76, 100}, {101, 400}};
static constexpr int INDEX_GRID[NUM_LEVELS][2] = {{0, 25}, {26, 50}, {51, 75}, {76, 100}, {101, 400}};
int pm2_5_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 15}, {16, 30}, {31, 55}, {56, 110}, {111, 400}};
static constexpr int PM2_5_GRID[NUM_LEVELS][2] = {{0, 15}, {16, 30}, {31, 55}, {56, 110}, {111, 400}};
int pm10_0_calculation_grid_[AMOUNT_OF_LEVELS][2] = {{0, 25}, {26, 50}, {51, 90}, {91, 180}, {181, 400}};
static constexpr int PM10_0_GRID[NUM_LEVELS][2] = {{0, 25}, {26, 50}, {51, 90}, {91, 180}, {181, 400}};
int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
int grid_index = get_grid_index_(value, array);
static int calculate_index(uint16_t value, const int array[NUM_LEVELS][2]) {
int grid_index = get_grid_index(value, array);
if (grid_index == -1) {
return -1;
}
int aqi_lo = index_grid_[grid_index][0];
int aqi_hi = index_grid_[grid_index][1];
int aqi_lo = INDEX_GRID[grid_index][0];
int aqi_hi = INDEX_GRID[grid_index][1];
int conc_lo = array[grid_index][0];
int conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
}
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
for (int i = 0; i < AMOUNT_OF_LEVELS; i++) {
static int get_grid_index(uint16_t value, const int array[NUM_LEVELS][2]) {
for (int i = 0; i < NUM_LEVELS; i++) {
if (value >= array[i][0] && value <= array[i][1]) {
return i;
}

View File

@@ -0,0 +1,51 @@
import esphome.codegen as cg
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_PM_2_5,
CONF_PM_10_0,
DEVICE_CLASS_AQI,
STATE_CLASS_MEASUREMENT,
)
from . import AQI_CALCULATION_TYPE, CONF_CALCULATION_TYPE, aqi_ns
CODEOWNERS = ["@jasstrong"]
DEPENDENCIES = ["sensor"]
UNIT_INDEX = "index"
AQISensor = aqi_ns.class_("AQISensor", sensor.Sensor, cg.Component)
CONFIG_SCHEMA = (
sensor.sensor_schema(
AQISensor,
unit_of_measurement=UNIT_INDEX,
accuracy_decimals=0,
device_class=DEVICE_CLASS_AQI,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.Required(CONF_PM_2_5): cv.use_id(sensor.Sensor),
cv.Required(CONF_PM_10_0): cv.use_id(sensor.Sensor),
cv.Required(CONF_CALCULATION_TYPE): cv.enum(
AQI_CALCULATION_TYPE, upper=True
),
}
)
.extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
pm_2_5_sensor = await cg.get_variable(config[CONF_PM_2_5])
cg.add(var.set_pm_2_5_sensor(pm_2_5_sensor))
pm_10_0_sensor = await cg.get_variable(config[CONF_PM_10_0])
cg.add(var.set_pm_10_0_sensor(pm_10_0_sensor))
cg.add(var.set_aqi_calculation_type(config[CONF_CALCULATION_TYPE]))

View File

@@ -26,12 +26,12 @@ CONFIG_SCHEMA = cv.Schema({})
@coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT)
async def to_code(config):
if CORE.using_esp_idf:
# ESP-IDF needs the IDF component
if CORE.is_esp32:
# https://github.com/ESP32Async/AsyncTCP
from esphome.components.esp32 import add_idf_component
add_idf_component(name="esp32async/asynctcp", ref="3.4.91")
elif CORE.is_esp32 or CORE.is_libretiny:
elif CORE.is_libretiny:
# https://github.com/ESP32Async/AsyncTCP
cg.add_library("ESP32Async/AsyncTCP", "3.4.5")
elif CORE.is_esp8266:

View File

@@ -1,9 +1,8 @@
#pragma once
#include "esphome/core/defines.h"
#if (defined(USE_ESP32) || defined(USE_LIBRETINY)) && !defined(CLANG_TIDY)
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
// Use AsyncTCP library for ESP32 (Arduino or ESP-IDF) and LibreTiny
// But not for clang-tidy as the header file isn't present in that case
#include <AsyncTCP.h>
#elif defined(USE_ESP8266)
// Use ESPAsyncTCP library for ESP8266 (always Arduino)
@@ -12,6 +11,6 @@
// Use AsyncTCP_RP2040W library for RP2040
#include <AsyncTCP_RP2040W.h>
#else
// Use socket-based implementation for other platforms and clang-tidy
// Use socket-based implementation for other platforms
#include "async_tcp_socket.h"
#endif

View File

@@ -1,6 +1,7 @@
#include "async_tcp_socket.h"
#if defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS)
#if !defined(USE_ESP32) && !defined(USE_ESP8266) && !defined(USE_RP2040) && !defined(USE_LIBRETINY) && \
(defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS))
#include "esphome/components/network/util.h"
#include "esphome/core/log.h"
@@ -158,4 +159,4 @@ void AsyncClient::loop() {
} // namespace esphome::async_tcp
#endif // defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS)
#endif

View File

@@ -2,7 +2,8 @@
#include "esphome/core/defines.h"
#if defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS)
#if !defined(USE_ESP32) && !defined(USE_ESP8266) && !defined(USE_RP2040) && !defined(USE_LIBRETINY) && \
(defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS))
#include "esphome/components/socket/socket.h"
#include <functional>
@@ -69,5 +70,4 @@ class AsyncClient {
// Expose AsyncClient in global namespace to match library behavior
using esphome::async_tcp::AsyncClient; // NOLINT(google-global-names-in-headers)
#define ESPHOME_ASYNC_TCP_SOCKET_IMPL
#endif // defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS)
#endif

View File

@@ -1,7 +1,8 @@
#pragma once
#include <cinttypes>
#include <cstdio>
#include <ctime>
#include <string>
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
@@ -15,17 +16,13 @@ namespace ble_scanner {
class BLEScanner : public text_sensor::TextSensor, public esp32_ble_tracker::ESPBTDeviceListener, public Component {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override {
this->publish_state("{\"timestamp\":" + to_string(::time(nullptr)) +
","
"\"address\":\"" +
device.address_str() +
"\","
"\"rssi\":" +
to_string(device.get_rssi()) +
","
"\"name\":\"" +
device.get_name() + "\"}");
// Format JSON using stack buffer to avoid heap allocations from string concatenation
char buf[128];
char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
snprintf(buf, sizeof(buf), "{\"timestamp\":%" PRId64 ",\"address\":\"%s\",\"rssi\":%d,\"name\":\"%s\"}",
static_cast<int64_t>(::time(nullptr)), device.address_str_to(addr_buf), device.get_rssi(),
device.get_name().c_str());
this->publish_state(buf);
return true;
}
void dump_config() override;

View File

@@ -140,7 +140,10 @@ void CC1101Component::setup() {
this->write_(static_cast<Register>(i));
}
this->set_output_power(this->output_power_requested_);
this->strobe_(Command::RX);
if (!this->enter_rx_()) {
this->mark_failed();
return;
}
// Defer pin mode setup until after all components have completed setup()
// This handles the case where remote_transmitter runs after CC1101 and changes pin mode
@@ -163,8 +166,7 @@ void CC1101Component::loop() {
ESP_LOGW(TAG, "RX FIFO overflow, flushing");
this->enter_idle_();
this->strobe_(Command::FRX);
this->strobe_(Command::RX);
this->wait_for_state_(State::RX);
this->enter_rx_();
return;
}
@@ -181,8 +183,7 @@ void CC1101Component::loop() {
ESP_LOGW(TAG, "Invalid packet: rx_bytes %u, payload_length %u", rx_bytes, payload_length);
this->enter_idle_();
this->strobe_(Command::FRX);
this->strobe_(Command::RX);
this->wait_for_state_(State::RX);
this->enter_rx_();
return;
}
this->packet_.resize(payload_length);
@@ -203,8 +204,7 @@ void CC1101Component::loop() {
// Return to rx
this->enter_idle_();
this->strobe_(Command::FRX);
this->strobe_(Command::RX);
this->wait_for_state_(State::RX);
this->enter_rx_();
}
void CC1101Component::dump_config() {
@@ -235,9 +235,8 @@ void CC1101Component::begin_tx() {
if (this->gdo0_pin_ != nullptr) {
this->gdo0_pin_->pin_mode(gpio::FLAG_OUTPUT);
}
this->strobe_(Command::TX);
if (!this->wait_for_state_(State::TX, 50)) {
ESP_LOGW(TAG, "Timed out waiting for TX state!");
if (!this->enter_tx_()) {
ESP_LOGW(TAG, "Failed to enter TX state!");
}
}
@@ -246,7 +245,9 @@ void CC1101Component::begin_rx() {
if (this->gdo0_pin_ != nullptr) {
this->gdo0_pin_->pin_mode(gpio::FLAG_INPUT);
}
this->strobe_(Command::RX);
if (!this->enter_rx_()) {
ESP_LOGW(TAG, "Failed to enter RX state!");
}
}
void CC1101Component::reset() {
@@ -272,11 +273,33 @@ bool CC1101Component::wait_for_state_(State target_state, uint32_t timeout_ms) {
return false;
}
bool CC1101Component::enter_calibrated_(State target_state, Command cmd) {
// The PLL must be recalibrated until PLL lock is achieved
for (uint8_t retries = PLL_LOCK_RETRIES; retries > 0; retries--) {
this->strobe_(cmd);
if (!this->wait_for_state_(target_state)) {
return false;
}
this->read_(Register::FSCAL1);
if (this->state_.FSCAL1 != FSCAL1_PLL_NOT_LOCKED) {
return true;
}
ESP_LOGW(TAG, "PLL lock failed, retrying calibration");
this->enter_idle_();
}
ESP_LOGE(TAG, "PLL lock failed after retries");
return false;
}
void CC1101Component::enter_idle_() {
this->strobe_(Command::IDLE);
this->wait_for_state_(State::IDLE);
}
bool CC1101Component::enter_rx_() { return this->enter_calibrated_(State::RX, Command::RX); }
bool CC1101Component::enter_tx_() { return this->enter_calibrated_(State::TX, Command::TX); }
uint8_t CC1101Component::strobe_(Command cmd) {
uint8_t index = static_cast<uint8_t>(cmd);
if (cmd < Command::RES || cmd > Command::NOP) {
@@ -338,18 +361,26 @@ CC1101Error CC1101Component::transmit_packet(const std::vector<uint8_t> &packet)
this->write_(Register::FIFO, static_cast<uint8_t>(packet.size()));
}
this->write_(Register::FIFO, packet.data(), packet.size());
// Calibrate PLL
if (!this->enter_calibrated_(State::FSTXON, Command::FSTXON)) {
ESP_LOGW(TAG, "PLL lock failed during TX");
this->enter_idle_();
this->enter_rx_();
return CC1101Error::PLL_LOCK;
}
// Transmit packet
this->strobe_(Command::TX);
if (!this->wait_for_state_(State::IDLE, 1000)) {
ESP_LOGW(TAG, "TX timeout");
this->enter_idle_();
this->strobe_(Command::RX);
this->wait_for_state_(State::RX);
this->enter_rx_();
return CC1101Error::TIMEOUT;
}
// Return to rx
this->strobe_(Command::RX);
this->wait_for_state_(State::RX);
this->enter_rx_();
return CC1101Error::NONE;
}
@@ -406,7 +437,7 @@ void CC1101Component::set_frequency(float value) {
this->write_(Register::FREQ2);
this->write_(Register::FREQ1);
this->write_(Register::FREQ0);
this->strobe_(Command::RX);
this->enter_rx_();
}
}
@@ -433,7 +464,7 @@ void CC1101Component::set_channel(uint8_t value) {
if (this->initialized_) {
this->enter_idle_();
this->write_(Register::CHANNR);
this->strobe_(Command::RX);
this->enter_rx_();
}
}
@@ -502,7 +533,7 @@ void CC1101Component::set_modulation_type(Modulation value) {
this->set_output_power(this->output_power_requested_);
this->write_(Register::MDMCFG2);
this->write_(Register::FREND0);
this->strobe_(Command::RX);
this->enter_rx_();
}
}

View File

@@ -9,7 +9,7 @@
namespace esphome::cc1101 {
enum class CC1101Error { NONE = 0, TIMEOUT, PARAMS, CRC_ERROR, FIFO_OVERFLOW };
enum class CC1101Error { NONE = 0, TIMEOUT, PARAMS, CRC_ERROR, FIFO_OVERFLOW, PLL_LOCK };
class CC1101Component : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
@@ -103,7 +103,10 @@ class CC1101Component : public Component,
// State Management
bool wait_for_state_(State target_state, uint32_t timeout_ms = 100);
bool enter_calibrated_(State target_state, Command cmd);
void enter_idle_();
bool enter_rx_();
bool enter_tx_();
};
// Action Wrappers

View File

@@ -9,6 +9,9 @@ static constexpr float XTAL_FREQUENCY = 26000000;
static constexpr float RSSI_OFFSET = 74.0f;
static constexpr float RSSI_STEP = 0.5f;
static constexpr uint8_t FSCAL1_PLL_NOT_LOCKED = 0x3F;
static constexpr uint8_t PLL_LOCK_RETRIES = 3;
static constexpr uint8_t STATUS_CRC_OK_MASK = 0x80;
static constexpr uint8_t STATUS_LQI_MASK = 0x7F;

View File

@@ -268,7 +268,7 @@ bool Dsmr::parse_telegram() {
// publish the telegram, after publishing the sensors so it can also trigger action based on latest values
if (this->s_telegram_ != nullptr) {
this->s_telegram_->publish_state(std::string(this->telegram_, this->bytes_read_));
this->s_telegram_->publish_state(this->telegram_, this->bytes_read_);
}
return true;
}

View File

@@ -429,9 +429,11 @@ void ESP32Camera::framebuffer_task(void *pv) {
camera_fb_t *framebuffer = esp_camera_fb_get();
xQueueSend(that->framebuffer_get_queue_, &framebuffer, portMAX_DELAY);
// Only wake the main loop if there's a pending request to consume the frame
#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
if (that->has_requested_image_()) {
App.wake_loop_threadsafe();
}
#endif
// return is no-op for config with 1 fb
xQueueReceive(that->framebuffer_return_queue_, &framebuffer, portMAX_DELAY);
esp_camera_fb_return(framebuffer);

View File

@@ -398,9 +398,12 @@ void ESP32ImprovComponent::check_wifi_connection_() {
#ifdef USE_ESP32_IMPROV_NEXT_URL
// Add next_url if configured (should be first per Improv BLE spec)
std::string next_url = this->get_formatted_next_url_();
if (!next_url.empty()) {
url_strings[url_count++] = std::move(next_url);
{
char url_buffer[384];
size_t len = this->get_formatted_next_url_(url_buffer, sizeof(url_buffer));
if (len > 0) {
url_strings[url_count++] = std::string(url_buffer, len);
}
}
#endif

View File

@@ -4,6 +4,7 @@
#include "esphome/components/sha256/sha256.h"
#endif
#include "esphome/components/network/util.h"
#include "esphome/components/socket/socket.h"
#include "esphome/components/ota/ota_backend.h"
#include "esphome/components/ota/ota_backend_esp8266.h"
#include "esphome/components/ota/ota_backend_arduino_libretiny.h"
@@ -443,7 +444,9 @@ void ESPHomeOTAComponent::log_socket_error_(const LogString *msg) {
void ESPHomeOTAComponent::log_read_error_(const LogString *what) { ESP_LOGW(TAG, "Read %s failed", LOG_STR_ARG(what)); }
void ESPHomeOTAComponent::log_start_(const LogString *phase) {
ESP_LOGD(TAG, "Starting %s from %s", LOG_STR_ARG(phase), this->client_->getpeername().c_str());
char peername[socket::SOCKADDR_STR_LEN];
this->client_->getpeername_to(peername);
ESP_LOGD(TAG, "Starting %s from %s", LOG_STR_ARG(phase), peername);
}
void ESPHomeOTAComponent::log_remote_closed_(const LogString *during) {
@@ -560,7 +563,9 @@ bool ESPHomeOTAComponent::handle_auth_send_() {
// CRITICAL ESP32-S3 HARDWARE SHA ACCELERATION: Hash object must stay in same stack frame
// (no passing to other functions). All hash operations must happen in this function.
sha256::SHA256 hasher;
// NOTE: On ESP32-S3 with IDF 5.5.x, the SHA256 context must be properly aligned for
// hardware SHA acceleration DMA operations.
alignas(32) sha256::SHA256 hasher;
const size_t hex_size = hasher.get_size() * 2;
const size_t nonce_len = hasher.get_size() / 4;
@@ -634,7 +639,9 @@ bool ESPHomeOTAComponent::handle_auth_read_() {
// CRITICAL ESP32-S3 HARDWARE SHA ACCELERATION: Hash object must stay in same stack frame
// (no passing to other functions). All hash operations must happen in this function.
sha256::SHA256 hasher;
// NOTE: On ESP32-S3 with IDF 5.5.x, the SHA256 context must be properly aligned for
// hardware SHA acceleration DMA operations.
alignas(32) sha256::SHA256 hasher;
hasher.init();
hasher.add(this->password_.c_str(), this->password_.length());

View File

@@ -14,12 +14,15 @@ class IPAddressEthernetInfo : public PollingComponent, public text_sensor::TextS
auto ips = ethernet::global_eth_component->get_ip_addresses();
if (ips != this->last_ips_) {
this->last_ips_ = ips;
this->publish_state(ips[0].str());
char buf[network::IP_ADDRESS_BUFFER_SIZE];
ips[0].str_to(buf);
this->publish_state(buf);
uint8_t sensor = 0;
for (auto &ip : ips) {
if (ip.is_set()) {
if (this->ip_sensors_[sensor] != nullptr) {
this->ip_sensors_[sensor]->publish_state(ip.str());
ip.str_to(buf);
this->ip_sensors_[sensor]->publish_state(buf);
}
sensor++;
}
@@ -64,7 +67,10 @@ class DNSAddressEthernetInfo : public PollingComponent, public text_sensor::Text
class MACAddressEthernetInfo : public Component, public text_sensor::TextSensor {
public:
void setup() override { this->publish_state(ethernet::global_eth_component->get_eth_mac_address_pretty()); }
void setup() override {
char buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
this->publish_state(ethernet::global_eth_component->get_eth_mac_address_pretty_into_buffer(buf));
}
float get_setup_priority() const override { return setup_priority::ETHERNET; }
void dump_config() override;
};

View File

@@ -181,6 +181,11 @@ void HeatpumpIRClimate::transmit_state() {
power_mode_cmd = POWER_ON;
operating_mode_cmd = MODE_HEAT;
break;
// Map HEAT_COOL to hardware AUTO mode (automatic heat/cool changeover based on temperature).
// In hardware AUTO mode, the device automatically switches between heating and cooling
// based on the current temperature versus the target temperature.
// See https://github.com/esphome/esphome/issues/11161 for further discussion.
case climate::CLIMATE_MODE_HEAT_COOL:
case climate::CLIMATE_MODE_AUTO:
power_mode_cmd = POWER_ON;
operating_mode_cmd = MODE_AUTO;

View File

@@ -1,3 +1,5 @@
import logging
import esphome.codegen as cg
from esphome.components import i2c, sensor
from esphome.components.aqi import AQI_CALCULATION_TYPE, CONF_AQI, CONF_CALCULATION_TYPE
@@ -16,6 +18,8 @@ from esphome.const import (
UNIT_MICROGRAMS_PER_CUBIC_METER,
)
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ["i2c"]
AUTO_LOAD = ["aqi"]
CODEOWNERS = ["@freekode"]
@@ -99,7 +103,12 @@ async def to_code(config):
sens = await sensor.new_sensor(config[CONF_PM_10_0])
cg.add(var.set_pm_10_0_sensor(sens))
# Remove before 2026.12.0
if CONF_AQI in config:
_LOGGER.warning(
"The 'aqi' option in hm3301 is deprecated, "
"please use the standalone 'aqi' sensor platform instead."
)
sens = await sensor.new_sensor(config[CONF_AQI])
cg.add(var.set_aqi_sensor(sens))
cg.add(var.set_aqi_calculation_type(config[CONF_AQI][CONF_CALCULATION_TYPE]))

View File

@@ -15,7 +15,7 @@ void HomeassistantTextSensor::setup() {
} else {
ESP_LOGD(TAG, "'%s': Got state '%s'", this->entity_id_, state.c_str());
}
this->publish_state(state.str());
this->publish_state(state.c_str(), state.size());
});
}
void HomeassistantTextSensor::dump_config() {

View File

@@ -1,5 +1,6 @@
#include "improv_base.h"
#include <cstring>
#include "esphome/components/network/util.h"
#include "esphome/core/application.h"
#include "esphome/core/defines.h"
@@ -13,37 +14,54 @@ static constexpr size_t DEVICE_NAME_PLACEHOLDER_LEN = sizeof(DEVICE_NAME_PLACEHO
static constexpr const char IP_ADDRESS_PLACEHOLDER[] = "{{ip_address}}";
static constexpr size_t IP_ADDRESS_PLACEHOLDER_LEN = sizeof(IP_ADDRESS_PLACEHOLDER) - 1;
static void replace_all_in_place(std::string &str, const char *placeholder, size_t placeholder_len,
const std::string &replacement) {
size_t pos = 0;
const size_t replacement_len = replacement.length();
while ((pos = str.find(placeholder, pos)) != std::string::npos) {
str.replace(pos, placeholder_len, replacement);
pos += replacement_len;
/// Copy src to dest, returning pointer past last written char. Stops at end or if src is null.
static char *copy_to_buffer(char *dest, const char *end, const char *src) {
if (src == nullptr) {
return dest;
}
while (*src != '\0' && dest < end) {
*dest++ = *src++;
}
return dest;
}
std::string ImprovBase::get_formatted_next_url_() {
if (this->next_url_.empty()) {
return "";
size_t ImprovBase::get_formatted_next_url_(char *buffer, size_t buffer_size) {
if (this->next_url_ == nullptr || buffer_size == 0) {
if (buffer_size > 0) {
buffer[0] = '\0';
}
return 0;
}
std::string formatted_url = this->next_url_;
// Replace all occurrences of {{device_name}}
replace_all_in_place(formatted_url, DEVICE_NAME_PLACEHOLDER, DEVICE_NAME_PLACEHOLDER_LEN, App.get_name());
// Replace all occurrences of {{ip_address}}
// Get IP address once for replacement
const char *ip_str = nullptr;
char ip_buffer[network::IP_ADDRESS_BUFFER_SIZE];
for (auto &ip : network::get_ip_addresses()) {
if (ip.is_ip4()) {
replace_all_in_place(formatted_url, IP_ADDRESS_PLACEHOLDER, IP_ADDRESS_PLACEHOLDER_LEN, ip.str());
ip.str_to(ip_buffer);
ip_str = ip_buffer;
break;
}
}
// Note: {{esphome_version}} is replaced at code generation time in Python
const char *device_name = App.get_name().c_str();
char *out = buffer;
const char *end = buffer + buffer_size - 1;
return formatted_url;
// Note: {{esphome_version}} is replaced at code generation time in Python
for (const char *p = this->next_url_; *p != '\0' && out < end;) {
if (strncmp(p, DEVICE_NAME_PLACEHOLDER, DEVICE_NAME_PLACEHOLDER_LEN) == 0) {
out = copy_to_buffer(out, end, device_name);
p += DEVICE_NAME_PLACEHOLDER_LEN;
} else if (ip_str != nullptr && strncmp(p, IP_ADDRESS_PLACEHOLDER, IP_ADDRESS_PLACEHOLDER_LEN) == 0) {
out = copy_to_buffer(out, end, ip_str);
p += IP_ADDRESS_PLACEHOLDER_LEN;
} else {
*out++ = *p++;
}
}
*out = '\0';
return out - buffer;
}
#endif

View File

@@ -1,6 +1,6 @@
#pragma once
#include <string>
#include <cstddef>
#include "esphome/core/defines.h"
namespace esphome {
@@ -9,13 +9,14 @@ namespace improv_base {
class ImprovBase {
public:
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
void set_next_url(const std::string &next_url) { this->next_url_ = next_url; }
void set_next_url(const char *next_url) { this->next_url_ = next_url; }
#endif
protected:
#if defined(USE_ESP32_IMPROV_NEXT_URL) || defined(USE_IMPROV_SERIAL_NEXT_URL)
std::string get_formatted_next_url_();
std::string next_url_;
/// Format next_url_ into buffer, replacing placeholders. Returns length written.
size_t get_formatted_next_url_(char *buffer, size_t buffer_size);
const char *next_url_{nullptr};
#endif
};

View File

@@ -182,8 +182,12 @@ void ImprovSerialComponent::write_data_(const uint8_t *data, const size_t size)
std::vector<uint8_t> ImprovSerialComponent::build_rpc_settings_response_(improv::Command command) {
std::vector<std::string> urls;
#ifdef USE_IMPROV_SERIAL_NEXT_URL
if (!this->next_url_.empty()) {
urls.push_back(this->get_formatted_next_url_());
{
char url_buffer[384];
size_t len = this->get_formatted_next_url_(url_buffer, sizeof(url_buffer));
if (len > 0) {
urls.emplace_back(url_buffer, len);
}
}
#endif
#ifdef USE_WEBSERVER

View File

@@ -4,8 +4,7 @@
#include "esphome/core/log.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.custom";
@@ -29,7 +28,6 @@ bool CustomMQTTDevice::publish_json(const std::string &topic, const json::json_b
}
bool CustomMQTTDevice::is_connected() { return global_mqtt_client != nullptr && global_mqtt_client->is_connected(); }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#include "esphome/core/component.h"
#include "mqtt_client.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
/** This class is a helper class for custom components that communicate using
* MQTT. It has 5 helper functions that you can use (square brackets indicate optional):
@@ -214,7 +213,6 @@ void CustomMQTTDevice::subscribe_json(const std::string &topic, void (T::*callba
global_mqtt_client->subscribe_json(topic, f, qos);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_ALARM_CONTROL_PANEL
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.alarm_control_panel";
@@ -123,8 +122,7 @@ bool MQTTAlarmControlPanelComponent::publish_state() {
return this->publish(this->get_state_topic_(), state_s);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "mqtt_component.h"
#include "esphome/components/alarm_control_panel/alarm_control_panel.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTAlarmControlPanelComponent : public mqtt::MQTTComponent {
public:
@@ -32,8 +31,7 @@ class MQTTAlarmControlPanelComponent : public mqtt::MQTTComponent {
alarm_control_panel::AlarmControlPanel *alarm_control_panel_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#include "esphome/components/network/ip_address.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
enum class MQTTClientDisconnectReason : int8_t {
TCP_DISCONNECTED = 0,
@@ -67,6 +66,5 @@ class MQTTBackend {
virtual void loop() {}
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif

View File

@@ -8,8 +8,7 @@
#include "esphome/core/log.h"
#include "esphome/core/application.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.idf";
@@ -270,7 +269,6 @@ bool MQTTBackendESP32::enqueue_(MqttQueueTypeT type, const char *topic, int qos,
}
#endif // USE_MQTT_IDF_ENQUEUE
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_ESP32
#endif

View File

@@ -15,8 +15,7 @@
#include "esphome/core/lock_free_queue.h"
#include "esphome/core/event_pool.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
struct Event {
esp_mqtt_event_id_t event_id;
@@ -273,8 +272,7 @@ class MQTTBackendESP32 final : public MQTTBackend {
#endif
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif

View File

@@ -6,8 +6,7 @@
#include <AsyncMqttClient.h>
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTBackendESP8266 final : public MQTTBackend {
public:
@@ -67,8 +66,7 @@ class MQTTBackendESP8266 final : public MQTTBackend {
AsyncMqttClient mqtt_client_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // defined(USE_ESP8266)
#endif

View File

@@ -6,8 +6,7 @@
#include <AsyncMqttClient.h>
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTBackendLibreTiny final : public MQTTBackend {
public:
@@ -67,8 +66,7 @@ class MQTTBackendLibreTiny final : public MQTTBackend {
AsyncMqttClient mqtt_client_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // defined(USE_LIBRETINY)
#endif

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_BINARY_SENSOR
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.binary_sensor";
@@ -57,8 +56,7 @@ bool MQTTBinarySensorComponent::publish_state(bool state) {
return this->publish(this->get_state_topic_(), state_s);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -7,8 +7,7 @@
#include "mqtt_component.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTBinarySensorComponent : public mqtt::MQTTComponent {
public:
@@ -36,8 +35,7 @@ class MQTTBinarySensorComponent : public mqtt::MQTTComponent {
binary_sensor::BinarySensor *binary_sensor_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_BUTTON
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.button";
@@ -43,8 +42,7 @@ void MQTTButtonComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCon
std::string MQTTButtonComponent::component_type() const { return "button"; }
const EntityBase *MQTTButtonComponent::get_entity() const { return this->button_; }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/button/button.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTButtonComponent : public mqtt::MQTTComponent {
public:
@@ -33,8 +32,7 @@ class MQTTButtonComponent : public mqtt::MQTTComponent {
button::Button *button_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -22,8 +22,7 @@
#include "esphome/components/dashboard_import/dashboard_import.h"
#endif
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt";
@@ -751,7 +750,6 @@ void MQTTMessageTrigger::dump_config() {
}
float MQTTMessageTrigger::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTT

View File

@@ -24,8 +24,7 @@
#include <vector>
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
/** Callback for MQTT events.
*/
@@ -462,7 +461,6 @@ template<typename... Ts> class MQTTDisableAction : public Action<Ts...> {
MQTTClientComponent *parent_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_CLIMATE
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.climate";
@@ -460,8 +459,7 @@ bool MQTTClimateComponent::publish_state_() {
return success;
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/climate/climate.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTClimateComponent : public mqtt::MQTTComponent {
public:
@@ -49,8 +48,7 @@ class MQTTClimateComponent : public mqtt::MQTTComponent {
climate::Climate *device_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -9,8 +9,7 @@
#include "mqtt_const.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.component";
@@ -306,7 +305,6 @@ bool MQTTComponent::is_internal() {
return this->get_entity()->is_internal();
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTT

View File

@@ -11,8 +11,7 @@
#include "esphome/core/string_ref.h"
#include "mqtt_client.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
/// Simple Helper struct used for Home Assistant MQTT send_discovery().
struct SendDiscoveryConfig {
@@ -205,7 +204,6 @@ class MQTTComponent : public Component {
bool resend_state_{false};
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_MQTt

View File

@@ -1,547 +1,332 @@
#pragma once
#include "esphome/core/defines.h"
#include "esphome/core/progmem.h"
#ifdef USE_MQTT
namespace esphome {
namespace mqtt {
// MQTT JSON Key Constants for Home Assistant Discovery
//
// This file defines string constants used as JSON keys in MQTT discovery payloads
// for Home Assistant integration. These are used exclusively with ArduinoJson as:
// root[MQTT_DEVICE_CLASS] = "temperature";
//
// Implementation:
// - ESP8266: Stores strings in PROGMEM (flash) using __FlashStringHelper* pointers.
// ArduinoJson recognizes this type and reads from flash memory.
// - Other platforms: Uses constexpr const char* for compile-time optimization.
// - USE_MQTT_ABBREVIATIONS: When defined, uses shortened key names to reduce message size.
//
// Adding new keys:
// Add a single line to MQTT_KEYS_LIST: X(MQTT_NEW_KEY, "abbr", "full_name")
// The X-macro will generate the appropriate constants for each platform.
//
// Note: Other MQTT_* constants (e.g., MQTT_CLIENT_CONNECTED, MQTT_LEGACY_UNIQUE_ID_GENERATOR)
// are C++ enums defined in mqtt_client.h and mqtt_backend*.h - unrelated to these JSON keys.
// X-macro list: MQTT_KEYS_LIST(X) calls X(name, abbr, full) for each key
// clang-format off
#define MQTT_KEYS_LIST(X) \
X(MQTT_ACTION_TEMPLATE, "act_tpl", "action_template") \
X(MQTT_ACTION_TOPIC, "act_t", "action_topic") \
X(MQTT_AUTOMATION_TYPE, "atype", "automation_type") \
X(MQTT_AUX_COMMAND_TOPIC, "aux_cmd_t", "aux_command_topic") \
X(MQTT_AUX_STATE_TEMPLATE, "aux_stat_tpl", "aux_state_template") \
X(MQTT_AUX_STATE_TOPIC, "aux_stat_t", "aux_state_topic") \
X(MQTT_AVAILABILITY, "avty", "availability") \
X(MQTT_AVAILABILITY_MODE, "avty_mode", "availability_mode") \
X(MQTT_AVAILABILITY_TOPIC, "avty_t", "availability_topic") \
X(MQTT_AWAY_MODE_COMMAND_TOPIC, "away_mode_cmd_t", "away_mode_command_topic") \
X(MQTT_AWAY_MODE_STATE_TEMPLATE, "away_mode_stat_tpl", "away_mode_state_template") \
X(MQTT_AWAY_MODE_STATE_TOPIC, "away_mode_stat_t", "away_mode_state_topic") \
X(MQTT_BATTERY_LEVEL_TEMPLATE, "bat_lev_tpl", "battery_level_template") \
X(MQTT_BATTERY_LEVEL_TOPIC, "bat_lev_t", "battery_level_topic") \
X(MQTT_BLUE_TEMPLATE, "b_tpl", "blue_template") \
X(MQTT_BRIGHTNESS_COMMAND_TOPIC, "bri_cmd_t", "brightness_command_topic") \
X(MQTT_BRIGHTNESS_SCALE, "bri_scl", "brightness_scale") \
X(MQTT_BRIGHTNESS_STATE_TOPIC, "bri_stat_t", "brightness_state_topic") \
X(MQTT_BRIGHTNESS_TEMPLATE, "bri_tpl", "brightness_template") \
X(MQTT_BRIGHTNESS_VALUE_TEMPLATE, "bri_val_tpl", "brightness_value_template") \
X(MQTT_CHARGING_TEMPLATE, "chrg_tpl", "charging_template") \
X(MQTT_CHARGING_TOPIC, "chrg_t", "charging_topic") \
X(MQTT_CLEANING_TEMPLATE, "cln_tpl", "cleaning_template") \
X(MQTT_CLEANING_TOPIC, "cln_t", "cleaning_topic") \
X(MQTT_CODE_ARM_REQUIRED, "cod_arm_req", "code_arm_required") \
X(MQTT_CODE_DISARM_REQUIRED, "cod_dis_req", "code_disarm_required") \
X(MQTT_COLOR_MODE, "clrm", "color_mode") \
X(MQTT_COLOR_MODE_STATE_TOPIC, "clrm_stat_t", "color_mode_state_topic") \
X(MQTT_COLOR_MODE_VALUE_TEMPLATE, "clrm_val_tpl", "color_mode_value_template") \
X(MQTT_COLOR_TEMP_COMMAND_TEMPLATE, "clr_temp_cmd_tpl", "color_temp_command_template") \
X(MQTT_COLOR_TEMP_COMMAND_TOPIC, "clr_temp_cmd_t", "color_temp_command_topic") \
X(MQTT_COLOR_TEMP_STATE_TOPIC, "clr_temp_stat_t", "color_temp_state_topic") \
X(MQTT_COLOR_TEMP_TEMPLATE, "clr_temp_tpl", "color_temp_template") \
X(MQTT_COLOR_TEMP_VALUE_TEMPLATE, "clr_temp_val_tpl", "color_temp_value_template") \
X(MQTT_COMMAND_OFF_TEMPLATE, "cmd_off_tpl", "command_off_template") \
X(MQTT_COMMAND_ON_TEMPLATE, "cmd_on_tpl", "command_on_template") \
X(MQTT_COMMAND_RETAIN, "ret", "retain") \
X(MQTT_COMMAND_TEMPLATE, "cmd_tpl", "command_template") \
X(MQTT_COMMAND_TOPIC, "cmd_t", "command_topic") \
X(MQTT_CONFIGURATION_URL, "cu", "configuration_url") \
X(MQTT_CURRENT_HUMIDITY_TEMPLATE, "curr_hum_tpl", "current_humidity_template") \
X(MQTT_CURRENT_HUMIDITY_TOPIC, "curr_hum_t", "current_humidity_topic") \
X(MQTT_CURRENT_TEMPERATURE_STEP, "precision", "precision") \
X(MQTT_CURRENT_TEMPERATURE_TEMPLATE, "curr_temp_tpl", "current_temperature_template") \
X(MQTT_CURRENT_TEMPERATURE_TOPIC, "curr_temp_t", "current_temperature_topic") \
X(MQTT_DEVICE, "dev", "device") \
X(MQTT_DEVICE_CLASS, "dev_cla", "device_class") \
X(MQTT_DEVICE_CONNECTIONS, "cns", "connections") \
X(MQTT_DEVICE_IDENTIFIERS, "ids", "identifiers") \
X(MQTT_DEVICE_MANUFACTURER, "mf", "manufacturer") \
X(MQTT_DEVICE_MODEL, "mdl", "model") \
X(MQTT_DEVICE_NAME, "name", "name") \
X(MQTT_DEVICE_SUGGESTED_AREA, "sa", "suggested_area") \
X(MQTT_DEVICE_SW_VERSION, "sw", "sw_version") \
X(MQTT_DEVICE_HW_VERSION, "hw", "hw_version") \
X(MQTT_DIRECTION_COMMAND_TOPIC, "dir_cmd_t", "direction_command_topic") \
X(MQTT_DIRECTION_STATE_TOPIC, "dir_stat_t", "direction_state_topic") \
X(MQTT_DOCKED_TEMPLATE, "dock_tpl", "docked_template") \
X(MQTT_DOCKED_TOPIC, "dock_t", "docked_topic") \
X(MQTT_EFFECT_COMMAND_TOPIC, "fx_cmd_t", "effect_command_topic") \
X(MQTT_EFFECT_LIST, "fx_list", "effect_list") \
X(MQTT_EFFECT_STATE_TOPIC, "fx_stat_t", "effect_state_topic") \
X(MQTT_EFFECT_TEMPLATE, "fx_tpl", "effect_template") \
X(MQTT_EFFECT_VALUE_TEMPLATE, "fx_val_tpl", "effect_value_template") \
X(MQTT_ENABLED_BY_DEFAULT, "en", "enabled_by_default") \
X(MQTT_ENTITY_CATEGORY, "ent_cat", "entity_category") \
X(MQTT_ERROR_TEMPLATE, "err_tpl", "error_template") \
X(MQTT_ERROR_TOPIC, "err_t", "error_topic") \
X(MQTT_EVENT_TYPE, "event_type", "event_type") \
X(MQTT_EVENT_TYPES, "evt_typ", "event_types") \
X(MQTT_EXPIRE_AFTER, "exp_aft", "expire_after") \
X(MQTT_FAN_MODE_COMMAND_TEMPLATE, "fan_mode_cmd_tpl", "fan_mode_command_template") \
X(MQTT_FAN_MODE_COMMAND_TOPIC, "fan_mode_cmd_t", "fan_mode_command_topic") \
X(MQTT_FAN_MODE_STATE_TEMPLATE, "fan_mode_stat_tpl", "fan_mode_state_template") \
X(MQTT_FAN_MODE_STATE_TOPIC, "fan_mode_stat_t", "fan_mode_state_topic") \
X(MQTT_FAN_SPEED_LIST, "fanspd_lst", "fan_speed_list") \
X(MQTT_FAN_SPEED_TEMPLATE, "fanspd_tpl", "fan_speed_template") \
X(MQTT_FAN_SPEED_TOPIC, "fanspd_t", "fan_speed_topic") \
X(MQTT_FLASH_TIME_LONG, "flsh_tlng", "flash_time_long") \
X(MQTT_FLASH_TIME_SHORT, "flsh_tsht", "flash_time_short") \
X(MQTT_FORCE_UPDATE, "frc_upd", "force_update") \
X(MQTT_GREEN_TEMPLATE, "g_tpl", "green_template") \
X(MQTT_HOLD_COMMAND_TEMPLATE, "hold_cmd_tpl", "hold_command_template") \
X(MQTT_HOLD_COMMAND_TOPIC, "hold_cmd_t", "hold_command_topic") \
X(MQTT_HOLD_STATE_TEMPLATE, "hold_stat_tpl", "hold_state_template") \
X(MQTT_HOLD_STATE_TOPIC, "hold_stat_t", "hold_state_topic") \
X(MQTT_HS_COMMAND_TOPIC, "hs_cmd_t", "hs_command_topic") \
X(MQTT_HS_STATE_TOPIC, "hs_stat_t", "hs_state_topic") \
X(MQTT_HS_VALUE_TEMPLATE, "hs_val_tpl", "hs_value_template") \
X(MQTT_ICON, "ic", "icon") \
X(MQTT_INITIAL, "init", "initial") \
X(MQTT_JSON_ATTRIBUTES, "json_attr", "json_attributes") \
X(MQTT_JSON_ATTRIBUTES_TEMPLATE, "json_attr_tpl", "json_attributes_template") \
X(MQTT_JSON_ATTRIBUTES_TOPIC, "json_attr_t", "json_attributes_topic") \
X(MQTT_LAST_RESET_TOPIC, "lrst_t", "last_reset_topic") \
X(MQTT_LAST_RESET_VALUE_TEMPLATE, "lrst_val_tpl", "last_reset_value_template") \
X(MQTT_MAX, "max", "max") \
X(MQTT_MAX_HUMIDITY, "max_hum", "max_humidity") \
X(MQTT_MAX_MIREDS, "max_mirs", "max_mireds") \
X(MQTT_MAX_TEMP, "max_temp", "max_temp") \
X(MQTT_MIN, "min", "min") \
X(MQTT_MIN_HUMIDITY, "min_hum", "min_humidity") \
X(MQTT_MIN_MIREDS, "min_mirs", "min_mireds") \
X(MQTT_MIN_TEMP, "min_temp", "min_temp") \
X(MQTT_MODE, "mode", "mode") \
X(MQTT_MODE_COMMAND_TEMPLATE, "mode_cmd_tpl", "mode_command_template") \
X(MQTT_MODE_COMMAND_TOPIC, "mode_cmd_t", "mode_command_topic") \
X(MQTT_MODE_STATE_TEMPLATE, "mode_stat_tpl", "mode_state_template") \
X(MQTT_MODE_STATE_TOPIC, "mode_stat_t", "mode_state_topic") \
X(MQTT_MODES, "modes", "modes") \
X(MQTT_NAME, "name", "name") \
X(MQTT_OBJECT_ID, "obj_id", "object_id") \
X(MQTT_OFF_DELAY, "off_dly", "off_delay") \
X(MQTT_ON_COMMAND_TYPE, "on_cmd_type", "on_command_type") \
X(MQTT_OPTIMISTIC, "opt", "optimistic") \
X(MQTT_OPTIONS, "ops", "options") \
X(MQTT_OSCILLATION_COMMAND_TEMPLATE, "osc_cmd_tpl", "oscillation_command_template") \
X(MQTT_OSCILLATION_COMMAND_TOPIC, "osc_cmd_t", "oscillation_command_topic") \
X(MQTT_OSCILLATION_STATE_TOPIC, "osc_stat_t", "oscillation_state_topic") \
X(MQTT_OSCILLATION_VALUE_TEMPLATE, "osc_val_tpl", "oscillation_value_template") \
X(MQTT_PAYLOAD, "pl", "payload") \
X(MQTT_PAYLOAD_ARM_AWAY, "pl_arm_away", "payload_arm_away") \
X(MQTT_PAYLOAD_ARM_CUSTOM_BYPASS, "pl_arm_custom_b", "payload_arm_custom_bypass") \
X(MQTT_PAYLOAD_ARM_HOME, "pl_arm_home", "payload_arm_home") \
X(MQTT_PAYLOAD_ARM_NIGHT, "pl_arm_nite", "payload_arm_night") \
X(MQTT_PAYLOAD_ARM_VACATION, "pl_arm_vacation", "payload_arm_vacation") \
X(MQTT_PAYLOAD_AVAILABLE, "pl_avail", "payload_available") \
X(MQTT_PAYLOAD_CLEAN_SPOT, "pl_cln_sp", "payload_clean_spot") \
X(MQTT_PAYLOAD_CLOSE, "pl_cls", "payload_close") \
X(MQTT_PAYLOAD_DISARM, "pl_disarm", "payload_disarm") \
X(MQTT_PAYLOAD_HIGH_SPEED, "pl_hi_spd", "payload_high_speed") \
X(MQTT_PAYLOAD_HOME, "pl_home", "payload_home") \
X(MQTT_PAYLOAD_INSTALL, "pl_inst", "payload_install") \
X(MQTT_PAYLOAD_LOCATE, "pl_loc", "payload_locate") \
X(MQTT_PAYLOAD_LOCK, "pl_lock", "payload_lock") \
X(MQTT_PAYLOAD_LOW_SPEED, "pl_lo_spd", "payload_low_speed") \
X(MQTT_PAYLOAD_MEDIUM_SPEED, "pl_med_spd", "payload_medium_speed") \
X(MQTT_PAYLOAD_NOT_AVAILABLE, "pl_not_avail", "payload_not_available") \
X(MQTT_PAYLOAD_NOT_HOME, "pl_not_home", "payload_not_home") \
X(MQTT_PAYLOAD_OFF, "pl_off", "payload_off") \
X(MQTT_PAYLOAD_OFF_SPEED, "pl_off_spd", "payload_off_speed") \
X(MQTT_PAYLOAD_ON, "pl_on", "payload_on") \
X(MQTT_PAYLOAD_OPEN, "pl_open", "payload_open") \
X(MQTT_PAYLOAD_OSCILLATION_OFF, "pl_osc_off", "payload_oscillation_off") \
X(MQTT_PAYLOAD_OSCILLATION_ON, "pl_osc_on", "payload_oscillation_on") \
X(MQTT_PAYLOAD_PAUSE, "pl_paus", "payload_pause") \
X(MQTT_PAYLOAD_RESET, "pl_rst", "payload_reset") \
X(MQTT_PAYLOAD_RESET_HUMIDITY, "pl_rst_hum", "payload_reset_humidity") \
X(MQTT_PAYLOAD_RESET_MODE, "pl_rst_mode", "payload_reset_mode") \
X(MQTT_PAYLOAD_RESET_PERCENTAGE, "pl_rst_pct", "payload_reset_percentage") \
X(MQTT_PAYLOAD_RESET_PRESET_MODE, "pl_rst_pr_mode", "payload_reset_preset_mode") \
X(MQTT_PAYLOAD_RETURN_TO_BASE, "pl_ret", "payload_return_to_base") \
X(MQTT_PAYLOAD_START, "pl_strt", "payload_start") \
X(MQTT_PAYLOAD_START_PAUSE, "pl_stpa", "payload_start_pause") \
X(MQTT_PAYLOAD_STOP, "pl_stop", "payload_stop") \
X(MQTT_PAYLOAD_TURN_OFF, "pl_toff", "payload_turn_off") \
X(MQTT_PAYLOAD_TURN_ON, "pl_ton", "payload_turn_on") \
X(MQTT_PAYLOAD_UNLOCK, "pl_unlk", "payload_unlock") \
X(MQTT_PERCENTAGE_COMMAND_TEMPLATE, "pct_cmd_tpl", "percentage_command_template") \
X(MQTT_PERCENTAGE_COMMAND_TOPIC, "pct_cmd_t", "percentage_command_topic") \
X(MQTT_PERCENTAGE_STATE_TOPIC, "pct_stat_t", "percentage_state_topic") \
X(MQTT_PERCENTAGE_VALUE_TEMPLATE, "pct_val_tpl", "percentage_value_template") \
X(MQTT_POSITION_CLOSED, "pos_clsd", "position_closed") \
X(MQTT_POSITION_OPEN, "pos_open", "position_open") \
X(MQTT_POSITION_TEMPLATE, "pos_tpl", "position_template") \
X(MQTT_POSITION_TOPIC, "pos_t", "position_topic") \
X(MQTT_POWER_COMMAND_TOPIC, "pow_cmd_t", "power_command_topic") \
X(MQTT_POWER_STATE_TEMPLATE, "pow_stat_tpl", "power_state_template") \
X(MQTT_POWER_STATE_TOPIC, "pow_stat_t", "power_state_topic") \
X(MQTT_PRESET_MODE_COMMAND_TEMPLATE, "pr_mode_cmd_tpl", "preset_mode_command_template") \
X(MQTT_PRESET_MODE_COMMAND_TOPIC, "pr_mode_cmd_t", "preset_mode_command_topic") \
X(MQTT_PRESET_MODE_STATE_TOPIC, "pr_mode_stat_t", "preset_mode_state_topic") \
X(MQTT_PRESET_MODE_VALUE_TEMPLATE, "pr_mode_val_tpl", "preset_mode_value_template") \
X(MQTT_PRESET_MODES, "pr_modes", "preset_modes") \
X(MQTT_QOS, "qos", "qos") \
X(MQTT_RED_TEMPLATE, "r_tpl", "red_template") \
X(MQTT_RETAIN, "ret", "retain") \
X(MQTT_RGB_COMMAND_TEMPLATE, "rgb_cmd_tpl", "rgb_command_template") \
X(MQTT_RGB_COMMAND_TOPIC, "rgb_cmd_t", "rgb_command_topic") \
X(MQTT_RGB_STATE_TOPIC, "rgb_stat_t", "rgb_state_topic") \
X(MQTT_RGB_VALUE_TEMPLATE, "rgb_val_tpl", "rgb_value_template") \
X(MQTT_RGBW_COMMAND_TEMPLATE, "rgbw_cmd_tpl", "rgbw_command_template") \
X(MQTT_RGBW_COMMAND_TOPIC, "rgbw_cmd_t", "rgbw_command_topic") \
X(MQTT_RGBW_STATE_TOPIC, "rgbw_stat_t", "rgbw_state_topic") \
X(MQTT_RGBW_VALUE_TEMPLATE, "rgbw_val_tpl", "rgbw_value_template") \
X(MQTT_RGBWW_COMMAND_TEMPLATE, "rgbww_cmd_tpl", "rgbww_command_template") \
X(MQTT_RGBWW_COMMAND_TOPIC, "rgbww_cmd_t", "rgbww_command_topic") \
X(MQTT_RGBWW_STATE_TOPIC, "rgbww_stat_t", "rgbww_state_topic") \
X(MQTT_RGBWW_VALUE_TEMPLATE, "rgbww_val_tpl", "rgbww_value_template") \
X(MQTT_SEND_COMMAND_TOPIC, "send_cmd_t", "send_command_topic") \
X(MQTT_SEND_IF_OFF, "send_if_off", "send_if_off") \
X(MQTT_SET_FAN_SPEED_TOPIC, "set_fan_spd_t", "set_fan_speed_topic") \
X(MQTT_SET_POSITION_TEMPLATE, "set_pos_tpl", "set_position_template") \
X(MQTT_SET_POSITION_TOPIC, "set_pos_t", "set_position_topic") \
X(MQTT_SOURCE_TYPE, "src_type", "source_type") \
X(MQTT_SPEED_COMMAND_TOPIC, "spd_cmd_t", "speed_command_topic") \
X(MQTT_SPEED_RANGE_MAX, "spd_rng_max", "speed_range_max") \
X(MQTT_SPEED_RANGE_MIN, "spd_rng_min", "speed_range_min") \
X(MQTT_SPEED_STATE_TOPIC, "spd_stat_t", "speed_state_topic") \
X(MQTT_SPEED_VALUE_TEMPLATE, "spd_val_tpl", "speed_value_template") \
X(MQTT_SPEEDS, "spds", "speeds") \
X(MQTT_STATE_CLASS, "stat_cla", "state_class") \
X(MQTT_STATE_CLOSED, "stat_clsd", "state_closed") \
X(MQTT_STATE_CLOSING, "stat_closing", "state_closing") \
X(MQTT_STATE_LOCKED, "stat_locked", "state_locked") \
X(MQTT_STATE_OFF, "stat_off", "state_off") \
X(MQTT_STATE_ON, "stat_on", "state_on") \
X(MQTT_STATE_OPEN, "stat_open", "state_open") \
X(MQTT_STATE_OPENING, "stat_opening", "state_opening") \
X(MQTT_STATE_STOPPED, "stat_stopped", "state_stopped") \
X(MQTT_STATE_TEMPLATE, "stat_tpl", "state_template") \
X(MQTT_STATE_TOPIC, "stat_t", "state_topic") \
X(MQTT_STATE_UNLOCKED, "stat_unlocked", "state_unlocked") \
X(MQTT_STATE_VALUE_TEMPLATE, "stat_val_tpl", "state_value_template") \
X(MQTT_STEP, "step", "step") \
X(MQTT_SUBTYPE, "stype", "subtype") \
X(MQTT_SUPPORTED_COLOR_MODES, "sup_clrm", "supported_color_modes") \
X(MQTT_SUPPORTED_FEATURES, "sup_feat", "supported_features") \
X(MQTT_SWING_MODE_COMMAND_TEMPLATE, "swing_mode_cmd_tpl", "swing_mode_command_template") \
X(MQTT_SWING_MODE_COMMAND_TOPIC, "swing_mode_cmd_t", "swing_mode_command_topic") \
X(MQTT_SWING_MODE_STATE_TEMPLATE, "swing_mode_stat_tpl", "swing_mode_state_template") \
X(MQTT_SWING_MODE_STATE_TOPIC, "swing_mode_stat_t", "swing_mode_state_topic") \
X(MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE, "hum_cmd_tpl", "target_humidity_command_template") \
X(MQTT_TARGET_HUMIDITY_COMMAND_TOPIC, "hum_cmd_t", "target_humidity_command_topic") \
X(MQTT_TARGET_HUMIDITY_STATE_TEMPLATE, "hum_state_tpl", "target_humidity_state_template") \
X(MQTT_TARGET_HUMIDITY_STATE_TOPIC, "hum_stat_t", "target_humidity_state_topic") \
X(MQTT_TARGET_TEMPERATURE_STEP, "temp_step", "temp_step") \
X(MQTT_TEMPERATURE_COMMAND_TEMPLATE, "temp_cmd_tpl", "temperature_command_template") \
X(MQTT_TEMPERATURE_COMMAND_TOPIC, "temp_cmd_t", "temperature_command_topic") \
X(MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE, "temp_hi_cmd_tpl", "temperature_high_command_template") \
X(MQTT_TEMPERATURE_HIGH_COMMAND_TOPIC, "temp_hi_cmd_t", "temperature_high_command_topic") \
X(MQTT_TEMPERATURE_HIGH_STATE_TEMPLATE, "temp_hi_stat_tpl", "temperature_high_state_template") \
X(MQTT_TEMPERATURE_HIGH_STATE_TOPIC, "temp_hi_stat_t", "temperature_high_state_topic") \
X(MQTT_TEMPERATURE_LOW_COMMAND_TEMPLATE, "temp_lo_cmd_tpl", "temperature_low_command_template") \
X(MQTT_TEMPERATURE_LOW_COMMAND_TOPIC, "temp_lo_cmd_t", "temperature_low_command_topic") \
X(MQTT_TEMPERATURE_LOW_STATE_TEMPLATE, "temp_lo_stat_tpl", "temperature_low_state_template") \
X(MQTT_TEMPERATURE_LOW_STATE_TOPIC, "temp_lo_stat_t", "temperature_low_state_topic") \
X(MQTT_TEMPERATURE_STATE_TEMPLATE, "temp_stat_tpl", "temperature_state_template") \
X(MQTT_TEMPERATURE_STATE_TOPIC, "temp_stat_t", "temperature_state_topic") \
X(MQTT_TEMPERATURE_UNIT, "temp_unit", "temperature_unit") \
X(MQTT_TILT_CLOSED_VALUE, "tilt_clsd_val", "tilt_closed_value") \
X(MQTT_TILT_COMMAND_TEMPLATE, "tilt_cmd_tpl", "tilt_command_template") \
X(MQTT_TILT_COMMAND_TOPIC, "tilt_cmd_t", "tilt_command_topic") \
X(MQTT_TILT_INVERT_STATE, "tilt_inv_stat", "tilt_invert_state") \
X(MQTT_TILT_MAX, "tilt_max", "tilt_max") \
X(MQTT_TILT_MIN, "tilt_min", "tilt_min") \
X(MQTT_TILT_OPENED_VALUE, "tilt_opnd_val", "tilt_opened_value") \
X(MQTT_TILT_OPTIMISTIC, "tilt_opt", "tilt_optimistic") \
X(MQTT_TILT_STATUS_TEMPLATE, "tilt_status_tpl", "tilt_status_template") \
X(MQTT_TILT_STATUS_TOPIC, "tilt_status_t", "tilt_status_topic") \
X(MQTT_TOPIC, "t", "topic") \
X(MQTT_UNIQUE_ID, "uniq_id", "unique_id") \
X(MQTT_UNIT_OF_MEASUREMENT, "unit_of_meas", "unit_of_measurement") \
X(MQTT_VALUE_TEMPLATE, "val_tpl", "value_template") \
X(MQTT_WHITE_COMMAND_TOPIC, "whit_cmd_t", "white_command_topic") \
X(MQTT_WHITE_SCALE, "whit_scl", "white_scale") \
X(MQTT_WHITE_VALUE_COMMAND_TOPIC, "whit_val_cmd_t", "white_value_command_topic") \
X(MQTT_WHITE_VALUE_SCALE, "whit_val_scl", "white_value_scale") \
X(MQTT_WHITE_VALUE_STATE_TOPIC, "whit_val_stat_t", "white_value_state_topic") \
X(MQTT_WHITE_VALUE_TEMPLATE, "whit_val_tpl", "white_value_template") \
X(MQTT_XY_COMMAND_TOPIC, "xy_cmd_t", "xy_command_topic") \
X(MQTT_XY_STATE_TOPIC, "xy_stat_t", "xy_state_topic") \
X(MQTT_XY_VALUE_TEMPLATE, "xy_val_tpl", "xy_value_template")
// clang-format on
#ifdef USE_ESP8266
// ESP8266: Store strings in PROGMEM (flash) and expose as __FlashStringHelper* pointers.
// ArduinoJson recognizes this type and reads from flash memory.
namespace esphome::mqtt {
// Generate PROGMEM data arrays
#ifdef USE_MQTT_ABBREVIATIONS
constexpr const char *const MQTT_ACTION_TEMPLATE = "act_tpl";
constexpr const char *const MQTT_ACTION_TOPIC = "act_t";
constexpr const char *const MQTT_AUTOMATION_TYPE = "atype";
constexpr const char *const MQTT_AUX_COMMAND_TOPIC = "aux_cmd_t";
constexpr const char *const MQTT_AUX_STATE_TEMPLATE = "aux_stat_tpl";
constexpr const char *const MQTT_AUX_STATE_TOPIC = "aux_stat_t";
constexpr const char *const MQTT_AVAILABILITY = "avty";
constexpr const char *const MQTT_AVAILABILITY_MODE = "avty_mode";
constexpr const char *const MQTT_AVAILABILITY_TOPIC = "avty_t";
constexpr const char *const MQTT_AWAY_MODE_COMMAND_TOPIC = "away_mode_cmd_t";
constexpr const char *const MQTT_AWAY_MODE_STATE_TEMPLATE = "away_mode_stat_tpl";
constexpr const char *const MQTT_AWAY_MODE_STATE_TOPIC = "away_mode_stat_t";
constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "bat_lev_tpl";
constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "bat_lev_t";
constexpr const char *const MQTT_BLUE_TEMPLATE = "b_tpl";
constexpr const char *const MQTT_BRIGHTNESS_COMMAND_TOPIC = "bri_cmd_t";
constexpr const char *const MQTT_BRIGHTNESS_SCALE = "bri_scl";
constexpr const char *const MQTT_BRIGHTNESS_STATE_TOPIC = "bri_stat_t";
constexpr const char *const MQTT_BRIGHTNESS_TEMPLATE = "bri_tpl";
constexpr const char *const MQTT_BRIGHTNESS_VALUE_TEMPLATE = "bri_val_tpl";
constexpr const char *const MQTT_CHARGING_TEMPLATE = "chrg_tpl";
constexpr const char *const MQTT_CHARGING_TOPIC = "chrg_t";
constexpr const char *const MQTT_CLEANING_TEMPLATE = "cln_tpl";
constexpr const char *const MQTT_CLEANING_TOPIC = "cln_t";
constexpr const char *const MQTT_CODE_ARM_REQUIRED = "cod_arm_req";
constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "cod_dis_req";
constexpr const char *const MQTT_COLOR_MODE = "clrm";
constexpr const char *const MQTT_COLOR_MODE_STATE_TOPIC = "clrm_stat_t";
constexpr const char *const MQTT_COLOR_MODE_VALUE_TEMPLATE = "clrm_val_tpl";
constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "clr_temp_cmd_tpl";
constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TOPIC = "clr_temp_cmd_t";
constexpr const char *const MQTT_COLOR_TEMP_STATE_TOPIC = "clr_temp_stat_t";
constexpr const char *const MQTT_COLOR_TEMP_TEMPLATE = "clr_temp_tpl";
constexpr const char *const MQTT_COLOR_TEMP_VALUE_TEMPLATE = "clr_temp_val_tpl";
constexpr const char *const MQTT_COMMAND_OFF_TEMPLATE = "cmd_off_tpl";
constexpr const char *const MQTT_COMMAND_ON_TEMPLATE = "cmd_on_tpl";
constexpr const char *const MQTT_COMMAND_RETAIN = "ret";
constexpr const char *const MQTT_COMMAND_TEMPLATE = "cmd_tpl";
constexpr const char *const MQTT_COMMAND_TOPIC = "cmd_t";
constexpr const char *const MQTT_CONFIGURATION_URL = "cu";
constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "curr_hum_tpl";
constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "curr_hum_t";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_STEP = "precision";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "curr_temp_tpl";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "curr_temp_t";
constexpr const char *const MQTT_DEVICE = "dev";
constexpr const char *const MQTT_DEVICE_CLASS = "dev_cla";
constexpr const char *const MQTT_DEVICE_CONNECTIONS = "cns";
constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "ids";
constexpr const char *const MQTT_DEVICE_MANUFACTURER = "mf";
constexpr const char *const MQTT_DEVICE_MODEL = "mdl";
constexpr const char *const MQTT_DEVICE_NAME = "name";
constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "sa";
constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw";
constexpr const char *const MQTT_DEVICE_HW_VERSION = "hw";
constexpr const char *const MQTT_DIRECTION_COMMAND_TOPIC = "dir_cmd_t";
constexpr const char *const MQTT_DIRECTION_STATE_TOPIC = "dir_stat_t";
constexpr const char *const MQTT_DOCKED_TEMPLATE = "dock_tpl";
constexpr const char *const MQTT_DOCKED_TOPIC = "dock_t";
constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "fx_cmd_t";
constexpr const char *const MQTT_EFFECT_LIST = "fx_list";
constexpr const char *const MQTT_EFFECT_STATE_TOPIC = "fx_stat_t";
constexpr const char *const MQTT_EFFECT_TEMPLATE = "fx_tpl";
constexpr const char *const MQTT_EFFECT_VALUE_TEMPLATE = "fx_val_tpl";
constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "en";
constexpr const char *const MQTT_ENTITY_CATEGORY = "ent_cat";
constexpr const char *const MQTT_ERROR_TEMPLATE = "err_tpl";
constexpr const char *const MQTT_ERROR_TOPIC = "err_t";
constexpr const char *const MQTT_EVENT_TYPE = "event_type";
constexpr const char *const MQTT_EVENT_TYPES = "evt_typ";
constexpr const char *const MQTT_EXPIRE_AFTER = "exp_aft";
constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_cmd_tpl";
constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_cmd_t";
constexpr const char *const MQTT_FAN_MODE_STATE_TEMPLATE = "fan_mode_stat_tpl";
constexpr const char *const MQTT_FAN_MODE_STATE_TOPIC = "fan_mode_stat_t";
constexpr const char *const MQTT_FAN_SPEED_LIST = "fanspd_lst";
constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fanspd_tpl";
constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fanspd_t";
constexpr const char *const MQTT_FLASH_TIME_LONG = "flsh_tlng";
constexpr const char *const MQTT_FLASH_TIME_SHORT = "flsh_tsht";
constexpr const char *const MQTT_FORCE_UPDATE = "frc_upd";
constexpr const char *const MQTT_GREEN_TEMPLATE = "g_tpl";
constexpr const char *const MQTT_HOLD_COMMAND_TEMPLATE = "hold_cmd_tpl";
constexpr const char *const MQTT_HOLD_COMMAND_TOPIC = "hold_cmd_t";
constexpr const char *const MQTT_HOLD_STATE_TEMPLATE = "hold_stat_tpl";
constexpr const char *const MQTT_HOLD_STATE_TOPIC = "hold_stat_t";
constexpr const char *const MQTT_HS_COMMAND_TOPIC = "hs_cmd_t";
constexpr const char *const MQTT_HS_STATE_TOPIC = "hs_stat_t";
constexpr const char *const MQTT_HS_VALUE_TEMPLATE = "hs_val_tpl";
constexpr const char *const MQTT_ICON = "ic";
constexpr const char *const MQTT_INITIAL = "init";
constexpr const char *const MQTT_JSON_ATTRIBUTES = "json_attr";
constexpr const char *const MQTT_JSON_ATTRIBUTES_TEMPLATE = "json_attr_tpl";
constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attr_t";
constexpr const char *const MQTT_LAST_RESET_TOPIC = "lrst_t";
constexpr const char *const MQTT_LAST_RESET_VALUE_TEMPLATE = "lrst_val_tpl";
constexpr const char *const MQTT_MAX = "max";
constexpr const char *const MQTT_MAX_HUMIDITY = "max_hum";
constexpr const char *const MQTT_MAX_MIREDS = "max_mirs";
constexpr const char *const MQTT_MAX_TEMP = "max_temp";
constexpr const char *const MQTT_MIN = "min";
constexpr const char *const MQTT_MIN_HUMIDITY = "min_hum";
constexpr const char *const MQTT_MIN_MIREDS = "min_mirs";
constexpr const char *const MQTT_MIN_TEMP = "min_temp";
constexpr const char *const MQTT_MODE = "mode";
constexpr const char *const MQTT_MODE_COMMAND_TEMPLATE = "mode_cmd_tpl";
constexpr const char *const MQTT_MODE_COMMAND_TOPIC = "mode_cmd_t";
constexpr const char *const MQTT_MODE_STATE_TEMPLATE = "mode_stat_tpl";
constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_stat_t";
constexpr const char *const MQTT_MODES = "modes";
constexpr const char *const MQTT_NAME = "name";
constexpr const char *const MQTT_OBJECT_ID = "obj_id";
constexpr const char *const MQTT_OFF_DELAY = "off_dly";
constexpr const char *const MQTT_ON_COMMAND_TYPE = "on_cmd_type";
constexpr const char *const MQTT_OPTIMISTIC = "opt";
constexpr const char *const MQTT_OPTIONS = "ops";
constexpr const char *const MQTT_OSCILLATION_COMMAND_TEMPLATE = "osc_cmd_tpl";
constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "osc_cmd_t";
constexpr const char *const MQTT_OSCILLATION_STATE_TOPIC = "osc_stat_t";
constexpr const char *const MQTT_OSCILLATION_VALUE_TEMPLATE = "osc_val_tpl";
constexpr const char *const MQTT_PAYLOAD = "pl";
constexpr const char *const MQTT_PAYLOAD_ARM_AWAY = "pl_arm_away";
constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "pl_arm_custom_b";
constexpr const char *const MQTT_PAYLOAD_ARM_HOME = "pl_arm_home";
constexpr const char *const MQTT_PAYLOAD_ARM_NIGHT = "pl_arm_nite";
constexpr const char *const MQTT_PAYLOAD_ARM_VACATION = "pl_arm_vacation";
constexpr const char *const MQTT_PAYLOAD_AVAILABLE = "pl_avail";
constexpr const char *const MQTT_PAYLOAD_CLEAN_SPOT = "pl_cln_sp";
constexpr const char *const MQTT_PAYLOAD_CLOSE = "pl_cls";
constexpr const char *const MQTT_PAYLOAD_DISARM = "pl_disarm";
constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "pl_hi_spd";
constexpr const char *const MQTT_PAYLOAD_HOME = "pl_home";
constexpr const char *const MQTT_PAYLOAD_INSTALL = "pl_inst";
constexpr const char *const MQTT_PAYLOAD_LOCATE = "pl_loc";
constexpr const char *const MQTT_PAYLOAD_LOCK = "pl_lock";
constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "pl_lo_spd";
constexpr const char *const MQTT_PAYLOAD_MEDIUM_SPEED = "pl_med_spd";
constexpr const char *const MQTT_PAYLOAD_NOT_AVAILABLE = "pl_not_avail";
constexpr const char *const MQTT_PAYLOAD_NOT_HOME = "pl_not_home";
constexpr const char *const MQTT_PAYLOAD_OFF = "pl_off";
constexpr const char *const MQTT_PAYLOAD_OFF_SPEED = "pl_off_spd";
constexpr const char *const MQTT_PAYLOAD_ON = "pl_on";
constexpr const char *const MQTT_PAYLOAD_OPEN = "pl_open";
constexpr const char *const MQTT_PAYLOAD_OSCILLATION_OFF = "pl_osc_off";
constexpr const char *const MQTT_PAYLOAD_OSCILLATION_ON = "pl_osc_on";
constexpr const char *const MQTT_PAYLOAD_PAUSE = "pl_paus";
constexpr const char *const MQTT_PAYLOAD_RESET = "pl_rst";
constexpr const char *const MQTT_PAYLOAD_RESET_HUMIDITY = "pl_rst_hum";
constexpr const char *const MQTT_PAYLOAD_RESET_MODE = "pl_rst_mode";
constexpr const char *const MQTT_PAYLOAD_RESET_PERCENTAGE = "pl_rst_pct";
constexpr const char *const MQTT_PAYLOAD_RESET_PRESET_MODE = "pl_rst_pr_mode";
constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "pl_ret";
constexpr const char *const MQTT_PAYLOAD_START = "pl_strt";
constexpr const char *const MQTT_PAYLOAD_START_PAUSE = "pl_stpa";
constexpr const char *const MQTT_PAYLOAD_STOP = "pl_stop";
constexpr const char *const MQTT_PAYLOAD_TURN_OFF = "pl_toff";
constexpr const char *const MQTT_PAYLOAD_TURN_ON = "pl_ton";
constexpr const char *const MQTT_PAYLOAD_UNLOCK = "pl_unlk";
constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "pct_cmd_tpl";
constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "pct_cmd_t";
constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "pct_stat_t";
constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "pct_val_tpl";
constexpr const char *const MQTT_POSITION_CLOSED = "pos_clsd";
constexpr const char *const MQTT_POSITION_OPEN = "pos_open";
constexpr const char *const MQTT_POSITION_TEMPLATE = "pos_tpl";
constexpr const char *const MQTT_POSITION_TOPIC = "pos_t";
constexpr const char *const MQTT_POWER_COMMAND_TOPIC = "pow_cmd_t";
constexpr const char *const MQTT_POWER_STATE_TEMPLATE = "pow_stat_tpl";
constexpr const char *const MQTT_POWER_STATE_TOPIC = "pow_stat_t";
constexpr const char *const MQTT_PRESET_MODE_COMMAND_TEMPLATE = "pr_mode_cmd_tpl";
constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "pr_mode_cmd_t";
constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "pr_mode_stat_t";
constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "pr_mode_val_tpl";
constexpr const char *const MQTT_PRESET_MODES = "pr_modes";
constexpr const char *const MQTT_QOS = "qos";
constexpr const char *const MQTT_RED_TEMPLATE = "r_tpl";
constexpr const char *const MQTT_RETAIN = "ret";
constexpr const char *const MQTT_RGB_COMMAND_TEMPLATE = "rgb_cmd_tpl";
constexpr const char *const MQTT_RGB_COMMAND_TOPIC = "rgb_cmd_t";
constexpr const char *const MQTT_RGB_STATE_TOPIC = "rgb_stat_t";
constexpr const char *const MQTT_RGB_VALUE_TEMPLATE = "rgb_val_tpl";
constexpr const char *const MQTT_RGBW_COMMAND_TEMPLATE = "rgbw_cmd_tpl";
constexpr const char *const MQTT_RGBW_COMMAND_TOPIC = "rgbw_cmd_t";
constexpr const char *const MQTT_RGBW_STATE_TOPIC = "rgbw_stat_t";
constexpr const char *const MQTT_RGBW_VALUE_TEMPLATE = "rgbw_val_tpl";
constexpr const char *const MQTT_RGBWW_COMMAND_TEMPLATE = "rgbww_cmd_tpl";
constexpr const char *const MQTT_RGBWW_COMMAND_TOPIC = "rgbww_cmd_t";
constexpr const char *const MQTT_RGBWW_STATE_TOPIC = "rgbww_stat_t";
constexpr const char *const MQTT_RGBWW_VALUE_TEMPLATE = "rgbww_val_tpl";
constexpr const char *const MQTT_SEND_COMMAND_TOPIC = "send_cmd_t";
constexpr const char *const MQTT_SEND_IF_OFF = "send_if_off";
constexpr const char *const MQTT_SET_FAN_SPEED_TOPIC = "set_fan_spd_t";
constexpr const char *const MQTT_SET_POSITION_TEMPLATE = "set_pos_tpl";
constexpr const char *const MQTT_SET_POSITION_TOPIC = "set_pos_t";
constexpr const char *const MQTT_SOURCE_TYPE = "src_type";
constexpr const char *const MQTT_SPEED_COMMAND_TOPIC = "spd_cmd_t";
constexpr const char *const MQTT_SPEED_RANGE_MAX = "spd_rng_max";
constexpr const char *const MQTT_SPEED_RANGE_MIN = "spd_rng_min";
constexpr const char *const MQTT_SPEED_STATE_TOPIC = "spd_stat_t";
constexpr const char *const MQTT_SPEED_VALUE_TEMPLATE = "spd_val_tpl";
constexpr const char *const MQTT_SPEEDS = "spds";
constexpr const char *const MQTT_STATE_CLASS = "stat_cla";
constexpr const char *const MQTT_STATE_CLOSED = "stat_clsd";
constexpr const char *const MQTT_STATE_CLOSING = "stat_closing";
constexpr const char *const MQTT_STATE_LOCKED = "stat_locked";
constexpr const char *const MQTT_STATE_OFF = "stat_off";
constexpr const char *const MQTT_STATE_ON = "stat_on";
constexpr const char *const MQTT_STATE_OPEN = "stat_open";
constexpr const char *const MQTT_STATE_OPENING = "stat_opening";
constexpr const char *const MQTT_STATE_STOPPED = "stat_stopped";
constexpr const char *const MQTT_STATE_TEMPLATE = "stat_tpl";
constexpr const char *const MQTT_STATE_TOPIC = "stat_t";
constexpr const char *const MQTT_STATE_UNLOCKED = "stat_unlocked";
constexpr const char *const MQTT_STATE_VALUE_TEMPLATE = "stat_val_tpl";
constexpr const char *const MQTT_STEP = "step";
constexpr const char *const MQTT_SUBTYPE = "stype";
constexpr const char *const MQTT_SUPPORTED_COLOR_MODES = "sup_clrm";
constexpr const char *const MQTT_SUPPORTED_FEATURES = "sup_feat";
constexpr const char *const MQTT_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_cmd_tpl";
constexpr const char *const MQTT_SWING_MODE_COMMAND_TOPIC = "swing_mode_cmd_t";
constexpr const char *const MQTT_SWING_MODE_STATE_TEMPLATE = "swing_mode_stat_tpl";
constexpr const char *const MQTT_SWING_MODE_STATE_TOPIC = "swing_mode_stat_t";
constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "hum_cmd_tpl";
constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "hum_cmd_t";
constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "hum_state_tpl";
constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "hum_stat_t";
constexpr const char *const MQTT_TARGET_TEMPERATURE_STEP = "temp_step";
constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temp_cmd_tpl";
constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temp_cmd_t";
constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temp_hi_cmd_tpl";
constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TOPIC = "temp_hi_cmd_t";
constexpr const char *const MQTT_TEMPERATURE_HIGH_STATE_TEMPLATE = "temp_hi_stat_tpl";
constexpr const char *const MQTT_TEMPERATURE_HIGH_STATE_TOPIC = "temp_hi_stat_t";
constexpr const char *const MQTT_TEMPERATURE_LOW_COMMAND_TEMPLATE = "temp_lo_cmd_tpl";
constexpr const char *const MQTT_TEMPERATURE_LOW_COMMAND_TOPIC = "temp_lo_cmd_t";
constexpr const char *const MQTT_TEMPERATURE_LOW_STATE_TEMPLATE = "temp_lo_stat_tpl";
constexpr const char *const MQTT_TEMPERATURE_LOW_STATE_TOPIC = "temp_lo_stat_t";
constexpr const char *const MQTT_TEMPERATURE_STATE_TEMPLATE = "temp_stat_tpl";
constexpr const char *const MQTT_TEMPERATURE_STATE_TOPIC = "temp_stat_t";
constexpr const char *const MQTT_TEMPERATURE_UNIT = "temp_unit";
constexpr const char *const MQTT_TILT_CLOSED_VALUE = "tilt_clsd_val";
constexpr const char *const MQTT_TILT_COMMAND_TEMPLATE = "tilt_cmd_tpl";
constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_cmd_t";
constexpr const char *const MQTT_TILT_INVERT_STATE = "tilt_inv_stat";
constexpr const char *const MQTT_TILT_MAX = "tilt_max";
constexpr const char *const MQTT_TILT_MIN = "tilt_min";
constexpr const char *const MQTT_TILT_OPENED_VALUE = "tilt_opnd_val";
constexpr const char *const MQTT_TILT_OPTIMISTIC = "tilt_opt";
constexpr const char *const MQTT_TILT_STATUS_TEMPLATE = "tilt_status_tpl";
constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_t";
constexpr const char *const MQTT_TOPIC = "t";
constexpr const char *const MQTT_UNIQUE_ID = "uniq_id";
constexpr const char *const MQTT_UNIT_OF_MEASUREMENT = "unit_of_meas";
constexpr const char *const MQTT_VALUE_TEMPLATE = "val_tpl";
constexpr const char *const MQTT_WHITE_COMMAND_TOPIC = "whit_cmd_t";
constexpr const char *const MQTT_WHITE_SCALE = "whit_scl";
constexpr const char *const MQTT_WHITE_VALUE_COMMAND_TOPIC = "whit_val_cmd_t";
constexpr const char *const MQTT_WHITE_VALUE_SCALE = "whit_val_scl";
constexpr const char *const MQTT_WHITE_VALUE_STATE_TOPIC = "whit_val_stat_t";
constexpr const char *const MQTT_WHITE_VALUE_TEMPLATE = "whit_val_tpl";
constexpr const char *const MQTT_XY_COMMAND_TOPIC = "xy_cmd_t";
constexpr const char *const MQTT_XY_STATE_TOPIC = "xy_stat_t";
constexpr const char *const MQTT_XY_VALUE_TEMPLATE = "xy_val_tpl";
#define MQTT_DATA(name, abbr, full) static const char name##_data[] PROGMEM = abbr;
#else
#define MQTT_DATA(name, abbr, full) static const char name##_data[] PROGMEM = full;
#endif
MQTT_KEYS_LIST(MQTT_DATA)
#undef MQTT_DATA
constexpr const char *const MQTT_ACTION_TEMPLATE = "action_template";
constexpr const char *const MQTT_ACTION_TOPIC = "action_topic";
constexpr const char *const MQTT_AUTOMATION_TYPE = "automation_type";
constexpr const char *const MQTT_AUX_COMMAND_TOPIC = "aux_command_topic";
constexpr const char *const MQTT_AUX_STATE_TEMPLATE = "aux_state_template";
constexpr const char *const MQTT_AUX_STATE_TOPIC = "aux_state_topic";
constexpr const char *const MQTT_AVAILABILITY = "availability";
constexpr const char *const MQTT_AVAILABILITY_MODE = "availability_mode";
constexpr const char *const MQTT_AVAILABILITY_TOPIC = "availability_topic";
constexpr const char *const MQTT_AWAY_MODE_COMMAND_TOPIC = "away_mode_command_topic";
constexpr const char *const MQTT_AWAY_MODE_STATE_TEMPLATE = "away_mode_state_template";
constexpr const char *const MQTT_AWAY_MODE_STATE_TOPIC = "away_mode_state_topic";
constexpr const char *const MQTT_BATTERY_LEVEL_TEMPLATE = "battery_level_template";
constexpr const char *const MQTT_BATTERY_LEVEL_TOPIC = "battery_level_topic";
constexpr const char *const MQTT_BLUE_TEMPLATE = "blue_template";
constexpr const char *const MQTT_BRIGHTNESS_COMMAND_TOPIC = "brightness_command_topic";
constexpr const char *const MQTT_BRIGHTNESS_SCALE = "brightness_scale";
constexpr const char *const MQTT_BRIGHTNESS_STATE_TOPIC = "brightness_state_topic";
constexpr const char *const MQTT_BRIGHTNESS_TEMPLATE = "brightness_template";
constexpr const char *const MQTT_BRIGHTNESS_VALUE_TEMPLATE = "brightness_value_template";
constexpr const char *const MQTT_CHARGING_TEMPLATE = "charging_template";
constexpr const char *const MQTT_CHARGING_TOPIC = "charging_topic";
constexpr const char *const MQTT_CLEANING_TEMPLATE = "cleaning_template";
constexpr const char *const MQTT_CLEANING_TOPIC = "cleaning_topic";
constexpr const char *const MQTT_CODE_ARM_REQUIRED = "code_arm_required";
constexpr const char *const MQTT_CODE_DISARM_REQUIRED = "code_disarm_required";
constexpr const char *const MQTT_COLOR_MODE = "color_mode";
constexpr const char *const MQTT_COLOR_MODE_STATE_TOPIC = "color_mode_state_topic";
constexpr const char *const MQTT_COLOR_MODE_VALUE_TEMPLATE = "color_mode_value_template";
constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TEMPLATE = "color_temp_command_template";
constexpr const char *const MQTT_COLOR_TEMP_COMMAND_TOPIC = "color_temp_command_topic";
constexpr const char *const MQTT_COLOR_TEMP_STATE_TOPIC = "color_temp_state_topic";
constexpr const char *const MQTT_COLOR_TEMP_TEMPLATE = "color_temp_template";
constexpr const char *const MQTT_COLOR_TEMP_VALUE_TEMPLATE = "color_temp_value_template";
constexpr const char *const MQTT_COMMAND_OFF_TEMPLATE = "command_off_template";
constexpr const char *const MQTT_COMMAND_ON_TEMPLATE = "command_on_template";
constexpr const char *const MQTT_COMMAND_RETAIN = "retain";
constexpr const char *const MQTT_COMMAND_TEMPLATE = "command_template";
constexpr const char *const MQTT_COMMAND_TOPIC = "command_topic";
constexpr const char *const MQTT_CONFIGURATION_URL = "configuration_url";
constexpr const char *const MQTT_CURRENT_HUMIDITY_TEMPLATE = "current_humidity_template";
constexpr const char *const MQTT_CURRENT_HUMIDITY_TOPIC = "current_humidity_topic";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_STEP = "precision";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_TEMPLATE = "current_temperature_template";
constexpr const char *const MQTT_CURRENT_TEMPERATURE_TOPIC = "current_temperature_topic";
constexpr const char *const MQTT_DEVICE = "device";
constexpr const char *const MQTT_DEVICE_CLASS = "device_class";
constexpr const char *const MQTT_DEVICE_CONNECTIONS = "connections";
constexpr const char *const MQTT_DEVICE_IDENTIFIERS = "identifiers";
constexpr const char *const MQTT_DEVICE_MANUFACTURER = "manufacturer";
constexpr const char *const MQTT_DEVICE_MODEL = "model";
constexpr const char *const MQTT_DEVICE_NAME = "name";
constexpr const char *const MQTT_DEVICE_SUGGESTED_AREA = "suggested_area";
constexpr const char *const MQTT_DEVICE_SW_VERSION = "sw_version";
constexpr const char *const MQTT_DEVICE_HW_VERSION = "hw_version";
constexpr const char *const MQTT_DIRECTION_COMMAND_TOPIC = "direction_command_topic";
constexpr const char *const MQTT_DIRECTION_STATE_TOPIC = "direction_state_topic";
constexpr const char *const MQTT_DOCKED_TEMPLATE = "docked_template";
constexpr const char *const MQTT_DOCKED_TOPIC = "docked_topic";
constexpr const char *const MQTT_EFFECT_COMMAND_TOPIC = "effect_command_topic";
constexpr const char *const MQTT_EFFECT_LIST = "effect_list";
constexpr const char *const MQTT_EFFECT_STATE_TOPIC = "effect_state_topic";
constexpr const char *const MQTT_EFFECT_TEMPLATE = "effect_template";
constexpr const char *const MQTT_EFFECT_VALUE_TEMPLATE = "effect_value_template";
constexpr const char *const MQTT_ENABLED_BY_DEFAULT = "enabled_by_default";
constexpr const char *const MQTT_ENTITY_CATEGORY = "entity_category";
constexpr const char *const MQTT_ERROR_TEMPLATE = "error_template";
constexpr const char *const MQTT_ERROR_TOPIC = "error_topic";
constexpr const char *const MQTT_EVENT_TYPE = "event_type";
constexpr const char *const MQTT_EVENT_TYPES = "event_types";
constexpr const char *const MQTT_EXPIRE_AFTER = "expire_after";
constexpr const char *const MQTT_FAN_MODE_COMMAND_TEMPLATE = "fan_mode_command_template";
constexpr const char *const MQTT_FAN_MODE_COMMAND_TOPIC = "fan_mode_command_topic";
constexpr const char *const MQTT_FAN_MODE_STATE_TEMPLATE = "fan_mode_state_template";
constexpr const char *const MQTT_FAN_MODE_STATE_TOPIC = "fan_mode_state_topic";
constexpr const char *const MQTT_FAN_SPEED_LIST = "fan_speed_list";
constexpr const char *const MQTT_FAN_SPEED_TEMPLATE = "fan_speed_template";
constexpr const char *const MQTT_FAN_SPEED_TOPIC = "fan_speed_topic";
constexpr const char *const MQTT_FLASH_TIME_LONG = "flash_time_long";
constexpr const char *const MQTT_FLASH_TIME_SHORT = "flash_time_short";
constexpr const char *const MQTT_FORCE_UPDATE = "force_update";
constexpr const char *const MQTT_GREEN_TEMPLATE = "green_template";
constexpr const char *const MQTT_HOLD_COMMAND_TEMPLATE = "hold_command_template";
constexpr const char *const MQTT_HOLD_COMMAND_TOPIC = "hold_command_topic";
constexpr const char *const MQTT_HOLD_STATE_TEMPLATE = "hold_state_template";
constexpr const char *const MQTT_HOLD_STATE_TOPIC = "hold_state_topic";
constexpr const char *const MQTT_HS_COMMAND_TOPIC = "hs_command_topic";
constexpr const char *const MQTT_HS_STATE_TOPIC = "hs_state_topic";
constexpr const char *const MQTT_HS_VALUE_TEMPLATE = "hs_value_template";
constexpr const char *const MQTT_ICON = "icon";
constexpr const char *const MQTT_INITIAL = "initial";
constexpr const char *const MQTT_JSON_ATTRIBUTES = "json_attributes";
constexpr const char *const MQTT_JSON_ATTRIBUTES_TEMPLATE = "json_attributes_template";
constexpr const char *const MQTT_JSON_ATTRIBUTES_TOPIC = "json_attributes_topic";
constexpr const char *const MQTT_LAST_RESET_TOPIC = "last_reset_topic";
constexpr const char *const MQTT_LAST_RESET_VALUE_TEMPLATE = "last_reset_value_template";
constexpr const char *const MQTT_MAX = "max";
constexpr const char *const MQTT_MAX_HUMIDITY = "max_humidity";
constexpr const char *const MQTT_MAX_MIREDS = "max_mireds";
constexpr const char *const MQTT_MAX_TEMP = "max_temp";
constexpr const char *const MQTT_MIN = "min";
constexpr const char *const MQTT_MIN_HUMIDITY = "min_humidity";
constexpr const char *const MQTT_MIN_MIREDS = "min_mireds";
constexpr const char *const MQTT_MIN_TEMP = "min_temp";
constexpr const char *const MQTT_MODE = "mode";
constexpr const char *const MQTT_MODE_COMMAND_TEMPLATE = "mode_command_template";
constexpr const char *const MQTT_MODE_COMMAND_TOPIC = "mode_command_topic";
constexpr const char *const MQTT_MODE_STATE_TEMPLATE = "mode_state_template";
constexpr const char *const MQTT_MODE_STATE_TOPIC = "mode_state_topic";
constexpr const char *const MQTT_MODES = "modes";
constexpr const char *const MQTT_NAME = "name";
constexpr const char *const MQTT_OBJECT_ID = "object_id";
constexpr const char *const MQTT_OFF_DELAY = "off_delay";
constexpr const char *const MQTT_ON_COMMAND_TYPE = "on_command_type";
constexpr const char *const MQTT_OPTIMISTIC = "optimistic";
constexpr const char *const MQTT_OPTIONS = "options";
constexpr const char *const MQTT_OSCILLATION_COMMAND_TEMPLATE = "oscillation_command_template";
constexpr const char *const MQTT_OSCILLATION_COMMAND_TOPIC = "oscillation_command_topic";
constexpr const char *const MQTT_OSCILLATION_STATE_TOPIC = "oscillation_state_topic";
constexpr const char *const MQTT_OSCILLATION_VALUE_TEMPLATE = "oscillation_value_template";
constexpr const char *const MQTT_PAYLOAD = "payload";
constexpr const char *const MQTT_PAYLOAD_ARM_AWAY = "payload_arm_away";
constexpr const char *const MQTT_PAYLOAD_ARM_CUSTOM_BYPASS = "payload_arm_custom_bypass";
constexpr const char *const MQTT_PAYLOAD_ARM_HOME = "payload_arm_home";
constexpr const char *const MQTT_PAYLOAD_ARM_NIGHT = "payload_arm_night";
constexpr const char *const MQTT_PAYLOAD_ARM_VACATION = "payload_arm_vacation";
constexpr const char *const MQTT_PAYLOAD_AVAILABLE = "payload_available";
constexpr const char *const MQTT_PAYLOAD_CLEAN_SPOT = "payload_clean_spot";
constexpr const char *const MQTT_PAYLOAD_CLOSE = "payload_close";
constexpr const char *const MQTT_PAYLOAD_DISARM = "payload_disarm";
constexpr const char *const MQTT_PAYLOAD_HIGH_SPEED = "payload_high_speed";
constexpr const char *const MQTT_PAYLOAD_HOME = "payload_home";
constexpr const char *const MQTT_PAYLOAD_INSTALL = "payload_install";
constexpr const char *const MQTT_PAYLOAD_LOCATE = "payload_locate";
constexpr const char *const MQTT_PAYLOAD_LOCK = "payload_lock";
constexpr const char *const MQTT_PAYLOAD_LOW_SPEED = "payload_low_speed";
constexpr const char *const MQTT_PAYLOAD_MEDIUM_SPEED = "payload_medium_speed";
constexpr const char *const MQTT_PAYLOAD_NOT_AVAILABLE = "payload_not_available";
constexpr const char *const MQTT_PAYLOAD_NOT_HOME = "payload_not_home";
constexpr const char *const MQTT_PAYLOAD_OFF = "payload_off";
constexpr const char *const MQTT_PAYLOAD_OFF_SPEED = "payload_off_speed";
constexpr const char *const MQTT_PAYLOAD_ON = "payload_on";
constexpr const char *const MQTT_PAYLOAD_OPEN = "payload_open";
constexpr const char *const MQTT_PAYLOAD_OSCILLATION_OFF = "payload_oscillation_off";
constexpr const char *const MQTT_PAYLOAD_OSCILLATION_ON = "payload_oscillation_on";
constexpr const char *const MQTT_PAYLOAD_PAUSE = "payload_pause";
constexpr const char *const MQTT_PAYLOAD_RESET = "payload_reset";
constexpr const char *const MQTT_PAYLOAD_RESET_HUMIDITY = "payload_reset_humidity";
constexpr const char *const MQTT_PAYLOAD_RESET_MODE = "payload_reset_mode";
constexpr const char *const MQTT_PAYLOAD_RESET_PERCENTAGE = "payload_reset_percentage";
constexpr const char *const MQTT_PAYLOAD_RESET_PRESET_MODE = "payload_reset_preset_mode";
constexpr const char *const MQTT_PAYLOAD_RETURN_TO_BASE = "payload_return_to_base";
constexpr const char *const MQTT_PAYLOAD_START = "payload_start";
constexpr const char *const MQTT_PAYLOAD_START_PAUSE = "payload_start_pause";
constexpr const char *const MQTT_PAYLOAD_STOP = "payload_stop";
constexpr const char *const MQTT_PAYLOAD_TURN_OFF = "payload_turn_off";
constexpr const char *const MQTT_PAYLOAD_TURN_ON = "payload_turn_on";
constexpr const char *const MQTT_PAYLOAD_UNLOCK = "payload_unlock";
constexpr const char *const MQTT_PERCENTAGE_COMMAND_TEMPLATE = "percentage_command_template";
constexpr const char *const MQTT_PERCENTAGE_COMMAND_TOPIC = "percentage_command_topic";
constexpr const char *const MQTT_PERCENTAGE_STATE_TOPIC = "percentage_state_topic";
constexpr const char *const MQTT_PERCENTAGE_VALUE_TEMPLATE = "percentage_value_template";
constexpr const char *const MQTT_POSITION_CLOSED = "position_closed";
constexpr const char *const MQTT_POSITION_OPEN = "position_open";
constexpr const char *const MQTT_POSITION_TEMPLATE = "position_template";
constexpr const char *const MQTT_POSITION_TOPIC = "position_topic";
constexpr const char *const MQTT_POWER_COMMAND_TOPIC = "power_command_topic";
constexpr const char *const MQTT_POWER_STATE_TEMPLATE = "power_state_template";
constexpr const char *const MQTT_POWER_STATE_TOPIC = "power_state_topic";
constexpr const char *const MQTT_PRESET_MODE_COMMAND_TEMPLATE = "preset_mode_command_template";
constexpr const char *const MQTT_PRESET_MODE_COMMAND_TOPIC = "preset_mode_command_topic";
constexpr const char *const MQTT_PRESET_MODE_STATE_TOPIC = "preset_mode_state_topic";
constexpr const char *const MQTT_PRESET_MODE_VALUE_TEMPLATE = "preset_mode_value_template";
constexpr const char *const MQTT_PRESET_MODES = "preset_modes";
constexpr const char *const MQTT_QOS = "qos";
constexpr const char *const MQTT_RED_TEMPLATE = "red_template";
constexpr const char *const MQTT_RETAIN = "retain";
constexpr const char *const MQTT_RGB_COMMAND_TEMPLATE = "rgb_command_template";
constexpr const char *const MQTT_RGB_COMMAND_TOPIC = "rgb_command_topic";
constexpr const char *const MQTT_RGB_STATE_TOPIC = "rgb_state_topic";
constexpr const char *const MQTT_RGB_VALUE_TEMPLATE = "rgb_value_template";
constexpr const char *const MQTT_RGBW_COMMAND_TEMPLATE = "rgbw_command_template";
constexpr const char *const MQTT_RGBW_COMMAND_TOPIC = "rgbw_command_topic";
constexpr const char *const MQTT_RGBW_STATE_TOPIC = "rgbw_state_topic";
constexpr const char *const MQTT_RGBW_VALUE_TEMPLATE = "rgbw_value_template";
constexpr const char *const MQTT_RGBWW_COMMAND_TEMPLATE = "rgbww_command_template";
constexpr const char *const MQTT_RGBWW_COMMAND_TOPIC = "rgbww_command_topic";
constexpr const char *const MQTT_RGBWW_STATE_TOPIC = "rgbww_state_topic";
constexpr const char *const MQTT_RGBWW_VALUE_TEMPLATE = "rgbww_value_template";
constexpr const char *const MQTT_SEND_COMMAND_TOPIC = "send_command_topic";
constexpr const char *const MQTT_SEND_IF_OFF = "send_if_off";
constexpr const char *const MQTT_SET_FAN_SPEED_TOPIC = "set_fan_speed_topic";
constexpr const char *const MQTT_SET_POSITION_TEMPLATE = "set_position_template";
constexpr const char *const MQTT_SET_POSITION_TOPIC = "set_position_topic";
constexpr const char *const MQTT_SOURCE_TYPE = "source_type";
constexpr const char *const MQTT_SPEED_COMMAND_TOPIC = "speed_command_topic";
constexpr const char *const MQTT_SPEED_RANGE_MAX = "speed_range_max";
constexpr const char *const MQTT_SPEED_RANGE_MIN = "speed_range_min";
constexpr const char *const MQTT_SPEED_STATE_TOPIC = "speed_state_topic";
constexpr const char *const MQTT_SPEED_VALUE_TEMPLATE = "speed_value_template";
constexpr const char *const MQTT_SPEEDS = "speeds";
constexpr const char *const MQTT_STATE_CLASS = "state_class";
constexpr const char *const MQTT_STATE_CLOSED = "state_closed";
constexpr const char *const MQTT_STATE_CLOSING = "state_closing";
constexpr const char *const MQTT_STATE_LOCKED = "state_locked";
constexpr const char *const MQTT_STATE_OFF = "state_off";
constexpr const char *const MQTT_STATE_ON = "state_on";
constexpr const char *const MQTT_STATE_OPEN = "state_open";
constexpr const char *const MQTT_STATE_OPENING = "state_opening";
constexpr const char *const MQTT_STATE_STOPPED = "state_stopped";
constexpr const char *const MQTT_STATE_TEMPLATE = "state_template";
constexpr const char *const MQTT_STATE_TOPIC = "state_topic";
constexpr const char *const MQTT_STATE_UNLOCKED = "state_unlocked";
constexpr const char *const MQTT_STATE_VALUE_TEMPLATE = "state_value_template";
constexpr const char *const MQTT_STEP = "step";
constexpr const char *const MQTT_SUBTYPE = "subtype";
constexpr const char *const MQTT_SUPPORTED_COLOR_MODES = "supported_color_modes";
constexpr const char *const MQTT_SUPPORTED_FEATURES = "supported_features";
constexpr const char *const MQTT_SWING_MODE_COMMAND_TEMPLATE = "swing_mode_command_template";
constexpr const char *const MQTT_SWING_MODE_COMMAND_TOPIC = "swing_mode_command_topic";
constexpr const char *const MQTT_SWING_MODE_STATE_TEMPLATE = "swing_mode_state_template";
constexpr const char *const MQTT_SWING_MODE_STATE_TOPIC = "swing_mode_state_topic";
constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TEMPLATE = "target_humidity_command_template";
constexpr const char *const MQTT_TARGET_HUMIDITY_COMMAND_TOPIC = "target_humidity_command_topic";
constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TEMPLATE = "target_humidity_state_template";
constexpr const char *const MQTT_TARGET_HUMIDITY_STATE_TOPIC = "target_humidity_state_topic";
constexpr const char *const MQTT_TARGET_TEMPERATURE_STEP = "temp_step";
constexpr const char *const MQTT_TEMPERATURE_COMMAND_TEMPLATE = "temperature_command_template";
constexpr const char *const MQTT_TEMPERATURE_COMMAND_TOPIC = "temperature_command_topic";
constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TEMPLATE = "temperature_high_command_template";
constexpr const char *const MQTT_TEMPERATURE_HIGH_COMMAND_TOPIC = "temperature_high_command_topic";
constexpr const char *const MQTT_TEMPERATURE_HIGH_STATE_TEMPLATE = "temperature_high_state_template";
constexpr const char *const MQTT_TEMPERATURE_HIGH_STATE_TOPIC = "temperature_high_state_topic";
constexpr const char *const MQTT_TEMPERATURE_LOW_COMMAND_TEMPLATE = "temperature_low_command_template";
constexpr const char *const MQTT_TEMPERATURE_LOW_COMMAND_TOPIC = "temperature_low_command_topic";
constexpr const char *const MQTT_TEMPERATURE_LOW_STATE_TEMPLATE = "temperature_low_state_template";
constexpr const char *const MQTT_TEMPERATURE_LOW_STATE_TOPIC = "temperature_low_state_topic";
constexpr const char *const MQTT_TEMPERATURE_STATE_TEMPLATE = "temperature_state_template";
constexpr const char *const MQTT_TEMPERATURE_STATE_TOPIC = "temperature_state_topic";
constexpr const char *const MQTT_TEMPERATURE_UNIT = "temperature_unit";
constexpr const char *const MQTT_TILT_CLOSED_VALUE = "tilt_closed_value";
constexpr const char *const MQTT_TILT_COMMAND_TEMPLATE = "tilt_command_template";
constexpr const char *const MQTT_TILT_COMMAND_TOPIC = "tilt_command_topic";
constexpr const char *const MQTT_TILT_INVERT_STATE = "tilt_invert_state";
constexpr const char *const MQTT_TILT_MAX = "tilt_max";
constexpr const char *const MQTT_TILT_MIN = "tilt_min";
constexpr const char *const MQTT_TILT_OPENED_VALUE = "tilt_opened_value";
constexpr const char *const MQTT_TILT_OPTIMISTIC = "tilt_optimistic";
constexpr const char *const MQTT_TILT_STATUS_TEMPLATE = "tilt_status_template";
constexpr const char *const MQTT_TILT_STATUS_TOPIC = "tilt_status_topic";
constexpr const char *const MQTT_TOPIC = "topic";
constexpr const char *const MQTT_UNIQUE_ID = "unique_id";
constexpr const char *const MQTT_UNIT_OF_MEASUREMENT = "unit_of_measurement";
constexpr const char *const MQTT_VALUE_TEMPLATE = "value_template";
constexpr const char *const MQTT_WHITE_COMMAND_TOPIC = "white_command_topic";
constexpr const char *const MQTT_WHITE_SCALE = "white_scale";
constexpr const char *const MQTT_WHITE_VALUE_COMMAND_TOPIC = "white_value_command_topic";
constexpr const char *const MQTT_WHITE_VALUE_SCALE = "white_value_scale";
constexpr const char *const MQTT_WHITE_VALUE_STATE_TOPIC = "white_value_state_topic";
constexpr const char *const MQTT_WHITE_VALUE_TEMPLATE = "white_value_template";
constexpr const char *const MQTT_XY_COMMAND_TOPIC = "xy_command_topic";
constexpr const char *const MQTT_XY_STATE_TOPIC = "xy_state_topic";
constexpr const char *const MQTT_XY_VALUE_TEMPLATE = "xy_value_template";
// Generate flash string pointers from the PROGMEM data
// NOLINTNEXTLINE(bugprone-macro-parentheses)
#define MQTT_PTR(name, abbr, full) \
static const __FlashStringHelper *const name = reinterpret_cast<const __FlashStringHelper *>(name##_data);
MQTT_KEYS_LIST(MQTT_PTR)
#undef MQTT_PTR
} // namespace esphome::mqtt
#else
// Other platforms: constexpr in namespace
namespace esphome::mqtt {
#ifdef USE_MQTT_ABBREVIATIONS
// NOLINTNEXTLINE(bugprone-macro-parentheses)
#define MQTT_CONST(name, abbr, full) constexpr const char *name = abbr;
#else
// NOLINTNEXTLINE(bugprone-macro-parentheses)
#define MQTT_CONST(name, abbr, full) constexpr const char *name = full;
#endif
MQTT_KEYS_LIST(MQTT_CONST)
#undef MQTT_CONST
} // namespace esphome::mqtt
#endif
} // namespace mqtt
} // namespace esphome
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_COVER
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.cover";
@@ -119,8 +118,7 @@ bool MQTTCoverComponent::publish_state() {
return success;
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/cover/cover.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTCoverComponent : public mqtt::MQTTComponent {
public:
@@ -36,8 +35,7 @@ class MQTTCoverComponent : public mqtt::MQTTComponent {
cover::Cover *cover_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#ifdef USE_MQTT
#ifdef USE_DATETIME_DATE
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.datetime";
@@ -62,8 +61,7 @@ bool MQTTDateComponent::publish_state(uint16_t year, uint8_t month, uint8_t day)
});
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_DATE
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/datetime/date_entity.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTDateComponent : public mqtt::MQTTComponent {
public:
@@ -38,8 +37,7 @@ class MQTTDateComponent : public mqtt::MQTTComponent {
datetime::DateEntity *date_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_DATE
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#ifdef USE_MQTT
#ifdef USE_DATETIME_DATETIME
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.datetime.datetime";
@@ -78,8 +77,7 @@ bool MQTTDateTimeComponent::publish_state(uint16_t year, uint8_t month, uint8_t
});
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_DATETIME
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/datetime/datetime_entity.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTDateTimeComponent : public mqtt::MQTTComponent {
public:
@@ -38,8 +37,7 @@ class MQTTDateTimeComponent : public mqtt::MQTTComponent {
datetime::DateTimeEntity *datetime_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_DATETIME
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_EVENT
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.event";
@@ -54,8 +53,7 @@ bool MQTTEventComponent::publish_event_(const std::string &event_type) {
std::string MQTTEventComponent::component_type() const { return "event"; }
const EntityBase *MQTTEventComponent::get_entity() const { return this->event_; }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/event/event.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTEventComponent : public mqtt::MQTTComponent {
public:
@@ -32,8 +31,7 @@ class MQTTEventComponent : public mqtt::MQTTComponent {
event::Event *event_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_FAN
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.fan";
@@ -182,8 +181,7 @@ bool MQTTFanComponent::publish_state() {
return !failed;
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/fan/fan.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTFanComponent : public mqtt::MQTTComponent {
public:
@@ -47,8 +46,7 @@ class MQTTFanComponent : public mqtt::MQTTComponent {
fan::Fan *state_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#ifdef USE_LIGHT
#include "esphome/components/light/light_json_schema.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.light";
@@ -92,8 +91,7 @@ void MQTTJSONLightComponent::dump_config() {
LOG_MQTT_COMPONENT(true, true)
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "mqtt_component.h"
#include "esphome/components/light/light_state.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTJSONLightComponent : public mqtt::MQTTComponent, public light::LightRemoteValuesListener {
public:
@@ -37,8 +36,7 @@ class MQTTJSONLightComponent : public mqtt::MQTTComponent, public light::LightRe
light::LightState *state_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_LOCK
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.lock";
@@ -58,8 +57,7 @@ bool MQTTLockComponent::publish_state() {
#endif
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/lock/lock.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTLockComponent : public mqtt::MQTTComponent {
public:
@@ -34,8 +33,7 @@ class MQTTLockComponent : public mqtt::MQTTComponent {
lock::Lock *lock_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_NUMBER
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.number";
@@ -80,8 +79,7 @@ bool MQTTNumberComponent::publish_state(float value) {
return this->publish(this->get_state_topic_(), buffer);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/number/number.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTNumberComponent : public mqtt::MQTTComponent {
public:
@@ -39,8 +38,7 @@ class MQTTNumberComponent : public mqtt::MQTTComponent {
number::Number *number_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_SELECT
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.select";
@@ -53,8 +52,7 @@ bool MQTTSelectComponent::publish_state(const std::string &value) {
return this->publish(this->get_state_topic_(), value);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/select/select.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTSelectComponent : public mqtt::MQTTComponent {
public:
@@ -39,8 +38,7 @@ class MQTTSelectComponent : public mqtt::MQTTComponent {
select::Select *select_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -11,8 +11,7 @@
#include "esphome/components/deep_sleep/deep_sleep_component.h"
#endif
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.sensor";
@@ -86,8 +85,7 @@ bool MQTTSensorComponent::publish_state(float value) {
return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/sensor/sensor.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTSensorComponent : public mqtt::MQTTComponent {
public:
@@ -51,8 +50,7 @@ class MQTTSensorComponent : public mqtt::MQTTComponent {
optional<uint32_t> expire_after_; // Override the expire after advertised to Home Assistant
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_SWITCH
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.switch";
@@ -57,8 +56,7 @@ bool MQTTSwitchComponent::publish_state(bool state) {
return this->publish(this->get_state_topic_(), state_s);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/switch/switch.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTSwitchComponent : public mqtt::MQTTComponent {
public:
@@ -34,8 +33,7 @@ class MQTTSwitchComponent : public mqtt::MQTTComponent {
switch_::Switch *switch_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_TEXT
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.text";
@@ -57,8 +56,7 @@ bool MQTTTextComponent::publish_state(const std::string &value) {
return this->publish(this->get_state_topic_(), value);
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/text/text.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTTextComponent : public mqtt::MQTTComponent {
public:
@@ -39,8 +38,7 @@ class MQTTTextComponent : public mqtt::MQTTComponent {
text::Text *text_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_TEXT_SENSOR
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.text_sensor";
@@ -43,8 +42,7 @@ bool MQTTTextSensor::send_initial_state() {
std::string MQTTTextSensor::component_type() const { return "sensor"; }
const EntityBase *MQTTTextSensor::get_entity() const { return this->sensor_; }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/text_sensor/text_sensor.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTTextSensor : public mqtt::MQTTComponent {
public:
@@ -32,8 +31,7 @@ class MQTTTextSensor : public mqtt::MQTTComponent {
text_sensor::TextSensor *sensor_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#ifdef USE_MQTT
#ifdef USE_DATETIME_TIME
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.datetime.time";
@@ -62,8 +61,7 @@ bool MQTTTimeComponent::publish_state(uint8_t hour, uint8_t minute, uint8_t seco
});
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_TIME
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/datetime/time_entity.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTTimeComponent : public mqtt::MQTTComponent {
public:
@@ -38,8 +37,7 @@ class MQTTTimeComponent : public mqtt::MQTTComponent {
datetime::TimeEntity *time_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_DATETIME_DATE
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_UPDATE
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.update";
@@ -56,8 +55,7 @@ void MQTTUpdateComponent::dump_config() {
std::string MQTTUpdateComponent::component_type() const { return "update"; }
const EntityBase *MQTTUpdateComponent::get_entity() const { return this->update_; }
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_UPDATE
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/update/update_entity.h"
#include "mqtt_component.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTUpdateComponent : public mqtt::MQTTComponent {
public:
@@ -34,8 +33,7 @@ class MQTTUpdateComponent : public mqtt::MQTTComponent {
update::UpdateEntity *update_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif // USE_UPDATE
#endif // USE_MQTT

View File

@@ -6,8 +6,7 @@
#ifdef USE_MQTT
#ifdef USE_VALVE
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
static const char *const TAG = "mqtt.valve";
@@ -89,8 +88,7 @@ bool MQTTValveComponent::publish_state() {
return success;
}
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -8,8 +8,7 @@
#include "esphome/components/valve/valve.h"
namespace esphome {
namespace mqtt {
namespace esphome::mqtt {
class MQTTValveComponent : public mqtt::MQTTComponent {
public:
@@ -34,8 +33,7 @@ class MQTTValveComponent : public mqtt::MQTTComponent {
valve::Valve *valve_;
};
} // namespace mqtt
} // namespace esphome
} // namespace esphome::mqtt
#endif
#endif // USE_MQTT

View File

@@ -131,9 +131,9 @@ void NAU7802Sensor::dump_config() {
}
// Note these may differ from the values on the device if calbration has been run
ESP_LOGCONFIG(TAG,
" Offset Calibration: %s\n"
" Offset Calibration: %" PRId32 "\n"
" Gain Calibration: %f",
to_string(this->offset_calibration_).c_str(), this->gain_calibration_);
this->offset_calibration_, this->gain_calibration_);
std::string voltage = "unknown";
switch (this->ldo_) {
@@ -289,7 +289,7 @@ void NAU7802Sensor::loop() {
this->status_clear_error();
int32_t ocal = this->read_value_(OCAL1_B2_REG, 3);
ESP_LOGI(TAG, "New Offset: %s", to_string(ocal).c_str());
ESP_LOGI(TAG, "New Offset: %" PRId32, ocal);
uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4);
float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL));
ESP_LOGI(TAG, "New Gain: %f", gcal_f);

View File

@@ -194,6 +194,14 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config):
if CORE.is_esp8266:
# NeoPixelBus library unconditionally includes NeoEsp8266UartMethod.h
# which references Serial and Serial1, so we must enable both
from esphome.components.esp8266.const import enable_serial, enable_serial1
enable_serial()
enable_serial1()
has_white = "W" in config[CONF_TYPE]
method = config[CONF_METHOD]

View File

@@ -21,7 +21,6 @@ namespace esphome {
namespace opentherm {
using std::string;
using std::to_string;
static const char *const TAG = "opentherm";
@@ -564,10 +563,9 @@ const char *OpenTherm::message_id_to_str(MessageId id) {
void OpenTherm::debug_data(OpenthermData &data) {
ESP_LOGD(TAG, "%s %s %s %s", format_bin(data.type).c_str(), format_bin(data.id).c_str(),
format_bin(data.valueHB).c_str(), format_bin(data.valueLB).c_str());
ESP_LOGD(TAG, "type: %s; id: %s; HB: %s; LB: %s; uint_16: %s; float: %s",
this->message_type_to_str((MessageType) data.type), to_string(data.id).c_str(),
to_string(data.valueHB).c_str(), to_string(data.valueLB).c_str(), to_string(data.u16()).c_str(),
to_string(data.f88()).c_str());
ESP_LOGD(TAG, "type: %s; id: %u; HB: %u; LB: %u; uint_16: %u; float: %f",
this->message_type_to_str((MessageType) data.type), data.id, data.valueHB, data.valueLB, data.u16(),
data.f88());
}
void OpenTherm::debug_error(OpenThermError &error) const {
ESP_LOGD(TAG, "data: 0x%08" PRIx32 "; clock: %u; capture: 0x%08" PRIx32 "; bit_pos: %u", error.data, this->clock_,

View File

@@ -33,13 +33,12 @@ class IPAddressOpenThreadInfo : public PollingComponent, public text_sensor::Tex
return;
}
char address_as_string[40];
otIp6AddressToString(&*address, address_as_string, 40);
std::string ip = address_as_string;
char buf[OT_IP6_ADDRESS_STRING_SIZE];
otIp6AddressToString(&*address, buf, sizeof(buf));
if (this->last_ip_ != ip) {
this->last_ip_ = ip;
this->publish_state(this->last_ip_);
if (this->last_ip_ != buf) {
this->last_ip_ = buf;
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
@@ -89,7 +88,9 @@ class ExtAddrOpenThreadInfo : public OpenThreadInstancePollingComponent, public
const auto *extaddr = otLinkGetExtendedAddress(instance);
if (!std::equal(this->last_extaddr_.begin(), this->last_extaddr_.end(), extaddr->m8)) {
std::copy(extaddr->m8, extaddr->m8 + 8, this->last_extaddr_.begin());
this->publish_state(format_hex(extaddr->m8, 8));
char buf[format_hex_size(8)];
format_hex_to(buf, extaddr->m8, 8);
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
@@ -107,7 +108,9 @@ class Eui64OpenThreadInfo : public OpenThreadInstancePollingComponent, public te
if (!std::equal(this->last_eui64_.begin(), this->last_eui64_.end(), addr.m8)) {
std::copy(addr.m8, addr.m8 + 8, this->last_eui64_.begin());
this->publish_state(format_hex(this->last_eui64_.begin(), 8));
char buf[format_hex_size(8)];
format_hex_to(buf, this->last_eui64_.data(), 8);
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
@@ -123,7 +126,9 @@ class ChannelOpenThreadInfo : public OpenThreadInstancePollingComponent, public
uint8_t channel = otLinkGetChannel(instance);
if (this->last_channel_ != channel) {
this->last_channel_ = channel;
this->publish_state(std::to_string(this->last_channel_));
char buf[4]; // max "255" + null
snprintf(buf, sizeof(buf), "%u", channel);
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
@@ -168,7 +173,9 @@ class NetworkKeyOpenThreadInfo : public DatasetOpenThreadInfo, public text_senso
void update_dataset(otOperationalDataset *dataset) override {
if (!std::equal(this->last_key_.begin(), this->last_key_.end(), dataset->mNetworkKey.m8)) {
std::copy(dataset->mNetworkKey.m8, dataset->mNetworkKey.m8 + 16, this->last_key_.begin());
this->publish_state(format_hex(dataset->mNetworkKey.m8, 16));
char buf[format_hex_size(16)];
format_hex_to(buf, dataset->mNetworkKey.m8, 16);
this->publish_state(buf);
}
}
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
@@ -201,7 +208,9 @@ class ExtPanIdOpenThreadInfo : public DatasetOpenThreadInfo, public text_sensor:
void update_dataset(otOperationalDataset *dataset) override {
if (!std::equal(this->last_extpanid_.begin(), this->last_extpanid_.end(), dataset->mExtendedPanId.m8)) {
std::copy(dataset->mExtendedPanId.m8, dataset->mExtendedPanId.m8 + 8, this->last_extpanid_.begin());
this->publish_state(format_hex(this->last_extpanid_.begin(), 8));
char buf[format_hex_size(8)];
format_hex_to(buf, this->last_extpanid_.data(), 8);
this->publish_state(buf);
}
}

View File

@@ -265,13 +265,6 @@ void PMSX003Component::parse_data_() {
if (this->pm_particles_25um_sensor_ != nullptr)
this->pm_particles_25um_sensor_->publish_state(pm_particles_25um);
// Calculate and publish AQI if sensor is configured
if (this->aqi_sensor_ != nullptr) {
aqi::AbstractAQICalculator *calculator = this->aqi_calculator_factory_.get_calculator(this->aqi_calc_type_);
int32_t aqi_value = calculator->get_aqi(pm_2_5_concentration, pm_10_0_concentration);
this->aqi_sensor_->publish_state(aqi_value);
}
if (this->type_ == PMSX003_TYPE_5003T) {
ESP_LOGD(TAG,
"Got PM0.3 Particles: %u Count/0.1L, PM0.5 Particles: %u Count/0.1L, PM1.0 Particles: %u Count/0.1L, "

View File

@@ -4,7 +4,6 @@
#include "esphome/core/helpers.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
#include "esphome/components/aqi/aqi_calculator_factory.h"
namespace esphome {
namespace pmsx003 {
@@ -74,10 +73,6 @@ class PMSX003Component : public uart::UARTDevice, public Component {
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
void set_aqi_sensor(sensor::Sensor *aqi_sensor) { aqi_sensor_ = aqi_sensor; }
void set_aqi_calculation_type(aqi::AQICalculatorType aqi_calc_type) { aqi_calc_type_ = aqi_calc_type; }
protected:
optional<bool> check_byte_();
void parse_data_();
@@ -121,12 +116,6 @@ class PMSX003Component : public uart::UARTDevice, public Component {
// Temperature and Humidity
sensor::Sensor *temperature_sensor_{nullptr};
sensor::Sensor *humidity_sensor_{nullptr};
// AQI
sensor::Sensor *aqi_sensor_{nullptr};
aqi::AQICalculatorType aqi_calc_type_;
aqi::AQICalculatorFactory aqi_calculator_factory_ = aqi::AQICalculatorFactory();
};
} // namespace pmsx003

View File

@@ -1,6 +1,5 @@
import esphome.codegen as cg
from esphome.components import sensor, uart
from esphome.components.aqi import AQI_CALCULATION_TYPE, CONF_AQI, CONF_CALCULATION_TYPE
import esphome.config_validation as cv
from esphome.const import (
CONF_FORMALDEHYDE,
@@ -21,7 +20,6 @@ from esphome.const import (
CONF_TEMPERATURE,
CONF_TYPE,
CONF_UPDATE_INTERVAL,
DEVICE_CLASS_AQI,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_PM1,
DEVICE_CLASS_PM10,
@@ -37,13 +35,11 @@ from esphome.const import (
CODEOWNERS = ["@ximex"]
DEPENDENCIES = ["uart"]
AUTO_LOAD = ["aqi"]
pmsx003_ns = cg.esphome_ns.namespace("pmsx003")
PMSX003Component = pmsx003_ns.class_("PMSX003Component", uart.UARTDevice, cg.Component)
PMSX003Sensor = pmsx003_ns.class_("PMSX003Sensor", sensor.Sensor)
UNIT_INDEX = "index"
TYPE_PMSX003 = "PMSX003"
TYPE_PMS5003T = "PMS5003T"
TYPE_PMS5003ST = "PMS5003ST"
@@ -81,10 +77,6 @@ def validate_pmsx003_sensors(value):
for key, types in SENSORS_TO_TYPE.items():
if key in value and value[CONF_TYPE] not in types:
raise cv.Invalid(f"{value[CONF_TYPE]} does not have {key} sensor!")
if CONF_AQI in value and CONF_PM_2_5 not in value:
raise cv.Invalid("AQI computation requires PM 2.5 sensor")
if CONF_AQI in value and CONF_PM_10_0 not in value:
raise cv.Invalid("AQI computation requires PM 10 sensor")
return value
@@ -200,19 +192,6 @@ CONFIG_SCHEMA = (
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_AQI): sensor.sensor_schema(
unit_of_measurement=UNIT_INDEX,
icon=ICON_CHEMICAL_WEAPON,
accuracy_decimals=0,
device_class=DEVICE_CLASS_AQI,
state_class=STATE_CLASS_MEASUREMENT,
).extend(
{
cv.Required(CONF_CALCULATION_TYPE): cv.enum(
AQI_CALCULATION_TYPE, upper=True
),
}
),
cv.Optional(CONF_UPDATE_INTERVAL, default="0s"): validate_update_interval,
}
)
@@ -299,9 +278,4 @@ async def to_code(config):
sens = await sensor.new_sensor(config[CONF_HUMIDITY])
cg.add(var.set_humidity_sensor(sens))
if CONF_AQI in config:
sens = await sensor.new_sensor(config[CONF_AQI])
cg.add(var.set_aqi_sensor(sens))
cg.add(var.set_aqi_calculation_type(config[CONF_AQI][CONF_CALCULATION_TYPE]))
cg.add(var.set_update_interval(config[CONF_UPDATE_INTERVAL]))

View File

@@ -25,16 +25,16 @@ void PylontechTextSensor::on_line_read(PylontechListener::LineContents *line) {
return;
}
if (this->base_state_text_sensor_ != nullptr) {
this->base_state_text_sensor_->publish_state(std::string(line->base_st));
this->base_state_text_sensor_->publish_state(line->base_st);
}
if (this->voltage_state_text_sensor_ != nullptr) {
this->voltage_state_text_sensor_->publish_state(std::string(line->volt_st));
this->voltage_state_text_sensor_->publish_state(line->volt_st);
}
if (this->current_state_text_sensor_ != nullptr) {
this->current_state_text_sensor_->publish_state(std::string(line->curr_st));
this->current_state_text_sensor_->publish_state(line->curr_st);
}
if (this->temperature_state_text_sensor_ != nullptr) {
this->temperature_state_text_sensor_->publish_state(std::string(line->temp_st));
this->temperature_state_text_sensor_->publish_state(line->temp_st);
}
}

View File

@@ -10,23 +10,26 @@ namespace esphome::sha256 {
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
// CRITICAL ESP32-S3 HARDWARE SHA ACCELERATION REQUIREMENTS:
// CRITICAL ESP32-S3 HARDWARE SHA ACCELERATION REQUIREMENTS (IDF 5.5.x):
//
// The ESP32-S3 uses hardware DMA for SHA acceleration. The mbedtls_sha256_context structure contains
// internal state that the DMA engine references. This imposes two critical constraints:
// internal state that the DMA engine references. This imposes three critical constraints:
//
// 1. NO VARIABLE LENGTH ARRAYS (VLAs): VLAs corrupt the stack layout, causing the DMA engine to
// 1. ALIGNMENT: The SHA256 object MUST be declared with `alignas(32)` for proper DMA alignment.
// Without this, the DMA engine may crash with an abort in sha_hal_read_digest().
//
// 2. NO VARIABLE LENGTH ARRAYS (VLAs): VLAs corrupt the stack layout, causing the DMA engine to
// write to incorrect memory locations. This results in null pointer dereferences and crashes.
// ALWAYS use fixed-size arrays (e.g., char buf[65], not char buf[size+1]).
//
// 2. SAME STACK FRAME ONLY: The SHA256 object must be created and used entirely within the same
// 3. SAME STACK FRAME ONLY: The SHA256 object must be created and used entirely within the same
// function. NEVER pass the SHA256 object or HashBase pointer to another function. When the stack
// frame changes (function call/return), the DMA references become invalid and will produce
// truncated hash output (20 bytes instead of 32) or corrupt memory.
//
// CORRECT USAGE:
// void my_function() {
// sha256::SHA256 hasher; // Created locally
// alignas(32) sha256::SHA256 hasher; // Created locally with proper alignment
// hasher.init();
// hasher.add(data, len); // Any size, no chunking needed
// hasher.calculate();
@@ -36,7 +39,7 @@ namespace esphome::sha256 {
//
// INCORRECT USAGE (WILL FAIL ON ESP32-S3):
// void my_function() {
// sha256::SHA256 hasher;
// sha256::SHA256 hasher; // WRONG: Missing alignas(32)
// helper(&hasher); // WRONG: Passed to different stack frame
// }
// void helper(HashBase *h) {

View File

@@ -22,6 +22,18 @@
namespace esphome::sha256 {
/// SHA256 hash implementation.
///
/// CRITICAL for ESP32-S3 with IDF 5.5.x hardware SHA acceleration:
/// 1. SHA256 objects MUST be declared with `alignas(32)` for proper DMA alignment
/// 2. The object MUST stay in the same stack frame (no passing to other functions)
/// 3. NO Variable Length Arrays (VLAs) in the same function
///
/// Example usage:
/// alignas(32) sha256::SHA256 hasher;
/// hasher.init();
/// hasher.add(data, len);
/// hasher.calculate();
class SHA256 : public esphome::HashBase {
public:
SHA256() = default;
@@ -39,10 +51,8 @@ class SHA256 : public esphome::HashBase {
protected:
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
// CRITICAL: The mbedtls context MUST be stack-allocated (not a pointer) for ESP32-S3 hardware SHA acceleration.
// The ESP32-S3 DMA engine references this structure's memory addresses. If the context is passed to another
// function (crossing stack frames) or if VLAs are present, the DMA operations will corrupt memory and produce
// truncated/incorrect hash results.
// The mbedtls context for ESP32-S3 hardware SHA requires proper alignment and stack frame constraints.
// See class documentation above for critical requirements.
mbedtls_sha256_context ctx_{};
#elif defined(USE_ESP8266) || defined(USE_RP2040)
br_sha256_context ctx_{};

View File

@@ -2,6 +2,7 @@
#include "esphome/core/log.h"
#include "sml_text_sensor.h"
#include "../sml_parser.h"
#include <cinttypes>
namespace esphome {
namespace sml {
@@ -21,22 +22,33 @@ void SmlTextSensor::publish_val(const ObisInfo &obis_info) {
switch (value_type) {
case SML_HEX: {
publish_state("0x" + bytes_repr(obis_info.value));
// Buffer for "0x" + up to 32 bytes as hex + null
char buf[67];
buf[0] = '0';
buf[1] = 'x';
// Max 32 bytes of data fit in remaining buffer ((65-1)/2)
size_t hex_bytes = std::min(obis_info.value.size(), size_t(32));
format_hex_to(buf + 2, sizeof(buf) - 2, obis_info.value.begin(), hex_bytes);
publish_state(buf, 2 + hex_bytes * 2);
break;
}
case SML_INT: {
publish_state(to_string(bytes_to_int(obis_info.value)));
char buf[21]; // Enough for int64_t (-9223372036854775808)
int len = snprintf(buf, sizeof(buf), "%" PRId64, bytes_to_int(obis_info.value));
publish_state(buf, static_cast<size_t>(len));
break;
}
case SML_BOOL:
publish_state(bytes_to_uint(obis_info.value) ? "True" : "False");
break;
case SML_UINT: {
publish_state(to_string(bytes_to_uint(obis_info.value)));
char buf[21]; // Enough for uint64_t (18446744073709551615)
int len = snprintf(buf, sizeof(buf), "%" PRIu64, bytes_to_uint(obis_info.value));
publish_state(buf, static_cast<size_t>(len));
break;
}
case SML_OCTET: {
publish_state(std::string(obis_info.value.begin(), obis_info.value.end()));
publish_state(reinterpret_cast<const char *>(obis_info.value.begin()), obis_info.value.size());
break;
}
}

View File

@@ -14,31 +14,7 @@
namespace esphome::socket {
std::string format_sockaddr(const struct sockaddr_storage &storage) {
if (storage.ss_family == AF_INET) {
const struct sockaddr_in *addr = reinterpret_cast<const struct sockaddr_in *>(&storage);
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) != nullptr)
return std::string{buf};
}
#if LWIP_IPV6
else if (storage.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr = reinterpret_cast<const struct sockaddr_in6 *>(&storage);
char buf[INET6_ADDRSTRLEN];
// Format IPv4-mapped IPv6 addresses as regular IPv4 addresses
if (addr->sin6_addr.un.u32_addr[0] == 0 && addr->sin6_addr.un.u32_addr[1] == 0 &&
addr->sin6_addr.un.u32_addr[2] == htonl(0xFFFF) &&
inet_ntop(AF_INET, &addr->sin6_addr.un.u32_addr[3], buf, sizeof(buf)) != nullptr) {
return std::string{buf};
}
if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) != nullptr)
return std::string{buf};
}
#endif
return {};
}
class BSDSocketImpl : public Socket {
class BSDSocketImpl final : public Socket {
public:
BSDSocketImpl(int fd, bool monitor_loop = false) : fd_(fd) {
#ifdef USE_SOCKET_SELECT_SUPPORT
@@ -93,23 +69,9 @@ class BSDSocketImpl : public Socket {
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
return ::getpeername(this->fd_, addr, addrlen);
}
std::string getpeername() override {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
if (::getpeername(this->fd_, (struct sockaddr *) &storage, &len) != 0)
return {};
return format_sockaddr(storage);
}
int getsockname(struct sockaddr *addr, socklen_t *addrlen) override {
return ::getsockname(this->fd_, addr, addrlen);
}
std::string getsockname() override {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
if (::getsockname(this->fd_, (struct sockaddr *) &storage, &len) != 0)
return {};
return format_sockaddr(storage);
}
int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
return ::getsockopt(this->fd_, level, optname, optval, optlen);
}

View File

@@ -71,7 +71,7 @@ class LWIPRawImpl : public Socket {
errno = EINVAL;
return nullptr;
}
int bind(const struct sockaddr *name, socklen_t addrlen) override {
int bind(const struct sockaddr *name, socklen_t addrlen) final {
if (pcb_ == nullptr) {
errno = EBADF;
return -1;
@@ -135,7 +135,7 @@ class LWIPRawImpl : public Socket {
}
return 0;
}
int close() override {
int close() final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -152,7 +152,7 @@ class LWIPRawImpl : public Socket {
pcb_ = nullptr;
return 0;
}
int shutdown(int how) override {
int shutdown(int how) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -178,7 +178,7 @@ class LWIPRawImpl : public Socket {
return 0;
}
int getpeername(struct sockaddr *name, socklen_t *addrlen) override {
int getpeername(struct sockaddr *name, socklen_t *addrlen) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -189,14 +189,7 @@ class LWIPRawImpl : public Socket {
}
return this->ip2sockaddr_(&pcb_->remote_ip, pcb_->remote_port, name, addrlen);
}
std::string getpeername() override {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return "";
}
return this->format_ip_address_(pcb_->remote_ip);
}
int getsockname(struct sockaddr *name, socklen_t *addrlen) override {
int getsockname(struct sockaddr *name, socklen_t *addrlen) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -207,14 +200,7 @@ class LWIPRawImpl : public Socket {
}
return this->ip2sockaddr_(&pcb_->local_ip, pcb_->local_port, name, addrlen);
}
std::string getsockname() override {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return "";
}
return this->format_ip_address_(pcb_->local_ip);
}
int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
int getsockopt(int level, int optname, void *optval, socklen_t *optlen) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -248,7 +234,7 @@ class LWIPRawImpl : public Socket {
errno = EINVAL;
return -1;
}
int setsockopt(int level, int optname, const void *optval, socklen_t optlen) override {
int setsockopt(int level, int optname, const void *optval, socklen_t optlen) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -282,7 +268,7 @@ class LWIPRawImpl : public Socket {
errno = EOPNOTSUPP;
return -1;
}
ssize_t read(void *buf, size_t len) override {
ssize_t read(void *buf, size_t len) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -340,7 +326,7 @@ class LWIPRawImpl : public Socket {
return read;
}
ssize_t readv(const struct iovec *iov, int iovcnt) override {
ssize_t readv(const struct iovec *iov, int iovcnt) final {
ssize_t ret = 0;
for (int i = 0; i < iovcnt; i++) {
ssize_t err = read(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len);
@@ -358,7 +344,7 @@ class LWIPRawImpl : public Socket {
return ret;
}
ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) override {
ssize_t recvfrom(void *buf, size_t len, sockaddr *addr, socklen_t *addr_len) final {
errno = ENOTSUP;
return -1;
}
@@ -412,7 +398,7 @@ class LWIPRawImpl : public Socket {
}
return 0;
}
ssize_t write(const void *buf, size_t len) override {
ssize_t write(const void *buf, size_t len) final {
ssize_t written = internal_write(buf, len);
if (written == -1)
return -1;
@@ -427,7 +413,7 @@ class LWIPRawImpl : public Socket {
}
return written;
}
ssize_t writev(const struct iovec *iov, int iovcnt) override {
ssize_t writev(const struct iovec *iov, int iovcnt) final {
ssize_t written = 0;
for (int i = 0; i < iovcnt; i++) {
ssize_t err = internal_write(reinterpret_cast<uint8_t *>(iov[i].iov_base), iov[i].iov_len);
@@ -453,12 +439,12 @@ class LWIPRawImpl : public Socket {
}
return written;
}
ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) override {
ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) final {
// return ::sendto(fd_, buf, len, flags, to, tolen);
errno = ENOSYS;
return -1;
}
int setblocking(bool blocking) override {
int setblocking(bool blocking) final {
if (pcb_ == nullptr) {
errno = ECONNRESET;
return -1;
@@ -517,19 +503,6 @@ class LWIPRawImpl : public Socket {
}
protected:
std::string format_ip_address_(const ip_addr_t &ip) {
char buffer[50] = {};
if (IP_IS_V4_VAL(ip)) {
inet_ntoa_r(ip, buffer, sizeof(buffer));
}
#if LWIP_IPV6
else if (IP_IS_V6_VAL(ip)) {
inet6_ntoa_r(ip, buffer, sizeof(buffer));
}
#endif
return std::string(buffer);
}
int ip2sockaddr_(ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen) {
if (family_ == AF_INET) {
if (*addrlen < sizeof(struct sockaddr_in)) {
@@ -584,7 +557,7 @@ class LWIPRawImpl : public Socket {
// Listening socket class - only allocates accept queue when needed (for bind+listen sockets)
// This saves 16 bytes (12 bytes array + 1 byte count + 3 bytes padding) for regular connected sockets on ESP8266/RP2040
class LWIPRawListenImpl : public LWIPRawImpl {
class LWIPRawListenImpl final : public LWIPRawImpl {
public:
LWIPRawListenImpl(sa_family_t family, struct tcp_pcb *pcb) : LWIPRawImpl(family, pcb) {}

View File

@@ -9,29 +9,7 @@
namespace esphome::socket {
std::string format_sockaddr(const struct sockaddr_storage &storage) {
if (storage.ss_family == AF_INET) {
const struct sockaddr_in *addr = reinterpret_cast<const struct sockaddr_in *>(&storage);
char buf[INET_ADDRSTRLEN];
const char *ret = lwip_inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf));
if (ret == nullptr)
return {};
return std::string{buf};
}
#if LWIP_IPV6
else if (storage.ss_family == AF_INET6) {
const struct sockaddr_in6 *addr = reinterpret_cast<const struct sockaddr_in6 *>(&storage);
char buf[INET6_ADDRSTRLEN];
const char *ret = lwip_inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf));
if (ret == nullptr)
return {};
return std::string{buf};
}
#endif
return {};
}
class LwIPSocketImpl : public Socket {
class LwIPSocketImpl final : public Socket {
public:
LwIPSocketImpl(int fd, bool monitor_loop = false) : fd_(fd) {
#ifdef USE_SOCKET_SELECT_SUPPORT
@@ -88,23 +66,9 @@ class LwIPSocketImpl : public Socket {
int getpeername(struct sockaddr *addr, socklen_t *addrlen) override {
return lwip_getpeername(this->fd_, addr, addrlen);
}
std::string getpeername() override {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
if (lwip_getpeername(this->fd_, (struct sockaddr *) &storage, &len) != 0)
return {};
return format_sockaddr(storage);
}
int getsockname(struct sockaddr *addr, socklen_t *addrlen) override {
return lwip_getsockname(this->fd_, addr, addrlen);
}
std::string getsockname() override {
struct sockaddr_storage storage;
socklen_t len = sizeof(storage);
if (lwip_getsockname(this->fd_, (struct sockaddr *) &storage, &len) != 0)
return {};
return format_sockaddr(storage);
}
int getsockopt(int level, int optname, void *optval, socklen_t *optlen) override {
return lwip_getsockopt(this->fd_, level, optname, optval, optlen);
}

Some files were not shown because too many files have changed in this diff Show More