diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 73b2f53..211a056 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -77,419 +77,418 @@ namespace ratgdo { uint16_t RATGDOComponent::readRollingCode() { - { - uint32_t rolling = 0; - uint64_t fixed = 0; - uint32_t data = 0; + uint32_t rolling = 0; + uint64_t fixed = 0; + uint32_t data = 0; - uint16_t cmd = 0; - uint8_t nibble = 0; - uint8_t byte1 = 0; - uint8_t byte2 = 0; + uint16_t cmd = 0; + uint8_t nibble = 0; + uint8_t byte1 = 0; + uint8_t byte2 = 0; - decode_wireline(this->rxRollingCode, &rolling, &fixed, &data); + decode_wireline(this->rxRollingCode, &rolling, &fixed, &data); - cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); + cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); - nibble = (data >> 8) & 0xf; - byte1 = (data >> 16) & 0xff; - byte2 = (data >> 24) & 0xff; + nibble = (data >> 8) & 0xf; + byte1 = (data >> 16) & 0xff; + byte2 = (data >> 24) & 0xff; - if (cmd == STATUS_CMD) { - this->doorState = nibble; - this->lightState = (byte2 >> 1) & 1; - this->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 - // obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction - ESP_LOGD(TAG, "Door: %d Light: %d Lock: %dd", this->doorState, this->lightState, this->lockState); + if (cmd == STATUS_CMD) { + this->doorState = nibble; + this->lightState = (byte2 >> 1) & 1; + this->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 + // obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction + ESP_LOGD(TAG, "Door: %d Light: %d Lock: %dd", this->doorState, this->lightState, this->lockState); - } else if (cmd == 0x281) { - this->lightState ^= 1; // toggle bit - ESP_LOGD(TAG, "Light: %d (toggle)", this->lightState); - } else if (cmd == 0x84) { - ESP_LOGD(TAG, "Unknown 0x84"); - } else if (cmd == 0x284) { - this->motorState = MotorState::MOTOR_STATE_ON; - } else if (cmd == 0x280) { - this->buttonState = byte1 == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; - ESP_LOGD(TAG, "Pressed: %s", byte1 == 1 ? "pressed" : "released"); - } else if (cmd == 0x48c) { - this->openings = (byte1 << 8) | byte2; - ESP_LOGD(TAG, "Openings: %d", (byte1 << 8) | byte2); - } else if (cmd == 0x285) { - this->motionState = MotionState::MOTION_STATE_DETECTED; // toggle bit - ESP_LOGD(TAG, "Motion: %d (toggle)", this->motionState); - } else { - ESP_LOGD(TAG, "Unknown command: %04x", cmd); - } - return cmd; + } else if (cmd == 0x281) { + this->lightState ^= 1; // toggle bit + ESP_LOGD(TAG, "Light: %d (toggle)", this->lightState); + } else if (cmd == 0x84) { + ESP_LOGD(TAG, "Unknown 0x84"); + } else if (cmd == 0x284) { + this->motorState = MotorState::MOTOR_STATE_ON; + } else if (cmd == 0x280) { + this->buttonState = byte1 == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; + ESP_LOGD(TAG, "Pressed: %s", byte1 == 1 ? "pressed" : "released"); + } else if (cmd == 0x48c) { + this->openings = (byte1 << 8) | byte2; + ESP_LOGD(TAG, "Openings: %d", (byte1 << 8) | byte2); + } else if (cmd == 0x285) { + this->motionState = MotionState::MOTION_STATE_DETECTED; // toggle bit + ESP_LOGD(TAG, "Motion: %d (toggle)", this->motionState); + } else { + ESP_LOGD(TAG, "Unknown command: %04x", cmd); } + return cmd; + } - void RATGDOComponent::getRollingCode(cmd command) - { - uint64_t fixed = command.fixed | REMOTE_ID; - encode_wireline(this->rollingCodeCounter, fixed, command.data, this->txRollingCode); - printRollingCode(); - if (command != Command.DOOR1) { // door2 is created with same counter and should always be called after door1 - incrementRollingCodeCounter(); + void RATGDOComponent::getRollingCode(cmd command) + { + uint64_t fixed = command.fixed | REMOTE_ID; + encode_wireline(this->rollingCodeCounter, fixed, command.data, this->txRollingCode); + printRollingCode(); + if (command != Command.DOOR1) { // door2 is created with same counter and should always be called after door1 + incrementRollingCodeCounter(); + } + } + + void RATGDOComponent::setRollingCodeCounter(uint32_t counter) + { + ESP_LOGD(TAG, "Set rolling code counter to %d", counter); + this->rollingCodeCounter = counter; + this->pref_.save(&this->rollingCodeCounter); + sendRollingCodeChanged(); + } + + void RATGDOComponent::incrementRollingCodeCounter() + { + ESP_LOGD(TAG, "Incrementing rolling code counter"); + this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff; + sendRollingCodeChanged(); + } + + void RATGDOComponent::sendRollingCodeChanged() + { + for (auto* child : this->children_) { + child->on_rolling_code_change(this->rollingCodeCounter); + } + } + + void RATGDOComponent::printRollingCode() + { + ESP_LOGD(TAG, "Counter: %d Send code: [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X]", + this->rollingCodeCounter, + this->txRollingCode[0], + this->txRollingCode[1], + this->txRollingCode[2], + this->txRollingCode[3], + this->txRollingCode[4], + this->txRollingCode[5], + this->txRollingCode[6], + this->txRollingCode[7], + this->txRollingCode[8], + this->txRollingCode[9], + this->txRollingCode[10], + this->txRollingCode[11], + this->txRollingCode[12], + this->txRollingCode[13], + this->txRollingCode[14], + this->txRollingCode[15], + this->txRollingCode[16], + this->txRollingCode[17], + this->txRollingCode[18]); + } + + /*************************** OBSTRUCTION DETECTION ***************************/ + + void RATGDOComponent::obstructionLoop() + { + long currentMillis = millis(); + static unsigned long lastMillis = 0; + + // the obstruction sensor has 3 states: clear (HIGH with LOW pulse every 7ms), obstructed (HIGH), asleep (LOW) + // the transitions between awake and asleep are tricky because the voltage drops slowly when falling asleep + // and is high without pulses when waking up + + // If at least 3 low pulses are counted within 50ms, the door is awake, not obstructed and we don't have to check anything else + + // Every 50ms + if (currentMillis - lastMillis > 50) { + // check to see if we got between 3 and 8 low pulses on the line + if (this->store_.obstructionLowCount >= 3 && this->store_.obstructionLowCount <= 8) { + // obstructionCleared(); + this->obstructionState = ObstructionState::OBSTRUCTION_STATE_CLEAR; + + // if there have been no pulses the line is steady high or low + } else if (this->store_.obstructionLowCount == 0) { + // if the line is high and the last high pulse was more than 70ms ago, then there is an obstruction present + if (this->input_obst_pin_->digital_read() && currentMillis - this->store_.lastObstructionHigh > 70) { + this->obstructionState = ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED; + // obstructionDetected(); + } else { + // asleep + } + } + + lastMillis = currentMillis; + this->store_.obstructionLowCount = 0; + } + } + + void RATGDOComponent::gdoStateLoop() + { + static uint32_t msgStart; + static bool reading = false; + static uint16_t byteCount = 0; + static bool isStatus = false; + + if (!this->available()) { + // ESP_LOGD(TAG, "No data available input:%d output:%d", this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin()); + return; + } + uint8_t serData; + if (!this->read_byte(&serData)) { + ESP_LOGD(TAG, "Failed to read byte"); + return; + } + if (!reading) { + // shift serial byte onto msg start + msgStart <<= 8; + msgStart |= serData; + + // truncate to 3 bytes + msgStart &= 0x00FFFFFF; + + // if we are at the start of a message, capture the next 16 bytes + if (msgStart == 0x550100) { + byteCount = 3; + rxRollingCode[0] = 0x55; + rxRollingCode[1] = 0x01; + rxRollingCode[2] = 0x00; + + reading = true; + return; } } + if (reading) { + this->rxRollingCode[byteCount] = serData; + byteCount++; - void RATGDOComponent::setRollingCodeCounter(uint32_t counter) - { - ESP_LOGD(TAG, "Set rolling code counter to %d", counter); - this->rollingCodeCounter = counter; - this->pref_.save(&this->rollingCodeCounter); - sendRollingCodeChanged(); + if (byteCount == CODE_LENGTH) { + reading = false; + msgStart = 0; + byteCount = 0; + if (readRollingCode() == STATUS_CMD && this->forceUpdate_) { + this->forceUpdate_ = false; + this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN; + this->previousLightState = LightState::LIGHT_STATE_UNKNOWN; + this->previousLockState = LockState::LOCK_STATE_UNKNOWN; + } + } } + } - void RATGDOComponent::incrementRollingCodeCounter() - { - ESP_LOGD(TAG, "Incrementing rolling code counter"); - this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff; - sendRollingCodeChanged(); - } - - void RATGDOComponent::sendRollingCodeChanged() - { + void RATGDOComponent::statusUpdateLoop() + { + if (this->doorState != this->previousDoorState) { + DoorState val = static_cast(this->doorState); + ESP_LOGD(TAG, "Door state: %s", door_state_to_string(val)); for (auto* child : this->children_) { - child->on_rolling_code_change(this->rollingCodeCounter); + child->on_door_state(val); } + this->previousDoorState = this->doorState; } - - void RATGDOComponent::printRollingCode() - { - ESP_LOGD(TAG, "Counter: %d Send code: [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X]", - this->rollingCodeCounter, - this->txRollingCode[0], - this->txRollingCode[1], - this->txRollingCode[2], - this->txRollingCode[3], - this->txRollingCode[4], - this->txRollingCode[5], - this->txRollingCode[6], - this->txRollingCode[7], - this->txRollingCode[8], - this->txRollingCode[9], - this->txRollingCode[10], - this->txRollingCode[11], - this->txRollingCode[12], - this->txRollingCode[13], - this->txRollingCode[14], - this->txRollingCode[15], - this->txRollingCode[16], - this->txRollingCode[17], - this->txRollingCode[18]); - } - - /*************************** OBSTRUCTION DETECTION ***************************/ - - void RATGDOComponent::obstructionLoop() - { - long currentMillis = millis(); - static unsigned long lastMillis = 0; - - // the obstruction sensor has 3 states: clear (HIGH with LOW pulse every 7ms), obstructed (HIGH), asleep (LOW) - // the transitions between awake and asleep are tricky because the voltage drops slowly when falling asleep - // and is high without pulses when waking up - - // If at least 3 low pulses are counted within 50ms, the door is awake, not obstructed and we don't have to check anything else - - // Every 50ms - if (currentMillis - lastMillis > 50) { - // check to see if we got between 3 and 8 low pulses on the line - if (this->store_.obstructionLowCount >= 3 && this->store_.obstructionLowCount <= 8) { - // obstructionCleared(); - this->obstructionState = ObstructionState::OBSTRUCTION_STATE_CLEAR; - - // if there have been no pulses the line is steady high or low - } else if (this->store_.obstructionLowCount == 0) { - // if the line is high and the last high pulse was more than 70ms ago, then there is an obstruction present - if (this->input_obst_pin_->digital_read() && currentMillis - this->store_.lastObstructionHigh > 70) { - this->obstructionState = ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED; - // obstructionDetected(); - } else { - // asleep - } - } - - lastMillis = currentMillis; - this->store_.obstructionLowCount = 0; + if (this->lightState != this->previousLightState) { + LightState val = static_cast(this->lightState); + ESP_LOGD(TAG, "Light state %s (%d)", light_state_to_string(val), this->lightState); + for (auto* child : this->children_) { + child->on_light_state(val); } - } - - void RATGDOComponent::gdoStateLoop() - { - static uint32_t msgStart; - static bool reading = false; - static uint16_t byteCount = 0; - static bool isStatus = false; - - if (!this->available()) { - // ESP_LOGD(TAG, "No data available input:%d output:%d", this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin()); - return; - } - uint8_t serData; - if (!this->read_byte(&serData)) { - ESP_LOGD(TAG, "Failed to read byte"); - return; - } - if (!reading) { - // shift serial byte onto msg start - msgStart <<= 8; - msgStart |= serData; - - // truncate to 3 bytes - msgStart &= 0x00FFFFFF; - - // if we are at the start of a message, capture the next 16 bytes - if (msgStart == 0x550100) { - byteCount = 3; - rxRollingCode[0] = 0x55; - rxRollingCode[1] = 0x01; - rxRollingCode[2] = 0x00; - - reading = true; - return; - } - } - if (reading) { - this->rxRollingCode[byteCount] = serData; - byteCount++; - - if (byteCount == CODE_LENGTH) { - reading = false; - msgStart = 0; - byteCount = 0; - if (readRollingCode() == STATUS_CMD && this->forceUpdate_) { - this->forceUpdate_ = false; - this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN; - this->previousLightState = LightState::LIGHT_STATE_UNKNOWN; - this->previousLockState = LockState::LOCK_STATE_UNKNOWN; - } - } - } - } - - void RATGDOComponent::statusUpdateLoop() - { - if (this->doorState != this->previousDoorState) { - DoorState val = static_cast(this->doorState); - ESP_LOGD(TAG, "Door state: %s", door_state_to_string(val)); - for (auto* child : this->children_) { - child->on_door_state(val); - } - this->previousDoorState = this->doorState; - } - if (this->lightState != this->previousLightState) { - LightState val = static_cast(this->lightState); - ESP_LOGD(TAG, "Light state %s (%d)", light_state_to_string(val), this->lightState); - for (auto* child : this->children_) { - child->on_light_state(val); - } - this->previousLightState = this->lightState; - } - if (this->lockState != this->previousLockState) { - LockState val = static_cast(this->lockState); - ESP_LOGD(TAG, "Lock state %s", lock_state_to_string(val)); - for (auto* child : this->children_) { - child->on_lock_state(val); - } - this->previousLockState = this->lockState; - } - if (this->obstructionState != this->previousObstructionState) { - ObstructionState val = static_cast(this->obstructionState); - ESP_LOGD(TAG, "Obstruction state %s", obstruction_state_to_string(val)); - for (auto* child : this->children_) { - child->on_obstruction_state(val); - } - this->previousObstructionState = this->obstructionState; - } - if (this->motorState != this->previousMotorState) { - MotorState val = static_cast(this->motorState); - ESP_LOGD(TAG, "Motor state %s", motor_state_to_string(val)); - for (auto* child : this->children_) { - child->on_motor_state(val); - } - this->previousMotorState = this->motorState; - } - if (this->motionState == this->previousMotionState) { - MotionState val = static_cast(this->motionState); - ESP_LOGD(TAG, "Motion state %s", motion_state_to_string(val)); - for (auto* child : this->children_) { - child->on_motion_state(val); - } - this->previousMotionState = this->motionState; - } - if (this->buttonState != this->previousButtonState) { - ButtonState val = static_cast(this->buttonState); - ESP_LOGD(TAG, "Button state %s", button_state_to_string(val)); - for (auto* child : this->children_) { - child->on_button_state(val); - } - this->previousButtonState = this->buttonState; - } - if (this->openings != this->previousOpenings) { - ESP_LOGD(TAG, "Openings: %d", this->openings); - for (auto* child : this->children_) { - child->on_openings_change(this->openings); - } - this->previousOpenings = this->openings; - } - } - - void RATGDOComponent::query() - { - this->forceUpdate_ = true; - sendCommandAndSaveCounter(Command.REBOOT2); - } - - /************************* DOOR COMMUNICATION *************************/ - /* - * Transmit a message to the door opener over uart1 - * The TX1 pin is controlling a transistor, so the logic is inverted - * A HIGH state on TX1 will pull the 12v line LOW - * - * The opener requires a specific duration low/high pulse before it will accept - * a message - */ - void RATGDOComponent::transmit(cmd command) - { - getRollingCode(command); - this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the - // door opener responds to the message - delayMicroseconds(1305); - this->output_gdo_pin_->digital_write(false); // bring the line low - - delayMicroseconds(1260); // "LOW" pulse duration before the message start - this->write_array(this->txRollingCode, CODE_LENGTH); - } - - void RATGDOComponent::sync() - { - transmit(Command.REBOOT1); - delay(65); - transmit(Command.REBOOT2); - delay(65); - transmit(Command.REBOOT3); - delay(65); - transmit(Command.REBOOT4); - delay(65); - transmit(Command.REBOOT5); - delay(65); - sendCommandAndSaveCounter(Command.REBOOT6); - delay(65); - } - - void RATGDOComponent::openDoor() - { - if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_OPENING) { - ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); - return; - } - toggleDoor(); - } - - void RATGDOComponent::closeDoor() - { - if (this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_CLOSING) { - ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); - return; - } - toggleDoor(); - } - - void RATGDOComponent::stopDoor() - { - if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) { - ESP_LOGD(TAG, "The door is not moving."); - return; - } - toggleDoor(); - } - - void RATGDOComponent::toggleDoor() - { - transmit(Command.DOOR1); - delay(40); - sendCommandAndSaveCounter(Command.DOOR2); - } - - bool RATGDOComponent::isLightOn() - { - return this->lightState == LightState::LIGHT_STATE_ON; - } - - void RATGDOComponent::lightOn() - { - if (this->lightState == LightState::LIGHT_STATE_ON) { - ESP_LOGD(TAG, "The light is already on"); - return; - } - toggleLight(); - // We don't always get the state back so be optimistic this->previousLightState = this->lightState; - this->lightState = LightState::LIGHT_STATE_ON; } - - void RATGDOComponent::lightOff() - { - if (this->lightState == LightState::LIGHT_STATE_OFF) { - ESP_LOGD(TAG, "The light is already off"); - return; + if (this->lockState != this->previousLockState) { + LockState val = static_cast(this->lockState); + ESP_LOGD(TAG, "Lock state %s", lock_state_to_string(val)); + for (auto* child : this->children_) { + child->on_lock_state(val); } - toggleLight(); - // We don't always get the state back so be optimistic - this->previousLightState = this->lightState; - this->lightState = LightState::LIGHT_STATE_OFF; + this->previousLockState = this->lockState; } - - void RATGDOComponent::toggleLight() - { - sendCommandAndSaveCounter(Command.LIGHT); - } - - // Lock functions - void RATGDOComponent::lock() - { - if (this->lockState == LockState::LOCK_STATE_LOCKED) { - ESP_LOGD(TAG, "already locked"); - return; + if (this->obstructionState != this->previousObstructionState) { + ObstructionState val = static_cast(this->obstructionState); + ESP_LOGD(TAG, "Obstruction state %s", obstruction_state_to_string(val)); + for (auto* child : this->children_) { + child->on_obstruction_state(val); } - toggleLock(); + this->previousObstructionState = this->obstructionState; } - - void RATGDOComponent::unlock() - { - if (this->lockState == LockState::LOCK_STATE_UNLOCKED) { - ESP_LOGD(TAG, "already unlocked"); - return; + if (this->motorState != this->previousMotorState) { + MotorState val = static_cast(this->motorState); + ESP_LOGD(TAG, "Motor state %s", motor_state_to_string(val)); + for (auto* child : this->children_) { + child->on_motor_state(val); } - toggleLock(); + this->previousMotorState = this->motorState; } + if (this->motionState == this->previousMotionState) { + MotionState val = static_cast(this->motionState); + ESP_LOGD(TAG, "Motion state %s", motion_state_to_string(val)); + for (auto* child : this->children_) { + child->on_motion_state(val); + } + this->previousMotionState = this->motionState; + } + if (this->buttonState != this->previousButtonState) { + ButtonState val = static_cast(this->buttonState); + ESP_LOGD(TAG, "Button state %s", button_state_to_string(val)); + for (auto* child : this->children_) { + child->on_button_state(val); + } + this->previousButtonState = this->buttonState; + } + if (this->openings != this->previousOpenings) { + ESP_LOGD(TAG, "Openings: %d", this->openings); + for (auto* child : this->children_) { + child->on_openings_change(this->openings); + } + this->previousOpenings = this->openings; + } + } - void RATGDOComponent::toggleLock() - { - sendCommandAndSaveCounter(Command.LOCK); - } + void RATGDOComponent::query() + { + this->forceUpdate_ = true; + sendCommandAndSaveCounter(Command.REBOOT2); + } - void RATGDOComponent::sendCommandAndSaveCounter(cmd command) - { - transmit(command); - this->pref_.save(&this->rollingCodeCounter); - global_preferences->sync(); - } + /************************* DOOR COMMUNICATION *************************/ + /* + * Transmit a message to the door opener over uart1 + * The TX1 pin is controlling a transistor, so the logic is inverted + * A HIGH state on TX1 will pull the 12v line LOW + * + * The opener requires a specific duration low/high pulse before it will accept + * a message + */ + void RATGDOComponent::transmit(cmd command) + { + getRollingCode(command); + this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the + // door opener responds to the message + delayMicroseconds(1305); + this->output_gdo_pin_->digital_write(false); // bring the line low - void RATGDOComponent::register_child(RATGDOClient * obj) - { - this->children_.push_back(obj); - obj->set_parent(this); - } - LightState RATGDOComponent::getLightState() - { - return static_cast(this->lightState); - } + delayMicroseconds(1260); // "LOW" pulse duration before the message start + this->write_array(this->txRollingCode, CODE_LENGTH); + } - } // namespace ratgdo + void RATGDOComponent::sync() + { + transmit(Command.REBOOT1); + delay(65); + transmit(Command.REBOOT2); + delay(65); + transmit(Command.REBOOT3); + delay(65); + transmit(Command.REBOOT4); + delay(65); + transmit(Command.REBOOT5); + delay(65); + sendCommandAndSaveCounter(Command.REBOOT6); + delay(65); + } + + void RATGDOComponent::openDoor() + { + if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_OPENING) { + ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); + return; + } + toggleDoor(); + } + + void RATGDOComponent::closeDoor() + { + if (this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_CLOSING) { + ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); + return; + } + toggleDoor(); + } + + void RATGDOComponent::stopDoor() + { + if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) { + ESP_LOGD(TAG, "The door is not moving."); + return; + } + toggleDoor(); + } + + void RATGDOComponent::toggleDoor() + { + transmit(Command.DOOR1); + delay(40); + sendCommandAndSaveCounter(Command.DOOR2); + } + + bool RATGDOComponent::isLightOn() + { + return this->lightState == LightState::LIGHT_STATE_ON; + } + + void RATGDOComponent::lightOn() + { + if (this->lightState == LightState::LIGHT_STATE_ON) { + ESP_LOGD(TAG, "The light is already on"); + return; + } + toggleLight(); + // We don't always get the state back so be optimistic + this->previousLightState = this->lightState; + this->lightState = LightState::LIGHT_STATE_ON; + } + + void RATGDOComponent::lightOff() + { + if (this->lightState == LightState::LIGHT_STATE_OFF) { + ESP_LOGD(TAG, "The light is already off"); + return; + } + toggleLight(); + // We don't always get the state back so be optimistic + this->previousLightState = this->lightState; + this->lightState = LightState::LIGHT_STATE_OFF; + } + + void RATGDOComponent::toggleLight() + { + sendCommandAndSaveCounter(Command.LIGHT); + } + + // Lock functions + void RATGDOComponent::lock() + { + if (this->lockState == LockState::LOCK_STATE_LOCKED) { + ESP_LOGD(TAG, "already locked"); + return; + } + toggleLock(); + } + + void RATGDOComponent::unlock() + { + if (this->lockState == LockState::LOCK_STATE_UNLOCKED) { + ESP_LOGD(TAG, "already unlocked"); + return; + } + toggleLock(); + } + + void RATGDOComponent::toggleLock() + { + sendCommandAndSaveCounter(Command.LOCK); + } + + void RATGDOComponent::sendCommandAndSaveCounter(cmd command) + { + transmit(command); + this->pref_.save(&this->rollingCodeCounter); + global_preferences->sync(); + } + + void RATGDOComponent::register_child(RATGDOClient* obj) + { + this->children_.push_back(obj); + obj->set_parent(this); + } + LightState RATGDOComponent::getLightState() + { + return static_cast(this->lightState); + } + +} // namespace ratgdo } // namespace esphome