mirror of
https://github.com/esphome/esphome.git
synced 2024-11-29 12:55:46 +01:00
commit
ab48e4a466
@ -33,7 +33,7 @@ class AQICalculator : public AbstractAQICalculator {
|
||||
}
|
||||
|
||||
int get_grid_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
|
||||
for (int i = 0; i < AMOUNT_OF_LEVELS - 1; i++) {
|
||||
for (int i = 0; i < AMOUNT_OF_LEVELS; i++) {
|
||||
if (value >= array[i][0] && value <= array[i][1]) {
|
||||
return i;
|
||||
}
|
||||
|
@ -102,17 +102,18 @@ class LightTurnOnTrigger : public Trigger<> {
|
||||
public:
|
||||
LightTurnOnTrigger(LightState *a_light) {
|
||||
a_light->add_new_remote_values_callback([this, a_light]() {
|
||||
auto is_on = a_light->current_values.is_on();
|
||||
// using the remote value because of transitions we need to trigger as early as possible
|
||||
auto is_on = a_light->remote_values.is_on();
|
||||
// only trigger when going from off to on
|
||||
auto should_trigger = is_on && !last_on_;
|
||||
auto should_trigger = is_on && !this->last_on_;
|
||||
// Set new state immediately so that trigger() doesn't devolve
|
||||
// into infinite loop
|
||||
last_on_ = is_on;
|
||||
this->last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
last_on_ = a_light->current_values.is_on();
|
||||
this->last_on_ = a_light->current_values.is_on();
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -122,22 +123,14 @@ class LightTurnOnTrigger : public Trigger<> {
|
||||
class LightTurnOffTrigger : public Trigger<> {
|
||||
public:
|
||||
LightTurnOffTrigger(LightState *a_light) {
|
||||
a_light->add_new_remote_values_callback([this, a_light]() {
|
||||
a_light->add_new_target_state_reached_callback([this, a_light]() {
|
||||
auto is_on = a_light->current_values.is_on();
|
||||
// only trigger when going from on to off
|
||||
auto should_trigger = !is_on && last_on_;
|
||||
// Set new state immediately so that trigger() doesn't devolve
|
||||
// into infinite loop
|
||||
last_on_ = is_on;
|
||||
if (should_trigger) {
|
||||
if (!is_on) {
|
||||
this->trigger();
|
||||
}
|
||||
});
|
||||
last_on_ = a_light->current_values.is_on();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool last_on_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class AddressableSet : public Action<Ts...> {
|
||||
|
@ -145,6 +145,7 @@ void LightState::loop() {
|
||||
if (this->transformer_ != nullptr) {
|
||||
if (this->transformer_->is_finished()) {
|
||||
this->remote_values = this->current_values = this->transformer_->get_end_values();
|
||||
this->target_state_reached_callback_.call();
|
||||
if (this->transformer_->publish_at_end())
|
||||
this->publish_state();
|
||||
this->transformer_ = nullptr;
|
||||
@ -336,6 +337,9 @@ void LightCall::perform() {
|
||||
this->parent_->set_immediately_(v, this->publish_);
|
||||
}
|
||||
|
||||
if (!this->has_transition_()) {
|
||||
this->parent_->target_state_reached_callback_.call();
|
||||
}
|
||||
if (this->publish_) {
|
||||
this->parent_->publish_state();
|
||||
}
|
||||
@ -395,13 +399,13 @@ LightColorValues LightCall::validate_() {
|
||||
|
||||
// sets RGB to 100% if only White specified
|
||||
if (this->white_.has_value()) {
|
||||
if (traits.get_supports_color_interlock()) {
|
||||
if (!this->red_.has_value() && !this->green_.has_value() && !this->blue_.has_value()) {
|
||||
this->red_ = optional<float>(1.0f);
|
||||
this->green_ = optional<float>(1.0f);
|
||||
this->blue_ = optional<float>(1.0f);
|
||||
}
|
||||
// make white values binary aka 0.0f or 1.0f...this allows brightness to do its job
|
||||
if (traits.get_supports_color_interlock()) {
|
||||
if (*this->white_ > 0.0f) {
|
||||
this->white_ = optional<float>(1.0f);
|
||||
} else {
|
||||
@ -411,13 +415,15 @@ LightColorValues LightCall::validate_() {
|
||||
}
|
||||
// White to 0% if (exclusively) setting any RGB value that isn't 255,255,255
|
||||
else if (this->red_.has_value() || this->green_.has_value() || this->blue_.has_value()) {
|
||||
if (*this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f && traits.get_supports_rgb_white_value() &&
|
||||
traits.get_supports_color_interlock()) {
|
||||
if (traits.get_supports_color_interlock()) {
|
||||
if (*this->red_ == 1.0f && *this->green_ == 1.0f && *this->blue_ == 1.0f &&
|
||||
traits.get_supports_rgb_white_value() && traits.get_supports_color_interlock()) {
|
||||
this->white_ = optional<float>(1.0f);
|
||||
} else if (!this->white_.has_value() || !traits.get_supports_rgb_white_value()) {
|
||||
this->white_ = optional<float>(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if changing Kelvin alone, change to white light
|
||||
else if (this->color_temperature_.has_value()) {
|
||||
if (!traits.get_supports_color_interlock()) {
|
||||
@ -752,6 +758,10 @@ void LightState::current_values_as_cwww(float *cold_white, float *warm_white, bo
|
||||
void LightState::add_new_remote_values_callback(std::function<void()> &&send_callback) {
|
||||
this->remote_values_callback_.add(std::move(send_callback));
|
||||
}
|
||||
void LightState::add_new_target_state_reached_callback(std::function<void()> &&send_callback) {
|
||||
this->target_state_reached_callback_.add(std::move(send_callback));
|
||||
}
|
||||
|
||||
LightEffect *LightState::get_active_effect_() {
|
||||
if (this->active_effect_index_ == 0)
|
||||
return nullptr;
|
||||
|
@ -242,6 +242,13 @@ class LightState : public Nameable, public Component {
|
||||
*/
|
||||
void add_new_remote_values_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/**
|
||||
* The callback is called once the state of current_values and remote_values are equal
|
||||
*
|
||||
* @param send_callback
|
||||
*/
|
||||
void add_new_target_state_reached_callback(std::function<void()> &&send_callback);
|
||||
|
||||
/// Return whether the light has any effects that meet the trait requirements.
|
||||
bool supports_effects();
|
||||
|
||||
@ -318,6 +325,12 @@ class LightState : public Nameable, public Component {
|
||||
* starting with the beginning of the transition.
|
||||
*/
|
||||
CallbackManager<void()> remote_values_callback_{};
|
||||
|
||||
/** Callback to call when the state of current_values and remote_values are equal
|
||||
* This should be called once the state of current_values changed and equals the state of remote_values
|
||||
*/
|
||||
CallbackManager<void()> target_state_reached_callback_{};
|
||||
|
||||
LightOutput *output_; ///< Store the output to allow effects to have more access.
|
||||
/// Whether the light value should be written in the next cycle.
|
||||
bool next_write_{true};
|
||||
|
@ -229,7 +229,7 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) {
|
||||
b = pixels[col];
|
||||
} else if (this->orientation_ == 2) {
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
b |= ((pixels[i] >> (7 - col)) << (7 - i));
|
||||
b |= ((pixels[i] >> (7 - col)) & 1) << i;
|
||||
}
|
||||
} else {
|
||||
b = pixels[7 - col];
|
||||
|
@ -12,6 +12,75 @@ namespace xiaomi_ble {
|
||||
|
||||
static const char *TAG = "xiaomi_ble";
|
||||
|
||||
bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result) {
|
||||
// motion detection, 1 byte, 8-bit unsigned integer
|
||||
if ((value_type == 0x03) && (value_length == 1)) {
|
||||
result.has_motion = (data[0]) ? true : false;
|
||||
}
|
||||
// temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C
|
||||
else if ((value_type == 0x04) && (value_length == 2)) {
|
||||
const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.temperature = temperature / 10.0f;
|
||||
}
|
||||
// humidity, 2 bytes, 16-bit signed integer (LE), 0.1 %
|
||||
else if ((value_type == 0x06) && (value_length == 2)) {
|
||||
const int16_t humidity = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.humidity = humidity / 10.0f;
|
||||
}
|
||||
// illuminance (+ motion), 3 bytes, 24-bit unsigned integer (LE), 1 lx
|
||||
else if (((value_type == 0x07) || (value_type == 0x0F)) && (value_length == 3)) {
|
||||
const uint32_t illuminance = uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16);
|
||||
result.illuminance = illuminance;
|
||||
result.is_light = (illuminance == 100) ? true : false;
|
||||
if (value_type == 0x0F)
|
||||
result.has_motion = true;
|
||||
}
|
||||
// soil moisture, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((value_type == 0x08) && (value_length == 1)) {
|
||||
result.moisture = data[0];
|
||||
}
|
||||
// conductivity, 2 bytes, 16-bit unsigned integer (LE), 1 µS/cm
|
||||
else if ((value_type == 0x09) && (value_length == 2)) {
|
||||
const uint16_t conductivity = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.conductivity = conductivity;
|
||||
}
|
||||
// battery, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((value_type == 0x0A) && (value_length == 1)) {
|
||||
result.battery_level = data[0];
|
||||
}
|
||||
// temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 %
|
||||
else if ((value_type == 0x0D) && (value_length == 4)) {
|
||||
const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
const int16_t humidity = uint16_t(data[2]) | (uint16_t(data[3]) << 8);
|
||||
result.temperature = temperature / 10.0f;
|
||||
result.humidity = humidity / 10.0f;
|
||||
}
|
||||
// formaldehyde, 2 bytes, 16-bit unsigned integer (LE), 0.01 mg / m3
|
||||
else if ((value_type == 0x10) && (value_length == 2)) {
|
||||
const uint16_t formaldehyde = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.formaldehyde = formaldehyde / 100.0f;
|
||||
}
|
||||
// on/off state, 1 byte, 8-bit unsigned integer
|
||||
else if ((value_type == 0x12) && (value_length == 1)) {
|
||||
result.is_active = (data[0]) ? true : false;
|
||||
}
|
||||
// mosquito tablet, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((value_type == 0x13) && (value_length == 1)) {
|
||||
result.tablet = data[0];
|
||||
}
|
||||
// idle time since last motion, 4 byte, 32-bit unsigned integer, 1 min
|
||||
else if ((value_type == 0x17) && (value_length == 4)) {
|
||||
const uint32_t idle_time =
|
||||
uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[2]) << 24);
|
||||
result.idle_time = idle_time / 60.0f;
|
||||
result.has_motion = (idle_time) ? false : true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result) {
|
||||
result.has_encryption = (message[0] & 0x08) ? true : false; // update encryption status
|
||||
if (result.has_encryption) {
|
||||
@ -25,81 +94,39 @@ bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult
|
||||
// Byte 2: length
|
||||
// Byte 3..3+len-1: data point value
|
||||
|
||||
const uint8_t *raw = message.data() + result.raw_offset;
|
||||
const uint8_t *data = raw + 3;
|
||||
const uint8_t data_length = raw[2];
|
||||
const uint8_t *payload = message.data() + result.raw_offset;
|
||||
uint8_t payload_length = message.size() - result.raw_offset;
|
||||
uint8_t payload_offset = 0;
|
||||
bool success = false;
|
||||
|
||||
if ((data_length < 1) || (data_length > 4)) {
|
||||
ESP_LOGVV(TAG, "parse_xiaomi_message(): payload has wrong size (%d)!", data_length);
|
||||
if (payload_length < 4) {
|
||||
ESP_LOGVV(TAG, "parse_xiaomi_message(): payload has wrong size (%d)!", payload_length);
|
||||
return false;
|
||||
}
|
||||
|
||||
// motion detection, 1 byte, 8-bit unsigned integer
|
||||
if ((raw[0] == 0x03) && (data_length == 1)) {
|
||||
result.has_motion = (data[0]) ? true : false;
|
||||
}
|
||||
// temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C
|
||||
else if ((raw[0] == 0x04) && (data_length == 2)) {
|
||||
const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.temperature = temperature / 10.0f;
|
||||
}
|
||||
// humidity, 2 bytes, 16-bit signed integer (LE), 0.1 %
|
||||
else if ((raw[0] == 0x06) && (data_length == 2)) {
|
||||
const int16_t humidity = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.humidity = humidity / 10.0f;
|
||||
}
|
||||
// illuminance (+ motion), 3 bytes, 24-bit unsigned integer (LE), 1 lx
|
||||
else if (((raw[0] == 0x07) || (raw[0] == 0x0F)) && (data_length == 3)) {
|
||||
const uint32_t illuminance = uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16);
|
||||
result.illuminance = illuminance;
|
||||
result.is_light = (illuminance == 100) ? true : false;
|
||||
if (raw[0] == 0x0F)
|
||||
result.has_motion = true;
|
||||
}
|
||||
// soil moisture, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((raw[0] == 0x08) && (data_length == 1)) {
|
||||
result.moisture = data[0];
|
||||
}
|
||||
// conductivity, 2 bytes, 16-bit unsigned integer (LE), 1 µS/cm
|
||||
else if ((raw[0] == 0x09) && (data_length == 2)) {
|
||||
const uint16_t conductivity = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.conductivity = conductivity;
|
||||
}
|
||||
// battery, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((raw[0] == 0x0A) && (data_length == 1)) {
|
||||
result.battery_level = data[0];
|
||||
}
|
||||
// temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 %
|
||||
else if ((raw[0] == 0x0D) && (data_length == 4)) {
|
||||
const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
const int16_t humidity = uint16_t(data[2]) | (uint16_t(data[3]) << 8);
|
||||
result.temperature = temperature / 10.0f;
|
||||
result.humidity = humidity / 10.0f;
|
||||
}
|
||||
// formaldehyde, 2 bytes, 16-bit unsigned integer (LE), 0.01 mg / m3
|
||||
else if ((raw[0] == 0x10) && (data_length == 2)) {
|
||||
const uint16_t formaldehyde = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
|
||||
result.formaldehyde = formaldehyde / 100.0f;
|
||||
}
|
||||
// on/off state, 1 byte, 8-bit unsigned integer
|
||||
else if ((raw[0] == 0x12) && (data_length == 1)) {
|
||||
result.is_active = (data[0]) ? true : false;
|
||||
}
|
||||
// mosquito tablet, 1 byte, 8-bit unsigned integer, 1 %
|
||||
else if ((raw[0] == 0x13) && (data_length == 1)) {
|
||||
result.tablet = data[0];
|
||||
}
|
||||
// idle time since last motion, 4 byte, 32-bit unsigned integer, 1 min
|
||||
else if ((raw[0] == 0x17) && (data_length == 4)) {
|
||||
const uint32_t idle_time =
|
||||
uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[2]) << 24);
|
||||
result.idle_time = idle_time / 60.0f;
|
||||
result.has_motion = (idle_time) ? false : true;
|
||||
} else {
|
||||
return false;
|
||||
while (payload_length > 0) {
|
||||
if (payload[payload_offset + 1] != 0x10) {
|
||||
ESP_LOGVV(TAG, "parse_xiaomi_message(): fixed byte not found, stop parsing residual data.");
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
const uint8_t value_length = payload[payload_offset + 2];
|
||||
if ((value_length < 1) || (value_length > 4) || (payload_length < (3 + value_length))) {
|
||||
ESP_LOGVV(TAG, "parse_xiaomi_message(): value has wrong size (%d)!", value_length);
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t value_type = payload[payload_offset + 0];
|
||||
const uint8_t *data = &payload[payload_offset + 3];
|
||||
|
||||
if (parse_xiaomi_value(value_type, data, value_length, result))
|
||||
success = true;
|
||||
|
||||
payload_length -= 3 + value_length;
|
||||
payload_offset += 3 + value_length;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data) {
|
||||
|
@ -57,6 +57,7 @@ struct XiaomiAESVector {
|
||||
size_t ivsize;
|
||||
};
|
||||
|
||||
bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result);
|
||||
bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result);
|
||||
optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data);
|
||||
bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, const uint64_t &address);
|
||||
|
@ -11,10 +11,11 @@ from string import ascii_letters, digits
|
||||
import voluptuous as vol
|
||||
|
||||
from esphome import core
|
||||
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, CONF_DISCOVERY, CONF_ID, \
|
||||
CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, \
|
||||
CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, \
|
||||
CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE, CONF_UPDATE_INTERVAL, CONF_TYPE_ID, CONF_TYPE
|
||||
from esphome.const import CONF_AVAILABILITY, CONF_COMMAND_TOPIC, \
|
||||
CONF_DISCOVERY, CONF_ID, CONF_INTERNAL, CONF_NAME, CONF_PAYLOAD_AVAILABLE, \
|
||||
CONF_PAYLOAD_NOT_AVAILABLE, CONF_RETAIN, CONF_SETUP_PRIORITY, CONF_STATE_TOPIC, CONF_TOPIC, \
|
||||
CONF_HOUR, CONF_MINUTE, CONF_SECOND, CONF_VALUE, CONF_UPDATE_INTERVAL, CONF_TYPE_ID, \
|
||||
CONF_TYPE, CONF_PACKAGES
|
||||
from esphome.core import CORE, HexInt, IPAddress, Lambda, TimePeriod, TimePeriodMicroseconds, \
|
||||
TimePeriodMilliseconds, TimePeriodSeconds, TimePeriodMinutes
|
||||
from esphome.helpers import list_starts_with, add_class_to_obj
|
||||
@ -1167,9 +1168,12 @@ class OnlyWith(Optional):
|
||||
@property
|
||||
def default(self):
|
||||
# pylint: disable=unsupported-membership-test
|
||||
if self._component not in CORE.raw_config:
|
||||
return vol.UNDEFINED
|
||||
if (self._component in CORE.raw_config or
|
||||
(CONF_PACKAGES in CORE.raw_config and
|
||||
self._component in
|
||||
{list(x.keys())[0] for x in CORE.raw_config[CONF_PACKAGES].values()})):
|
||||
return self._default
|
||||
return vol.UNDEFINED
|
||||
|
||||
@default.setter
|
||||
def default(self, value):
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
MAJOR_VERSION = 1
|
||||
MINOR_VERSION = 15
|
||||
PATCH_VERSION = '2'
|
||||
PATCH_VERSION = '3'
|
||||
__short_version__ = f'{MAJOR_VERSION}.{MINOR_VERSION}'
|
||||
__version__ = f'{__short_version__}.{PATCH_VERSION}'
|
||||
|
||||
|
@ -178,8 +178,8 @@ void delay_microseconds_accurate(uint32_t usec) {
|
||||
if (usec <= 16383UL) {
|
||||
delayMicroseconds(usec);
|
||||
} else {
|
||||
delay(usec / 16383UL);
|
||||
delayMicroseconds(usec % 16383UL);
|
||||
delay(usec / 1000UL);
|
||||
delayMicroseconds(usec % 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ namespace esphome {
|
||||
static const char *TAG = "scheduler";
|
||||
|
||||
static const uint32_t SCHEDULER_DONT_RUN = 4294967295UL;
|
||||
static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10;
|
||||
|
||||
// Uncomment to debug scheduler
|
||||
// #define ESPHOME_DEBUG_SCHEDULER
|
||||
@ -107,6 +108,26 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
||||
}
|
||||
#endif // ESPHOME_DEBUG_SCHEDULER
|
||||
|
||||
auto to_remove_was = to_remove_;
|
||||
auto items_was = items_.size();
|
||||
// If we have too many items to remove
|
||||
if (to_remove_ > MAX_LOGICALLY_DELETED_ITEMS) {
|
||||
std::vector<std::unique_ptr<SchedulerItem>> valid_items;
|
||||
while (!this->empty_()) {
|
||||
auto item = std::move(this->items_[0]);
|
||||
this->pop_raw_();
|
||||
valid_items.push_back(std::move(item));
|
||||
}
|
||||
this->items_ = std::move(valid_items);
|
||||
|
||||
// The following should not happen unless I'm missing something
|
||||
if (to_remove_ != 0) {
|
||||
ESP_LOGW(TAG, "to_remove_ was %u now: %u items where %zu now %zu. Please report this", to_remove_was, to_remove_,
|
||||
items_was, items_.size());
|
||||
to_remove_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while (!this->empty_()) {
|
||||
// use scoping to indicate visibility of `item` variable
|
||||
{
|
||||
@ -147,6 +168,7 @@ void ICACHE_RAM_ATTR HOT Scheduler::call() {
|
||||
|
||||
if (item->remove) {
|
||||
// We were removed/cancelled in the function call, stop
|
||||
to_remove_--;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -182,6 +204,7 @@ void HOT Scheduler::cleanup_() {
|
||||
if (!item->remove)
|
||||
return;
|
||||
|
||||
to_remove_--;
|
||||
this->pop_raw_();
|
||||
}
|
||||
}
|
||||
@ -193,7 +216,8 @@ void HOT Scheduler::push_(std::unique_ptr<Scheduler::SchedulerItem> item) { this
|
||||
bool HOT Scheduler::cancel_item_(Component *component, const std::string &name, Scheduler::SchedulerItem::Type type) {
|
||||
bool ret = false;
|
||||
for (auto &it : this->items_)
|
||||
if (it->component == component && it->name == name && it->type == type) {
|
||||
if (it->component == component && it->name == name && it->type == type && !it->remove) {
|
||||
to_remove_++;
|
||||
it->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ class Scheduler {
|
||||
std::vector<std::unique_ptr<SchedulerItem>> to_add_;
|
||||
uint32_t last_millis_{0};
|
||||
uint8_t millis_major_{0};
|
||||
uint32_t to_remove_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome
|
||||
|
Loading…
Reference in New Issue
Block a user