mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 06:58:11 +01:00
Addressable updates
This commit is contained in:
parent
766f6c045d
commit
595dfe7e24
13 changed files with 193 additions and 41 deletions
|
@ -27,11 +27,6 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
|
|||
|
||||
inline int32_t size() const override { return this->num_leds_; }
|
||||
|
||||
inline light::ESPColorView operator[](int32_t index) const override {
|
||||
return light::ESPColorView(&this->leds_[index].r, &this->leds_[index].g, &this->leds_[index].b, nullptr,
|
||||
&this->effect_data_[index], &this->correction_);
|
||||
}
|
||||
|
||||
/// Set a maximum refresh rate in µs as some lights do not like being updated too often.
|
||||
void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
|
||||
|
||||
|
@ -236,6 +231,11 @@ class FastLEDLightOutput : public Component, public light::AddressableLight {
|
|||
}
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
return {&this->leds_[index].r, &this->leds_[index].g, &this->leds_[index].b, nullptr,
|
||||
&this->effect_data_[index], &this->correction_};
|
||||
}
|
||||
|
||||
CLEDController *controller_{nullptr};
|
||||
CRGB *leds_{nullptr};
|
||||
uint8_t *effect_data_{nullptr};
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
namespace esphome {
|
||||
namespace light {
|
||||
|
||||
const ESPColor ESPColor::BLACK = ESPColor(0, 0, 0, 0);
|
||||
const ESPColor ESPColor::WHITE = ESPColor(255, 255, 255, 255);
|
||||
|
||||
ESPColor ESPHSVColor::to_rgb() const {
|
||||
// based on FastLED's hsv rainbow to rgb
|
||||
const uint8_t hue = this->hue;
|
||||
|
@ -76,9 +79,18 @@ void ESPRangeView::set(const ESPColor &color) {
|
|||
(*this->parent_)[i] = color;
|
||||
}
|
||||
}
|
||||
ESPColorView ESPRangeView::operator[](int32_t index) const { return (*this->parent_)[index]; }
|
||||
ESPColorView ESPRangeView::operator[](int32_t index) const {
|
||||
index = interpret_index(index, this->size());
|
||||
return (*this->parent_)[index];
|
||||
}
|
||||
|
||||
ESPColorView ESPRangeView::Iterator::operator*() const { return (*this->range_->parent_)[this->i_]; }
|
||||
|
||||
int32_t HOT interpret_index(int32_t index, int32_t size) {
|
||||
if (index < 0)
|
||||
return size + index;
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
|
|
|
@ -147,6 +147,9 @@ struct ESPColor {
|
|||
ESPColor fade_to_black(uint8_t amnt) { return *this * amnt; }
|
||||
ESPColor lighten(uint8_t delta) { return *this + delta; }
|
||||
ESPColor darken(uint8_t delta) { return *this - delta; }
|
||||
|
||||
static const ESPColor BLACK;
|
||||
static const ESPColor WHITE;
|
||||
};
|
||||
|
||||
struct ESPHSVColor {
|
||||
|
@ -353,6 +356,8 @@ class ESPColorView : public ESPColorSettable {
|
|||
|
||||
class AddressableLight;
|
||||
|
||||
int32_t interpret_index(int32_t index, int32_t size);
|
||||
|
||||
class ESPRangeView : public ESPColorSettable {
|
||||
public:
|
||||
class Iterator {
|
||||
|
@ -385,6 +390,10 @@ class ESPRangeView : public ESPColorSettable {
|
|||
this->set(rhs);
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPColorView &rhs) {
|
||||
this->set(rhs.get());
|
||||
return *this;
|
||||
}
|
||||
ESPRangeView &operator=(const ESPHSVColor &rhs) {
|
||||
this->set_hsv(rhs);
|
||||
return *this;
|
||||
|
@ -463,9 +472,14 @@ class ESPRangeView : public ESPColorSettable {
|
|||
class AddressableLight : public LightOutput {
|
||||
public:
|
||||
virtual int32_t size() const = 0;
|
||||
virtual ESPColorView operator[](int32_t index) const = 0;
|
||||
ESPColorView operator[](int32_t index) const { return this->get_view_internal(interpret_index(index, this->size())); }
|
||||
ESPColorView get(int32_t index) { return this->get_view_internal(interpret_index(index, this->size())); }
|
||||
virtual void clear_effect_data() = 0;
|
||||
ESPRangeView range(int32_t from, int32_t to) { return ESPRangeView(this, from, to); }
|
||||
ESPRangeView range(int32_t from, int32_t to) {
|
||||
from = interpret_index(from, this->size());
|
||||
to = interpret_index(to, this->size());
|
||||
return ESPRangeView(this, from, to);
|
||||
}
|
||||
ESPRangeView all() { return ESPRangeView(this, 0, this->size()); }
|
||||
ESPRangeView::Iterator begin() { return this->all().begin(); }
|
||||
ESPRangeView::Iterator end() { return this->all().end(); }
|
||||
|
@ -476,7 +490,7 @@ class AddressableLight : public LightOutput {
|
|||
}
|
||||
if (amnt > this->size())
|
||||
amnt = this->size();
|
||||
this->range(0, this->size() - amnt) = this->range(amnt, this->size());
|
||||
this->range(0, -amnt) = this->range(amnt, this->size());
|
||||
}
|
||||
void shift_right(int32_t amnt) {
|
||||
if (amnt < 0) {
|
||||
|
@ -485,7 +499,7 @@ class AddressableLight : public LightOutput {
|
|||
}
|
||||
if (amnt > this->size())
|
||||
amnt = this->size();
|
||||
this->range(amnt, this->size()) = this->range(0, this->size() - amnt);
|
||||
this->range(amnt, this->size()) = this->range(0, -amnt);
|
||||
}
|
||||
bool is_effect_active() const { return this->effect_active_; }
|
||||
void set_effect_active(bool effect_active) { this->effect_active_ = effect_active; }
|
||||
|
@ -516,6 +530,7 @@ class AddressableLight : public LightOutput {
|
|||
protected:
|
||||
bool should_show_() const { return this->effect_active_ || this->next_show_; }
|
||||
void mark_shown_() { this->next_show_ = false; }
|
||||
virtual ESPColorView get_view_internal(int32_t index) const = 0;
|
||||
|
||||
bool effect_active_{false};
|
||||
bool next_show_{true};
|
||||
|
|
|
@ -113,11 +113,10 @@ class AddressableColorWipeEffect : public AddressableLightEffect {
|
|||
it.shift_right(1);
|
||||
const AddressableColorWipeEffectColor color = this->colors_[this->at_color_];
|
||||
const ESPColor esp_color = ESPColor(color.r, color.g, color.b, color.w);
|
||||
if (!this->reverse_) {
|
||||
it[it.size() - 1] = esp_color;
|
||||
} else {
|
||||
if (!this->reverse_)
|
||||
it[-1] = esp_color;
|
||||
else
|
||||
it[0] = esp_color;
|
||||
}
|
||||
if (++this->leds_added_ >= color.num_leds) {
|
||||
this->leds_added_ = 0;
|
||||
this->at_color_ = (this->at_color_ + 1) % this->colors_.size();
|
||||
|
@ -145,7 +144,7 @@ class AddressableScanEffect : public AddressableLightEffect {
|
|||
explicit AddressableScanEffect(const std::string &name) : AddressableLightEffect(name) {}
|
||||
void set_move_interval(uint32_t move_interval) { this->move_interval_ = move_interval; }
|
||||
void apply(AddressableLight &it, const ESPColor ¤t_color) override {
|
||||
it.all() = ESPColor(0, 0, 0, 0);
|
||||
it.all() = ESPColor::BLACK;
|
||||
it[this->at_led_] = current_color;
|
||||
const uint32_t now = millis();
|
||||
if (now - this->last_move_ > this->move_interval_) {
|
||||
|
@ -190,7 +189,7 @@ class AddressableTwinkleEffect : public AddressableLightEffect {
|
|||
else
|
||||
view.set_effect_data(new_pos);
|
||||
} else {
|
||||
view = ESPColor(0, 0, 0, 0);
|
||||
view = ESPColor::BLACK;
|
||||
}
|
||||
}
|
||||
while (random_float() < this->twinkle_probability_) {
|
||||
|
@ -220,8 +219,7 @@ class AddressableRandomTwinkleEffect : public AddressableLightEffect {
|
|||
this->last_progress_ = now;
|
||||
}
|
||||
uint8_t subsine = ((8 * (now - this->last_progress_)) / this->progress_interval_) & 0b111;
|
||||
for (auto &&i : it) {
|
||||
ESPColorView view = i;
|
||||
for (auto view : it) {
|
||||
if (view.get_effect_data() != 0) {
|
||||
const uint8_t x = (view.get_effect_data() >> 3) & 0b11111;
|
||||
const uint8_t color = view.get_effect_data() & 0b111;
|
||||
|
@ -261,9 +259,8 @@ class AddressableFireworksEffect : public AddressableLightEffect {
|
|||
public:
|
||||
explicit AddressableFireworksEffect(const std::string &name) : AddressableLightEffect(name) {}
|
||||
void start() override {
|
||||
const auto &it = *this->get_addressable_();
|
||||
for (int i = 0; i < it.size(); i++)
|
||||
it[i] = ESPColor(0, 0, 0, 0);
|
||||
auto &it = *this->get_addressable_();
|
||||
it.all() = ESPColor::BLACK;
|
||||
}
|
||||
void apply(AddressableLight &it, const ESPColor ¤t_color) override {
|
||||
const uint32_t now = millis();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "light_state.h"
|
||||
#include "addressable_light.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
@ -83,7 +84,7 @@ template<typename... Ts> class DimRelativeAction : public Action<Ts...> {
|
|||
template<typename... Ts> class LightIsOnCondition : public Condition<Ts...> {
|
||||
public:
|
||||
explicit LightIsOnCondition(LightState *state) : state_(state) {}
|
||||
bool check(Ts... x) override { return this->state_->get_current_values().is_on(); }
|
||||
bool check(Ts... x) override { return this->state_->current_values.is_on(); }
|
||||
|
||||
protected:
|
||||
LightState *state_;
|
||||
|
@ -91,11 +92,41 @@ template<typename... Ts> class LightIsOnCondition : public Condition<Ts...> {
|
|||
template<typename... Ts> class LightIsOffCondition : public Condition<LightState, Ts...> {
|
||||
public:
|
||||
explicit LightIsOffCondition(LightState *state) : state_(state) {}
|
||||
bool check(Ts... x) override { return !this->state_->get_current_values().is_on(); }
|
||||
bool check(Ts... x) override { return !this->state_->current_values.is_on(); }
|
||||
|
||||
protected:
|
||||
LightState *state_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class AddressableSet : public Action<Ts...> {
|
||||
public:
|
||||
explicit AddressableSet(LightState *parent) : parent_(parent) {}
|
||||
|
||||
TEMPLATABLE_VALUE(int32_t, range_from)
|
||||
TEMPLATABLE_VALUE(int32_t, range_to)
|
||||
TEMPLATABLE_VALUE(uint8_t, red)
|
||||
TEMPLATABLE_VALUE(uint8_t, green)
|
||||
TEMPLATABLE_VALUE(uint8_t, blue)
|
||||
TEMPLATABLE_VALUE(uint8_t, white)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto *out = (AddressableLight *) this->parent_->get_output();
|
||||
int32_t range_from = this->range_from_.value_or(x..., 0);
|
||||
int32_t range_to = this->range_to_.value_or(x..., out->size());
|
||||
auto range = out->range(range_from, range_to);
|
||||
if (this->red_.has_value())
|
||||
range.set_red(this->red_.value(x...));
|
||||
if (this->green_.has_value())
|
||||
range.set_green(this->green_.value(x...));
|
||||
if (this->blue_.has_value())
|
||||
range.set_blue(this->blue_.value(x...));
|
||||
if (this->white_.has_value())
|
||||
range.set_white(this->white_.value(x...));
|
||||
}
|
||||
|
||||
protected:
|
||||
LightState *parent_;
|
||||
};
|
||||
|
||||
} // namespace light
|
||||
} // namespace esphome
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "light_effect.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace light {
|
||||
|
@ -63,6 +64,21 @@ class LambdaLightEffect : public LightEffect {
|
|||
uint32_t last_run_{0};
|
||||
};
|
||||
|
||||
class AutomationLightEffect : public LightEffect {
|
||||
public:
|
||||
AutomationLightEffect(const std::string &name) : LightEffect(name) {}
|
||||
void stop() override { this->trig_->stop(); }
|
||||
void apply() override {
|
||||
if (!this->trig_->is_running()) {
|
||||
this->trig_->trigger();
|
||||
}
|
||||
}
|
||||
Trigger<> *get_trig() const { return trig_; }
|
||||
|
||||
protected:
|
||||
Trigger<> *trig_{new Trigger<>};
|
||||
};
|
||||
|
||||
struct StrobeLightEffectColor {
|
||||
LightColorValues color;
|
||||
uint32_t duration;
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.const import CONF_NAME, CONF_LAMBDA, CONF_UPDATE_INTERVAL, CONF_TRANSITION_LENGTH, \
|
||||
CONF_COLORS, CONF_STATE, CONF_DURATION, CONF_BRIGHTNESS, CONF_RED, CONF_GREEN, CONF_BLUE, \
|
||||
CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM
|
||||
CONF_WHITE, CONF_ALPHA, CONF_INTENSITY, CONF_SPEED, CONF_WIDTH, CONF_NUM_LEDS, CONF_RANDOM, \
|
||||
CONF_THEN
|
||||
from esphome.util import Registry
|
||||
from .types import LambdaLightEffect, RandomLightEffect, StrobeLightEffect, \
|
||||
StrobeLightEffectColor, LightColorValues, AddressableLightRef, AddressableLambdaLightEffect, \
|
||||
FlickerLightEffect, AddressableRainbowLightEffect, AddressableColorWipeEffect, \
|
||||
AddressableColorWipeEffectColor, AddressableScanEffect, AddressableTwinkleEffect, \
|
||||
AddressableRandomTwinkleEffect, AddressableFireworksEffect, AddressableFlickerEffect
|
||||
AddressableRandomTwinkleEffect, AddressableFireworksEffect, AddressableFlickerEffect, \
|
||||
AutomationLightEffect
|
||||
|
||||
CONF_ADD_LED_INTERVAL = 'add_led_interval'
|
||||
CONF_REVERSE = 'reverse'
|
||||
|
@ -28,8 +31,9 @@ CONF_ADDRESSABLE_TWINKLE = 'addressable_twinkle'
|
|||
CONF_ADDRESSABLE_RANDOM_TWINKLE = 'addressable_random_twinkle'
|
||||
CONF_ADDRESSABLE_FIREWORKS = 'addressable_fireworks'
|
||||
CONF_ADDRESSABLE_FLICKER = 'addressable_flicker'
|
||||
CONF_AUTOMATION = 'automation'
|
||||
|
||||
BINARY_EFFECTS = ['lambda', 'strobe']
|
||||
BINARY_EFFECTS = ['lambda', 'automation', 'strobe']
|
||||
MONOCHROMATIC_EFFECTS = BINARY_EFFECTS + ['flicker']
|
||||
RGB_EFFECTS = MONOCHROMATIC_EFFECTS + ['random']
|
||||
ADDRESSABLE_EFFECTS = RGB_EFFECTS + [CONF_ADDRESSABLE_LAMBDA, CONF_ADDRESSABLE_RAINBOW,
|
||||
|
@ -58,6 +62,15 @@ def lambda_effect_to_code(config, effect_id):
|
|||
config[CONF_UPDATE_INTERVAL])
|
||||
|
||||
|
||||
@register_effect('automation', AutomationLightEffect, "Automation", {
|
||||
cv.Required(CONF_THEN): automation.validate_automation(single=True),
|
||||
})
|
||||
def automation_effect_to_code(config, effect_id):
|
||||
var = yield cg.new_Pvariable(effect_id, config[CONF_NAME])
|
||||
yield automation.build_automation(var.get_trig(), [], config[CONF_THEN])
|
||||
yield var
|
||||
|
||||
|
||||
@register_effect('random', RandomLightEffect, "Random", {
|
||||
cv.Optional(CONF_TRANSITION_LENGTH, default='7.5s'): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default='10s'): cv.positive_time_period_milliseconds,
|
||||
|
|
|
@ -20,6 +20,7 @@ DimRelativeAction = light_ns.class_('DimRelativeAction', automation.Action)
|
|||
LightEffect = light_ns.class_('LightEffect')
|
||||
RandomLightEffect = light_ns.class_('RandomLightEffect', LightEffect)
|
||||
LambdaLightEffect = light_ns.class_('LambdaLightEffect', LightEffect)
|
||||
AutomationLightEffect = light_ns.class_('AutomationLightEffect', LightEffect)
|
||||
StrobeLightEffect = light_ns.class_('StrobeLightEffect', LightEffect)
|
||||
StrobeLightEffectColor = light_ns.class_('StrobeLightEffectColor', LightEffect)
|
||||
FlickerLightEffect = light_ns.class_('FlickerLightEffect', LightEffect)
|
||||
|
|
|
@ -144,29 +144,24 @@ class NeoPixelBusLightOutputBase : public Component, public light::AddressableLi
|
|||
template<typename T_METHOD, typename T_COLOR_FEATURE = NeoRgbFeature>
|
||||
class NeoPixelRGBLightOutput : public NeoPixelBusLightOutputBase<T_METHOD, T_COLOR_FEATURE> {
|
||||
public:
|
||||
inline light::ESPColorView operator[](int32_t index) const override {
|
||||
uint8_t *base = this->controller_->Pixels() + 3ULL * index;
|
||||
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
|
||||
nullptr, this->effect_data_ + index, &this->correction_);
|
||||
}
|
||||
|
||||
light::LightTraits get_traits() override {
|
||||
auto traits = light::LightTraits();
|
||||
traits.set_supports_brightness(true);
|
||||
traits.set_supports_rgb(true);
|
||||
return traits;
|
||||
}
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
uint8_t *base = this->controller_->Pixels() + 3ULL * index;
|
||||
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
|
||||
nullptr, this->effect_data_ + index, &this->correction_);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T_METHOD, typename T_COLOR_FEATURE = NeoRgbwFeature>
|
||||
class NeoPixelRGBWLightOutput : public NeoPixelBusLightOutputBase<T_METHOD, T_COLOR_FEATURE> {
|
||||
public:
|
||||
inline light::ESPColorView operator[](int32_t index) const override {
|
||||
uint8_t *base = this->controller_->Pixels() + 4ULL * index;
|
||||
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
|
||||
base + this->rgb_offsets_[3], this->effect_data_ + index, &this->correction_);
|
||||
}
|
||||
|
||||
light::LightTraits get_traits() override {
|
||||
auto traits = light::LightTraits();
|
||||
traits.set_supports_brightness(true);
|
||||
|
@ -174,6 +169,13 @@ class NeoPixelRGBWLightOutput : public NeoPixelBusLightOutputBase<T_METHOD, T_CO
|
|||
traits.set_supports_rgb_white_value(true);
|
||||
return traits;
|
||||
}
|
||||
|
||||
protected:
|
||||
light::ESPColorView get_view_internal(int32_t index) const override {
|
||||
uint8_t *base = this->controller_->Pixels() + 4ULL * index;
|
||||
return light::ESPColorView(base + this->rgb_offsets_[0], base + this->rgb_offsets_[1], base + this->rgb_offsets_[2],
|
||||
base + this->rgb_offsets_[3], this->effect_data_ + index, &this->correction_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace neopixelbus
|
||||
|
|
|
@ -8,6 +8,7 @@ script_ns = cg.esphome_ns.namespace('script')
|
|||
Script = script_ns.class_('Script', automation.Trigger.template())
|
||||
ScriptExecuteAction = script_ns.class_('ScriptExecuteAction', automation.Action)
|
||||
ScriptStopAction = script_ns.class_('ScriptStopAction', automation.Action)
|
||||
IsRunningCondition = script_ns.class_('IsRunningCondition', automation.Condition)
|
||||
|
||||
CONFIG_SCHEMA = automation.validate_automation({
|
||||
cv.Required(CONF_ID): cv.declare_id(Script),
|
||||
|
@ -34,3 +35,11 @@ def script_execute_action_to_code(config, action_id, template_arg, args):
|
|||
def script_stop_action_to_code(config, action_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
|
||||
@automation.register_condition('script.is_running', IsRunningCondition, automation.maybe_simple_id({
|
||||
cv.Required(CONF_ID): cv.use_id(Script)
|
||||
}))
|
||||
def script_is_running_to_code(config, condition_id, template_arg, args):
|
||||
paren = yield cg.get_variable(config[CONF_ID])
|
||||
yield cg.new_Pvariable(condition_id, template_arg, paren)
|
||||
|
|
|
@ -7,7 +7,16 @@ namespace script {
|
|||
|
||||
class Script : public Trigger<> {
|
||||
public:
|
||||
void execute() { this->trigger(); }
|
||||
void execute() {
|
||||
bool prev = this->in_stack_;
|
||||
this->in_stack_ = true;
|
||||
this->trigger();
|
||||
this->in_stack_ = prev;
|
||||
}
|
||||
bool script_is_running() { return this->in_stack_ || this->is_running(); }
|
||||
|
||||
protected:
|
||||
bool in_stack_{false};
|
||||
};
|
||||
|
||||
template<typename... Ts> class ScriptExecuteAction : public Action<Ts...> {
|
||||
|
@ -30,5 +39,15 @@ template<typename... Ts> class ScriptStopAction : public Action<Ts...> {
|
|||
Script *script_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class IsRunningCondition : public Condition<Ts...> {
|
||||
public:
|
||||
explicit IsRunningCondition(Script *parent) : parent_(parent) {}
|
||||
|
||||
bool check(Ts... x) override { return this->parent_->script_is_running(); }
|
||||
|
||||
protected:
|
||||
Script *parent_;
|
||||
};
|
||||
|
||||
} // namespace script
|
||||
} // namespace esphome
|
||||
|
|
|
@ -52,6 +52,11 @@ template<typename... Ts> class Trigger {
|
|||
return;
|
||||
this->automation_parent_->stop();
|
||||
}
|
||||
bool is_running() {
|
||||
if (this->automation_parent_ == nullptr)
|
||||
return false;
|
||||
return this->automation_parent_.is_running();
|
||||
}
|
||||
|
||||
protected:
|
||||
Automation<Ts...> *automation_parent_{nullptr};
|
||||
|
@ -81,6 +86,12 @@ template<typename... Ts> class Action {
|
|||
this->next_->stop_complex();
|
||||
}
|
||||
}
|
||||
virtual bool is_running() { return this->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<Ts...> &tuple) {
|
||||
this->play_next_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
|
||||
|
@ -121,6 +132,11 @@ template<typename... Ts> class ActionList {
|
|||
this->actions_begin_->stop_complex();
|
||||
}
|
||||
bool empty() const { return this->actions_begin_ == nullptr; }
|
||||
bool is_running() {
|
||||
if (this->actions_begin_ == nullptr)
|
||||
return false;
|
||||
return this->actions_begin_->is_running();
|
||||
}
|
||||
|
||||
protected:
|
||||
template<int... S> void play_tuple_(const std::tuple<Ts...> &tuple, seq<S...>) { this->play(std::get<S>(tuple)...); }
|
||||
|
@ -140,6 +156,8 @@ template<typename... Ts> class Automation {
|
|||
|
||||
void trigger(Ts... x) { this->actions_.play(x...); }
|
||||
|
||||
bool is_running() { return this->actions_.is_running(); }
|
||||
|
||||
protected:
|
||||
Trigger<Ts...> *trigger_;
|
||||
ActionList<Ts...> actions_;
|
||||
|
|
|
@ -108,16 +108,29 @@ template<typename... Ts> class DelayAction : public Action<Ts...>, public Compon
|
|||
|
||||
TEMPLATABLE_VALUE(uint32_t, delay)
|
||||
|
||||
void stop() override { this->cancel_timeout(""); }
|
||||
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<Ts...>::play_next, this, x...);
|
||||
auto f = std::bind(&DelayAction<Ts...>::delay_end_, 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...);
|
||||
}
|
||||
int num_running_{0};
|
||||
};
|
||||
|
||||
template<typename... Ts> class LambdaAction : public Action<Ts...> {
|
||||
|
@ -168,6 +181,8 @@ template<typename... Ts> class IfAction : public Action<Ts...> {
|
|||
this->else_.stop();
|
||||
}
|
||||
|
||||
bool is_running() override { return this->then_.is_running() || this->else_.is_running() || this->is_running_next(); }
|
||||
|
||||
protected:
|
||||
Condition<Ts...> *condition_;
|
||||
ActionList<Ts...> then_;
|
||||
|
@ -210,6 +225,8 @@ template<typename... Ts> class WhileAction : public Action<Ts...> {
|
|||
|
||||
void stop() override { this->then_.stop(); }
|
||||
|
||||
bool is_running() override { return this->then_.is_running() || this->is_running_next(); }
|
||||
|
||||
protected:
|
||||
Condition<Ts...> *condition_;
|
||||
ActionList<Ts...> then_;
|
||||
|
@ -251,6 +268,8 @@ template<typename... Ts> class WaitUntilAction : public Action<Ts...>, public Co
|
|||
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
bool is_running() override { return this->triggered_ || this->is_running_next(); }
|
||||
|
||||
protected:
|
||||
Condition<Ts...> *condition_;
|
||||
bool triggered_{false};
|
||||
|
|
Loading…
Reference in a new issue