From 37a4b88355fb2931078d85ed068f2644ed890952 Mon Sep 17 00:00:00 2001 From: Marius Muja Date: Sat, 24 Jun 2023 13:38:44 -0700 Subject: [PATCH] Refactor command handling (#10) Co-authored-by: J. Nick Koston --- components/ratgdo/cover/ratgdo_cover.cpp | 10 +- components/ratgdo/ratgdo.cpp | 254 ++++++++++++++--------- components/ratgdo/ratgdo.h | 146 ++++++++----- components/ratgdo/ratgdo_state.cpp | 28 +++ components/ratgdo/ratgdo_state.h | 2 + 5 files changed, 287 insertions(+), 153 deletions(-) diff --git a/components/ratgdo/cover/ratgdo_cover.cpp b/components/ratgdo/cover/ratgdo_cover.cpp index 3798943..19ebed7 100644 --- a/components/ratgdo/cover/ratgdo_cover.cpp +++ b/components/ratgdo/cover/ratgdo_cover.cpp @@ -26,12 +26,15 @@ namespace ratgdo { break; case DoorState::DOOR_STATE_OPENING: this->current_operation = COVER_OPERATION_OPENING; + this->position = 0.5; break; case DoorState::DOOR_STATE_CLOSING: this->current_operation = COVER_OPERATION_CLOSING; + this->position = 0.5; break; case DoorState::DOOR_STATE_STOPPED: - this->position = COVER_OPEN; + this->current_operation = COVER_OPERATION_IDLE; + this->position = 0.5; default: this->current_operation = COVER_OPERATION_IDLE; @@ -45,6 +48,8 @@ namespace ratgdo { { auto traits = CoverTraits(); traits.set_supports_stop(true); + traits.set_supports_toggle(true); + traits.set_supports_position(true); return traits; } void RATGDOCover::control(const CoverCall& call) @@ -52,6 +57,9 @@ namespace ratgdo { if (call.get_stop()) { this->parent_->stopDoor(); } + if (call.get_toggle()) { + this->parent_->toggleDoor(); + } if (call.get_position().has_value()) { auto pos = *call.get_position(); if (pos == COVER_OPEN) { diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 4c1b4fb..22b5dbb 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -23,7 +23,6 @@ namespace ratgdo { static const char* const TAG = "ratgdo"; static const int STARTUP_DELAY = 2000; // delay before enabling interrupts static const uint64_t REMOTE_ID = 0x539; - static const uint16_t STATUS_CMD = 0x81; static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 3; void IRAM_ATTR HOT RATGDOStore::isrObstruction(RATGDOStore* arg) @@ -76,6 +75,56 @@ namespace ratgdo { ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", this->rollingCodeCounter); } + const char* cmd_name(uint16_t cmd) + { + // from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540 + switch (cmd) { + // sent by opener (motor) + case 0x081: + return "status"; + case 0x084: + return "unknown_1"; + case 0x085: + return "unknown_2"; + case 0x0a1: + return "pair_3_resp"; + case 0x284: + return "motor_on"; + case 0x393: + return "learn_3_resp"; + case 0x401: + return "pair_2_resp"; + case 0x48c: + return "openings"; + + // sent by switch + case 0x080: + return "get_status"; + case 0x0a0: + return "pair_3"; + case 0x181: + return "learn_2"; + case 0x18c: + return "lock"; + case 0x280: + return "open"; + case 0x281: + return "light"; + case 0x285: + return "motion"; + case 0x391: + return "learn_1"; + case 0x392: + return "learn_3"; + case 0x400: + return "pair_2"; + case 0x48b: + return "get_openings"; + default: + return "unknown"; + } + } + uint16_t RATGDOComponent::readRollingCode() { uint32_t rolling = 0; @@ -90,51 +139,80 @@ namespace ratgdo { decode_wireline(this->rxRollingCode, &rolling, &fixed, &data); cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); + data &= ~0xf000; // clear parity nibble - nibble = (data >> 8) & 0xf; + if ((fixed & 0xfff) == REMOTE_ID) { // my commands + ESP_LOGD(TAG, "[%ld] received mine: rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data); + return 0; + } else { + 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; - if (cmd == STATUS_CMD) { - this->doorState = nibble; - this->lightState = (byte2 >> 1) & 1; - this->lockState = byte2 & 1; + 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 = 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 - // obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction - ESP_LOGV(TAG, "Door: %d Light: %d Lock: %d", this->doorState, this->lightState, this->lockState); - - } else if (cmd == 0x281) { - if (this->lightState == LightState::LIGHT_STATE_ON) { + // this->obstructionState = static_cast((byte1 >> 6) & 1); + 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)); + } else if (cmd == command::LIGHT) { + if (nibble == 0) { this->lightState = LightState::LIGHT_STATE_OFF; - } else { + } else if (nibble == 1) { this->lightState = LightState::LIGHT_STATE_ON; + } else if (nibble == 2) { // toggle + this->lightState = light_state_toggle(this->lightState); } - ESP_LOGV(TAG, "Light: %d (toggle)", this->lightState); - } else if (cmd == 0x284) { + 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; - } else if (cmd == 0x280) { - this->buttonState = byte1 == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; - ESP_LOGV(TAG, "Pressed: %d", this->buttonState); - } else if (cmd == 0x48c) { + 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_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); - } else if (cmd == 0x285) { - this->motionState = MotionState::MOTION_STATE_DETECTED; // toggle bit - ESP_LOGV(TAG, "Motion: %d (toggle)", this->motionState); + 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_LOGD(TAG, "Motion: %s", motion_state_to_string(this->motionState)); } else { - // 0x84 -- is it used? - ESP_LOGV(TAG, "Unknown command: cmd=%04x nibble=%02d byte1=%02d byte2=%02d", cmd, nibble, byte1, byte2); + 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; } - void RATGDOComponent::getRollingCode(cmd command) + void RATGDOComponent::getRollingCode(command::cmd command, uint32_t data, bool increment) { - uint64_t fixed = command.fixed | REMOTE_ID; - encode_wireline(this->rollingCodeCounter, fixed, command.data, this->txRollingCode); + uint64_t fixed = ((command & ~0xff) << 24) | REMOTE_ID; + uint32_t send_data = (data << 8) | (command & 0xff); + + 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(); - if (command != Command.DOOR1) { // door2 is created with same counter and should always be called after door1 + if (increment) { incrementRollingCodeCounter(); } } @@ -260,7 +338,7 @@ namespace ratgdo { if (byte_count == CODE_LENGTH) { reading_msg = false; byte_count = 0; - if (readRollingCode() == STATUS_CMD && this->forceUpdate_) { + if (readRollingCode() == command::STATUS && this->forceUpdate_) { this->forceUpdate_ = false; this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN; this->previousLightState = LightState::LIGHT_STATE_UNKNOWN; @@ -275,58 +353,51 @@ namespace ratgdo { void RATGDOComponent::statusUpdateLoop() { if (this->doorState != this->previousDoorState) { - DoorState val = static_cast(this->doorState); - ESP_LOGV(TAG, "Door state: %s", door_state_to_string(val)); + ESP_LOGV(TAG, "Door state: %s", door_state_to_string(this->doorState)); for (auto* child : this->children_) { - child->on_door_state(val); + child->on_door_state(this->doorState); } this->previousDoorState = this->doorState; } if (this->lightState != this->previousLightState) { - LightState val = static_cast(this->lightState); - ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(val), this->lightState); + ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(this->lightState), this->lightState); for (auto* child : this->children_) { - child->on_light_state(val); + child->on_light_state(this->lightState); } this->previousLightState = this->lightState; } if (this->lockState != this->previousLockState) { - LockState val = static_cast(this->lockState); - ESP_LOGV(TAG, "Lock state %s", lock_state_to_string(val)); + ESP_LOGV(TAG, "Lock state %s", lock_state_to_string(this->lockState)); for (auto* child : this->children_) { - child->on_lock_state(val); + child->on_lock_state(this->lockState); } this->previousLockState = this->lockState; } if (this->obstructionState != this->previousObstructionState) { - ObstructionState val = static_cast(this->obstructionState); - ESP_LOGV(TAG, "Obstruction state %s", obstruction_state_to_string(val)); + ESP_LOGV(TAG, "Obstruction state %s", obstruction_state_to_string(this->obstructionState)); for (auto* child : this->children_) { - child->on_obstruction_state(val); + child->on_obstruction_state(this->obstructionState); } this->previousObstructionState = this->obstructionState; } if (this->motorState != this->previousMotorState) { - MotorState val = static_cast(this->motorState); - ESP_LOGV(TAG, "Motor state %s", motor_state_to_string(val)); + ESP_LOGV(TAG, "Motor state %s", motor_state_to_string(this->motorState)); for (auto* child : this->children_) { - child->on_motor_state(val); + child->on_motor_state(this->motorState); } this->previousMotorState = this->motorState; } if (this->motionState != this->previousMotionState) { - MotionState val = static_cast(this->motionState); - ESP_LOGV(TAG, "Motion state %s", motion_state_to_string(val)); + ESP_LOGV(TAG, "Motion state %s", motion_state_to_string(this->motionState)); for (auto* child : this->children_) { - child->on_motion_state(val); + child->on_motion_state(this->motionState); } this->previousMotionState = this->motionState; } if (this->buttonState != this->previousButtonState) { - ButtonState val = static_cast(this->buttonState); - ESP_LOGV(TAG, "Button state %s", button_state_to_string(val)); + ESP_LOGV(TAG, "Button state %s", button_state_to_string(this->buttonState)); for (auto* child : this->children_) { - child->on_button_state(val); + child->on_button_state(this->buttonState); } this->previousButtonState = this->buttonState; } @@ -342,7 +413,7 @@ namespace ratgdo { void RATGDOComponent::query() { this->forceUpdate_ = true; - sendCommandAndSaveCounter(Command.REBOOT2); + sendCommandAndSaveCounter(command::GET_STATUS); } /************************* DOOR COMMUNICATION *************************/ @@ -354,9 +425,9 @@ namespace ratgdo { * The opener requires a specific duration low/high pulse before it will accept * a message */ - void RATGDOComponent::transmit(cmd command) + void RATGDOComponent::transmit(command::cmd command, uint32_t data, bool increment) { - getRollingCode(command); + getRollingCode(command, data, increment); this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the // door opener responds to the message delayMicroseconds(1305); @@ -370,38 +441,30 @@ namespace ratgdo { { this->rollingCodeUpdatesEnabled_ = false; for (int i = 0; i <= MAX_CODES_WITHOUT_FLASH_WRITE; i++) { - transmit(Command.REBOOT1); // get openings + transmit(command::GET_OPENINGS); // get openings delay(65); } - transmit(Command.REBOOT2); // get state + transmit(command::GET_STATUS); // get state delay(65); - transmit(Command.REBOOT3); + transmit(command::PAIR_3); delay(65); - transmit(Command.REBOOT4); + transmit(command::GET_STATUS); delay(65); - transmit(Command.REBOOT5); + transmit(command::LEARN_3); delay(65); this->rollingCodeUpdatesEnabled_ = true; - sendCommandAndSaveCounter(Command.REBOOT6); + sendCommandAndSaveCounter(command::LEARN_3); delay(65); } void RATGDOComponent::openDoor() { - if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_OPENING) { - ESP_LOGV(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); - return; - } - toggleDoor(); + doorCommand(data::OPEN); } void RATGDOComponent::closeDoor() { - if (this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_CLOSING) { - ESP_LOGV(TAG, "The door is already %s", door_state_to_string(static_cast(this->doorState))); - return; - } - toggleDoor(); + doorCommand(data::CLOSE); } void RATGDOComponent::stopDoor() @@ -415,66 +478,59 @@ namespace ratgdo { void RATGDOComponent::toggleDoor() { - transmit(Command.DOOR1); - delay(40); - sendCommandAndSaveCounter(Command.DOOR2); + doorCommand(data::TOGGLE); } - bool RATGDOComponent::isLightOn() + void RATGDOComponent::doorCommand(uint32_t data) { - return this->lightState == LightState::LIGHT_STATE_ON; + data |= (1 << 16); // button 1 ? + data |= (1 << 8); // button press + transmit(command::OPEN, data, false); + delay(40); + data &= ~(1 << 8); // button release + sendCommandAndSaveCounter(command::OPEN, data); } void RATGDOComponent::lightOn() { - if (this->lightState == LightState::LIGHT_STATE_ON) { - ESP_LOGV(TAG, "The light is already on"); - return; - } - toggleLight(); + this->lightState = LightState::LIGHT_STATE_ON; + sendCommandAndSaveCounter(command::LIGHT, data::ON); } void RATGDOComponent::lightOff() { - if (this->lightState == LightState::LIGHT_STATE_OFF) { - ESP_LOGV(TAG, "The light is already off"); - return; - } - toggleLight(); + this->lightState = LightState::LIGHT_STATE_OFF; + sendCommandAndSaveCounter(command::LIGHT, data::OFF); } void RATGDOComponent::toggleLight() { - sendCommandAndSaveCounter(Command.LIGHT); + this->lightState = light_state_toggle(this->lightState); + sendCommandAndSaveCounter(command::LIGHT, data::TOGGLE); } // Lock functions void RATGDOComponent::lock() { - if (this->lockState == LockState::LOCK_STATE_LOCKED) { - ESP_LOGV(TAG, "already locked"); - return; - } - toggleLock(); + this->lockState = LockState::LOCK_STATE_LOCKED; + sendCommandAndSaveCounter(command::LOCK, data::ON); } void RATGDOComponent::unlock() { - if (this->lockState == LockState::LOCK_STATE_UNLOCKED) { - ESP_LOGV(TAG, "already unlocked"); - return; - } - toggleLock(); + this->lockState = LockState::LOCK_STATE_UNLOCKED; + sendCommandAndSaveCounter(command::LOCK, data::OFF); } void RATGDOComponent::toggleLock() { - sendCommandAndSaveCounter(Command.LOCK); + this->lockState = lock_state_toggle(this->lockState); + sendCommandAndSaveCounter(command::LOCK, data::TOGGLE); } - void RATGDOComponent::sendCommandAndSaveCounter(cmd command) + void RATGDOComponent::sendCommandAndSaveCounter(command::cmd command, uint32_t data, bool increment) { - transmit(command); + transmit(command, data, increment); this->pref_.save(&this->rollingCodeCounter); if (!this->lastSyncedRollingCodeCounter || this->rollingCodeCounter - this->lastSyncedRollingCodeCounter >= MAX_CODES_WITHOUT_FLASH_WRITE) { this->lastSyncedRollingCodeCounter = this->rollingCodeCounter; @@ -489,7 +545,7 @@ namespace ratgdo { } LightState RATGDOComponent::getLightState() { - return static_cast(this->lightState); + return this->lightState; } } // namespace ratgdo diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index dcd68d3..9520eba 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -33,40 +33,71 @@ namespace ratgdo { static const uint8_t CODE_LENGTH = 19; - struct cmd { - uint64_t fixed; - uint32_t data; - inline bool operator!=(cmd const& other) const - { - return (fixed != other.fixed || data != other.data); - } - }; + /* + from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540 + _WIRELINE_COMMANDS = { + # sent by opener + 0x081: "status", + 0x084: "unknown_1", + 0x085: "unknown_2", + 0x0a1: "pair_3_resp", + 0x284: "motor_on", + 0x393: "learn_3_resp", + 0x401: "pair_2_resp", + 0x48c: "openings", - typedef struct { - cmd REBOOT1; - cmd REBOOT2; - cmd REBOOT3; - cmd REBOOT4; - cmd REBOOT5; - cmd REBOOT6; - cmd DOOR1; - cmd DOOR2; - cmd LIGHT; - cmd LOCK; - } cmds; + # sent by switch + 0x080: "get_status", + 0x0a0: "pair_3", + 0x181: "learn_2", + 0x18c: "lock", + 0x280: "open", + 0x281: "light", + 0x285: "motion", + 0x391: "learn_1", + 0x392: "learn_3", + 0x400: "pair_2", + 0x48b: "get_openings", + } + */ + + namespace data { + const uint32_t OFF = 0; + const uint32_t CLOSE = 0; + const uint32_t ON = 1; + const uint32_t OPEN = 1; + const uint32_t TOGGLE = 2; + } + + namespace command { + + enum cmd : uint64_t { + GET_STATUS = 0x080, + STATUS = 0x081, + OBST_1 = 0x084, // sent when an obstruction happens? + OBST_2 = 0x085, // sent when an obstruction happens? + PAIR_3 = 0x0a0, + PAIR_3_RESP = 0x0a1, + + LEARN_2 = 0x181, + LOCK = 0x18c, + + OPEN = 0x280, + LIGHT = 0x281, + MOTOR_ON = 0x284, + MOTION = 0x285, + + LEARN_1 = 0x391, + LEARN_3 = 0x392, + LEARN_3_RESP = 0x393, + + PAIR_2 = 0x400, + PAIR_2_RESP = 0x401, + GET_OPENINGS = 0x48b, + OPENINGS = 0x48c, + }; + } - const cmds Command = { - .REBOOT1 = (cmd) { 0x400000000, 0x0000618b }, - .REBOOT2 = (cmd) { 0, 0x01009080 }, - .REBOOT3 = (cmd) { 0, 0x0000b1a0 }, - .REBOOT4 = (cmd) { 0, 0x01009080 }, - .REBOOT5 = (cmd) { 0x300000000, 0x00008092 }, - .REBOOT6 = (cmd) { 0x300000000, 0x00008092 }, - .DOOR1 = (cmd) { 0x200000000, 0x01018280 }, - .DOOR2 = (cmd) { 0x200000000, 0x01009280 }, - .LIGHT = (cmd) { 0x200000000, 0x00009281 }, - .LOCK = (cmd) { 0x0100000000, 0x0000728c }, - }; struct RATGDOStore { ISRInternalGPIOPin input_obst; @@ -87,27 +118,32 @@ namespace ratgdo { uint32_t rollingCodeCounter { 0 }; uint32_t lastSyncedRollingCodeCounter { 0 }; - uint16_t previousOpenings { 0 }; // number of times the door has been opened - uint16_t openings { 0 }; // number of times the door has been opened - uint8_t txRollingCode[CODE_LENGTH]; uint8_t rxRollingCode[CODE_LENGTH]; - uint8_t previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; - uint8_t previousLightState { LightState::LIGHT_STATE_UNKNOWN }; - uint8_t previousLockState { LockState::LOCK_STATE_UNKNOWN }; - uint8_t previousObstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN }; - uint8_t previousMotorState { MotorState::MOTOR_STATE_UNKNOWN }; - uint8_t previousButtonState { ButtonState::BUTTON_STATE_UNKNOWN }; - uint8_t previousMotionState { MotionState::MOTION_STATE_UNKNOWN }; + uint16_t previousOpenings { 0 }; // number of times the door has been opened + uint16_t openings { 0 }; // number of times the door has been opened - uint8_t doorState { DoorState::DOOR_STATE_UNKNOWN }; - uint8_t lightState { LightState::LIGHT_STATE_UNKNOWN }; - uint8_t lockState { LockState::LOCK_STATE_UNKNOWN }; - uint8_t obstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN }; - uint8_t motorState { MotorState::MOTOR_STATE_UNKNOWN }; - uint8_t buttonState { ButtonState::BUTTON_STATE_UNKNOWN }; - uint8_t motionState { MotionState::MOTION_STATE_UNKNOWN }; + DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; + DoorState doorState { DoorState::DOOR_STATE_UNKNOWN }; + + LightState previousLightState { LightState::LIGHT_STATE_UNKNOWN }; + LightState lightState { LightState::LIGHT_STATE_UNKNOWN }; + + LockState previousLockState { LockState::LOCK_STATE_UNKNOWN }; + LockState lockState { LockState::LOCK_STATE_UNKNOWN }; + + ObstructionState previousObstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN }; + ObstructionState obstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN }; + + MotorState previousMotorState { MotorState::MOTOR_STATE_UNKNOWN }; + MotorState motorState { MotorState::MOTOR_STATE_UNKNOWN }; + + ButtonState previousButtonState { ButtonState::BUTTON_STATE_UNKNOWN }; + ButtonState buttonState { ButtonState::BUTTON_STATE_UNKNOWN }; + + MotionState previousMotionState { MotionState::MOTION_STATE_UNKNOWN }; + MotionState motionState { MotionState::MOTION_STATE_UNKNOWN }; void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; }; void set_input_gdo_pin(InternalGPIOPin* pin) { this->input_gdo_pin_ = pin; }; @@ -115,29 +151,33 @@ namespace ratgdo { /********************************** FUNCTION DECLARATION * *****************************************/ - void transmit(cmd command); + void transmit(command::cmd command, uint32_t data = 0, bool increment = true); + void sync(); void gdoStateLoop(); void obstructionLoop(); void statusUpdateLoop(); - void sendCommandAndSaveCounter(cmd command); + void sendCommandAndSaveCounter(command::cmd command, uint32_t data = 0, bool increment = true); + + void doorCommand(uint32_t data); void toggleDoor(); void openDoor(); void closeDoor(); void stopDoor(); + void toggleLight(); void lightOn(); void lightOff(); - bool isLightOn(); + void toggleLock(); void lock(); void unlock(); void query(); void printRollingCode(); - void getRollingCode(cmd command); + void getRollingCode(command::cmd command, uint32_t data, bool increment); uint16_t readRollingCode(); void incrementRollingCodeCounter(); void sendRollingCodeChanged(); diff --git a/components/ratgdo/ratgdo_state.cpp b/components/ratgdo/ratgdo_state.cpp index 4438508..5dcc84e 100644 --- a/components/ratgdo/ratgdo_state.cpp +++ b/components/ratgdo/ratgdo_state.cpp @@ -38,6 +38,20 @@ namespace ratgdo { } } + LightState light_state_toggle(LightState state) + { + switch (state) { + case LIGHT_STATE_OFF: + return LIGHT_STATE_ON; + case LIGHT_STATE_ON: + return LIGHT_STATE_OFF; + // 2 and 3 appears sometimes + case LIGHT_STATE_UNKNOWN: + default: + return LIGHT_STATE_UNKNOWN; + } + } + const char* lock_state_to_string(LockState state) { switch (state) { @@ -51,6 +65,20 @@ namespace ratgdo { } } + LockState lock_state_toggle(LockState state) + { + switch (state) { + case LOCK_STATE_UNLOCKED: + return LOCK_STATE_LOCKED; + case LOCK_STATE_LOCKED: + return LOCK_STATE_UNLOCKED; + // 2 and 3 appears sometimes + case LOCK_STATE_UNKNOWN: + default: + return LOCK_STATE_UNKNOWN; + } + } + const char* motion_state_to_string(MotionState state) { switch (state) { diff --git a/components/ratgdo/ratgdo_state.h b/components/ratgdo/ratgdo_state.h index c581f17..434d47f 100644 --- a/components/ratgdo/ratgdo_state.h +++ b/components/ratgdo/ratgdo_state.h @@ -38,6 +38,7 @@ namespace ratgdo { LIGHT_STATE_UNKNOWN = 2, }; const char* light_state_to_string(LightState state); + LightState light_state_toggle(LightState state); /// Enum for all states a the lock can be in. enum LockState : uint8_t { @@ -46,6 +47,7 @@ namespace ratgdo { LOCK_STATE_UNKNOWN = 2, }; const char* lock_state_to_string(LockState state); + LockState lock_state_toggle(LockState state); /// Enum for all states a the motion can be in. enum MotionState : uint8_t {