1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-07 13:52:20 +01:00

Merge branch 'component_source_logstring' into integration

This commit is contained in:
J. Nick Koston
2025-09-05 17:11:16 -05:00
15 changed files with 127 additions and 128 deletions

View File

@@ -52,7 +52,7 @@ void DebugComponent::on_shutdown() {
char buffer[REBOOT_MAX_LEN]{}; char buffer[REBOOT_MAX_LEN]{};
auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name())); auto pref = global_preferences->make_preference(REBOOT_MAX_LEN, fnv1_hash(REBOOT_KEY + App.get_name()));
if (component != nullptr) { if (component != nullptr) {
strncpy(buffer, component->get_component_source(), REBOOT_MAX_LEN - 1); strncpy(buffer, LOG_STR_ARG(component->get_component_log_str()), REBOOT_MAX_LEN - 1);
buffer[REBOOT_MAX_LEN - 1] = '\0'; buffer[REBOOT_MAX_LEN - 1] = '\0';
} }
ESP_LOGD(TAG, "Storing reboot source: %s", buffer); ESP_LOGD(TAG, "Storing reboot source: %s", buffer);

View File

@@ -17,16 +17,8 @@ void RuntimeStatsCollector::record_component_time(Component *component, uint32_t
if (component == nullptr) if (component == nullptr)
return; return;
// Check if we have cached the name for this component // Record stats using component pointer as key
auto name_it = this->component_names_cache_.find(component); this->component_stats_[component].record_time(duration_ms);
if (name_it == this->component_names_cache_.end()) {
// First time seeing this component, cache its name
const char *source = component->get_component_source();
this->component_names_cache_[component] = source;
this->component_stats_[source].record_time(duration_ms);
} else {
this->component_stats_[name_it->second].record_time(duration_ms);
}
if (this->next_log_time_ == 0) { if (this->next_log_time_ == 0) {
this->next_log_time_ = current_time + this->log_interval_; this->next_log_time_ = current_time + this->log_interval_;
@@ -42,9 +34,10 @@ void RuntimeStatsCollector::log_stats_() {
std::vector<ComponentStatPair> stats_to_display; std::vector<ComponentStatPair> stats_to_display;
for (const auto &it : this->component_stats_) { for (const auto &it : this->component_stats_) {
Component *component = it.first;
const ComponentRuntimeStats &stats = it.second; const ComponentRuntimeStats &stats = it.second;
if (stats.get_period_count() > 0) { if (stats.get_period_count() > 0) {
ComponentStatPair pair = {it.first, &stats}; ComponentStatPair pair = {component, &stats};
stats_to_display.push_back(pair); stats_to_display.push_back(pair);
} }
} }
@@ -54,7 +47,7 @@ void RuntimeStatsCollector::log_stats_() {
// Log top components by period runtime // Log top components by period runtime
for (const auto &it : stats_to_display) { for (const auto &it : stats_to_display) {
const char *source = it.name; const char *source = LOG_STR_ARG(it.component->get_component_log_str());
const ComponentRuntimeStats *stats = it.stats; const ComponentRuntimeStats *stats = it.stats;
ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source, ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source,
@@ -72,7 +65,7 @@ void RuntimeStatsCollector::log_stats_() {
}); });
for (const auto &it : stats_to_display) { for (const auto &it : stats_to_display) {
const char *source = it.name; const char *source = LOG_STR_ARG(it.component->get_component_log_str());
const ComponentRuntimeStats *stats = it.stats; const ComponentRuntimeStats *stats = it.stats;
ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source, ESP_LOGI(TAG, " %s: count=%" PRIu32 ", avg=%.2fms, max=%" PRIu32 "ms, total=%" PRIu32 "ms", source,

View File

@@ -79,7 +79,7 @@ class ComponentRuntimeStats {
// For sorting components by run time // For sorting components by run time
struct ComponentStatPair { struct ComponentStatPair {
const char *name; Component *component;
const ComponentRuntimeStats *stats; const ComponentRuntimeStats *stats;
bool operator>(const ComponentStatPair &other) const { bool operator>(const ComponentStatPair &other) const {
@@ -109,15 +109,9 @@ class RuntimeStatsCollector {
} }
} }
// Use const char* keys for efficiency // Map from component to its stats
// Custom comparator for const char* keys in map // We use Component* as the key since each component is unique
// Without this, std::map would compare pointer addresses instead of string contents, std::map<Component *, ComponentRuntimeStats> component_stats_;
// causing identical component names at different addresses to be treated as different keys
struct CStrCompare {
bool operator()(const char *a, const char *b) const { return std::strcmp(a, b) < 0; }
};
std::map<const char *, ComponentRuntimeStats, CStrCompare> component_stats_;
std::map<Component *, const char *> component_names_cache_;
uint32_t log_interval_; uint32_t log_interval_;
uint32_t next_log_time_; uint32_t next_log_time_;
}; };

View File

@@ -15,6 +15,8 @@ namespace sensirion_common {
* Format: * Format:
* | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | .. * | 16 Bit Command Code | 16 bit Data word 1 | CRC of DW 1 | 16 bit Data word 1 | CRC of DW 2 | ..
*/ */
static const uint8_t CRC_POLYNOMIAL = 0x31; // default for Sensirion
class SensirionI2CDevice : public i2c::I2CDevice { class SensirionI2CDevice : public i2c::I2CDevice {
public: public:
enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 }; enum CommandLen : uint8_t { ADDR_8_BIT = 1, ADDR_16_BIT = 2 };

View File

@@ -1,9 +1,11 @@
#include "sgp30.h" #include "sgp30.h"
#include <cinttypes>
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include <cinttypes>
namespace esphome { namespace esphome {
namespace sgp30 { namespace sgp30 {
@@ -39,9 +41,8 @@ void SGP30Component::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
this->serial_number_ = (uint64_t(raw_serial_number[0]) << 24) | (uint64_t(raw_serial_number[1]) << 16) | this->serial_number_ = encode_uint24(raw_serial_number[0], raw_serial_number[1], raw_serial_number[2]);
(uint64_t(raw_serial_number[2])); ESP_LOGD(TAG, "Serial number: %" PRIu64, this->serial_number_);
ESP_LOGD(TAG, "Serial Number: %" PRIu64, this->serial_number_);
// Featureset identification for future use // Featureset identification for future use
uint16_t raw_featureset; uint16_t raw_featureset;
@@ -61,11 +62,11 @@ void SGP30Component::setup() {
this->mark_failed(); this->mark_failed();
return; return;
} }
ESP_LOGD(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF)); ESP_LOGV(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF));
// Sensor initialization // Sensor initialization
if (!this->write_command(SGP30_CMD_IAQ_INIT)) { if (!this->write_command(SGP30_CMD_IAQ_INIT)) {
ESP_LOGE(TAG, "Sensor sgp30_iaq_init failed."); ESP_LOGE(TAG, "sgp30_iaq_init failed");
this->error_code_ = MEASUREMENT_INIT_FAILED; this->error_code_ = MEASUREMENT_INIT_FAILED;
this->mark_failed(); this->mark_failed();
return; return;
@@ -123,7 +124,7 @@ void SGP30Component::read_iaq_baseline_() {
uint16_t eco2baseline = (raw_data[0]); uint16_t eco2baseline = (raw_data[0]);
uint16_t tvocbaseline = (raw_data[1]); uint16_t tvocbaseline = (raw_data[1]);
ESP_LOGI(TAG, "Current eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2baseline, tvocbaseline); ESP_LOGI(TAG, "Baselines: eCO2: 0x%04X, TVOC: 0x%04X", eco2baseline, tvocbaseline);
if (eco2baseline != this->eco2_baseline_ || tvocbaseline != this->tvoc_baseline_) { if (eco2baseline != this->eco2_baseline_ || tvocbaseline != this->tvoc_baseline_) {
this->eco2_baseline_ = eco2baseline; this->eco2_baseline_ = eco2baseline;
this->tvoc_baseline_ = tvocbaseline; this->tvoc_baseline_ = tvocbaseline;
@@ -142,7 +143,7 @@ void SGP30Component::read_iaq_baseline_() {
this->baselines_storage_.eco2 = this->eco2_baseline_; this->baselines_storage_.eco2 = this->eco2_baseline_;
this->baselines_storage_.tvoc = this->tvoc_baseline_; this->baselines_storage_.tvoc = this->tvoc_baseline_;
if (this->pref_.save(&this->baselines_storage_)) { if (this->pref_.save(&this->baselines_storage_)) {
ESP_LOGI(TAG, "Store eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", this->baselines_storage_.eco2, ESP_LOGI(TAG, "Store baselines: eCO2: 0x%04X, TVOC: 0x%04X", this->baselines_storage_.eco2,
this->baselines_storage_.tvoc); this->baselines_storage_.tvoc);
} else { } else {
ESP_LOGW(TAG, "Could not store eCO2 and TVOC baselines"); ESP_LOGW(TAG, "Could not store eCO2 and TVOC baselines");
@@ -164,7 +165,7 @@ void SGP30Component::send_env_data_() {
if (this->humidity_sensor_ != nullptr) if (this->humidity_sensor_ != nullptr)
humidity = this->humidity_sensor_->state; humidity = this->humidity_sensor_->state;
if (std::isnan(humidity) || humidity < 0.0f || humidity > 100.0f) { if (std::isnan(humidity) || humidity < 0.0f || humidity > 100.0f) {
ESP_LOGW(TAG, "Compensation not possible yet: bad humidity data."); ESP_LOGW(TAG, "Compensation not possible yet: bad humidity data");
return; return;
} else { } else {
ESP_LOGD(TAG, "External compensation data received: Humidity %0.2f%%", humidity); ESP_LOGD(TAG, "External compensation data received: Humidity %0.2f%%", humidity);
@@ -174,7 +175,7 @@ void SGP30Component::send_env_data_() {
temperature = float(this->temperature_sensor_->state); temperature = float(this->temperature_sensor_->state);
} }
if (std::isnan(temperature) || temperature < -40.0f || temperature > 85.0f) { if (std::isnan(temperature) || temperature < -40.0f || temperature > 85.0f) {
ESP_LOGW(TAG, "Compensation not possible yet: bad temperature value data."); ESP_LOGW(TAG, "Compensation not possible yet: bad temperature value");
return; return;
} else { } else {
ESP_LOGD(TAG, "External compensation data received: Temperature %0.2f°C", temperature); ESP_LOGD(TAG, "External compensation data received: Temperature %0.2f°C", temperature);
@@ -192,18 +193,17 @@ void SGP30Component::send_env_data_() {
((humidity * 0.061121f * std::exp((18.678f - temperature / 234.5f) * (temperature / (257.14f + temperature)))) / ((humidity * 0.061121f * std::exp((18.678f - temperature / 234.5f) * (temperature / (257.14f + temperature)))) /
(273.15f + temperature)); (273.15f + temperature));
} }
uint8_t humidity_full = uint8_t(std::floor(absolute_humidity)); uint8_t data[4] = {
uint8_t humidity_dec = uint8_t(std::floor((absolute_humidity - std::floor(absolute_humidity)) * 256)); SGP30_CMD_SET_ABSOLUTE_HUMIDITY & 0xFF,
ESP_LOGD(TAG, "Calculated Absolute humidity: %0.3f g/m³ (0x%04X)", absolute_humidity, uint8_t(std::floor(absolute_humidity)), // humidity_full
uint16_t(uint16_t(humidity_full) << 8 | uint16_t(humidity_dec))); uint8_t(std::floor((absolute_humidity - std::floor(absolute_humidity)) * 256)), // humidity_dec
uint8_t crc = sht_crc_(humidity_full, humidity_dec); 0,
uint8_t data[4]; };
data[0] = SGP30_CMD_SET_ABSOLUTE_HUMIDITY & 0xFF; data[3] = crc8(&data[1], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
data[1] = humidity_full; ESP_LOGD(TAG, "Calculated absolute humidity: %0.3f g/m³ (0x%04X)", absolute_humidity,
data[2] = humidity_dec; encode_uint16(data[1], data[2]));
data[3] = crc;
if (!this->write_bytes(SGP30_CMD_SET_ABSOLUTE_HUMIDITY >> 8, data, 4)) { if (!this->write_bytes(SGP30_CMD_SET_ABSOLUTE_HUMIDITY >> 8, data, 4)) {
ESP_LOGE(TAG, "Error sending compensation data."); ESP_LOGE(TAG, "Error sending compensation data");
} }
} }
@@ -212,15 +212,14 @@ void SGP30Component::write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_b
data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF; data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF;
data[1] = tvoc_baseline >> 8; data[1] = tvoc_baseline >> 8;
data[2] = tvoc_baseline & 0xFF; data[2] = tvoc_baseline & 0xFF;
data[3] = sht_crc_(data[1], data[2]); data[3] = crc8(&data[1], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
data[4] = eco2_baseline >> 8; data[4] = eco2_baseline >> 8;
data[5] = eco2_baseline & 0xFF; data[5] = eco2_baseline & 0xFF;
data[6] = sht_crc_(data[4], data[5]); data[6] = crc8(&data[4], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true);
if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) { if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) {
ESP_LOGE(TAG, "Error applying eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2_baseline, tvoc_baseline); ESP_LOGE(TAG, "Error applying baselines: eCO2: 0x%04X, TVOC: 0x%04X", eco2_baseline, tvoc_baseline);
} else { } else {
ESP_LOGI(TAG, "Initial baselines applied successfully! eCO2 baseline: 0x%04X, TVOC baseline: 0x%04X", eco2_baseline, ESP_LOGI(TAG, "Initial baselines applied: eCO2: 0x%04X, TVOC: 0x%04X", eco2_baseline, tvoc_baseline);
tvoc_baseline);
} }
} }
@@ -236,10 +235,10 @@ void SGP30Component::dump_config() {
ESP_LOGW(TAG, "Measurement Initialization failed"); ESP_LOGW(TAG, "Measurement Initialization failed");
break; break;
case INVALID_ID: case INVALID_ID:
ESP_LOGW(TAG, "Sensor reported an invalid ID. Is this an SGP30?"); ESP_LOGW(TAG, "Invalid ID");
break; break;
case UNSUPPORTED_ID: case UNSUPPORTED_ID:
ESP_LOGW(TAG, "Sensor reported an unsupported ID (SGPC3)"); ESP_LOGW(TAG, "Unsupported ID");
break; break;
default: default:
ESP_LOGW(TAG, "Unknown setup error"); ESP_LOGW(TAG, "Unknown setup error");
@@ -249,12 +248,12 @@ void SGP30Component::dump_config() {
ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_); ESP_LOGCONFIG(TAG, " Serial number: %" PRIu64, this->serial_number_);
if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) { if (this->eco2_baseline_ != 0x0000 && this->tvoc_baseline_ != 0x0000) {
ESP_LOGCONFIG(TAG, ESP_LOGCONFIG(TAG,
" Baseline:\n" " Baselines:\n"
" eCO2 Baseline: 0x%04X\n" " eCO2: 0x%04X\n"
" TVOC Baseline: 0x%04X", " TVOC: 0x%04X",
this->eco2_baseline_, this->tvoc_baseline_); this->eco2_baseline_, this->tvoc_baseline_);
} else { } else {
ESP_LOGCONFIG(TAG, " Baseline: No baseline configured"); ESP_LOGCONFIG(TAG, " Baselines not configured");
} }
ESP_LOGCONFIG(TAG, " Warm up time: %" PRIu32 "s", this->required_warm_up_time_); ESP_LOGCONFIG(TAG, " Warm up time: %" PRIu32 "s", this->required_warm_up_time_);
} }
@@ -266,8 +265,8 @@ void SGP30Component::dump_config() {
ESP_LOGCONFIG(TAG, "Store baseline: %s", YESNO(this->store_baseline_)); ESP_LOGCONFIG(TAG, "Store baseline: %s", YESNO(this->store_baseline_));
if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) { if (this->humidity_sensor_ != nullptr && this->temperature_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " Compensation:"); ESP_LOGCONFIG(TAG, " Compensation:");
LOG_SENSOR(" ", "Temperature Source:", this->temperature_sensor_); LOG_SENSOR(" ", "Temperature source:", this->temperature_sensor_);
LOG_SENSOR(" ", "Humidity Source:", this->humidity_sensor_); LOG_SENSOR(" ", "Humidity source:", this->humidity_sensor_);
} else { } else {
ESP_LOGCONFIG(TAG, " Compensation: No source configured"); ESP_LOGCONFIG(TAG, " Compensation: No source configured");
} }
@@ -289,7 +288,7 @@ void SGP30Component::update() {
float eco2 = (raw_data[0]); float eco2 = (raw_data[0]);
float tvoc = (raw_data[1]); float tvoc = (raw_data[1]);
ESP_LOGD(TAG, "Got eCO2=%.1fppm TVOC=%.1fppb", eco2, tvoc); ESP_LOGV(TAG, "eCO2=%.1fppm TVOC=%.1fppb", eco2, tvoc);
if (this->eco2_sensor_ != nullptr) if (this->eco2_sensor_ != nullptr)
this->eco2_sensor_->publish_state(eco2); this->eco2_sensor_->publish_state(eco2);
if (this->tvoc_sensor_ != nullptr) if (this->tvoc_sensor_ != nullptr)

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/sensirion_common/i2c_sensirion.h" #include "esphome/components/sensirion_common/i2c_sensirion.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include <cinttypes> #include <cinttypes>
@@ -38,14 +38,16 @@ class SGP30Component : public PollingComponent, public sensirion_common::Sensiri
void read_iaq_baseline_(); void read_iaq_baseline_();
bool is_sensor_baseline_reliable_(); bool is_sensor_baseline_reliable_();
void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline); void write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline);
uint64_t serial_number_; uint64_t serial_number_;
uint16_t featureset_;
uint32_t required_warm_up_time_; uint32_t required_warm_up_time_;
uint32_t seconds_since_last_store_; uint32_t seconds_since_last_store_;
SGP30Baselines baselines_storage_; uint16_t featureset_;
ESPPreferenceObject pref_; uint16_t eco2_baseline_{0x0000};
uint16_t tvoc_baseline_{0x0000};
bool store_baseline_;
enum ErrorCode { enum ErrorCode : uint8_t {
COMMUNICATION_FAILED, COMMUNICATION_FAILED,
MEASUREMENT_INIT_FAILED, MEASUREMENT_INIT_FAILED,
INVALID_ID, INVALID_ID,
@@ -53,14 +55,13 @@ class SGP30Component : public PollingComponent, public sensirion_common::Sensiri
UNKNOWN UNKNOWN
} error_code_{UNKNOWN}; } error_code_{UNKNOWN};
ESPPreferenceObject pref_;
SGP30Baselines baselines_storage_;
sensor::Sensor *eco2_sensor_{nullptr}; sensor::Sensor *eco2_sensor_{nullptr};
sensor::Sensor *tvoc_sensor_{nullptr}; sensor::Sensor *tvoc_sensor_{nullptr};
sensor::Sensor *eco2_sensor_baseline_{nullptr}; sensor::Sensor *eco2_sensor_baseline_{nullptr};
sensor::Sensor *tvoc_sensor_baseline_{nullptr}; sensor::Sensor *tvoc_sensor_baseline_{nullptr};
uint16_t eco2_baseline_{0x0000};
uint16_t tvoc_baseline_{0x0000};
bool store_baseline_;
/// Input sensor for humidity and temperature compensation. /// Input sensor for humidity and temperature compensation.
sensor::Sensor *humidity_sensor_{nullptr}; sensor::Sensor *humidity_sensor_{nullptr};
sensor::Sensor *temperature_sensor_{nullptr}; sensor::Sensor *temperature_sensor_{nullptr};

View File

@@ -43,20 +43,20 @@ void SPS30Component::setup() {
this->serial_number_[i * 2] = static_cast<char>(raw_serial_number[i] >> 8); this->serial_number_[i * 2] = static_cast<char>(raw_serial_number[i] >> 8);
this->serial_number_[i * 2 + 1] = uint16_t(uint16_t(raw_serial_number[i] & 0xFF)); this->serial_number_[i * 2 + 1] = uint16_t(uint16_t(raw_serial_number[i] & 0xFF));
} }
ESP_LOGD(TAG, " Serial Number: '%s'", this->serial_number_); ESP_LOGV(TAG, " Serial number: %s", this->serial_number_);
bool result; bool result;
if (this->fan_interval_.has_value()) { if (this->fan_interval_.has_value()) {
// override default value // override default value
result = write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS, this->fan_interval_.value()); result = this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS, this->fan_interval_.value());
} else { } else {
result = write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS); result = this->write_command(SPS30_CMD_SET_AUTOMATIC_CLEANING_INTERVAL_SECONDS);
} }
if (result) { if (result) {
delay(20); delay(20);
uint16_t secs[2]; uint16_t secs[2];
if (this->read_data(secs, 2)) { if (this->read_data(secs, 2)) {
fan_interval_ = secs[0] << 16 | secs[1]; this->fan_interval_ = secs[0] << 16 | secs[1];
} }
} }
@@ -67,7 +67,7 @@ void SPS30Component::setup() {
} }
void SPS30Component::dump_config() { void SPS30Component::dump_config() {
ESP_LOGCONFIG(TAG, "sps30:"); ESP_LOGCONFIG(TAG, "SPS30:");
LOG_I2C_DEVICE(this); LOG_I2C_DEVICE(this);
if (this->is_failed()) { if (this->is_failed()) {
switch (this->error_code_) { switch (this->error_code_) {
@@ -78,16 +78,16 @@ void SPS30Component::dump_config() {
ESP_LOGW(TAG, "Measurement Initialization failed"); ESP_LOGW(TAG, "Measurement Initialization failed");
break; break;
case SERIAL_NUMBER_REQUEST_FAILED: case SERIAL_NUMBER_REQUEST_FAILED:
ESP_LOGW(TAG, "Unable to request sensor serial number"); ESP_LOGW(TAG, "Unable to request serial number");
break; break;
case SERIAL_NUMBER_READ_FAILED: case SERIAL_NUMBER_READ_FAILED:
ESP_LOGW(TAG, "Unable to read sensor serial number"); ESP_LOGW(TAG, "Unable to read serial number");
break; break;
case FIRMWARE_VERSION_REQUEST_FAILED: case FIRMWARE_VERSION_REQUEST_FAILED:
ESP_LOGW(TAG, "Unable to request sensor firmware version"); ESP_LOGW(TAG, "Unable to request firmware version");
break; break;
case FIRMWARE_VERSION_READ_FAILED: case FIRMWARE_VERSION_READ_FAILED:
ESP_LOGW(TAG, "Unable to read sensor firmware version"); ESP_LOGW(TAG, "Unable to read firmware version");
break; break;
default: default:
ESP_LOGW(TAG, "Unknown setup error"); ESP_LOGW(TAG, "Unknown setup error");
@@ -96,9 +96,9 @@ void SPS30Component::dump_config() {
} }
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
ESP_LOGCONFIG(TAG, ESP_LOGCONFIG(TAG,
" Serial Number: '%s'\n" " Serial number: %s\n"
" Firmware version v%0d.%0d", " Firmware version v%0d.%0d",
this->serial_number_, (raw_firmware_version_ >> 8), uint16_t(raw_firmware_version_ & 0xFF)); this->serial_number_, this->raw_firmware_version_ >> 8, this->raw_firmware_version_ & 0xFF);
LOG_SENSOR(" ", "PM1.0 Weight Concentration", this->pm_1_0_sensor_); LOG_SENSOR(" ", "PM1.0 Weight Concentration", this->pm_1_0_sensor_);
LOG_SENSOR(" ", "PM2.5 Weight Concentration", this->pm_2_5_sensor_); LOG_SENSOR(" ", "PM2.5 Weight Concentration", this->pm_2_5_sensor_);
LOG_SENSOR(" ", "PM4 Weight Concentration", this->pm_4_0_sensor_); LOG_SENSOR(" ", "PM4 Weight Concentration", this->pm_4_0_sensor_);
@@ -113,15 +113,15 @@ void SPS30Component::dump_config() {
void SPS30Component::update() { void SPS30Component::update() {
/// Check if warning flag active (sensor reconnected?) /// Check if warning flag active (sensor reconnected?)
if (this->status_has_warning()) { if (this->status_has_warning()) {
ESP_LOGD(TAG, "Trying to reconnect"); ESP_LOGD(TAG, "Reconnecting");
if (this->write_command(SPS30_CMD_SOFT_RESET)) { if (this->write_command(SPS30_CMD_SOFT_RESET)) {
ESP_LOGD(TAG, "Soft-reset successful. Waiting for reconnection in 500 ms"); ESP_LOGD(TAG, "Soft-reset successful; waiting 500 ms");
this->set_timeout(500, [this]() { this->set_timeout(500, [this]() {
this->start_continuous_measurement_(); this->start_continuous_measurement_();
/// Sensor restarted and reading attempt made next cycle /// Sensor restarted and reading attempt made next cycle
this->status_clear_warning(); this->status_clear_warning();
this->skipped_data_read_cycles_ = 0; this->skipped_data_read_cycles_ = 0;
ESP_LOGD(TAG, "Reconnect successful. Resuming continuous measurement"); ESP_LOGD(TAG, "Reconnected; resuming continuous measurement");
}); });
} else { } else {
ESP_LOGD(TAG, "Soft-reset failed"); ESP_LOGD(TAG, "Soft-reset failed");
@@ -136,12 +136,12 @@ void SPS30Component::update() {
uint16_t raw_read_status; uint16_t raw_read_status;
if (!this->read_data(&raw_read_status, 1) || raw_read_status == 0x00) { if (!this->read_data(&raw_read_status, 1) || raw_read_status == 0x00) {
ESP_LOGD(TAG, "Not ready yet"); ESP_LOGD(TAG, "Not ready");
this->skipped_data_read_cycles_++; this->skipped_data_read_cycles_++;
/// The following logic is required to address the cases when a sensor is quickly replaced before it's marked /// The following logic is required to address the cases when a sensor is quickly replaced before it's marked
/// as failed so that new sensor is eventually forced to be reinitialized for continuous measurement. /// as failed so that new sensor is eventually forced to be reinitialized for continuous measurement.
if (this->skipped_data_read_cycles_ > MAX_SKIPPED_DATA_CYCLES_BEFORE_ERROR) { if (this->skipped_data_read_cycles_ > MAX_SKIPPED_DATA_CYCLES_BEFORE_ERROR) {
ESP_LOGD(TAG, "Exceeded max allowed attempts; communication will be reinitialized"); ESP_LOGD(TAG, "Exceeded max attempts; will reinitialize");
this->status_set_warning(); this->status_set_warning();
} }
return; return;
@@ -211,11 +211,6 @@ void SPS30Component::update() {
} }
bool SPS30Component::start_continuous_measurement_() { bool SPS30Component::start_continuous_measurement_() {
uint8_t data[4];
data[0] = SPS30_CMD_START_CONTINUOUS_MEASUREMENTS & 0xFF;
data[1] = 0x03;
data[2] = 0x00;
data[3] = sht_crc_(0x03, 0x00);
if (!this->write_command(SPS30_CMD_START_CONTINUOUS_MEASUREMENTS, SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG)) { if (!this->write_command(SPS30_CMD_START_CONTINUOUS_MEASUREMENTS, SPS30_CMD_START_CONTINUOUS_MEASUREMENTS_ARG)) {
ESP_LOGE(TAG, "Error initiating measurements"); ESP_LOGE(TAG, "Error initiating measurements");
return false; return false;
@@ -224,9 +219,9 @@ bool SPS30Component::start_continuous_measurement_() {
} }
bool SPS30Component::start_fan_cleaning() { bool SPS30Component::start_fan_cleaning() {
if (!write_command(SPS30_CMD_START_FAN_CLEANING)) { if (!this->write_command(SPS30_CMD_START_FAN_CLEANING)) {
this->status_set_warning(); this->status_set_warning();
ESP_LOGE(TAG, "write error start fan (%d)", this->last_error_); ESP_LOGE(TAG, "Start fan cleaning failed (%d)", this->last_error_);
return false; return false;
} else { } else {
ESP_LOGD(TAG, "Fan auto clean started"); ESP_LOGD(TAG, "Fan auto clean started");

View File

@@ -30,12 +30,12 @@ class SPS30Component : public PollingComponent, public sensirion_common::Sensiri
bool start_fan_cleaning(); bool start_fan_cleaning();
protected: protected:
char serial_number_[17] = {0}; /// Terminating NULL character
uint16_t raw_firmware_version_; uint16_t raw_firmware_version_;
bool start_continuous_measurement_(); char serial_number_[17] = {0}; /// Terminating NULL character
uint8_t skipped_data_read_cycles_ = 0; uint8_t skipped_data_read_cycles_ = 0;
bool start_continuous_measurement_();
enum ErrorCode { enum ErrorCode : uint8_t {
COMMUNICATION_FAILED, COMMUNICATION_FAILED,
FIRMWARE_VERSION_REQUEST_FAILED, FIRMWARE_VERSION_REQUEST_FAILED,
FIRMWARE_VERSION_READ_FAILED, FIRMWARE_VERSION_READ_FAILED,

View File

@@ -80,7 +80,7 @@ void Application::register_component_(Component *comp) {
for (auto *c : this->components_) { for (auto *c : this->components_) {
if (comp == c) { if (comp == c) {
ESP_LOGW(TAG, "Component %s already registered! (%p)", c->get_component_source(), c); ESP_LOGW(TAG, "Component %s already registered! (%p)", LOG_STR_ARG(c->get_component_log_str()), c);
return; return;
} }
} }
@@ -340,8 +340,8 @@ void Application::teardown_components(uint32_t timeout_ms) {
// Note: At this point, connections are either disconnected or in a bad state, // Note: At this point, connections are either disconnected or in a bad state,
// so this warning will only appear via serial rather than being transmitted to clients // so this warning will only appear via serial rather than being transmitted to clients
for (size_t i = 0; i < pending_count; ++i) { for (size_t i = 0; i < pending_count; ++i) {
ESP_LOGW(TAG, "%s did not complete teardown within %" PRIu32 " ms", pending_components[i]->get_component_source(), ESP_LOGW(TAG, "%s did not complete teardown within %" PRIu32 " ms",
timeout_ms); LOG_STR_ARG(pending_components[i]->get_component_log_str()), timeout_ms);
} }
} }
} }
@@ -473,7 +473,7 @@ void Application::enable_pending_loops_() {
// Clear the pending flag and enable the loop // Clear the pending flag and enable the loop
component->pending_enable_loop_ = false; component->pending_enable_loop_ = false;
ESP_LOGVV(TAG, "%s loop enabled from ISR", component->get_component_source()); ESP_LOGVV(TAG, "%s loop enabled from ISR", LOG_STR_ARG(component->get_component_log_str()));
component->component_state_ &= ~COMPONENT_STATE_MASK; component->component_state_ &= ~COMPONENT_STATE_MASK;
component->component_state_ |= COMPONENT_STATE_LOOP; component->component_state_ |= COMPONENT_STATE_LOOP;

View File

@@ -142,7 +142,7 @@ void Component::call_dump_config() {
} }
} }
} }
ESP_LOGE(TAG, " %s is marked FAILED: %s", this->get_component_source(), ESP_LOGE(TAG, " %s is marked FAILED: %s", LOG_STR_ARG(this->get_component_log_str()),
error_msg ? error_msg : UNSPECIFIED_MESSAGE); error_msg ? error_msg : UNSPECIFIED_MESSAGE);
} }
} }
@@ -154,14 +154,14 @@ void Component::call() {
case COMPONENT_STATE_CONSTRUCTION: { case COMPONENT_STATE_CONSTRUCTION: {
// State Construction: Call setup and set state to setup // State Construction: Call setup and set state to setup
this->set_component_state_(COMPONENT_STATE_SETUP); this->set_component_state_(COMPONENT_STATE_SETUP);
ESP_LOGV(TAG, "Setup %s", this->get_component_source()); ESP_LOGV(TAG, "Setup %s", LOG_STR_ARG(this->get_component_log_str()));
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
uint32_t start_time = millis(); uint32_t start_time = millis();
#endif #endif
this->call_setup(); this->call_setup();
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
uint32_t setup_time = millis() - start_time; uint32_t setup_time = millis() - start_time;
ESP_LOGCONFIG(TAG, "Setup %s took %ums", this->get_component_source(), (unsigned) setup_time); ESP_LOGCONFIG(TAG, "Setup %s took %ums", LOG_STR_ARG(this->get_component_log_str()), (unsigned) setup_time);
#endif #endif
break; break;
} }
@@ -182,10 +182,8 @@ void Component::call() {
break; break;
} }
} }
const char *Component::get_component_source() const { const LogString *Component::get_component_log_str() const {
if (this->component_source_ == nullptr) return this->component_source_ == nullptr ? LOG_STR("<unknown>") : this->component_source_;
return "<unknown>";
return this->component_source_;
} }
bool Component::should_warn_of_blocking(uint32_t blocking_time) { bool Component::should_warn_of_blocking(uint32_t blocking_time) {
if (blocking_time > this->warn_if_blocking_over_) { if (blocking_time > this->warn_if_blocking_over_) {
@@ -201,7 +199,7 @@ bool Component::should_warn_of_blocking(uint32_t blocking_time) {
return false; return false;
} }
void Component::mark_failed() { void Component::mark_failed() {
ESP_LOGE(TAG, "%s was marked as failed", this->get_component_source()); ESP_LOGE(TAG, "%s was marked as failed", LOG_STR_ARG(this->get_component_log_str()));
this->set_component_state_(COMPONENT_STATE_FAILED); this->set_component_state_(COMPONENT_STATE_FAILED);
this->status_set_error(); this->status_set_error();
// Also remove from loop since failed components shouldn't loop // Also remove from loop since failed components shouldn't loop
@@ -213,14 +211,14 @@ void Component::set_component_state_(uint8_t state) {
} }
void Component::disable_loop() { void Component::disable_loop() {
if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP_DONE) { if ((this->component_state_ & COMPONENT_STATE_MASK) != COMPONENT_STATE_LOOP_DONE) {
ESP_LOGVV(TAG, "%s loop disabled", this->get_component_source()); ESP_LOGVV(TAG, "%s loop disabled", LOG_STR_ARG(this->get_component_log_str()));
this->set_component_state_(COMPONENT_STATE_LOOP_DONE); this->set_component_state_(COMPONENT_STATE_LOOP_DONE);
App.disable_component_loop_(this); App.disable_component_loop_(this);
} }
} }
void Component::enable_loop() { void Component::enable_loop() {
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP_DONE) { if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_LOOP_DONE) {
ESP_LOGVV(TAG, "%s loop enabled", this->get_component_source()); ESP_LOGVV(TAG, "%s loop enabled", LOG_STR_ARG(this->get_component_log_str()));
this->set_component_state_(COMPONENT_STATE_LOOP); this->set_component_state_(COMPONENT_STATE_LOOP);
App.enable_component_loop_(this); App.enable_component_loop_(this);
} }
@@ -240,7 +238,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() {
} }
void Component::reset_to_construction_state() { void Component::reset_to_construction_state() {
if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) { if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
ESP_LOGI(TAG, "%s is being reset to construction state", this->get_component_source()); ESP_LOGI(TAG, "%s is being reset to construction state", LOG_STR_ARG(this->get_component_log_str()));
this->set_component_state_(COMPONENT_STATE_CONSTRUCTION); this->set_component_state_(COMPONENT_STATE_CONSTRUCTION);
// Clear error status when resetting // Clear error status when resetting
this->status_clear_error(); this->status_clear_error();
@@ -286,14 +284,16 @@ void Component::status_set_warning(const char *message) {
return; return;
this->component_state_ |= STATUS_LED_WARNING; this->component_state_ |= STATUS_LED_WARNING;
App.app_state_ |= STATUS_LED_WARNING; App.app_state_ |= STATUS_LED_WARNING;
ESP_LOGW(TAG, "%s set Warning flag: %s", this->get_component_source(), message ? message : UNSPECIFIED_MESSAGE); ESP_LOGW(TAG, "%s set Warning flag: %s", LOG_STR_ARG(this->get_component_log_str()),
message ? message : UNSPECIFIED_MESSAGE);
} }
void Component::status_set_error(const char *message) { void Component::status_set_error(const char *message) {
if ((this->component_state_ & STATUS_LED_ERROR) != 0) if ((this->component_state_ & STATUS_LED_ERROR) != 0)
return; return;
this->component_state_ |= STATUS_LED_ERROR; this->component_state_ |= STATUS_LED_ERROR;
App.app_state_ |= STATUS_LED_ERROR; App.app_state_ |= STATUS_LED_ERROR;
ESP_LOGE(TAG, "%s set Error flag: %s", this->get_component_source(), message ? message : UNSPECIFIED_MESSAGE); ESP_LOGE(TAG, "%s set Error flag: %s", LOG_STR_ARG(this->get_component_log_str()),
message ? message : UNSPECIFIED_MESSAGE);
if (message != nullptr) { if (message != nullptr) {
// Lazy allocate the error messages vector if needed // Lazy allocate the error messages vector if needed
if (!component_error_messages) { if (!component_error_messages) {
@@ -314,13 +314,13 @@ void Component::status_clear_warning() {
if ((this->component_state_ & STATUS_LED_WARNING) == 0) if ((this->component_state_ & STATUS_LED_WARNING) == 0)
return; return;
this->component_state_ &= ~STATUS_LED_WARNING; this->component_state_ &= ~STATUS_LED_WARNING;
ESP_LOGW(TAG, "%s cleared Warning flag", this->get_component_source()); ESP_LOGW(TAG, "%s cleared Warning flag", LOG_STR_ARG(this->get_component_log_str()));
} }
void Component::status_clear_error() { void Component::status_clear_error() {
if ((this->component_state_ & STATUS_LED_ERROR) == 0) if ((this->component_state_ & STATUS_LED_ERROR) == 0)
return; return;
this->component_state_ &= ~STATUS_LED_ERROR; this->component_state_ &= ~STATUS_LED_ERROR;
ESP_LOGE(TAG, "%s cleared Error flag", this->get_component_source()); ESP_LOGE(TAG, "%s cleared Error flag", LOG_STR_ARG(this->get_component_log_str()));
} }
void Component::status_momentary_warning(const std::string &name, uint32_t length) { void Component::status_momentary_warning(const std::string &name, uint32_t length) {
this->status_set_warning(); this->status_set_warning();
@@ -419,8 +419,9 @@ uint32_t WarnIfComponentBlockingGuard::finish() {
should_warn = blocking_time > WARN_IF_BLOCKING_OVER_MS; should_warn = blocking_time > WARN_IF_BLOCKING_OVER_MS;
} }
if (should_warn) { if (should_warn) {
const char *src = component_ == nullptr ? "<null>" : component_->get_component_source(); ESP_LOGW(TAG, "%s took a long time for an operation (%" PRIu32 " ms)",
ESP_LOGW(TAG, "%s took a long time for an operation (%" PRIu32 " ms)", src, blocking_time); component_ == nullptr ? LOG_STR_LITERAL("<null>") : LOG_STR_ARG(component_->get_component_log_str()),
blocking_time);
ESP_LOGW(TAG, "Components should block for at most 30 ms"); ESP_LOGW(TAG, "Components should block for at most 30 ms");
} }

View File

@@ -5,6 +5,7 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include "esphome/core/log.h"
#include "esphome/core/optional.h" #include "esphome/core/optional.h"
namespace esphome { namespace esphome {
@@ -220,12 +221,12 @@ class Component {
* *
* This is set by the ESPHome core, and should not be called manually. * This is set by the ESPHome core, and should not be called manually.
*/ */
void set_component_source(const char *source) { component_source_ = source; } void set_component_source(const LogString *source) { component_source_ = source; }
/** Get the integration where this component was declared as a string. /** Get the integration where this component was declared as a LogString for logging.
* *
* Returns "<unknown>" if source not set * Returns LOG_STR("<unknown>") if source not set
*/ */
const char *get_component_source() const; const LogString *get_component_log_str() const;
bool should_warn_of_blocking(uint32_t blocking_time); bool should_warn_of_blocking(uint32_t blocking_time);
@@ -405,7 +406,7 @@ class Component {
bool cancel_defer(const std::string &name); // NOLINT bool cancel_defer(const std::string &name); // NOLINT
// Ordered for optimal packing on 32-bit systems // Ordered for optimal packing on 32-bit systems
const char *component_source_{nullptr}; const LogString *component_source_{nullptr};
uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s) uint16_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_MS}; ///< Warn if blocked for this many ms (max 65.5s)
/// State of this component - each bit has a purpose: /// State of this component - each bit has a purpose:
/// Bits 0-2: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED, 0x04=LOOP_DONE) /// Bits 0-2: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED, 0x04=LOOP_DONE)

View File

@@ -163,10 +163,10 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
// Debug logging // Debug logging
const char *type_str = (type == SchedulerItem::TIMEOUT) ? "timeout" : "interval"; const char *type_str = (type == SchedulerItem::TIMEOUT) ? "timeout" : "interval";
if (type == SchedulerItem::TIMEOUT) { if (type == SchedulerItem::TIMEOUT) {
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ")", type_str, item->get_source(), ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ")", type_str, LOG_STR_ARG(item->get_source()),
name_cstr ? name_cstr : "(null)", type_str, delay); name_cstr ? name_cstr : "(null)", type_str, delay);
} else { } else {
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, item->get_source(), ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, LOG_STR_ARG(item->get_source()),
name_cstr ? name_cstr : "(null)", type_str, delay, name_cstr ? name_cstr : "(null)", type_str, delay,
static_cast<uint32_t>(item->get_next_execution() - now)); static_cast<uint32_t>(item->get_next_execution() - now));
} }
@@ -385,7 +385,7 @@ void HOT Scheduler::call(uint32_t now) {
const char *name = item->get_name(); const char *name = item->get_name();
bool is_cancelled = is_item_removed_(item.get()); bool is_cancelled = is_item_removed_(item.get());
ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64 "%s", ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64 "%s",
item->get_type_str(), item->get_source(), name ? name : "(null)", item->interval, item->get_type_str(), LOG_STR_ARG(item->get_source()), name ? name : "(null)", item->interval,
item->get_next_execution() - now_64, item->get_next_execution(), is_cancelled ? " [CANCELLED]" : ""); item->get_next_execution() - now_64, item->get_next_execution(), is_cancelled ? " [CANCELLED]" : "");
old_items.push_back(std::move(item)); old_items.push_back(std::move(item));
@@ -476,7 +476,7 @@ void HOT Scheduler::call(uint32_t now) {
#ifdef ESPHOME_DEBUG_SCHEDULER #ifdef ESPHOME_DEBUG_SCHEDULER
const char *item_name = item->get_name(); const char *item_name = item->get_name();
ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")", ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
item->get_type_str(), item->get_source(), item_name ? item_name : "(null)", item->interval, item->get_type_str(), LOG_STR_ARG(item->get_source()), item_name ? item_name : "(null)", item->interval,
item->get_next_execution(), now_64); item->get_next_execution(), now_64);
#endif /* ESPHOME_DEBUG_SCHEDULER */ #endif /* ESPHOME_DEBUG_SCHEDULER */

View File

@@ -204,7 +204,7 @@ class Scheduler {
next_execution_high_ = static_cast<uint16_t>(value >> 32); next_execution_high_ = static_cast<uint16_t>(value >> 32);
} }
constexpr const char *get_type_str() const { return (type == TIMEOUT) ? "timeout" : "interval"; } constexpr const char *get_type_str() const { return (type == TIMEOUT) ? "timeout" : "interval"; }
const char *get_source() const { return component ? component->get_component_source() : "unknown"; } const LogString *get_source() const { return component ? component->get_component_log_str() : LOG_STR("unknown"); }
}; };
// Common implementation for both timeout and interval // Common implementation for both timeout and interval

View File

@@ -253,6 +253,19 @@ class StringLiteral(Literal):
return cpp_string_escape(self.string) return cpp_string_escape(self.string)
class LogStringLiteral(Literal):
"""A string literal that uses LOG_STR() macro for flash storage on ESP8266."""
__slots__ = ("string",)
def __init__(self, string: str) -> None:
super().__init__()
self.string = string
def __str__(self) -> str:
return f"LOG_STR({cpp_string_escape(self.string)})"
class IntLiteral(Literal): class IntLiteral(Literal):
__slots__ = ("i",) __slots__ = ("i",)

View File

@@ -9,7 +9,7 @@ from esphome.const import (
) )
from esphome.core import CORE, ID, coroutine from esphome.core import CORE, ID, coroutine
from esphome.coroutine import FakeAwaitable from esphome.coroutine import FakeAwaitable
from esphome.cpp_generator import add, get_variable from esphome.cpp_generator import LogStringLiteral, add, get_variable
from esphome.cpp_types import App from esphome.cpp_types import App
from esphome.types import ConfigFragmentType, ConfigType from esphome.types import ConfigFragmentType, ConfigType
from esphome.util import Registry, RegistryEntry from esphome.util import Registry, RegistryEntry
@@ -76,7 +76,7 @@ async def register_component(var, config):
"Error while finding name of component, please report this", exc_info=e "Error while finding name of component, please report this", exc_info=e
) )
if name is not None: if name is not None:
add(var.set_component_source(name)) add(var.set_component_source(LogStringLiteral(name)))
add(App.register_component(var)) add(App.register_component(var))
return var return var