From f1993931a7bec96a4b84cc4f8d10d45147ff8143 Mon Sep 17 00:00:00 2001 From: Marius Muja Date: Sun, 25 Jun 2023 16:03:39 -0700 Subject: [PATCH] Door position control (#20) Co-authored-by: J. Nick Koston --- base.yaml | 16 ++ components/ratgdo/cover/ratgdo_cover.cpp | 10 +- components/ratgdo/cover/ratgdo_cover.h | 2 +- components/ratgdo/number/__init__.py | 2 + components/ratgdo/number/ratgdo_number.cpp | 45 +++- components/ratgdo/number/ratgdo_number.h | 9 +- components/ratgdo/ratgdo.cpp | 253 +++++++++++++++++++-- components/ratgdo/ratgdo.h | 25 +- components/ratgdo/ratgdo_child.cpp | 4 +- components/ratgdo/ratgdo_child.h | 4 +- 10 files changed, 335 insertions(+), 35 deletions(-) diff --git a/base.yaml b/base.yaml index 93ec369..e1354ad 100644 --- a/base.yaml +++ b/base.yaml @@ -136,6 +136,22 @@ number: name: "Rolling code counter" mode: box unit_of_measurement: "codes" + + - platform: ratgdo + id: ${id_prefix}_opening_duration + type: opening_duration + entity_category: config + ratgdo_id: ${id_prefix} + name: "Opening duration" + unit_of_measurement: "s" + + - platform: ratgdo + id: ${id_prefix}_closing_duration + type: closing_duration + entity_category: config + ratgdo_id: ${id_prefix} + name: "Closing duration" + unit_of_measurement: "s" cover: - platform: ratgdo diff --git a/components/ratgdo/cover/ratgdo_cover.cpp b/components/ratgdo/cover/ratgdo_cover.cpp index 19ebed7..9245da8 100644 --- a/components/ratgdo/cover/ratgdo_cover.cpp +++ b/components/ratgdo/cover/ratgdo_cover.cpp @@ -13,7 +13,7 @@ namespace ratgdo { { LOG_COVER("", "RATGDO Cover", this); } - void RATGDOCover::on_door_state(DoorState state) + void RATGDOCover::on_door_state(DoorState state, float position) { switch (state) { case DoorState::DOOR_STATE_OPEN: @@ -26,15 +26,15 @@ namespace ratgdo { break; case DoorState::DOOR_STATE_OPENING: this->current_operation = COVER_OPERATION_OPENING; - this->position = 0.5; + this->position = position; break; case DoorState::DOOR_STATE_CLOSING: this->current_operation = COVER_OPERATION_CLOSING; - this->position = 0.5; + this->position = position; break; case DoorState::DOOR_STATE_STOPPED: this->current_operation = COVER_OPERATION_IDLE; - this->position = 0.5; + this->position = position; default: this->current_operation = COVER_OPERATION_IDLE; @@ -66,6 +66,8 @@ namespace ratgdo { this->parent_->openDoor(); } else if (pos == COVER_CLOSED) { this->parent_->closeDoor(); + } else { + this->parent_->setDoorPosition(pos); } } } diff --git a/components/ratgdo/cover/ratgdo_cover.h b/components/ratgdo/cover/ratgdo_cover.h index 7542fd0..ded08d2 100644 --- a/components/ratgdo/cover/ratgdo_cover.h +++ b/components/ratgdo/cover/ratgdo_cover.h @@ -13,7 +13,7 @@ namespace ratgdo { public: void dump_config() override; cover::CoverTraits get_traits() override; - void on_door_state(DoorState state) override; + void on_door_state(DoorState state, float position) override; protected: void control(const cover::CoverCall& call) override; diff --git a/components/ratgdo/number/__init__.py b/components/ratgdo/number/__init__.py index 6e9268b..bf56e8f 100644 --- a/components/ratgdo/number/__init__.py +++ b/components/ratgdo/number/__init__.py @@ -13,6 +13,8 @@ NumberType = ratgdo_ns.enum("NumberType") CONF_TYPE = "type" TYPES = { "rolling_code_counter": NumberType.RATGDO_ROLLING_CODE_COUNTER, + "opening_duration": NumberType.RATGDO_OPENING_DURATION, + "closing_duration": NumberType.RATGDO_CLOSING_DURATION, } diff --git a/components/ratgdo/number/ratgdo_number.cpp b/components/ratgdo/number/ratgdo_number.cpp index b8a279a..d8d4c48 100644 --- a/components/ratgdo/number/ratgdo_number.cpp +++ b/components/ratgdo/number/ratgdo_number.cpp @@ -10,17 +10,56 @@ namespace ratgdo { void RATGDONumber::dump_config() { LOG_NUMBER("", "RATGDO Number", this); - ESP_LOGCONFIG(TAG, " Type: Rolling Code Counter"); + if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) { + ESP_LOGCONFIG(TAG, " Type: Rolling Code Counter"); + } else if (this->number_type_ == RATGDO_OPENING_DURATION) { + ESP_LOGCONFIG(TAG, " Type: Opening Duration"); + } else if (this->number_type_ == RATGDO_CLOSING_DURATION) { + ESP_LOGCONFIG(TAG, " Type: Closing Duration"); + } + } + + void RATGDONumber::set_number_type(NumberType number_type_) + { + this->number_type_ = number_type_; + if (this->number_type_ == RATGDO_OPENING_DURATION || this->number_type_ == RATGDO_CLOSING_DURATION) { + this->traits.set_step(0.1); + } } void RATGDONumber::on_rolling_code_change(uint32_t rollingCodeCounter) { + if (this->number_type_ != RATGDO_ROLLING_CODE_COUNTER) { + return; + } this->publish_state(rollingCodeCounter); } + + void RATGDONumber::on_opening_duration_change(float duration) + { + if (this->number_type_ != RATGDO_OPENING_DURATION) { + return; + } + this->publish_state(duration); + } + + void RATGDONumber::on_closing_duration_change(float duration) + { + if (this->number_type_ != RATGDO_CLOSING_DURATION) { + return; + } + this->publish_state(duration); + } + void RATGDONumber::control(float value) { - this->parent_->setRollingCodeCounter(value); - this->publish_state(value); + if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) { + this->parent_->setRollingCodeCounter(value); + } else if (this->number_type_ == RATGDO_OPENING_DURATION) { + this->parent_->setOpeningDuration(value); + } else if (this->number_type_ == RATGDO_CLOSING_DURATION) { + this->parent_->setClosingDuration(value); + } } } // namespace ratgdo diff --git a/components/ratgdo/number/ratgdo_number.h b/components/ratgdo/number/ratgdo_number.h index 1a7fc96..419800c 100644 --- a/components/ratgdo/number/ratgdo_number.h +++ b/components/ratgdo/number/ratgdo_number.h @@ -10,15 +10,20 @@ namespace esphome { namespace ratgdo { enum NumberType { - RATGDO_ROLLING_CODE_COUNTER + RATGDO_ROLLING_CODE_COUNTER, + RATGDO_OPENING_DURATION, + RATGDO_CLOSING_DURATION, }; class RATGDONumber : public number::Number, public RATGDOClient, public Component { public: void dump_config() override; - void set_number_type(NumberType number_type_) { this->number_type_ = number_type_; } + void set_number_type(NumberType number_type_); void on_rolling_code_change(uint32_t rollingCodeCounter) override; + void on_opening_duration_change(float duration) override; + void on_closing_duration_change(float duration) override; + void control(float value) override; protected: diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index cd2da80..53c2b41 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -46,10 +46,23 @@ namespace ratgdo { void RATGDOComponent::setup() { - this->pref_ = global_preferences->make_preference(734874333U); - if (!this->pref_.load(&this->rollingCodeCounter)) { + this->rollingCodePref_ = global_preferences->make_preference(734874333U); + if (!this->rollingCodePref_.load(&this->rollingCodeCounter)) { this->rollingCodeCounter = 0; } + this->openingDurationPref_ = global_preferences->make_preference(734874334U); + if (!this->openingDurationPref_.load(&this->openingDuration)) { + this->setOpeningDuration(0); + } else { + this->sendOpeningDuration(); + } + + this->closingDurationPref_ = global_preferences->make_preference(734874335U); + if (!this->closingDurationPref_.load(&this->closingDuration)) { + this->setClosingDuration(0.f); + } else { + this->sendClosingDuration(); + } this->output_gdo_pin_->setup(); this->input_gdo_pin_->setup(); @@ -157,31 +170,81 @@ namespace ratgdo { data &= ~0xf000; // clear parity nibble if ((fixed & 0xfff) == this->remote_id) { // my commands - ESP_LOGV(TAG, "[%ld] received mine: rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data); + ESP_LOGD(TAG, "[%ld] received mine: rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data); return 0; } else { - ESP_LOGV(TAG, "[%ld] received rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data); + ESP_LOGD(TAG, "[%ld] received rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data); } nibble = (data >> 8) & 0xff; byte1 = (data >> 16) & 0xff; byte2 = (data >> 24) & 0xff; - ESP_LOGV(TAG, "cmd=%03x (%s) byte2=%02x byte1=%02x nibble=%01x", cmd, cmd_name(cmd), byte2, byte1, nibble); + ESP_LOGD(TAG, "cmd=%03x (%s) byte2=%02x byte1=%02x nibble=%01x", cmd, cmd_name(cmd), byte2, byte1, nibble); if (cmd == command::STATUS) { - auto doorState = static_cast(nibble); - if (doorState == DoorState::DOOR_STATE_CLOSED && this->doorState != doorState) { - transmit(command::GET_OPENINGS); + + this->doorState = static_cast(nibble); + + if (this->doorState == DoorState::DOOR_STATE_OPENING && this->previousDoorState==DoorState::DOOR_STATE_CLOSED) { + this->startOpening = millis(); + } + if (this->doorState == DoorState::DOOR_STATE_OPEN && this->previousDoorState==DoorState::DOOR_STATE_OPENING) { + if (this->startOpening > 0) { + auto duration = (millis() - this->startOpening)/1000; + duration = this->openingDuration > 0 ? (duration + this->openingDuration)/2 : duration; + this->setOpeningDuration(round(duration*10)/10); + } + } + if (this->doorState == DoorState::DOOR_STATE_CLOSING && this->previousDoorState==DoorState::DOOR_STATE_OPEN) { + this->startClosing = millis(); + } + if (this->doorState == DoorState::DOOR_STATE_CLOSED && this->previousDoorState==DoorState::DOOR_STATE_CLOSING) { + if (this->startClosing > 0) { + auto duration = (millis() - this->startClosing)/1000; + duration = this->closingDuration > 0 ? (duration + this->closingDuration)/2 : duration; + this->setClosingDuration(round(duration*10)/10); + } + } + if (this->doorState == DoorState::DOOR_STATE_STOPPED) { + this->startOpening = -1; + this->startClosing = -1; + } + + if (this->doorState == DoorState::DOOR_STATE_OPEN) { + this->doorPosition = 1.0; + } else if (this->doorState == DoorState::DOOR_STATE_CLOSED) { + this->doorPosition = 0.0; + } else { + if (this->closingDuration == 0 || this->openingDuration == 0 || this->doorPosition == DOOR_POSITION_UNKNOWN) { + this->doorPosition = 0.5; // best guess + } + } + + if (this->doorState == DoorState::DOOR_STATE_OPENING && !this->movingToPosition) { + this->positionSyncWhileOpening(1.0 - this->doorPosition); + this->movingToPosition = true; + } + if (this->doorState == DoorState::DOOR_STATE_CLOSING && !this->movingToPosition) { + this->positionSyncWhileClosing(this->doorPosition); + this->movingToPosition = true; + } + + if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_STOPPED) { + this->cancelPositionSyncCallbacks(); } - this->doorState = doorState; this->lightState = static_cast((byte2 >> 1) & 1); this->lockState = static_cast(byte2 & 1); this->motionState = MotionState::MOTION_STATE_CLEAR; // when the status message is read, reset motion state to 0|clear this->motorState = MotorState::MOTOR_STATE_OFF; // when the status message is read, reset motor state to 0|off // this->obstructionState = static_cast((byte1 >> 6) & 1); - ESP_LOGV(TAG, "Status: door=%s light=%s lock=%s", + + if (this->doorState == DoorState::DOOR_STATE_CLOSED && this->doorState != this->previousDoorState) { + transmit(command::GET_OPENINGS); + } + + ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", door_state_to_string(this->doorState), light_state_to_string(this->lightState), lock_state_to_string(this->lockState)); @@ -193,27 +256,27 @@ namespace ratgdo { } else if (nibble == 2) { // toggle this->lightState = light_state_toggle(this->lightState); } - ESP_LOGV(TAG, "Light: action=%s state=%s", + ESP_LOGD(TAG, "Light: action=%s state=%s", nibble == 0 ? "OFF" : nibble == 1 ? "ON" : "TOGGLE", light_state_to_string(this->lightState)); } else if (cmd == command::MOTOR_ON) { this->motorState = MotorState::MOTOR_STATE_ON; - ESP_LOGV(TAG, "Motor: state=%s", motor_state_to_string(this->motorState)); + ESP_LOGD(TAG, "Motor: state=%s", motor_state_to_string(this->motorState)); } else if (cmd == command::OPEN) { this->buttonState = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; - ESP_LOGV(TAG, "Open: button=%s", button_state_to_string(this->buttonState)); + ESP_LOGD(TAG, "Open: button=%s", button_state_to_string(this->buttonState)); } else if (cmd == command::OPENINGS) { this->openings = (byte1 << 8) | byte2; - ESP_LOGV(TAG, "Openings: %d", this->openings); + ESP_LOGD(TAG, "Openings: %d", this->openings); } else if (cmd == command::MOTION) { this->motionState = MotionState::MOTION_STATE_DETECTED; if (this->lightState == LightState::LIGHT_STATE_OFF) { transmit(command::GET_STATUS); } - ESP_LOGV(TAG, "Motion: %s", motion_state_to_string(this->motionState)); + ESP_LOGD(TAG, "Motion: %s", motion_state_to_string(this->motionState)); } else { - ESP_LOGV(TAG, "Unhandled command: cmd=%03x nibble=%02x byte1=%02x byte2=%02x fixed=%010" PRIx64 " data=%08" PRIx32, cmd, nibble, byte1, byte2, fixed, data); + ESP_LOGD(TAG, "Unhandled command: cmd=%03x nibble=%02x byte1=%02x byte2=%02x fixed=%010" PRIx64 " data=%08" PRIx32, cmd, nibble, byte1, byte2, fixed, data); } return cmd; } @@ -223,7 +286,7 @@ namespace ratgdo { uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id; uint32_t send_data = (data << 8) | (command & 0xff); - ESP_LOGV(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), this->rollingCodeCounter, fixed, send_data); + ESP_LOGD(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), this->rollingCodeCounter, fixed, send_data); encode_wireline(this->rollingCodeCounter, fixed, send_data, this->txRollingCode); printRollingCode(); @@ -232,11 +295,51 @@ namespace ratgdo { } } + void RATGDOComponent::setOpeningDuration(float duration) + { + ESP_LOGD(TAG, "Set opening duration: %.1fs", duration); + this->openingDuration = duration; + this->openingDurationPref_.save(&this->openingDuration); + + sendOpeningDuration(); + + if (this->closingDuration == 0 && duration != 0) { + this->setClosingDuration(duration); + } + } + + void RATGDOComponent::sendOpeningDuration() + { + for (auto* child : this->children_) { + child->on_opening_duration_change(this->openingDuration); + } + } + + void RATGDOComponent::setClosingDuration(float duration) + { + ESP_LOGD(TAG, "Set closing duration: %.1fs", duration); + this->closingDuration = duration; + this->closingDurationPref_.save(&this->closingDuration); + + sendClosingDuration(); + + if (this->openingDuration == 0 && duration != 0) { + this->setOpeningDuration(duration); + } + } + + void RATGDOComponent::sendClosingDuration() + { + for (auto* child : this->children_) { + child->on_closing_duration_change(this->closingDuration); + } + } + void RATGDOComponent::setRollingCodeCounter(uint32_t counter) { ESP_LOGV(TAG, "Set rolling code counter to %d", counter); this->rollingCodeCounter = counter; - this->pref_.save(&this->rollingCodeCounter); + this->rollingCodePref_.save(&this->rollingCodeCounter); sendRollingCodeChanged(); } @@ -370,10 +473,17 @@ namespace ratgdo { if (this->doorState != this->previousDoorState) { ESP_LOGV(TAG, "Door state: %s", door_state_to_string(this->doorState)); for (auto* child : this->children_) { - child->on_door_state(this->doorState); + child->on_door_state(this->doorState, this->doorPosition); } this->previousDoorState = this->doorState; } + if (this->doorPosition != this->previousDoorPosition) { + ESP_LOGV(TAG, "Door position: %f", this->doorPosition); + for (auto* child : this->children_) { + child->on_door_state(this->doorState, this->doorPosition); + } + this->previousDoorPosition = this->doorPosition; + } if (this->lightState != this->previousLightState) { ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(this->lightState), this->lightState); for (auto* child : this->children_) { @@ -485,18 +595,28 @@ namespace ratgdo { void RATGDOComponent::openDoor() { + if (this->doorState == DoorState::DOOR_STATE_OPENING) { + return; // gets ignored by opener + } + this->cancelPositionSyncCallbacks(); + doorCommand(data::DOOR_OPEN); } void RATGDOComponent::closeDoor() { - doorCommand(data::DOOR_CLOSE); + if (this->doorState == DoorState::DOOR_STATE_CLOSING || this->doorState == DoorState::DOOR_STATE_OPENING) { + return; // gets ignored by opener + } + this->cancelPositionSyncCallbacks(); + + doorCommand(data::DOOR_CLOSE); } void RATGDOComponent::stopDoor() { if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) { - ESP_LOGV(TAG, "The door is not moving."); + ESP_LOGW(TAG, "The door is not moving."); return; } doorCommand(data::DOOR_STOP); @@ -504,9 +624,98 @@ namespace ratgdo { void RATGDOComponent::toggleDoor() { + if (this->doorState == DoorState::DOOR_STATE_OPENING) { + return; // gets ignored by opener + } + this->cancelPositionSyncCallbacks(); + doorCommand(data::DOOR_TOGGLE); } + + void RATGDOComponent::positionSyncWhileOpening(float delta, float update_period) { + if (this->openingDuration==0) { + ESP_LOGW(TAG, "I don't know opening duration, ignoring position sync"); + return; + } + auto updates = this->openingDuration * 1000 * delta/update_period; + auto d = delta/updates; + auto count = int(updates); + ESP_LOGD(TAG, "[Opening] Position sync %d times: ", count); + // try to keep position in sync while door is moving + set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) { + ESP_LOGD(TAG, "[Opening] Position sync: %d: ", r); + this->doorPosition += d; + return RetryResult::RETRY; + }); + } + + void RATGDOComponent::positionSyncWhileClosing(float delta, float update_period) { + if (this->closingDuration==0) { + ESP_LOGW(TAG, "I don't know closing duration, ignoring position sync"); + return; + } + auto updates = this->closingDuration * 1000 * delta/update_period; + auto d = delta/updates; + auto count = int(updates); + ESP_LOGD(TAG, "[Closing] Position sync %d times: ", count); + // try to keep position in sync while door is moving + set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) { + ESP_LOGD(TAG, "[Closing] Position sync: %d: ", r); + this->doorPosition -= d; + return RetryResult::RETRY; + }); + } + + void RATGDOComponent::setDoorPosition(float position) + { + if (this->doorState == DoorState::DOOR_STATE_OPENING || this->doorState == DoorState::DOOR_STATE_CLOSING) { + ESP_LOGW(TAG, "The door is moving, ignoring."); + return; + } + + auto delta = position - this->doorPosition; + if (delta > 0) { // open + if (this->openingDuration==0) { + ESP_LOGW(TAG, "I don't know opening duration, ignoring move to position"); + return; + } + auto opening_time = this->openingDuration * 1000 * delta; + doorCommand(data::DOOR_OPEN); + this->movingToPosition = true; + set_timeout("move_to_position", opening_time, [=] { + doorCommand(data::DOOR_STOP); + this->movingToPosition = false; + this->doorPosition = position; + }); + this->positionSyncWhileOpening(delta); + } else if (delta < 0) { // close + if (this->closingDuration==0) { + ESP_LOGW(TAG, "I don't know closing duration, ignoring move to position"); + return; + } + delta = -delta; + auto closing_time = this->closingDuration * 1000 * delta; + doorCommand(data::DOOR_CLOSE); + this->movingToPosition = true; + set_timeout("move_to_position", closing_time, [=] { + doorCommand(data::DOOR_STOP); + this->movingToPosition = false; + this->doorPosition = position; + }); + this->positionSyncWhileClosing(delta); + } + } + + void RATGDOComponent::cancelPositionSyncCallbacks() { + if (this->movingToPosition) { + ESP_LOGD(TAG, "Cancelling position callbacks"); + cancel_timeout("move_to_position"); + cancel_retry("position_sync_while_moving"); + } + movingToPosition = false; + } + void RATGDOComponent::doorCommand(uint32_t data) { data |= (1 << 16); // button 1 ? @@ -556,7 +765,7 @@ namespace ratgdo { void RATGDOComponent::saveCounter() { - this->pref_.save(&this->rollingCodeCounter); + this->rollingCodePref_.save(&this->rollingCodeCounter); // Forcing a sync results in a soft reset if there are too many // writes to flash in a short period of time. To avoid this, // we have configured preferences to write every 5s diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index 807a6e0..b036a78 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -33,6 +33,8 @@ namespace ratgdo { static const uint8_t CODE_LENGTH = 19; + const float DOOR_POSITION_UNKNOWN = -1.0; + /* from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540 _WIRELINE_COMMANDS = { @@ -129,6 +131,11 @@ namespace ratgdo { uint32_t rollingCodeCounter { 0 }; uint32_t lastSyncedRollingCodeCounter { 0 }; + float startOpening { -1 }; + float openingDuration { 0 }; + float startClosing { -1 }; + float closingDuration { 0 }; + uint8_t txRollingCode[CODE_LENGTH]; uint8_t rxRollingCode[CODE_LENGTH]; @@ -138,6 +145,10 @@ namespace ratgdo { DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; DoorState doorState { DoorState::DOOR_STATE_UNKNOWN }; + float doorPosition { DOOR_POSITION_UNKNOWN }; + float previousDoorPosition { DOOR_POSITION_UNKNOWN }; + bool movingToPosition { false }; + LightState previousLightState { LightState::LIGHT_STATE_UNKNOWN }; LightState lightState { LightState::LIGHT_STATE_UNKNOWN }; @@ -179,6 +190,10 @@ namespace ratgdo { void openDoor(); void closeDoor(); void stopDoor(); + void setDoorPosition(float position); + void positionSyncWhileOpening(float delta, float update_period = 500); + void positionSyncWhileClosing(float delta, float update_period = 500); + void cancelPositionSyncCallbacks(); void toggleLight(); void lightOn(); @@ -197,12 +212,20 @@ namespace ratgdo { void incrementRollingCodeCounter(); void sendRollingCodeChanged(); void setRollingCodeCounter(uint32_t counter); + + void setOpeningDuration(float duration); + void sendOpeningDuration(); + void setClosingDuration(float duration); + void sendClosingDuration(); + LightState getLightState(); /** Register a child component. */ void register_child(RATGDOClient* obj); protected: - ESPPreferenceObject pref_; + ESPPreferenceObject rollingCodePref_; + ESPPreferenceObject openingDurationPref_; + ESPPreferenceObject closingDurationPref_; std::vector children_; bool rollingCodeUpdatesEnabled_ { true }; bool forceUpdate_ { false }; diff --git a/components/ratgdo/ratgdo_child.cpp b/components/ratgdo/ratgdo_child.cpp index ef179d1..3cbc91b 100644 --- a/components/ratgdo/ratgdo_child.cpp +++ b/components/ratgdo/ratgdo_child.cpp @@ -6,13 +6,15 @@ namespace esphome { namespace ratgdo { - void RATGDOClient::on_door_state(DoorState state) {}; + void RATGDOClient::on_door_state(DoorState state, float position) {}; void RATGDOClient::on_light_state(LightState state) {}; void RATGDOClient::on_lock_state(LockState state) {}; void RATGDOClient::on_motion_state(MotionState state) {}; void RATGDOClient::on_obstruction_state(ObstructionState state) {}; void RATGDOClient::on_motor_state(MotorState state) {}; void RATGDOClient::on_rolling_code_change(uint32_t rollingCodeCounter) {}; + void RATGDOClient::on_opening_duration_change(float duration) {}; + void RATGDOClient::on_closing_duration_change(float duration) {}; void RATGDOClient::on_openings_change(uint32_t openings) {}; void RATGDOClient::on_button_state(ButtonState state) {}; diff --git a/components/ratgdo/ratgdo_child.h b/components/ratgdo/ratgdo_child.h index 81baa0f..61e0e71 100644 --- a/components/ratgdo/ratgdo_child.h +++ b/components/ratgdo/ratgdo_child.h @@ -13,13 +13,15 @@ namespace ratgdo { class RATGDOClient : public Parented { public: - virtual void on_door_state(DoorState state); + virtual void on_door_state(DoorState state, float position); virtual void on_light_state(LightState state); virtual void on_lock_state(LockState state); virtual void on_motion_state(MotionState state); virtual void on_obstruction_state(ObstructionState state); virtual void on_motor_state(MotorState state); virtual void on_rolling_code_change(uint32_t rollingCodeCounter); + virtual void on_opening_duration_change(float duration); + virtual void on_closing_duration_change(float duration); virtual void on_openings_change(uint32_t openings); virtual void on_button_state(ButtonState state);