Fix garage door not moving in opposite direction

This commit is contained in:
2026-05-22 22:11:42 +00:00
parent 1c507d6164
commit eea9f8438d
3 changed files with 65 additions and 17 deletions
+62 -8
View File
@@ -302,18 +302,65 @@ void RATGDOComponent::cancel_door_state_expiry()
this->cancel_timeout(TIMEOUT_DOOR_STATE_EXPIRY);
}
void RATGDOComponent::smart_door_action(DoorAction target_direction)
{
// target_direction must be OPEN or CLOSE
if (target_direction != DoorAction::OPEN && target_direction != DoorAction::CLOSE) {
return;
}
DoorState expected_state = (target_direction == DoorAction::OPEN) ? DoorState::OPENING : DoorState::CLOSING;
DoorState opposite_state = (target_direction == DoorAction::OPEN) ? DoorState::CLOSING : DoorState::OPENING;
// 1. Try the discrete command first
this->door_action(target_direction);
// 2. Set a timeout to check if it worked
this->set_timeout(2000, [this, target_direction, expected_state, opposite_state]() {
if (*this->door_state == expected_state ||
(*this->door_state == DoorState::OPEN && target_direction == DoorAction::OPEN) ||
(*this->door_state == DoorState::CLOSED && target_direction == DoorAction::CLOSE)) {
// It worked (or is already at destination)
return;
}
ESP_LOGW(TAG, "Discrete %s command ignored. Falling back to TOGGLE...",
target_direction == DoorAction::OPEN ? "OPEN" : "CLOSE");
// 3. Fallback: Send a TOGGLE
this->door_action(DoorAction::TOGGLE);
// 4. Check what the toggle did
this->on_door_state([this, target_direction, expected_state, opposite_state](DoorState s) {
if (s == opposite_state) {
// Wrong direction! Stop it.
ESP_LOGW(TAG, "Toggle went the wrong way. Stopping...");
this->door_action(DoorAction::STOP);
// Once stopped, toggle again to go the right way
this->on_door_state([this](DoorState s2) {
if (s2 == DoorState::STOPPED) {
ESP_LOGD(TAG, "Stopped. Toggling again for correct direction.");
this->door_action(DoorAction::TOGGLE);
}
});
}
});
});
}
void RATGDOComponent::door_open()
{
if (*this->door_state == DoorState::OPENING) {
return; // gets ignored by opener
}
this->door_action(DoorAction::OPEN);
this->smart_door_action(DoorAction::OPEN);
if (*this->opening_duration > 0) {
// query state in case we don't get a status message
this->set_timeout(
TIMEOUT_DOOR_QUERY_STATE, (*this->opening_duration + 2) * 1000,
TIMEOUT_DOOR_QUERY_STATE, (*this->opening_duration + 5) * 1000,
[this]() {
if (*this->door_state != DoorState::OPEN && *this->door_state != DoorState::STOPPED) {
this->received(DoorState::OPEN); // probably missed a status mesage,
@@ -335,7 +382,7 @@ void RATGDOComponent::door_close()
this->door_action(DoorAction::STOP);
this->on_door_state([this](DoorState s) {
if (s == DoorState::STOPPED) {
this->door_action(DoorAction::CLOSE);
this->smart_door_action(DoorAction::CLOSE);
} else {
ESP_LOGW(TAG, "Door did not stop, ignoring close command");
}
@@ -343,12 +390,12 @@ void RATGDOComponent::door_close()
return;
}
this->door_action(DoorAction::CLOSE);
this->smart_door_action(DoorAction::CLOSE);
if (*this->closing_duration > 0) {
// query state in case we don't get a status message
this->set_timeout(
TIMEOUT_DOOR_QUERY_STATE, (*this->closing_duration + 2) * 1000,
TIMEOUT_DOOR_QUERY_STATE, (*this->closing_duration + 5) * 1000,
[this]() {
if (*this->door_state != DoorState::CLOSED && *this->door_state != DoorState::STOPPED) {
this->received(DoorState::CLOSED); // probably missed a status
@@ -362,7 +409,6 @@ void RATGDOComponent::door_close()
void RATGDOComponent::door_stop()
{
if (*this->door_state != DoorState::OPENING && *this->door_state != DoorState::CLOSING) {
ESP_LOGW(TAG, "The door is not moving.");
return;
}
this->door_action(DoorAction::STOP);
@@ -401,12 +447,20 @@ void RATGDOComponent::door_move_to_position(float position)
auto operation_time = 1000 * duration * delta;
this->door_move_delta = delta;
ESP_LOGD(TAG, "Moving to position %.2f in %.1fs", position,
ESP_LOGD(TAG, "Moving to position %.2f (target duration %.1fs)", position,
operation_time / 1000.0);
this->door_action(delta > 0 ? DoorAction::OPEN : DoorAction::CLOSE);
// Wait for the door to actually start moving before starting the stop timer.
// This makes the timing independent of any smart fallback delays.
this->on_door_state([this, operation_time](DoorState s) {
if (s == DoorState::OPENING || s == DoorState::CLOSING) {
this->set_timeout(TIMEOUT_MOVE_TO_POSITION, operation_time,
[this] { this->door_action(DoorAction::STOP); });
}
});
this->smart_door_action(delta > 0 ? DoorAction::OPEN : DoorAction::CLOSE);
}
void RATGDOComponent::cancel_position_sync_callbacks()
+1
View File
@@ -98,6 +98,7 @@ public:
void door_stop();
void door_action(DoorAction action);
void smart_door_action(DoorAction target_direction);
void door_move_to_position(float position);
void set_door_position(float door_position) { this->door_position = door_position; }
void set_opening_duration(float duration);
-7
View File
@@ -168,13 +168,6 @@ button:
then:
lambda: !lambda |-
id(garage_gate).sync();
- platform: template
id: garage_gate_toggle_door
name: "Toggle door"
on_press:
then:
lambda: !lambda |-
id(garage_gate).door_toggle();
- platform: template
id: garage_gate_play_alert
name: "Play Alert"