From bc7a59b75b729b6acb8132ff7aaa3451f491468b Mon Sep 17 00:00:00 2001 From: Marius Muja Date: Sat, 20 Jan 2024 15:51:02 -0800 Subject: [PATCH] Added expiring callbacks that will only be called within a certain time. Defer sending operations in status handling methods. --- components/ratgdo/callbacks.h | 47 +++++++++++++++++++++++++++++++++- components/ratgdo/ratgdo.cpp | 27 +++++++++++-------- components/ratgdo/ratgdo.h | 2 +- components/ratgdo/secplus1.cpp | 12 ++++----- components/ratgdo/secplus1.h | 2 +- components/ratgdo/secplus2.cpp | 8 +++--- 6 files changed, 75 insertions(+), 23 deletions(-) diff --git a/components/ratgdo/callbacks.h b/components/ratgdo/callbacks.h index b436af4..6230816 100644 --- a/components/ratgdo/callbacks.h +++ b/components/ratgdo/callbacks.h @@ -17,8 +17,9 @@ namespace ratgdo { void trigger(Ts... args) { - for (auto& cb : this->callbacks_) + for (auto& cb : this->callbacks_) { cb(args...); + } this->callbacks_.clear(); } @@ -26,5 +27,49 @@ namespace ratgdo { std::vector> callbacks_; }; + + template + class ExpiringCallbacks; + + template + class ExpiringCallbacks { + public: + template + void operator()(uint32_t expiration, Callback&& callback) + { + this->callbacks_.push_back(std::make_pair(expiration, std::forward(callback))); + } + + void trigger(uint32_t now, Ts... args) + { + for (auto& cb : this->callbacks_) { + if (cb.first >= now) { + cb.second(args...); + } + } + this->callbacks_.clear(); + } + + bool is_expired(uint32_t now) const + { + bool expired = true; + for (auto& cb : this->callbacks_) { + if (cb.first >= now) { + expired = false; + } + } + return expired; + } + + void clear() + { + this->callbacks_.clear(); + } + + protected: + std::vector>> callbacks_; + }; + + } // namespace ratgdo } // namespace esphome diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 791b803..c84628c 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -176,12 +176,17 @@ namespace ratgdo { this->motor_state = MotorState::OFF; } - if (door_state == DoorState::CLOSED && door_state != prev_door_state) { - this->query_openings(); + if (door_state == DoorState::CLOSED) { + defer([=]() { this->query_openings(); }); } this->door_state = door_state; - this->on_door_state_.trigger(door_state); + auto now = millis(); + if (!this->on_door_state_.is_expired(now)) { + defer([=]() { this->on_door_state_.trigger(now, door_state); }); + } else { + this->on_door_state_.clear(); + } } void RATGDOComponent::received(const LearnState learn_state) @@ -193,7 +198,7 @@ namespace ratgdo { } if (learn_state == LearnState::INACTIVE) { - this->query_paired_devices(); + defer([=](){ this->query_paired_devices(); }); } this->learn_state = learn_state; @@ -244,7 +249,7 @@ namespace ratgdo { this->motion_state = MotionState::CLEAR; }); if (*this->light_state == LightState::OFF) { - this->query_status(); + defer([=]() {this->query_status(); }); } } } @@ -326,8 +331,8 @@ namespace ratgdo { return; } auto position = this->door_start_position + (now - this->door_start_moving) / (1000 * duration); - ESP_LOG2(TAG, "[%d] Position update: %f", now, position); this->door_position = clamp(position, 0.0f, 1.0f); + ESP_LOG2(TAG, "[%d] Position update: %f", now, position); } void RATGDOComponent::set_opening_duration(float duration) @@ -431,7 +436,7 @@ namespace ratgdo { // query state in case we don't get a status message set_timeout("door_query_state", (*this->opening_duration + 1) * 1000, [=]() { if (*this->door_state != DoorState::OPEN && *this->door_state != DoorState::STOPPED) { - this->door_state = DoorState::OPEN; // probably missed a status mesage, assume it's open + this->received(DoorState::OPEN); // probably missed a status mesage, assume it's open this->query_status(); // query in case we're wrong and it's stopped } }); @@ -446,7 +451,7 @@ namespace ratgdo { if (*this->door_state == DoorState::OPENING) { // have to stop door first, otherwise close command is ignored this->door_action(DoorAction::STOP); - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + 2000, [=](DoorState s) { if (s == DoorState::STOPPED) { this->door_action(DoorAction::CLOSE); } else { @@ -461,7 +466,7 @@ namespace ratgdo { // query state in case we don't get a status message set_timeout("door_query_state", (*this->closing_duration + 1) * 1000, [=]() { if (*this->door_state != DoorState::CLOSED && *this->door_state != DoorState::STOPPED) { - this->door_state = DoorState::CLOSED; // probably missed a status mesage, assume it's closed + this->received(DoorState::CLOSED); // probably missed a status mesage, assume it's closed this->query_status(); // query in case we're wrong and it's stopped } }); @@ -490,9 +495,11 @@ namespace ratgdo { { if (*this->door_state == DoorState::OPENING || *this->door_state == DoorState::CLOSING) { this->door_action(DoorAction::STOP); - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + 2000, [=](DoorState s) { if (s == DoorState::STOPPED) { this->door_move_to_position(position); + } else { + ESP_LOGW(TAG, "Door did not stop, ignoring move to position command"); } }); return; diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index 510f636..28f34e8 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -83,7 +83,7 @@ namespace ratgdo { observable motion_state { MotionState::UNKNOWN }; observable learn_state { LearnState::UNKNOWN }; - OnceCallbacks on_door_state_; + ExpiringCallbacks on_door_state_; observable sync_failed { false }; diff --git a/components/ratgdo/secplus1.cpp b/components/ratgdo/secplus1.cpp index ba5caf3..f53a528 100644 --- a/components/ratgdo/secplus1.cpp +++ b/components/ratgdo/secplus1.cpp @@ -134,7 +134,7 @@ namespace ratgdo { return; } - const uint32_t double_toggle_delay = 1000; + const uint32_t STATE_UPDATE_DELAY = 2000; if (action == DoorAction::TOGGLE) { this->toggle_door(); } else if (action == DoorAction::OPEN) { @@ -142,11 +142,11 @@ namespace ratgdo { this->toggle_door(); } else if (this->door_state == DoorState::STOPPED) { this->toggle_door(); // this starts closing door - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + STATE_UPDATE_DELAY, [=](DoorState s) { if (s == DoorState::CLOSING) { // this changes direction of the door on some openers, on others it stops it this->toggle_door(); - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + STATE_UPDATE_DELAY, [=](DoorState s) { if (s == DoorState::STOPPED) { this->toggle_door(); } @@ -160,7 +160,7 @@ namespace ratgdo { } else if (this->door_state == DoorState::OPENING) { this->toggle_door(); // this switches to stopped // another toggle needed to close - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + STATE_UPDATE_DELAY, [=](DoorState s) { if (s == DoorState::STOPPED) { this->toggle_door(); } @@ -175,7 +175,7 @@ namespace ratgdo { this->toggle_door(); // this switches to opening // another toggle needed to stop - this->on_door_state_([=](DoorState s) { + this->on_door_state_(millis() + STATE_UPDATE_DELAY, [=](DoorState s) { if (s == DoorState::OPENING) { this->toggle_door(); } @@ -319,7 +319,7 @@ namespace ratgdo { } if (this->maybe_door_state != door_state) { - this->on_door_state_.trigger(door_state); + this->on_door_state_.trigger(millis(), door_state); } if (!this->is_0x37_panel_ && door_state != this->maybe_door_state) { diff --git a/components/ratgdo/secplus1.h b/components/ratgdo/secplus1.h index 42d83fd..d5cb424 100644 --- a/components/ratgdo/secplus1.h +++ b/components/ratgdo/secplus1.h @@ -126,7 +126,7 @@ namespace ratgdo { LockState maybe_lock_state { LockState::UNKNOWN }; DoorState maybe_door_state { DoorState::UNKNOWN }; - OnceCallbacks on_door_state_; + ExpiringCallbacks on_door_state_; bool door_moving_ { false }; diff --git a/components/ratgdo/secplus2.cpp b/components/ratgdo/secplus2.cpp index ac8541b..aed61df 100644 --- a/components/ratgdo/secplus2.cpp +++ b/components/ratgdo/secplus2.cpp @@ -267,7 +267,7 @@ namespace ratgdo { last_read = millis(); if (ser_byte != 0x55 && ser_byte != 0x01 && ser_byte != 0x00) { - ESP_LOG2(TAG, "Ignoring byte (%d): %02X, baud: %d", byte_count, ser_byte, this->sw_serial_.baudRate()); + ESP_LOG1(TAG, "Ignoring byte (%d): %02X, baud: %d", byte_count, ser_byte, this->sw_serial_.baudRate()); byte_count = 0; continue; } @@ -276,7 +276,7 @@ namespace ratgdo { // if we are at the start of a message, capture the next 16 bytes if (msg_start == 0x550100) { - ESP_LOG1(TAG, "Baud: %d", this->sw_serial_.baudRate()); + ESP_LOG2(TAG, "Baud: %d", this->sw_serial_.baudRate()); rx_packet[0] = 0x55; rx_packet[1] = 0x01; rx_packet[2] = 0x00; @@ -370,7 +370,7 @@ namespace ratgdo { void Secplus2::handle_command(const Command& cmd) { - ESP_LOG1(TAG, "Handle command: %s", CommandType_to_string(cmd.type)); + ESP_LOG2(TAG, "[%d] Handle command: %s", millis(), CommandType_to_string(cmd.type)); if (cmd.type == CommandType::STATUS) { @@ -412,7 +412,7 @@ namespace ratgdo { this->ratgdo_->received(to_BatteryState(cmd.byte1, BatteryState::UNKNOWN)); } - ESP_LOG1(TAG, "Done handle command: %s", CommandType_to_string(cmd.type)); + ESP_LOG2(TAG, "[%d] Done handle command: %s", millis(), CommandType_to_string(cmd.type)); } void Secplus2::send_command(Command command, IncrementRollingCode increment)