Added expiring callbacks that will only be called within a certain time. Defer sending operations in status handling methods.

This commit is contained in:
Marius Muja 2024-01-20 15:51:02 -08:00
parent 727759eacb
commit bc7a59b75b
6 changed files with 75 additions and 23 deletions

View File

@ -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<std::function<void(Ts...)>> callbacks_;
};
template <typename... X>
class ExpiringCallbacks;
template <typename... Ts>
class ExpiringCallbacks<void(Ts...)> {
public:
template <typename Callback>
void operator()(uint32_t expiration, Callback&& callback)
{
this->callbacks_.push_back(std::make_pair(expiration, std::forward<Callback>(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<std::pair<uint32_t, std::function<void(Ts...)>>> callbacks_;
};
} // namespace ratgdo
} // namespace esphome

View File

@ -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;

View File

@ -83,7 +83,7 @@ namespace ratgdo {
observable<MotionState> motion_state { MotionState::UNKNOWN };
observable<LearnState> learn_state { LearnState::UNKNOWN };
OnceCallbacks<void(DoorState)> on_door_state_;
ExpiringCallbacks<void(DoorState)> on_door_state_;
observable<bool> sync_failed { false };

View File

@ -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) {

View File

@ -126,7 +126,7 @@ namespace ratgdo {
LockState maybe_lock_state { LockState::UNKNOWN };
DoorState maybe_door_state { DoorState::UNKNOWN };
OnceCallbacks<void(DoorState)> on_door_state_;
ExpiringCallbacks<void(DoorState)> on_door_state_;
bool door_moving_ { false };

View File

@ -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)