Door position control (#20)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
073b5440cb
commit
f1993931a7
16
base.yaml
16
base.yaml
|
@ -137,6 +137,22 @@ number:
|
|||
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
|
||||
id: ${id_prefix}_garage_door
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -46,10 +46,23 @@ namespace ratgdo {
|
|||
|
||||
void RATGDOComponent::setup()
|
||||
{
|
||||
this->pref_ = global_preferences->make_preference<int>(734874333U);
|
||||
if (!this->pref_.load(&this->rollingCodeCounter)) {
|
||||
this->rollingCodePref_ = global_preferences->make_preference<int>(734874333U);
|
||||
if (!this->rollingCodePref_.load(&this->rollingCodeCounter)) {
|
||||
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->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<DoorState>(nibble);
|
||||
if (doorState == DoorState::DOOR_STATE_CLOSED && this->doorState != doorState) {
|
||||
transmit(command::GET_OPENINGS);
|
||||
|
||||
this->doorState = static_cast<DoorState>(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<LightState>((byte2 >> 1) & 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->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);
|
||||
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()
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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<RATGDOClient*> children_;
|
||||
bool rollingCodeUpdatesEnabled_ { true };
|
||||
bool forceUpdate_ { false };
|
||||
|
|
|
@ -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) {};
|
||||
|
||||
|
|
|
@ -13,13 +13,15 @@ namespace ratgdo {
|
|||
|
||||
class RATGDOClient : public Parented<RATGDOComponent> {
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue