From 2f0722598404f5f6935b294f3e4668660d15ef2e Mon Sep 17 00:00:00 2001 From: Andrew Zaborowski Date: Mon, 29 Jun 2020 00:44:15 +0200 Subject: [PATCH] Fix: Component script not stopped in certain situations (#1004) * Move stop/is_running implementation to Action base class Try to fix issue #1105. Until now if an UpdateComponentAction, a LambdaAction, or any action that can contain those inside their "else" or "then" action lists, resulted in a call to script.stop on the script that contains them, the script would continue running, because they didn't implement a stop() method. Basically only the asynchronous ones did: DelayAction, WaitUntilAction and ScriptWaitAction. With this change num_running_ in Action replaces DelayAction::num_running_ and WaitUntilAction::triggered_ to provide the same is_running logic to other actions. * Make some Action methods protected Apparently play()/stop() etc. are not meant to be called directly by users of the class and if they're called directly that would not give the expected result for the classes that have an empty play(). Make all methods except play_complex, stop_comples and is_running protected. While there also make RemoteTransmitterActionBase::encode protected. * lint * format Co-authored-by: Guillermo Ruffino --- .../components/api/homeassistant_service.h | 1 + esphome/components/binary_sensor/automation.h | 1 + esphome/components/cover/automation.h | 16 ++-- esphome/components/dfplayer/dfplayer.h | 6 +- esphome/components/display/display_buffer.h | 5 +- esphome/components/esp8266_pwm/esp8266_pwm.h | 1 - esphome/components/fan/automation.h | 3 - esphome/components/mhz19/mhz19.h | 3 + esphome/components/mqtt/mqtt_client.h | 1 + esphome/components/output/automation.h | 1 + esphome/components/pid/pid_climate.h | 8 +- esphome/components/remote_base/jvc_protocol.h | 1 + esphome/components/remote_base/lg_protocol.h | 1 + esphome/components/remote_base/nec_protocol.h | 1 + .../remote_base/panasonic_protocol.h | 1 + .../components/remote_base/pioneer_protocol.h | 1 + esphome/components/remote_base/rc5_protocol.h | 1 + esphome/components/remote_base/remote_base.h | 8 +- .../components/remote_base/samsung_protocol.h | 1 + .../components/remote_base/sony_protocol.h | 1 + .../rotary_encoder/rotary_encoder.h | 1 + esphome/components/script/script.h | 19 ++-- esphome/components/sensor/automation.h | 1 + esphome/components/servo/servo.h | 2 + esphome/components/switch/automation.h | 1 + esphome/components/text_sensor/automation.h | 1 + esphome/core/automation.h | 56 +++++++----- esphome/core/base_automation.h | 87 ++++++++----------- 28 files changed, 121 insertions(+), 109 deletions(-) diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index d68dac3b6..8a7276519 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -29,6 +29,7 @@ template class HomeAssistantServiceCallAction : public Action void add_variable(std::string key, T value) { this->variables_.push_back(TemplatableKeyValuePair(key, value)); } + void play(Ts... x) override { HomeassistantServiceResponse resp; resp.service = this->service_.value(x...); diff --git a/esphome/components/binary_sensor/automation.h b/esphome/components/binary_sensor/automation.h index e9ff37446..6b0321628 100644 --- a/esphome/components/binary_sensor/automation.h +++ b/esphome/components/binary_sensor/automation.h @@ -137,6 +137,7 @@ template class BinarySensorPublishAction : public Action public: explicit BinarySensorPublishAction(BinarySensor *sensor) : sensor_(sensor) {} TEMPLATABLE_VALUE(bool, state) + void play(Ts... x) override { auto val = this->state_.value(x...); this->sensor_->publish_state(val); diff --git a/esphome/components/cover/automation.h b/esphome/components/cover/automation.h index a8eb0cdf9..0092f987f 100644 --- a/esphome/components/cover/automation.h +++ b/esphome/components/cover/automation.h @@ -41,6 +41,10 @@ template class ControlAction : public Action { public: explicit ControlAction(Cover *cover) : cover_(cover) {} + TEMPLATABLE_VALUE(bool, stop) + TEMPLATABLE_VALUE(float, position) + TEMPLATABLE_VALUE(float, tilt) + void play(Ts... x) override { auto call = this->cover_->make_call(); if (this->stop_.has_value()) @@ -52,10 +56,6 @@ template class ControlAction : public Action { call.perform(); } - TEMPLATABLE_VALUE(bool, stop) - TEMPLATABLE_VALUE(float, position) - TEMPLATABLE_VALUE(float, tilt) - protected: Cover *cover_; }; @@ -63,6 +63,10 @@ template class ControlAction : public Action { template class CoverPublishAction : public Action { public: CoverPublishAction(Cover *cover) : cover_(cover) {} + TEMPLATABLE_VALUE(float, position) + TEMPLATABLE_VALUE(float, tilt) + TEMPLATABLE_VALUE(CoverOperation, current_operation) + void play(Ts... x) override { if (this->position_.has_value()) this->cover_->position = this->position_.value(x...); @@ -73,10 +77,6 @@ template class CoverPublishAction : public Action { this->cover_->publish_state(); } - TEMPLATABLE_VALUE(float, position) - TEMPLATABLE_VALUE(float, tilt) - TEMPLATABLE_VALUE(CoverOperation, current_operation) - protected: Cover *cover_; }; diff --git a/esphome/components/dfplayer/dfplayer.h b/esphome/components/dfplayer/dfplayer.h index 22ca11c3b..cb9686bb6 100644 --- a/esphome/components/dfplayer/dfplayer.h +++ b/esphome/components/dfplayer/dfplayer.h @@ -104,7 +104,6 @@ class DFPlayer : public uart::UARTDevice, public Component { #define DFPLAYER_SIMPLE_ACTION(ACTION_CLASS, ACTION_METHOD) \ template class ACTION_CLASS : public Action, public Parented { \ - public: \ void play(Ts... x) override { this->parent_->ACTION_METHOD(); } \ }; @@ -115,6 +114,7 @@ template class PlayFileAction : public Action, public Par public: TEMPLATABLE_VALUE(uint16_t, file) TEMPLATABLE_VALUE(boolean, loop) + void play(Ts... x) override { auto file = this->file_.value(x...); auto loop = this->loop_.value(x...); @@ -131,6 +131,7 @@ template class PlayFolderAction : public Action, public P TEMPLATABLE_VALUE(uint16_t, folder) TEMPLATABLE_VALUE(uint16_t, file) TEMPLATABLE_VALUE(boolean, loop) + void play(Ts... x) override { auto folder = this->folder_.value(x...); auto file = this->file_.value(x...); @@ -146,6 +147,7 @@ template class PlayFolderAction : public Action, public P template class SetDeviceAction : public Action, public Parented { public: TEMPLATABLE_VALUE(Device, device) + void play(Ts... x) override { auto device = this->device_.value(x...); this->parent_->set_device(device); @@ -155,6 +157,7 @@ template class SetDeviceAction : public Action, public Pa template class SetVolumeAction : public Action, public Parented { public: TEMPLATABLE_VALUE(uint8_t, volume) + void play(Ts... x) override { auto volume = this->volume_.value(x...); this->parent_->set_volume(volume); @@ -164,6 +167,7 @@ template class SetVolumeAction : public Action, public Pa template class SetEqAction : public Action, public Parented { public: TEMPLATABLE_VALUE(EqPreset, eq) + void play(Ts... x) override { auto eq = this->eq_.value(x...); this->parent_->set_eq(eq); diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 969a5d80c..4b84e90a0 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -400,6 +400,7 @@ class Image { template class DisplayPageShowAction : public Action { public: TEMPLATABLE_VALUE(DisplayPage *, page) + void play(Ts... x) override { auto *page = this->page_.value(x...); if (page != nullptr) { @@ -411,18 +412,18 @@ template class DisplayPageShowAction : public Action { template class DisplayPageShowNextAction : public Action { public: DisplayPageShowNextAction(DisplayBuffer *buffer) : buffer_(buffer) {} + void play(Ts... x) override { this->buffer_->show_next_page(); } - protected: DisplayBuffer *buffer_; }; template class DisplayPageShowPrevAction : public Action { public: DisplayPageShowPrevAction(DisplayBuffer *buffer) : buffer_(buffer) {} + void play(Ts... x) override { this->buffer_->show_prev_page(); } - protected: DisplayBuffer *buffer_; }; diff --git a/esphome/components/esp8266_pwm/esp8266_pwm.h b/esphome/components/esp8266_pwm/esp8266_pwm.h index b6839985b..51b74f48b 100644 --- a/esphome/components/esp8266_pwm/esp8266_pwm.h +++ b/esphome/components/esp8266_pwm/esp8266_pwm.h @@ -43,7 +43,6 @@ template class SetFrequencyAction : public Action { this->parent_->update_frequency(freq); } - protected: ESP8266PWM *parent_; }; diff --git a/esphome/components/fan/automation.h b/esphome/components/fan/automation.h index dfa72a3ea..d96ed994e 100644 --- a/esphome/components/fan/automation.h +++ b/esphome/components/fan/automation.h @@ -25,7 +25,6 @@ template class TurnOnAction : public Action { call.perform(); } - protected: FanState *state_; }; @@ -35,7 +34,6 @@ template class TurnOffAction : public Action { void play(Ts... x) override { this->state_->turn_off().perform(); } - protected: FanState *state_; }; @@ -45,7 +43,6 @@ template class ToggleAction : public Action { void play(Ts... x) override { this->state_->toggle().perform(); } - protected: FanState *state_; }; diff --git a/esphome/components/mhz19/mhz19.h b/esphome/components/mhz19/mhz19.h index 2201fc87f..151351be4 100644 --- a/esphome/components/mhz19/mhz19.h +++ b/esphome/components/mhz19/mhz19.h @@ -37,6 +37,7 @@ class MHZ19Component : public PollingComponent, public uart::UARTDevice { template class MHZ19CalibrateZeroAction : public Action { public: MHZ19CalibrateZeroAction(MHZ19Component *mhz19) : mhz19_(mhz19) {} + void play(Ts... x) override { this->mhz19_->calibrate_zero(); } protected: @@ -46,6 +47,7 @@ template class MHZ19CalibrateZeroAction : public Action { template class MHZ19ABCEnableAction : public Action { public: MHZ19ABCEnableAction(MHZ19Component *mhz19) : mhz19_(mhz19) {} + void play(Ts... x) override { this->mhz19_->abc_enable(); } protected: @@ -55,6 +57,7 @@ template class MHZ19ABCEnableAction : public Action { template class MHZ19ABCDisableAction : public Action { public: MHZ19ABCDisableAction(MHZ19Component *mhz19) : mhz19_(mhz19) {} + void play(Ts... x) override { this->mhz19_->abc_disable(); } protected: diff --git a/esphome/components/mqtt/mqtt_client.h b/esphome/components/mqtt/mqtt_client.h index 6f14b0c92..2bbebff84 100644 --- a/esphome/components/mqtt/mqtt_client.h +++ b/esphome/components/mqtt/mqtt_client.h @@ -316,6 +316,7 @@ template class MQTTPublishJsonAction : public Action { TEMPLATABLE_VALUE(bool, retain) void set_payload(std::function payload) { this->payload_ = payload; } + void play(Ts... x) override { auto f = std::bind(&MQTTPublishJsonAction::encode_, this, x..., std::placeholders::_1); auto topic = this->topic_.value(x...); diff --git a/esphome/components/output/automation.h b/esphome/components/output/automation.h index 8c8a5ab61..51c284970 100644 --- a/esphome/components/output/automation.h +++ b/esphome/components/output/automation.h @@ -33,6 +33,7 @@ template class SetLevelAction : public Action { SetLevelAction(FloatOutput *output) : output_(output) {} TEMPLATABLE_VALUE(float, level) + void play(Ts... x) override { this->output_->set_level(this->level_.value(x...)); } protected: diff --git a/esphome/components/pid/pid_climate.h b/esphome/components/pid/pid_climate.h index 8f379c47b..3dae92af5 100644 --- a/esphome/components/pid/pid_climate.h +++ b/esphome/components/pid/pid_climate.h @@ -71,6 +71,10 @@ template class PIDAutotuneAction : public Action { public: PIDAutotuneAction(PIDClimate *parent) : parent_(parent) {} + void set_noiseband(float noiseband) { noiseband_ = noiseband; } + void set_positive_output(float positive_output) { positive_output_ = positive_output; } + void set_negative_output(float negative_output) { negative_output_ = negative_output; } + void play(Ts... x) { auto tuner = make_unique(); tuner->set_noiseband(this->noiseband_); @@ -79,10 +83,6 @@ template class PIDAutotuneAction : public Action { this->parent_->start_autotune(std::move(tuner)); } - void set_noiseband(float noiseband) { noiseband_ = noiseband; } - void set_positive_output(float positive_output) { positive_output_ = positive_output; } - void set_negative_output(float negative_output) { negative_output_ = negative_output; } - protected: float noiseband_; float positive_output_; diff --git a/esphome/components/remote_base/jvc_protocol.h b/esphome/components/remote_base/jvc_protocol.h index 8a216f534..fc40a6a87 100644 --- a/esphome/components/remote_base/jvc_protocol.h +++ b/esphome/components/remote_base/jvc_protocol.h @@ -23,6 +23,7 @@ DECLARE_REMOTE_PROTOCOL(JVC) template class JVCAction : public RemoteTransmitterActionBase { public: TEMPLATABLE_VALUE(uint32_t, data) + void encode(RemoteTransmitData *dst, Ts... x) override { JVCData data{}; data.data = this->data_.value(x...); diff --git a/esphome/components/remote_base/lg_protocol.h b/esphome/components/remote_base/lg_protocol.h index b810115f5..626756044 100644 --- a/esphome/components/remote_base/lg_protocol.h +++ b/esphome/components/remote_base/lg_protocol.h @@ -26,6 +26,7 @@ template class LGAction : public RemoteTransmitterActionBasedata_.value(x...); diff --git a/esphome/components/remote_base/nec_protocol.h b/esphome/components/remote_base/nec_protocol.h index c794991ea..593a3efe1 100644 --- a/esphome/components/remote_base/nec_protocol.h +++ b/esphome/components/remote_base/nec_protocol.h @@ -25,6 +25,7 @@ template class NECAction : public RemoteTransmitterActionBaseaddress_.value(x...); diff --git a/esphome/components/remote_base/panasonic_protocol.h b/esphome/components/remote_base/panasonic_protocol.h index b13bd3e92..eae97a8a1 100644 --- a/esphome/components/remote_base/panasonic_protocol.h +++ b/esphome/components/remote_base/panasonic_protocol.h @@ -26,6 +26,7 @@ template class PanasonicAction : public RemoteTransmitterActionB public: TEMPLATABLE_VALUE(uint16_t, address) TEMPLATABLE_VALUE(uint32_t, command) + void encode(RemoteTransmitData *dst, Ts... x) override { PanasonicData data{}; data.address = this->address_.value(x...); diff --git a/esphome/components/remote_base/pioneer_protocol.h b/esphome/components/remote_base/pioneer_protocol.h index f93e51a03..4cac4f9f3 100644 --- a/esphome/components/remote_base/pioneer_protocol.h +++ b/esphome/components/remote_base/pioneer_protocol.h @@ -25,6 +25,7 @@ template class PioneerAction : public RemoteTransmitterActionBas public: TEMPLATABLE_VALUE(uint16_t, rc_code_1) TEMPLATABLE_VALUE(uint16_t, rc_code_2) + void encode(RemoteTransmitData *dst, Ts... x) override { PioneerData data{}; data.rc_code_1 = this->rc_code_1_.value(x...); diff --git a/esphome/components/remote_base/rc5_protocol.h b/esphome/components/remote_base/rc5_protocol.h index 2e1da74d9..589c8d42d 100644 --- a/esphome/components/remote_base/rc5_protocol.h +++ b/esphome/components/remote_base/rc5_protocol.h @@ -26,6 +26,7 @@ template class RC5Action : public RemoteTransmitterActionBaseaddress_.value(x...); diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index 250b59e55..916fe29c1 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -323,6 +323,9 @@ template class RemoteTransmitterActionBase : public Actionparent_ = parent; } + TEMPLATABLE_VALUE(uint32_t, send_times); + TEMPLATABLE_VALUE(uint32_t, send_wait); + void play(Ts... x) override { auto call = this->parent_->transmit(); this->encode(call.get_data(), x...); @@ -331,12 +334,9 @@ template class RemoteTransmitterActionBase : public Action class SamsungAction : public RemoteTransmitterActionBase { public: TEMPLATABLE_VALUE(uint32_t, data) + void encode(RemoteTransmitData *dst, Ts... x) override { SamsungData data{}; data.data = this->data_.value(x...); diff --git a/esphome/components/remote_base/sony_protocol.h b/esphome/components/remote_base/sony_protocol.h index 9f0bcdf82..aecc8ab91 100644 --- a/esphome/components/remote_base/sony_protocol.h +++ b/esphome/components/remote_base/sony_protocol.h @@ -26,6 +26,7 @@ template class SonyAction : public RemoteTransmitterActionBasedata_.value(x...); diff --git a/esphome/components/rotary_encoder/rotary_encoder.h b/esphome/components/rotary_encoder/rotary_encoder.h index 422064547..f0e47dfe0 100644 --- a/esphome/components/rotary_encoder/rotary_encoder.h +++ b/esphome/components/rotary_encoder/rotary_encoder.h @@ -74,6 +74,7 @@ template class RotaryEncoderSetValueAction : public Actionencoder_->set_value(this->value_.value(x...)); } protected: diff --git a/esphome/components/script/script.h b/esphome/components/script/script.h index 3b97327da..8495014f0 100644 --- a/esphome/components/script/script.h +++ b/esphome/components/script/script.h @@ -53,41 +53,34 @@ template class ScriptWaitAction : public Action, public C public: ScriptWaitAction(Script *script) : script_(script) {} - void play(Ts... x) { /* ignore - see play_complex */ - } - void play_complex(Ts... x) override { + this->num_running_++; // Check if we can continue immediately. if (!this->script_->is_running()) { - this->triggered_ = false; - this->play_next(x...); + this->play_next_(x...); return; } this->var_ = std::make_tuple(x...); - this->triggered_ = true; this->loop(); } - void stop() override { this->triggered_ = false; } - void loop() override { - if (!this->triggered_) + if (this->num_running_ == 0) return; if (this->script_->is_running()) return; - this->triggered_ = false; - this->play_next_tuple(this->var_); + this->play_next_tuple_(this->var_); } float get_setup_priority() const override { return setup_priority::DATA; } - bool is_running() override { return this->triggered_ || this->is_running_next(); } + void play(Ts... x) override { /* ignore - see play_complex */ + } protected: Script *script_; - bool triggered_{false}; std::tuple var_{}; }; diff --git a/esphome/components/sensor/automation.h b/esphome/components/sensor/automation.h index 079077dba..c70fb9396 100644 --- a/esphome/components/sensor/automation.h +++ b/esphome/components/sensor/automation.h @@ -25,6 +25,7 @@ template class SensorPublishAction : public Action { public: SensorPublishAction(Sensor *sensor) : sensor_(sensor) {} TEMPLATABLE_VALUE(float, state) + void play(Ts... x) override { this->sensor_->publish_state(this->state_.value(x...)); } protected: diff --git a/esphome/components/servo/servo.h b/esphome/components/servo/servo.h index a37188740..b864efc87 100644 --- a/esphome/components/servo/servo.h +++ b/esphome/components/servo/servo.h @@ -64,6 +64,7 @@ template class ServoWriteAction : public Action { public: ServoWriteAction(Servo *servo) : servo_(servo) {} TEMPLATABLE_VALUE(float, value) + void play(Ts... x) override { this->servo_->write(this->value_.value(x...)); } protected: @@ -73,6 +74,7 @@ template class ServoWriteAction : public Action { template class ServoDetachAction : public Action { public: ServoDetachAction(Servo *servo) : servo_(servo) {} + void play(Ts... x) override { this->servo_->detach(); } protected: diff --git a/esphome/components/switch/automation.h b/esphome/components/switch/automation.h index 90bdabf0f..579daf4d2 100644 --- a/esphome/components/switch/automation.h +++ b/esphome/components/switch/automation.h @@ -73,6 +73,7 @@ template class SwitchPublishAction : public Action { public: SwitchPublishAction(Switch *a_switch) : switch_(a_switch) {} TEMPLATABLE_VALUE(bool, state) + void play(Ts... x) override { this->switch_->publish_state(this->state_.value(x...)); } protected: diff --git a/esphome/components/text_sensor/automation.h b/esphome/components/text_sensor/automation.h index 496efb1cc..6810d10b1 100644 --- a/esphome/components/text_sensor/automation.h +++ b/esphome/components/text_sensor/automation.h @@ -30,6 +30,7 @@ template class TextSensorPublishAction : public Action { public: TextSensorPublishAction(TextSensor *sensor) : sensor_(sensor) {} TEMPLATABLE_VALUE(std::string, state) + void play(Ts... x) override { this->sensor_->publish_state(this->state_.value(x...)); } protected: diff --git a/esphome/core/automation.h b/esphome/core/automation.h index cbe96a749..02bd8bb29 100644 --- a/esphome/core/automation.h +++ b/esphome/core/automation.h @@ -75,45 +75,55 @@ template class ActionList; template class Action { public: - virtual void play(Ts... x) = 0; virtual void play_complex(Ts... x) { + this->num_running_++; this->play(x...); - this->play_next(x...); + this->play_next_(x...); } - void play_next(Ts... x) { - if (this->next_ != nullptr) { - this->next_->play_complex(x...); + virtual void stop_complex() { + if (num_running_) { + this->stop(); + this->num_running_ = 0; + } + this->stop_next_(); + } + virtual bool is_running() { return this->num_running_ > 0 || this->is_running_next_(); } + + protected: + friend ActionList; + + virtual void play(Ts... x) = 0; + void play_next_(Ts... x) { + if (this->num_running_ > 0) { + this->num_running_--; + if (this->next_ != nullptr) { + this->next_->play_complex(x...); + } } } - virtual void stop() {} - virtual void stop_complex() { - this->stop(); - this->stop_next(); + template void play_next_tuple_(const std::tuple &tuple, seq) { + this->play_next_(std::get(tuple)...); } - void stop_next() { + void play_next_tuple_(const std::tuple &tuple) { + this->play_next_tuple_(tuple, typename gens::type()); + } + + virtual void stop() {} + void stop_next_() { if (this->next_ != nullptr) { this->next_->stop_complex(); } } - virtual bool is_running() { return this->is_running_next(); } - bool is_running_next() { + + bool is_running_next_() { if (this->next_ == nullptr) return false; return this->next_->is_running(); } - void play_next_tuple(const std::tuple &tuple) { - this->play_next_tuple_(tuple, typename gens::type()); - } - - protected: - friend ActionList; - - template void play_next_tuple_(const std::tuple &tuple, seq) { - this->play_next(std::get(tuple)...); - } - Action *next_ = nullptr; + + int num_running_{0}; }; template class ActionList { diff --git a/esphome/core/base_automation.h b/esphome/core/base_automation.h index add3df0bb..d2656290b 100644 --- a/esphome/core/base_automation.h +++ b/esphome/core/base_automation.h @@ -108,34 +108,23 @@ template class DelayAction : public Action, public Compon TEMPLATABLE_VALUE(uint32_t, delay) - void stop() override { - this->cancel_timeout(""); - this->num_running_ = 0; - } - - void play(Ts... x) override { /* ignore - see play_complex */ - } - void play_complex(Ts... x) override { - auto f = std::bind(&DelayAction::delay_end_, this, x...); + auto f = std::bind(&DelayAction::play_next_, this, x...); this->num_running_++; this->set_timeout(this->delay_.value(x...), f); } float get_setup_priority() const override { return setup_priority::HARDWARE; } - bool is_running() override { return this->num_running_ > 0 || this->is_running_next(); } - - protected: - void delay_end_(Ts... x) { - this->num_running_--; - this->play_next(x...); + void play(Ts... x) override { /* ignore - see play_complex */ } - int num_running_{0}; + + void stop() override { this->cancel_timeout(""); } }; template class LambdaAction : public Action { public: explicit LambdaAction(std::function &&f) : f_(std::move(f)) {} + void play(Ts... x) override { this->f_(x...); } protected: @@ -148,41 +137,40 @@ template class IfAction : public Action { void add_then(const std::vector *> &actions) { this->then_.add_actions(actions); - this->then_.add_action(new LambdaAction([this](Ts... x) { this->play_next(x...); })); + this->then_.add_action(new LambdaAction([this](Ts... x) { this->play_next_(x...); })); } void add_else(const std::vector *> &actions) { this->else_.add_actions(actions); - this->else_.add_action(new LambdaAction([this](Ts... x) { this->play_next(x...); })); - } - - void play(Ts... x) override { /* ignore - see play_complex */ + this->else_.add_action(new LambdaAction([this](Ts... x) { this->play_next_(x...); })); } void play_complex(Ts... x) override { + this->num_running_++; bool res = this->condition_->check(x...); if (res) { if (this->then_.empty()) { - this->play_next(x...); - } else { + this->play_next_(x...); + } else if (this->num_running_ > 0) { this->then_.play(x...); } } else { if (this->else_.empty()) { - this->play_next(x...); - } else { + this->play_next_(x...); + } else if (this->num_running_ > 0) { this->else_.play(x...); } } } + void play(Ts... x) override { /* ignore - see play_complex */ + } + void stop() override { this->then_.stop(); this->else_.stop(); } - bool is_running() override { return this->then_.is_running() || this->else_.is_running() || this->is_running_next(); } - protected: Condition *condition_; ActionList then_; @@ -196,37 +184,40 @@ template class WhileAction : public Action { void add_then(const std::vector *> &actions) { this->then_.add_actions(actions); this->then_.add_action(new LambdaAction([this](Ts... x) { - if (this->condition_->check_tuple(this->var_)) { + if (this->num_running_ > 0 && this->condition_->check_tuple(this->var_)) { // play again - this->then_.play_tuple(this->var_); + if (this->num_running_ > 0) { + this->then_.play_tuple(this->var_); + } } else { // condition false, play next - this->play_next_tuple(this->var_); + this->play_next_tuple_(this->var_); } })); } - void play(Ts... x) override { /* ignore - see play_complex */ - } - void play_complex(Ts... x) override { + this->num_running_++; // Store loop parameters this->var_ = std::make_tuple(x...); // Initial condition check if (!this->condition_->check_tuple(this->var_)) { // If new condition check failed, stop loop if running this->then_.stop(); - this->play_next_tuple(this->var_); + this->play_next_tuple_(this->var_); return; } - this->then_.play_tuple(this->var_); + if (this->num_running_ > 0) { + this->then_.play_tuple(this->var_); + } + } + + void play(Ts... x) override { /* ignore - see play_complex */ } void stop() override { this->then_.stop(); } - bool is_running() override { return this->then_.is_running() || this->is_running_next(); } - protected: Condition *condition_; ActionList then_; @@ -237,48 +228,44 @@ template class WaitUntilAction : public Action, public Co public: WaitUntilAction(Condition *condition) : condition_(condition) {} - void play(Ts... x) { /* ignore - see play_complex */ - } - void play_complex(Ts... x) override { + this->num_running_++; // Check if we can continue immediately. if (this->condition_->check(x...)) { - this->triggered_ = false; - this->play_next(x...); + if (this->num_running_ > 0) { + this->play_next_(x...); + } return; } this->var_ = std::make_tuple(x...); - this->triggered_ = true; this->loop(); } - void stop() override { this->triggered_ = false; } - void loop() override { - if (!this->triggered_) + if (this->num_running_ == 0) return; if (!this->condition_->check_tuple(this->var_)) { return; } - this->triggered_ = false; - this->play_next_tuple(this->var_); + this->play_next_tuple_(this->var_); } float get_setup_priority() const override { return setup_priority::DATA; } - bool is_running() override { return this->triggered_ || this->is_running_next(); } + void play(Ts... x) override { /* ignore - see play_complex */ + } protected: Condition *condition_; - bool triggered_{false}; std::tuple var_{}; }; template class UpdateComponentAction : public Action { public: UpdateComponentAction(PollingComponent *component) : component_(component) {} + void play(Ts... x) override { this->component_->update(); } protected: