diff --git a/esphome/components/epaper_spi/display.py b/esphome/components/epaper_spi/display.py index 3fa504539b..487e8e5ef4 100644 --- a/esphome/components/epaper_spi/display.py +++ b/esphome/components/epaper_spi/display.py @@ -62,6 +62,12 @@ automation.register_apply_action( automation.ApplyCall("request_full_update()"), ) +automation.register_apply_condition( + "epaper_spi.is_updating", + automation.maybe_simple_id({cv.Required(CONF_ID): cv.use_id(EPaperBase)}), + "is_updating()", +) + # Import all models dynamically from the models package for module_info in pkgutil.iter_modules(models.__path__): importlib.import_module(f".models.{module_info.name}", package=__package__) diff --git a/esphome/components/epaper_spi/epaper_spi.h b/esphome/components/epaper_spi/epaper_spi.h index 0040c867b2..96755a404e 100644 --- a/esphome/components/epaper_spi/epaper_spi.h +++ b/esphome/components/epaper_spi/epaper_spi.h @@ -109,6 +109,8 @@ class EPaperBase : public Display, void draw_pixel_at(int x, int y, Color color) override; // Make the next update a full one. Applied when that update starts, so one in progress is not affected. void request_full_update() { this->full_update_requested_ = true; } + // True from the start of an update until the display has refreshed and gone back to sleep. + bool is_updating() const { return this->state_ != EPaperState::IDLE; } protected: int get_height_internal() override { return this->height_; }; diff --git a/tests/component_tests/epaper_spi/config/full_update_next_test.yaml b/tests/component_tests/epaper_spi/config/full_update_next_test.yaml index de5e678a70..ab8389798b 100644 --- a/tests/component_tests/epaper_spi/config/full_update_next_test.yaml +++ b/tests/component_tests/epaper_spi/config/full_update_next_test.yaml @@ -27,3 +27,8 @@ binary_sensor: name: Trigger on_press: - epaper_spi.full_update_next: epaper_display + - if: + condition: + epaper_spi.is_updating: epaper_display + then: + - component.update: epaper_display diff --git a/tests/component_tests/epaper_spi/test_init.py b/tests/component_tests/epaper_spi/test_init.py index 9d6ebe831a..4b8f578892 100644 --- a/tests/component_tests/epaper_spi/test_init.py +++ b/tests/component_tests/epaper_spi/test_init.py @@ -551,6 +551,16 @@ def test_full_update_next_action_code_generation( assert "epaper_display->request_full_update();" in main_cpp +def test_is_updating_condition_code_generation( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], +) -> None: + """The epaper_spi.is_updating condition checks the configured display.""" + main_cpp = generate_main(component_config_path("full_update_next_test.yaml")) + + assert "epaper_display->is_updating()" in main_cpp + + def test_model_with_no_default_init_sequence_generates( generate_main: Callable[[str | Path], str], component_config_path: Callable[[str], Path], diff --git a/tests/components/epaper_spi/display/test_ssd1677_transfer.cpp b/tests/components/epaper_spi/display/test_ssd1677_transfer.cpp index cad853b197..01eea3c83a 100644 --- a/tests/components/epaper_spi/display/test_ssd1677_transfer.cpp +++ b/tests/components/epaper_spi/display/test_ssd1677_transfer.cpp @@ -196,6 +196,21 @@ TEST(EPaperSSD1677, RequestedFullUpdateAppliesWhenTheNextUpdateStarts) { EXPECT_FALSE(display.run_update_state()) << "request was applied more than once"; } +/// The display reports updating from the start of an update until it is back to idle. +TEST(EPaperSSD1677, IsUpdatingUntilBackToIdle) { + TestableSSD1677 display(16, 2); + RecordingDelegate bus(&display.dc); + display.install(&bus, 5); + + EXPECT_FALSE(display.is_updating()); + display.request_full_update(); + EXPECT_TRUE(display.run_update_state()); + EXPECT_TRUE(display.is_updating()); + + EXPECT_FALSE(display.run_update_state()) << "an update with nothing drawn should not push"; + EXPECT_FALSE(display.is_updating()); +} + /// Nothing a partial needs lives in controller RAM any more, so a partial push skips the reset /// altogether; a full one still gets the hardware pulse and the software reset. TEST(EPaperSSD1677, PartialPushSkipsTheResetAndAFullPushKeepsIt) { diff --git a/tests/components/epaper_spi/test.esp32-s3-idf.yaml b/tests/components/epaper_spi/test.esp32-s3-idf.yaml index 7a4ce3a5ff..8cb2a99521 100644 --- a/tests/components/epaper_spi/test.esp32-s3-idf.yaml +++ b/tests/components/epaper_spi/test.esp32-s3-idf.yaml @@ -8,6 +8,11 @@ esphome: on_boot: then: - epaper_spi.full_update_next: epaper_partial + - if: + condition: + epaper_spi.is_updating: epaper_partial + then: + - component.update: epaper_partial display: - platform: epaper_spi