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 d68dac3b61..8a72765195 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 e9ff37446d..6b0321628c 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 a8eb0cdf99..0092f987f2 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 22ca11c3be..cb9686bb64 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 969a5d80cd..4b84e90a08 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 b6839985b0..51b74f48ba 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 dfa72a3ea6..d96ed994e8 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 2201fc87f0..151351be4c 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 6f14b0c92c..2bbebff845 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 8c8a5ab61b..51c2849702 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 8f379c47b4..3dae92af5f 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 8a216f5348..fc40a6a874 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 b810115f58..6267560443 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 c794991eab..593a3efe17 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 b13bd3e92d..eae97a8a14 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 f93e51a033..4cac4f9f32 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 2e1da74d9f..589c8d42de 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 250b59e55e..916fe29c1f 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 9f0bcdf82f..aecc8ab91c 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 4220645478..f0e47dfe0a 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 3b97327da8..8495014f00 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 079077dba0..c70fb93963 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 a37188740c..b864efc877 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 90bdabf0f4..579daf4d24 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 496efb1cc3..6810d10b13 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 cbe96a749e..02bd8bb299 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 add3df0bb5..d2656290bc 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: