Door position control (#20)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Marius Muja 2023-06-25 16:03:39 -07:00 committed by GitHub
parent 073b5440cb
commit f1993931a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 335 additions and 35 deletions

View File

@ -137,6 +137,22 @@ number:
mode: box mode: box
unit_of_measurement: "codes" 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: cover:
- platform: ratgdo - platform: ratgdo
id: ${id_prefix}_garage_door id: ${id_prefix}_garage_door

View File

@ -13,7 +13,7 @@ namespace ratgdo {
{ {
LOG_COVER("", "RATGDO Cover", this); LOG_COVER("", "RATGDO Cover", this);
} }
void RATGDOCover::on_door_state(DoorState state) void RATGDOCover::on_door_state(DoorState state, float position)
{ {
switch (state) { switch (state) {
case DoorState::DOOR_STATE_OPEN: case DoorState::DOOR_STATE_OPEN:
@ -26,15 +26,15 @@ namespace ratgdo {
break; break;
case DoorState::DOOR_STATE_OPENING: case DoorState::DOOR_STATE_OPENING:
this->current_operation = COVER_OPERATION_OPENING; this->current_operation = COVER_OPERATION_OPENING;
this->position = 0.5; this->position = position;
break; break;
case DoorState::DOOR_STATE_CLOSING: case DoorState::DOOR_STATE_CLOSING:
this->current_operation = COVER_OPERATION_CLOSING; this->current_operation = COVER_OPERATION_CLOSING;
this->position = 0.5; this->position = position;
break; break;
case DoorState::DOOR_STATE_STOPPED: case DoorState::DOOR_STATE_STOPPED:
this->current_operation = COVER_OPERATION_IDLE; this->current_operation = COVER_OPERATION_IDLE;
this->position = 0.5; this->position = position;
default: default:
this->current_operation = COVER_OPERATION_IDLE; this->current_operation = COVER_OPERATION_IDLE;
@ -66,6 +66,8 @@ namespace ratgdo {
this->parent_->openDoor(); this->parent_->openDoor();
} else if (pos == COVER_CLOSED) { } else if (pos == COVER_CLOSED) {
this->parent_->closeDoor(); this->parent_->closeDoor();
} else {
this->parent_->setDoorPosition(pos);
} }
} }
} }

View File

@ -13,7 +13,7 @@ namespace ratgdo {
public: public:
void dump_config() override; void dump_config() override;
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;
void on_door_state(DoorState state) override; void on_door_state(DoorState state, float position) override;
protected: protected:
void control(const cover::CoverCall& call) override; void control(const cover::CoverCall& call) override;

View File

@ -13,6 +13,8 @@ NumberType = ratgdo_ns.enum("NumberType")
CONF_TYPE = "type" CONF_TYPE = "type"
TYPES = { TYPES = {
"rolling_code_counter": NumberType.RATGDO_ROLLING_CODE_COUNTER, "rolling_code_counter": NumberType.RATGDO_ROLLING_CODE_COUNTER,
"opening_duration": NumberType.RATGDO_OPENING_DURATION,
"closing_duration": NumberType.RATGDO_CLOSING_DURATION,
} }

View File

@ -10,17 +10,56 @@ namespace ratgdo {
void RATGDONumber::dump_config() void RATGDONumber::dump_config()
{ {
LOG_NUMBER("", "RATGDO Number", this); LOG_NUMBER("", "RATGDO Number", this);
if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
ESP_LOGCONFIG(TAG, " Type: 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) void RATGDONumber::on_rolling_code_change(uint32_t rollingCodeCounter)
{ {
if (this->number_type_ != RATGDO_ROLLING_CODE_COUNTER) {
return;
}
this->publish_state(rollingCodeCounter); 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) void RATGDONumber::control(float value)
{ {
if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
this->parent_->setRollingCodeCounter(value); this->parent_->setRollingCodeCounter(value);
this->publish_state(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 } // namespace ratgdo

View File

@ -10,15 +10,20 @@ namespace esphome {
namespace ratgdo { namespace ratgdo {
enum NumberType { 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 { class RATGDONumber : public number::Number, public RATGDOClient, public Component {
public: public:
void dump_config() override; 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_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; void control(float value) override;
protected: protected:

View File

@ -46,10 +46,23 @@ namespace ratgdo {
void RATGDOComponent::setup() void RATGDOComponent::setup()
{ {
this->pref_ = global_preferences->make_preference<int>(734874333U); this->rollingCodePref_ = global_preferences->make_preference<int>(734874333U);
if (!this->pref_.load(&this->rollingCodeCounter)) { if (!this->rollingCodePref_.load(&this->rollingCodeCounter)) {
this->rollingCodeCounter = 0; this->rollingCodeCounter = 0;
} }
this->openingDurationPref_ = global_preferences->make_preference<float>(734874334U);
if (!this->openingDurationPref_.load(&this->openingDuration)) {
this->setOpeningDuration(0);
} else {
this->sendOpeningDuration();
}
this->closingDurationPref_ = global_preferences->make_preference<float>(734874335U);
if (!this->closingDurationPref_.load(&this->closingDuration)) {
this->setClosingDuration(0.f);
} else {
this->sendClosingDuration();
}
this->output_gdo_pin_->setup(); this->output_gdo_pin_->setup();
this->input_gdo_pin_->setup(); this->input_gdo_pin_->setup();
@ -157,31 +170,81 @@ namespace ratgdo {
data &= ~0xf000; // clear parity nibble data &= ~0xf000; // clear parity nibble
if ((fixed & 0xfff) == this->remote_id) { // my commands 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; return 0;
} else { } 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; nibble = (data >> 8) & 0xff;
byte1 = (data >> 16) & 0xff; byte1 = (data >> 16) & 0xff;
byte2 = (data >> 24) & 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) { if (cmd == command::STATUS) {
auto doorState = static_cast<DoorState>(nibble);
if (doorState == DoorState::DOOR_STATE_CLOSED && this->doorState != doorState) { this->doorState = static_cast<DoorState>(nibble);
transmit(command::GET_OPENINGS);
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<LightState>((byte2 >> 1) & 1); this->lightState = static_cast<LightState>((byte2 >> 1) & 1);
this->lockState = static_cast<LockState>(byte2 & 1); this->lockState = static_cast<LockState>(byte2 & 1);
this->motionState = MotionState::MOTION_STATE_CLEAR; // when the status message is read, reset motion state to 0|clear 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->motorState = MotorState::MOTOR_STATE_OFF; // when the status message is read, reset motor state to 0|off
// this->obstructionState = static_cast<ObstructionState>((byte1 >> 6) & 1); // this->obstructionState = static_cast<ObstructionState>((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), door_state_to_string(this->doorState),
light_state_to_string(this->lightState), light_state_to_string(this->lightState),
lock_state_to_string(this->lockState)); lock_state_to_string(this->lockState));
@ -193,27 +256,27 @@ namespace ratgdo {
} else if (nibble == 2) { // toggle } else if (nibble == 2) { // toggle
this->lightState = light_state_toggle(this->lightState); 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" nibble == 0 ? "OFF" : nibble == 1 ? "ON"
: "TOGGLE", : "TOGGLE",
light_state_to_string(this->lightState)); light_state_to_string(this->lightState));
} else if (cmd == command::MOTOR_ON) { } else if (cmd == command::MOTOR_ON) {
this->motorState = MotorState::MOTOR_STATE_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) { } else if (cmd == command::OPEN) {
this->buttonState = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; 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) { } else if (cmd == command::OPENINGS) {
this->openings = (byte1 << 8) | byte2; this->openings = (byte1 << 8) | byte2;
ESP_LOGV(TAG, "Openings: %d", this->openings); ESP_LOGD(TAG, "Openings: %d", this->openings);
} else if (cmd == command::MOTION) { } else if (cmd == command::MOTION) {
this->motionState = MotionState::MOTION_STATE_DETECTED; this->motionState = MotionState::MOTION_STATE_DETECTED;
if (this->lightState == LightState::LIGHT_STATE_OFF) { if (this->lightState == LightState::LIGHT_STATE_OFF) {
transmit(command::GET_STATUS); 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 { } 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; return cmd;
} }
@ -223,7 +286,7 @@ namespace ratgdo {
uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id; uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id;
uint32_t send_data = (data << 8) | (command & 0xff); 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); encode_wireline(this->rollingCodeCounter, fixed, send_data, this->txRollingCode);
printRollingCode(); 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) void RATGDOComponent::setRollingCodeCounter(uint32_t counter)
{ {
ESP_LOGV(TAG, "Set rolling code counter to %d", counter); ESP_LOGV(TAG, "Set rolling code counter to %d", counter);
this->rollingCodeCounter = counter; this->rollingCodeCounter = counter;
this->pref_.save(&this->rollingCodeCounter); this->rollingCodePref_.save(&this->rollingCodeCounter);
sendRollingCodeChanged(); sendRollingCodeChanged();
} }
@ -370,10 +473,17 @@ namespace ratgdo {
if (this->doorState != this->previousDoorState) { if (this->doorState != this->previousDoorState) {
ESP_LOGV(TAG, "Door state: %s", door_state_to_string(this->doorState)); ESP_LOGV(TAG, "Door state: %s", door_state_to_string(this->doorState));
for (auto* child : this->children_) { for (auto* child : this->children_) {
child->on_door_state(this->doorState); child->on_door_state(this->doorState, this->doorPosition);
} }
this->previousDoorState = this->doorState; 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) { if (this->lightState != this->previousLightState) {
ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(this->lightState), this->lightState); ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(this->lightState), this->lightState);
for (auto* child : this->children_) { for (auto* child : this->children_) {
@ -485,18 +595,28 @@ namespace ratgdo {
void RATGDOComponent::openDoor() void RATGDOComponent::openDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener
}
this->cancelPositionSyncCallbacks();
doorCommand(data::DOOR_OPEN); doorCommand(data::DOOR_OPEN);
} }
void RATGDOComponent::closeDoor() void RATGDOComponent::closeDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_CLOSING || this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener
}
this->cancelPositionSyncCallbacks();
doorCommand(data::DOOR_CLOSE); doorCommand(data::DOOR_CLOSE);
} }
void RATGDOComponent::stopDoor() void RATGDOComponent::stopDoor()
{ {
if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) { 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; return;
} }
doorCommand(data::DOOR_STOP); doorCommand(data::DOOR_STOP);
@ -504,9 +624,98 @@ namespace ratgdo {
void RATGDOComponent::toggleDoor() void RATGDOComponent::toggleDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener
}
this->cancelPositionSyncCallbacks();
doorCommand(data::DOOR_TOGGLE); 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) void RATGDOComponent::doorCommand(uint32_t data)
{ {
data |= (1 << 16); // button 1 ? data |= (1 << 16); // button 1 ?
@ -556,7 +765,7 @@ namespace ratgdo {
void RATGDOComponent::saveCounter() 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 // 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, // writes to flash in a short period of time. To avoid this,
// we have configured preferences to write every 5s // we have configured preferences to write every 5s

View File

@ -33,6 +33,8 @@ namespace ratgdo {
static const uint8_t CODE_LENGTH = 19; 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 from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540
_WIRELINE_COMMANDS = { _WIRELINE_COMMANDS = {
@ -129,6 +131,11 @@ namespace ratgdo {
uint32_t rollingCodeCounter { 0 }; uint32_t rollingCodeCounter { 0 };
uint32_t lastSyncedRollingCodeCounter { 0 }; uint32_t lastSyncedRollingCodeCounter { 0 };
float startOpening { -1 };
float openingDuration { 0 };
float startClosing { -1 };
float closingDuration { 0 };
uint8_t txRollingCode[CODE_LENGTH]; uint8_t txRollingCode[CODE_LENGTH];
uint8_t rxRollingCode[CODE_LENGTH]; uint8_t rxRollingCode[CODE_LENGTH];
@ -138,6 +145,10 @@ namespace ratgdo {
DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN };
DoorState doorState { 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 previousLightState { LightState::LIGHT_STATE_UNKNOWN };
LightState lightState { LightState::LIGHT_STATE_UNKNOWN }; LightState lightState { LightState::LIGHT_STATE_UNKNOWN };
@ -179,6 +190,10 @@ namespace ratgdo {
void openDoor(); void openDoor();
void closeDoor(); void closeDoor();
void stopDoor(); 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 toggleLight();
void lightOn(); void lightOn();
@ -197,12 +212,20 @@ namespace ratgdo {
void incrementRollingCodeCounter(); void incrementRollingCodeCounter();
void sendRollingCodeChanged(); void sendRollingCodeChanged();
void setRollingCodeCounter(uint32_t counter); void setRollingCodeCounter(uint32_t counter);
void setOpeningDuration(float duration);
void sendOpeningDuration();
void setClosingDuration(float duration);
void sendClosingDuration();
LightState getLightState(); LightState getLightState();
/** Register a child component. */ /** Register a child component. */
void register_child(RATGDOClient* obj); void register_child(RATGDOClient* obj);
protected: protected:
ESPPreferenceObject pref_; ESPPreferenceObject rollingCodePref_;
ESPPreferenceObject openingDurationPref_;
ESPPreferenceObject closingDurationPref_;
std::vector<RATGDOClient*> children_; std::vector<RATGDOClient*> children_;
bool rollingCodeUpdatesEnabled_ { true }; bool rollingCodeUpdatesEnabled_ { true };
bool forceUpdate_ { false }; bool forceUpdate_ { false };

View File

@ -6,13 +6,15 @@
namespace esphome { namespace esphome {
namespace ratgdo { 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_light_state(LightState state) {};
void RATGDOClient::on_lock_state(LockState state) {}; void RATGDOClient::on_lock_state(LockState state) {};
void RATGDOClient::on_motion_state(MotionState state) {}; void RATGDOClient::on_motion_state(MotionState state) {};
void RATGDOClient::on_obstruction_state(ObstructionState state) {}; void RATGDOClient::on_obstruction_state(ObstructionState state) {};
void RATGDOClient::on_motor_state(MotorState state) {}; void RATGDOClient::on_motor_state(MotorState state) {};
void RATGDOClient::on_rolling_code_change(uint32_t rollingCodeCounter) {}; 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_openings_change(uint32_t openings) {};
void RATGDOClient::on_button_state(ButtonState state) {}; void RATGDOClient::on_button_state(ButtonState state) {};

View File

@ -13,13 +13,15 @@ namespace ratgdo {
class RATGDOClient : public Parented<RATGDOComponent> { class RATGDOClient : public Parented<RATGDOComponent> {
public: 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_light_state(LightState state);
virtual void on_lock_state(LockState state); virtual void on_lock_state(LockState state);
virtual void on_motion_state(MotionState state); virtual void on_motion_state(MotionState state);
virtual void on_obstruction_state(ObstructionState state); virtual void on_obstruction_state(ObstructionState state);
virtual void on_motor_state(MotorState state); virtual void on_motor_state(MotorState state);
virtual void on_rolling_code_change(uint32_t rollingCodeCounter); 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_openings_change(uint32_t openings);
virtual void on_button_state(ButtonState state); virtual void on_button_state(ButtonState state);