diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 420801f863..7cd85dabd4 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -32,9 +32,11 @@ void Rect::extend(Rect rect) { this->h = rect.h; } else { if (this->x > rect.x) { + this->w = this->w + (this->x - rect.x); this->x = rect.x; } if (this->y > rect.y) { + this->h = this->h + (this->y - rect.y); this->y = rect.y; } if (this->x2() < rect.x2()) { @@ -49,29 +51,35 @@ void Rect::shrink(Rect rect) { if (!this->inside(rect)) { (*this) = Rect(); } else { - if (this->x < rect.x) { - this->x = rect.x; - } - if (this->y < rect.y) { - this->y = rect.y; - } if (this->x2() > rect.x2()) { this->w = rect.x2() - this->x; } + if (this->x < rect.x) { + this->w = this->w + (this->x - rect.x); + this->x = rect.x; + } if (this->y2() > rect.y2()) { this->h = rect.y2() - this->y; } + if (this->y < rect.y) { + this->h = this->h + (this->y - rect.y); + this->y = rect.y; + } } } -bool Rect::inside(int16_t x, int16_t y, bool absolute) { // NOLINT +bool Rect::equal(Rect rect) { + return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h); +} + +bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT if (!this->is_set()) { return true; } if (absolute) { - return ((x >= 0) && (x <= this->w) && (y >= 0) && (y <= this->h)); + return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2())); } else { - return ((x >= this->x) && (x <= this->x2()) && (y >= this->y) && (y <= this->y2())); + return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h)); } } @@ -80,15 +88,16 @@ bool Rect::inside(Rect rect, bool absolute) { return true; } if (absolute) { - return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); - } else { return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y)); + } else { + return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); } } void Rect::info(const std::string &prefix) { if (this->is_set()) { - ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d]", prefix.c_str(), this->x, this->y, this->w, this->h); + ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(), + this->y2()); } else ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str()); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 0402826594..4477685e1b 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -120,8 +120,9 @@ class Rect { void extend(Rect rect); void shrink(Rect rect); - bool inside(Rect rect, bool absolute = false); - bool inside(int16_t x, int16_t y, bool absolute = false); + bool inside(Rect rect, bool absolute = true); + bool inside(int16_t test_x, int16_t test_y, bool absolute = true); + bool equal(Rect rect); void info(const std::string &prefix = "rect info:"); }; diff --git a/esphome/components/max7219digit/display.py b/esphome/components/max7219digit/display.py index 2753f70eef..faa8a08f4a 100644 --- a/esphome/components/max7219digit/display.py +++ b/esphome/components/max7219digit/display.py @@ -7,6 +7,7 @@ CODEOWNERS = ["@rspaargaren"] DEPENDENCIES = ["spi"] CONF_ROTATE_CHIP = "rotate_chip" +CONF_FLIP_X = "flip_x" CONF_SCROLL_SPEED = "scroll_speed" CONF_SCROLL_DWELL = "scroll_dwell" CONF_SCROLL_DELAY = "scroll_delay" @@ -67,6 +68,7 @@ CONFIG_SCHEMA = ( CONF_SCROLL_DWELL, default="1000ms" ): cv.positive_time_period_milliseconds, cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean, + cv.Optional(CONF_FLIP_X, default=False): cv.boolean, } ) .extend(cv.polling_component_schema("500ms")) @@ -91,6 +93,7 @@ async def to_code(config): cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE])) cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE])) cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) + cg.add(var.set_flip_x([CONF_FLIP_X])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( diff --git a/esphome/components/max7219digit/max7219digit.cpp b/esphome/components/max7219digit/max7219digit.cpp index 1b9ae230f7..c65b8e4823 100644 --- a/esphome/components/max7219digit/max7219digit.cpp +++ b/esphome/components/max7219digit/max7219digit.cpp @@ -261,13 +261,21 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) { if (this->orientation_ == 0) { for (uint8_t i = 0; i < 8; i++) { // run this loop 8 times for all the pixels[8] received - b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits + if (this->flip_x_) { + b |= ((pixels[i] >> col) & 1) << i; // change the column bits into row bits + } else { + b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits + } } } else if (this->orientation_ == 1) { b = pixels[col]; } else if (this->orientation_ == 2) { for (uint8_t i = 0; i < 8; i++) { - b |= ((pixels[i] >> (7 - col)) & 1) << i; + if (this->flip_x_) { + b |= ((pixels[i] >> (7 - col)) & 1) << (7 - i); + } else { + b |= ((pixels[i] >> (7 - col)) & 1) << i; + } } } else { b = pixels[7 - col]; diff --git a/esphome/components/max7219digit/max7219digit.h b/esphome/components/max7219digit/max7219digit.h index 3619478697..17e369a9d9 100644 --- a/esphome/components/max7219digit/max7219digit.h +++ b/esphome/components/max7219digit/max7219digit.h @@ -67,6 +67,7 @@ class MAX7219Component : public PollingComponent, void set_scroll(bool on_off) { this->scroll_ = on_off; }; void set_scroll_mode(ScrollMode mode) { this->scroll_mode_ = mode; }; void set_reverse(bool on_off) { this->reverse_ = on_off; }; + void set_flip_x(bool flip_x) { this->flip_x_ = flip_x; }; void send_char(uint8_t chip, uint8_t data); void send64pixels(uint8_t chip, const uint8_t pixels[8]); @@ -108,6 +109,7 @@ class MAX7219Component : public PollingComponent, ChipLinesStyle chip_lines_style_; bool scroll_; bool reverse_; + bool flip_x_; bool update_{false}; uint16_t scroll_speed_; uint16_t scroll_delay_; diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp index 43f2e12f55..04aba4382b 100644 --- a/esphome/components/pmsx003/pmsx003.cpp +++ b/esphome/components/pmsx003/pmsx003.cpp @@ -264,13 +264,52 @@ void PMSX003Component::parse_data_() { break; } case PMSX003_TYPE_5003T: { + uint16_t pm_1_0_std_concentration = this->get_16_bit_uint_(4); + uint16_t pm_2_5_std_concentration = this->get_16_bit_uint_(6); + uint16_t pm_10_0_std_concentration = this->get_16_bit_uint_(8); + + uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10); uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12); + uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14); + + uint16_t pm_particles_03um = this->get_16_bit_uint_(16); + uint16_t pm_particles_05um = this->get_16_bit_uint_(18); + uint16_t pm_particles_10um = this->get_16_bit_uint_(20); + uint16_t pm_particles_25um = this->get_16_bit_uint_(22); + // Note the pm particles 50um & 100um are not returned, + // as PMS5003T uses those data values for temperature and humidity. + float temperature = this->get_16_bit_uint_(24) / 10.0f; float humidity = this->get_16_bit_uint_(26) / 10.0f; - ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%%", pm_2_5_concentration, - temperature, humidity); + + ESP_LOGD(TAG, + "Got PM1.0 Concentration: %u µg/m^3, PM2.5 Concentration %u µg/m^3, PM10.0 Concentration: %u µg/m^3, " + "Temperature: %.1f°C, Humidity: %.1f%%", + pm_1_0_concentration, pm_2_5_concentration, pm_10_0_concentration, temperature, humidity); + + if (this->pm_1_0_std_sensor_ != nullptr) + this->pm_1_0_std_sensor_->publish_state(pm_1_0_std_concentration); + if (this->pm_2_5_std_sensor_ != nullptr) + this->pm_2_5_std_sensor_->publish_state(pm_2_5_std_concentration); + if (this->pm_10_0_std_sensor_ != nullptr) + this->pm_10_0_std_sensor_->publish_state(pm_10_0_std_concentration); + + if (this->pm_1_0_sensor_ != nullptr) + this->pm_1_0_sensor_->publish_state(pm_1_0_concentration); if (this->pm_2_5_sensor_ != nullptr) this->pm_2_5_sensor_->publish_state(pm_2_5_concentration); + if (this->pm_10_0_sensor_ != nullptr) + this->pm_10_0_sensor_->publish_state(pm_10_0_concentration); + + if (this->pm_particles_03um_sensor_ != nullptr) + this->pm_particles_03um_sensor_->publish_state(pm_particles_03um); + if (this->pm_particles_05um_sensor_ != nullptr) + this->pm_particles_05um_sensor_->publish_state(pm_particles_05um); + if (this->pm_particles_10um_sensor_ != nullptr) + this->pm_particles_10um_sensor_->publish_state(pm_particles_10um); + if (this->pm_particles_25um_sensor_ != nullptr) + this->pm_particles_25um_sensor_->publish_state(pm_particles_25um); + if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(temperature); if (this->humidity_sensor_ != nullptr) diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py index f3552f4081..eefcb529f2 100644 --- a/esphome/components/pmsx003/sensor.py +++ b/esphome/components/pmsx003/sensor.py @@ -55,9 +55,9 @@ PMSX003_TYPES = { } SENSORS_TO_TYPE = { - CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S], + CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], - CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S], + CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST], CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST], CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S], diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index d3cb39c2f6..821e0afac0 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -466,9 +466,21 @@ async def lambda_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id, lambda_) -@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_) +def validate_delta(config): + try: + return (cv.positive_float(config), False) + except cv.Invalid: + pass + try: + return (cv.percentage(config), True) + except cv.Invalid: + pass + raise cv.Invalid("Delta filter requires a positive number or percentage value.") + + +@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta) async def delta_filter_to_code(config, filter_id): - return cg.new_Pvariable(filter_id, config) + return cg.new_Pvariable(filter_id, *config) @FILTER_REGISTRY.register("or", OrFilter, validate_filters) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 7a2c98109c..bf65ac590f 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -315,19 +315,23 @@ optional ThrottleFilter::new_value(float value) { } // DeltaFilter -DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {} +DeltaFilter::DeltaFilter(float delta, bool percentage_mode) + : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} optional DeltaFilter::new_value(float value) { if (std::isnan(value)) { if (std::isnan(this->last_value_)) { return {}; } else { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } } - if (std::isnan(this->last_value_)) { - return this->last_value_ = value; - } - if (fabsf(value - this->last_value_) >= this->min_delta_) { + if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } return {}; diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index c17d14583b..b560545b76 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -325,12 +325,14 @@ class HeartbeatFilter : public Filter, public Component { class DeltaFilter : public Filter { public: - explicit DeltaFilter(float min_delta); + explicit DeltaFilter(float delta, bool percentage_mode); optional new_value(float value) override; protected: - float min_delta_; + float delta_; + float current_delta_; + bool percentage_mode_; float last_value_{NAN}; }; diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index eeaf37985b..e0fc9efb42 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -17,6 +17,7 @@ spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") MULTI_CONF = True +CONF_FORCE_SW = "force_sw" CONFIG_SCHEMA = cv.All( cv.Schema( @@ -25,6 +26,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_FORCE_SW, default=False): cv.boolean, } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), @@ -39,6 +41,7 @@ async def to_code(config): clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_clk(clk)) + cg.add(var.set_force_sw(config[CONF_FORCE_SW])) if CONF_MISO_PIN in config: miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN]) cg.add(var.set_miso(miso)) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 864f6ae39d..c3ffba4229 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -25,7 +25,7 @@ void SPIComponent::setup() { this->clk_->digital_write(true); #ifdef USE_SPI_ARDUINO_BACKEND - bool use_hw_spi = true; + bool use_hw_spi = !this->force_sw_; const bool has_miso = this->miso_ != nullptr; const bool has_mosi = this->mosi_ != nullptr; int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1; diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index b7124302f4..bacdad723b 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -74,6 +74,7 @@ class SPIComponent : public Component { void set_clk(GPIOPin *clk) { clk_ = clk; } void set_miso(GPIOPin *miso) { miso_ = miso; } void set_mosi(GPIOPin *mosi) { mosi_ = mosi; } + void set_force_sw(bool force_sw) { force_sw_ = force_sw; } void setup() override; @@ -260,6 +261,7 @@ class SPIComponent : public Component { GPIOPin *miso_{nullptr}; GPIOPin *mosi_{nullptr}; GPIOPin *active_cs_{nullptr}; + bool force_sw_{false}; #ifdef USE_SPI_ARDUINO_BACKEND SPIClass *hw_spi_{nullptr}; #endif // USE_SPI_ARDUINO_BACKEND diff --git a/esphome/components/status_led/light/__init__.py b/esphome/components/status_led/light/__init__.py index 8896046998..d6a4a245e6 100644 --- a/esphome/components/status_led/light/__init__.py +++ b/esphome/components/status_led/light/__init__.py @@ -1,26 +1,35 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import light -from esphome.const import CONF_OUTPUT_ID, CONF_PIN +from esphome.components import light, output +from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID, CONF_PIN from .. import status_led_ns +AUTO_LOAD = ["output"] + StatusLEDLightOutput = status_led_ns.class_( "StatusLEDLightOutput", light.LightOutput, cg.Component ) -CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend( - { - cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput), - cv.Required(CONF_PIN): pins.gpio_output_pin_schema, - } +CONFIG_SCHEMA = cv.All( + light.BINARY_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput), + cv.Optional(CONF_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_OUTPUT): cv.use_id(output.BinaryOutput), + } + ), + cv.has_at_least_one_key(CONF_PIN, CONF_OUTPUT), ) async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - pin = await cg.gpio_pin_expression(config[CONF_PIN]) - cg.add(var.set_pin(pin)) + if CONF_PIN in config: + pin = await cg.gpio_pin_expression(config[CONF_PIN]) + cg.add(var.set_pin(pin)) + if CONF_OUTPUT in config: + out = await cg.get_variable(config[CONF_OUTPUT]) + cg.add(var.set_output(out)) await cg.register_component(var, config) - # cg.add(cg.App.register_component(var)) await light.register_light(var, config) diff --git a/esphome/components/status_led/light/status_led_light.cpp b/esphome/components/status_led/light/status_led_light.cpp index 760c89f972..b47d1f5bd0 100644 --- a/esphome/components/status_led/light/status_led_light.cpp +++ b/esphome/components/status_led/light/status_led_light.cpp @@ -15,10 +15,10 @@ void StatusLEDLightOutput::loop() { } if ((new_state & STATUS_LED_ERROR) != 0u) { - this->pin_->digital_write(millis() % 250u < 150u); + this->output_state_(millis() % 250u < 150u); this->last_app_state_ = new_state; } else if ((new_state & STATUS_LED_WARNING) != 0u) { - this->pin_->digital_write(millis() % 1500u < 250u); + this->output_state_(millis() % 1500u < 250u); this->last_app_state_ = new_state; } else if (new_state != this->last_app_state_) { // if no error/warning -> restore light state or turn off @@ -26,17 +26,16 @@ void StatusLEDLightOutput::loop() { if (lightstate_) lightstate_->current_values_as_binary(&state); - - this->pin_->digital_write(state); - this->last_app_state_ = new_state; - ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state)); + + this->output_state_(state); + this->last_app_state_ = new_state; } } void StatusLEDLightOutput::setup_state(light::LightState *state) { lightstate_ = state; - ESP_LOGD(TAG, "'%s': Setting initital state", state->get_name().c_str()); + ESP_LOGD(TAG, "'%s': Setting initial state", state->get_name().c_str()); this->write_state(state); } @@ -47,16 +46,18 @@ void StatusLEDLightOutput::write_state(light::LightState *state) { // if in warning/error, don't overwrite the status_led // once it is back to OK, the loop will restore the state if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) { - this->pin_->digital_write(binary); ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary)); + this->output_state_(binary); } } void StatusLEDLightOutput::setup() { ESP_LOGCONFIG(TAG, "Setting up Status LED..."); - this->pin_->setup(); - this->pin_->digital_write(false); + if (this->pin_ != nullptr) { + this->pin_->setup(); + this->pin_->digital_write(false); + } } void StatusLEDLightOutput::dump_config() { @@ -64,5 +65,12 @@ void StatusLEDLightOutput::dump_config() { LOG_PIN(" Pin: ", this->pin_); } +void StatusLEDLightOutput::output_state_(bool state) { + if (this->pin_ != nullptr) + this->pin_->digital_write(state); + if (this->output_ != nullptr) + this->output_->set_state(state); +} + } // namespace status_led } // namespace esphome diff --git a/esphome/components/status_led/light/status_led_light.h b/esphome/components/status_led/light/status_led_light.h index e90d381e3c..e711a2e749 100644 --- a/esphome/components/status_led/light/status_led_light.h +++ b/esphome/components/status_led/light/status_led_light.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/components/light/light_output.h" +#include "esphome/components/output/binary_output.h" namespace esphome { namespace status_led { @@ -10,6 +11,7 @@ namespace status_led { class StatusLEDLightOutput : public light::LightOutput, public Component { public: void set_pin(GPIOPin *pin) { pin_ = pin; } + void set_output(output::BinaryOutput *output) { output_ = output; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); @@ -31,9 +33,11 @@ class StatusLEDLightOutput : public light::LightOutput, public Component { float get_loop_priority() const override { return 50.0f; } protected: - GPIOPin *pin_; + GPIOPin *pin_{nullptr}; + output::BinaryOutput *output_{nullptr}; light::LightState *lightstate_{}; uint32_t last_app_state_{0xFFFF}; + void output_state_(bool state); }; } // namespace status_led diff --git a/esphome/config_validation.py b/esphome/config_validation.py index a46d14053b..469b7031f6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1097,7 +1097,7 @@ def possibly_negative_percentage(value): if isinstance(value, str): try: if value.endswith("%"): - has_percent_sign = False + has_percent_sign = True value = float(value[:-1].rstrip()) / 100.0 else: value = float(value) diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index a9e1414018..6f88f069b3 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -23,8 +23,13 @@ bool EntityBase::is_disabled_by_default() const { return this->disabled_by_defau void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; } // Entity Icon -const std::string &EntityBase::get_icon() const { return this->icon_; } -void EntityBase::set_icon(const std::string &name) { this->icon_ = name; } +std::string EntityBase::get_icon() const { + if (this->icon_c_str_ == nullptr) { + return ""; + } + return this->icon_c_str_; +} +void EntityBase::set_icon(const char *icon) { this->icon_c_str_ = icon; } // Entity Category EntityCategory EntityBase::get_entity_category() const { return this->entity_category_; } diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index a9eedfd07e..f6aae4e978 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -42,8 +42,8 @@ class EntityBase { void set_entity_category(EntityCategory entity_category); // Get/set this entity's icon - const std::string &get_icon() const; - void set_icon(const std::string &name); + std::string get_icon() const; + void set_icon(const char *icon); protected: /// The hash_base() function has been deprecated. It is kept in this @@ -53,7 +53,7 @@ class EntityBase { std::string name_; std::string object_id_; - std::string icon_; + const char *icon_c_str_{nullptr}; uint32_t object_id_hash_; bool internal_{false}; bool disabled_by_default_{false}; diff --git a/tests/test1.yaml b/tests/test1.yaml index 2aa86e2fc4..90bbef6977 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -400,6 +400,7 @@ sensor: - heartbeat: 5s - debounce: 0.1s - delta: 5.0 + - delta: 1% - or: - throttle: 1s - delta: 5.0 diff --git a/tests/test3.yaml b/tests/test3.yaml index 85c0fccc0b..651683c381 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -630,8 +630,26 @@ sensor: - platform: pmsx003 uart_id: uart5 type: PMS5003T + pm_1_0: + name: PM 1.0 Concentration pm_2_5: name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um temperature: name: PMS Temperature humidity: