From b15063763a26dced8746172abc1a15b44e8f05a6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 5 Jun 2023 19:57:06 -0500 Subject: [PATCH] fix --- components/ratgdo/__init__.py | 7 +- components/ratgdo/ratgdo.cpp | 784 +++++++++++++++++----------------- 2 files changed, 397 insertions(+), 394 deletions(-) diff --git a/components/ratgdo/__init__.py b/components/ratgdo/__init__.py index efeebcc..56c0303 100644 --- a/components/ratgdo/__init__.py +++ b/components/ratgdo/__init__.py @@ -2,12 +2,13 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.const import CONF_ID from esphome import pins, automation +from esphome.components import uart -DEPENDENCIES = ["preferences"] +DEPENDENCIES = ["preferences", "uart"] ratgdo_ns = cg.esphome_ns.namespace("ratgdo") -RATGDO = ratgdo_ns.class_("RATGDOComponent", cg.Component) +RATGDO = ratgdo_ns.class_("RATGDOComponent", cg.Component, uart.UARTDevice) CONF_OUTPUT_GDO = "output_gdo_pin" @@ -46,7 +47,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_STATUS_DOOR, default=DEFAULT_STATUS_DOOR): pins.internal_gpio_input_pin_schema, cv.Optional(CONF_STATUS_OBST, default=DEFAULT_STATUS_OBST): pins.internal_gpio_input_pin_schema, } -).extend(cv.COMPONENT_SCHEMA) +).extend(cv.COMPONENT_SCHEMA).extend(uart.UART_DEVICE_SCHEMA) async def to_code(config): diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 5e5be27..8a49a3d 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -88,443 +88,445 @@ namespace ratgdo { } } - void RATGDOComponent::setup() - { - this->pref_ = global_preferences->make_preference(734874333U); - if (!this->pref_.load(&this->rollingCodeCounter)) { - this->rollingCodeCounter = 0; + class RATGDOComponent : public Component, public UARTDevice { + public: + RATGDOComponent(UARTComponent *parent) : UARTDevice(parent) {} + + void setup() + { + this->pref_ = global_preferences->make_preference(734874333U); + if (!this->pref_.load(&this->rollingCodeCounter)) { + this->rollingCodeCounter = 0; + } + + this->output_gdo_pin_->setup(); + this->input_gdo_pin_->setup(); + this->input_obst_pin_->setup(); + + this->trigger_open_pin_->setup(); + this->trigger_close_pin_->setup(); + this->trigger_light_pin_->setup(); + + this->status_door_pin_->setup(); + this->status_obst_pin_->setup(); + + this->store_.input_obst = this->input_obst_pin_->to_isr(); + + this->store_.trigger_open = this->trigger_open_pin_->to_isr(); + this->store_.trigger_close = this->trigger_close_pin_->to_isr(); + this->store_.trigger_light = this->trigger_light_pin_->to_isr(); + + this->trigger_open_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->trigger_close_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->trigger_light_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + + this->status_door_pin_->pin_mode(gpio::FLAG_OUTPUT); + this->status_obst_pin_->pin_mode(gpio::FLAG_OUTPUT); + + //this->output_gdo_pin_->pin_mode(gpio::FLAG_OUTPUT); + //this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); + this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT); + + this->swSerial.begin(9600, SWSERIAL_8N1, this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin(), true); + + this->trigger_open_pin_->attach_interrupt(RATGDOStore::isrDoorOpen, &this->store_, gpio::INTERRUPT_ANY_EDGE); + this->trigger_close_pin_->attach_interrupt(RATGDOStore::isrDoorClose, &this->store_, gpio::INTERRUPT_ANY_EDGE); + this->trigger_light_pin_->attach_interrupt(RATGDOStore::isrLight, &this->store_, gpio::INTERRUPT_ANY_EDGE); + this->input_obst_pin_->attach_interrupt(RATGDOStore::isrObstruction, &this->store_, gpio::INTERRUPT_ANY_EDGE); + + ESP_LOGD(TAG, "Syncing rolling code counter after reboot..."); + sync(); // if rolling codes are being used (rolling code counter > 0), send + // reboot/sync to the opener on startup + } - this->output_gdo_pin_->setup(); - this->input_gdo_pin_->setup(); - this->input_obst_pin_->setup(); - - this->trigger_open_pin_->setup(); - this->trigger_close_pin_->setup(); - this->trigger_light_pin_->setup(); - - this->status_door_pin_->setup(); - this->status_obst_pin_->setup(); - - this->store_.input_obst = this->input_obst_pin_->to_isr(); - - this->store_.trigger_open = this->trigger_open_pin_->to_isr(); - this->store_.trigger_close = this->trigger_close_pin_->to_isr(); - this->store_.trigger_light = this->trigger_light_pin_->to_isr(); - - this->trigger_open_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->trigger_close_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->trigger_light_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - - this->status_door_pin_->pin_mode(gpio::FLAG_OUTPUT); - this->status_obst_pin_->pin_mode(gpio::FLAG_OUTPUT); - - //this->output_gdo_pin_->pin_mode(gpio::FLAG_OUTPUT); - //this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); - this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT); - - this->swSerial.begin(9600, SWSERIAL_8N1, this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin(), true); - - this->trigger_open_pin_->attach_interrupt(RATGDOStore::isrDoorOpen, &this->store_, gpio::INTERRUPT_ANY_EDGE); - this->trigger_close_pin_->attach_interrupt(RATGDOStore::isrDoorClose, &this->store_, gpio::INTERRUPT_ANY_EDGE); - this->trigger_light_pin_->attach_interrupt(RATGDOStore::isrLight, &this->store_, gpio::INTERRUPT_ANY_EDGE); - this->input_obst_pin_->attach_interrupt(RATGDOStore::isrObstruction, &this->store_, gpio::INTERRUPT_ANY_EDGE); - - ESP_LOGD(TAG, "Syncing rolling code counter after reboot..."); - sync(); // if rolling codes are being used (rolling code counter > 0), send - // reboot/sync to the opener on startup - - } - - void RATGDOComponent::loop() - { - ESP_LOGD(TAG, "loop rollingCodeCounter: %d", this->rollingCodeCounter); - obstructionLoop(); - gdoStateLoop(); - dryContactLoop(); - statusUpdateLoop(); - //ESP_LOGD(TAG, "Door State: %s", this->doorState.c_str()); - } - - void RATGDOComponent::readRollingCode(uint8_t &door, uint8_t &light, uint8_t &lock, uint8_t &motion, uint8_t &obstruction){ - 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; - - decode_wireline(this->rxRollingCode, &rolling, &fixed, &data); - - cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); - - nibble = (data >> 8) & 0xf; - byte1 = (data >> 16) & 0xff; - byte2 = (data >> 24) & 0xff; - - if(cmd == 0x81){ - door = nibble; - light = (byte2 >> 1) & 1; - lock = byte2 & 1; - motion = 0; // when the status message is read, reset motion state to 0|clear - // obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction - - }else if(cmd == 0x281){ - light ^= 1; // toggle bit - }else if(cmd == 0x84){ - }else if(cmd == 0x285){ - motion = 1; // toggle bit + void loop() + { + ESP_LOGD(TAG, "loop rollingCodeCounter: %d", this->rollingCodeCounter); + obstructionLoop(); + gdoStateLoop(); + dryContactLoop(); + statusUpdateLoop(); + //ESP_LOGD(TAG, "Door State: %s", this->doorState.c_str()); } - } - void RATGDOComponent::getRollingCode(const char* command) - { + void readRollingCode(uint8_t &door, uint8_t &light, uint8_t &lock, uint8_t &motion, uint8_t &obstruction){ + uint32_t rolling = 0; + uint64_t fixed = 0; + uint32_t data = 0; - uint64_t id = 0x539; - uint64_t fixed = 0; - uint32_t data = 0; + uint16_t cmd = 0; + uint8_t nibble = 0; + uint8_t byte1 = 0; + uint8_t byte2 = 0; - if(strcmp(command,"reboot1") == 0){ - fixed = 0x400000000; - data = 0x0000618b; - }else if(strcmp(command,"reboot2") == 0){ - fixed = 0; - data = 0x01009080; - }else if(strcmp(command,"reboot3") == 0){ - fixed = 0; - data = 0x0000b1a0; - }else if(strcmp(command,"reboot4") == 0){ - fixed = 0; - data = 0x01009080; - }else if(strcmp(command,"reboot5") == 0){ - fixed = 0x300000000; - data = 0x00008092; - }else if(strcmp(command,"reboot6") == 0){ - fixed = 0x300000000; - data = 0x00008092; - }else if(strcmp(command,"door1") == 0){ - fixed = 0x200000000; - data = 0x01018280; - }else if(strcmp(command,"door2") == 0){ - fixed = 0x200000000; - data = 0x01009280; - }else if(strcmp(command,"light") == 0){ - fixed = 0x200000000; - data = 0x00009281; - }else if(strcmp(command,"lock") == 0){ - fixed = 0x0100000000; - data = 0x0000728c; - } else { - ESP_LOGD(TAG, "ERROR: Invalid command"); + decode_wireline(this->rxRollingCode, &rolling, &fixed, &data); + + cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); + + nibble = (data >> 8) & 0xf; + byte1 = (data >> 16) & 0xff; + byte2 = (data >> 24) & 0xff; + + if(cmd == 0x81){ + door = nibble; + light = (byte2 >> 1) & 1; + lock = byte2 & 1; + motion = 0; // when the status message is read, reset motion state to 0|clear + // obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction + + }else if(cmd == 0x281){ + light ^= 1; // toggle bit + }else if(cmd == 0x84){ + }else if(cmd == 0x285){ + motion = 1; // toggle bit + } + } + + void getRollingCode(const char* command) + { + + uint64_t id = 0x539; + uint64_t fixed = 0; + uint32_t data = 0; + + if(strcmp(command,"reboot1") == 0){ + fixed = 0x400000000; + data = 0x0000618b; + }else if(strcmp(command,"reboot2") == 0){ + fixed = 0; + data = 0x01009080; + }else if(strcmp(command,"reboot3") == 0){ + fixed = 0; + data = 0x0000b1a0; + }else if(strcmp(command,"reboot4") == 0){ + fixed = 0; + data = 0x01009080; + }else if(strcmp(command,"reboot5") == 0){ + fixed = 0x300000000; + data = 0x00008092; + }else if(strcmp(command,"reboot6") == 0){ + fixed = 0x300000000; + data = 0x00008092; + }else if(strcmp(command,"door1") == 0){ + fixed = 0x200000000; + data = 0x01018280; + }else if(strcmp(command,"door2") == 0){ + fixed = 0x200000000; + data = 0x01009280; + }else if(strcmp(command,"light") == 0){ + fixed = 0x200000000; + data = 0x00009281; + }else if(strcmp(command,"lock") == 0){ + fixed = 0x0100000000; + data = 0x0000728c; + } else { + ESP_LOGD(TAG, "ERROR: Invalid command"); + return; + } + + fixed = fixed | id; + + encode_wireline(this->rollingCodeCounter, fixed, data, this->txRollingCode); + + printRollingCode(); + + if (strcmp(command, "door1") != 0) { // door2 is created with same counter and should always be called after door1 + this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff; + } return; } - fixed = fixed | id; - - encode_wireline(this->rollingCodeCounter, fixed, data, this->txRollingCode); - - printRollingCode(); - - if (strcmp(command, "door1") != 0) { // door2 is created with same counter and should always be called after door1 - this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff; - } - return; - } - - void RATGDOComponent::printRollingCode() - { - for (int i = 0; i < CODE_LENGTH; i++) { - if (this->txRollingCode[i] <= 0x0f) - ESP_LOGD(TAG, "0"); - ESP_LOGD(TAG, "%x", this->txRollingCode[i]); - } - } - - // handle changes to the dry contact state - void RATGDOComponent::dryContactLoop() - { - if (this->store_.dryContactDoorOpen) { - ESP_LOGD(TAG, "Dry Contact: open the door"); - this->store_.dryContactDoorOpen = false; - openDoor(); + void printRollingCode() + { + for (int i = 0; i < CODE_LENGTH; i++) { + if (this->txRollingCode[i] <= 0x0f) + ESP_LOGD(TAG, "0"); + ESP_LOGD(TAG, "%x", this->txRollingCode[i]); + } } - if (this->store_.dryContactDoorClose) { - ESP_LOGD(TAG, "Dry Contact: close the door"); - this->store_.dryContactDoorClose = false; - closeDoor(); + // handle changes to the dry contact state + void dryContactLoop() + { + if (this->store_.dryContactDoorOpen) { + ESP_LOGD(TAG, "Dry Contact: open the door"); + this->store_.dryContactDoorOpen = false; + openDoor(); + } + + if (this->store_.dryContactDoorClose) { + ESP_LOGD(TAG, "Dry Contact: close the door"); + this->store_.dryContactDoorClose = false; + closeDoor(); + } + + if (this->store_.dryContactToggleLight) { + ESP_LOGD(TAG, "Dry Contact: toggle the light"); + this->store_.dryContactToggleLight = false; + toggleLight(); + } } - if (this->store_.dryContactToggleLight) { - ESP_LOGD(TAG, "Dry Contact: toggle the light"); - this->store_.dryContactToggleLight = false; - toggleLight(); + /*************************** OBSTRUCTION DETECTION ***************************/ + void 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->store_.obstructionState = 1; + + // 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->store_.obstructionState = 0; + // obstructionDetected(); + }else{ + // asleep + } + } + + lastMillis = currentMillis; + this->store_.obstructionLowCount = 0; + } } - } - /*************************** OBSTRUCTION DETECTION ***************************/ + void gdoStateLoop(){ + if(!this->swSerial.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 = this->swSerial.read(); + static uint32_t msgStart; + static bool reading = false; + static uint16_t byteCount = 0; - void RATGDOComponent::obstructionLoop() - { - long currentMillis = millis(); - static unsigned long lastMillis = 0; + if(!reading){ + // shift serial byte onto msg start + msgStart <<= 8; + msgStart |= serData; - // 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 + // truncate to 3 bytes + msgStart &= 0x00FFFFFF; - // 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 + // 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; - // 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->store_.obstructionState = 1; - - // 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->store_.obstructionState = 0; - // obstructionDetected(); - }else{ - // asleep + reading = true; + return; } } - lastMillis = currentMillis; - this->store_.obstructionLowCount = 0; + if(reading){ + this->rxRollingCode[byteCount] = serData; + byteCount++; + + if(byteCount == 19){ + reading = false; + msgStart = 0; + byteCount = 0; + + readRollingCode(this->store_.doorState, this->store_.lightState, this->store_.lockState, this->store_.motionState, this->store_.obstructionState); + } + } } - } - void RATGDOComponent::gdoStateLoop(){ - if(!this->swSerial.available()) { - //ESP_LOGD(TAG, "No data available input:%d output:%d", this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin()); - return; + + void statusUpdateLoop(){ + // initialize to unknown + static uint8_t previousDoorState = 0; + static uint8_t previousLightState = 2; + static uint8_t previousLockState = 2; + static uint8_t previousObstructionState = 2; + + if(this->store_.doorState != previousDoorState) sendDoorStatus(); + if(this->store_.lightState != previousLightState) sendLightStatus(); + if(this->store_.lockState != previousLockState) sendLockStatus(); + if(this->store_.obstructionState != previousObstructionState) sendObstructionStatus(); + + if(this->store_.motionState == 1){ + sendMotionStatus(); + this->store_.motionState = 0; + } + + previousDoorState = this->store_.doorState; + previousLightState = this->store_.lightState; + previousLockState = this->store_.lockState; + previousObstructionState = this->store_.obstructionState; } - uint8_t serData = this->swSerial.read(); - static uint32_t msgStart; - static bool reading = false; - static uint16_t byteCount = 0; + void sendDoorStatus(){ + ESP_LOGD(TAG, "Door state %d", this->store_.doorState); + this->status_door_pin_->digital_write(this->store_.doorState == 1); + } - if(!reading){ - // shift serial byte onto msg start - msgStart <<= 8; - msgStart |= serData; + void sendLightStatus(){ + ESP_LOGD(TAG, "Light state %d", this->store_.lightState); + } - // truncate to 3 bytes - msgStart &= 0x00FFFFFF; + void sendLockStatus(){ + ESP_LOGD(TAG, "Lock state %d", this->store_.lockState); + } - // 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; + void sendMotionStatus(){ + ESP_LOGD(TAG, "Motion state %d", this->store_.motionState); + this->store_.motionState = 0; // reset motion state + } - reading = true; + void sendObstructionStatus(){ + ESP_LOGD(TAG, "Obstruction state %d", this->store_.obstructionState); + this->status_obst_pin_->digital_write(this->store_.obstructionState == 0); + } + + /************************* 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 transmit(const unsigned char * payload) + { + 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->swSerial.write(payload, CODE_LENGTH); + } + + void sync() + { + getRollingCode("reboot1"); + transmit(this->txRollingCode); + delay(65); + + getRollingCode("reboot2"); + transmit(this->txRollingCode); + delay(65); + + getRollingCode("reboot3"); + transmit(this->txRollingCode); + delay(65); + + getRollingCode("reboot4"); + transmit(this->txRollingCode); + delay(65); + + getRollingCode("reboot5"); + transmit(this->txRollingCode); + delay(65); + + getRollingCode("reboot6"); + transmit(this->txRollingCode); + delay(65); + + this->pref_.save(&this->rollingCodeCounter); + } + + void openDoor() + { + if(this->doorStates[this->store_.doorState] == "open" || doorStates[this->store_.doorState] == "opening"){ + ESP_LOGD(TAG, "The door is already %s", this->doorStates[this->store_.doorState]); return; } + toggleDoor(); } - if(reading){ - this->rxRollingCode[byteCount] = serData; - byteCount++; + void closeDoor() + { + if(this->doorStates[this->store_.doorState] == "closed" || doorStates[this->store_.doorState] == "closing"){ + ESP_LOGD(TAG, "The door is already %s", this->doorStates[this->store_.doorState]); + return; + } + toggleDoor(); + } - if(byteCount == 19){ - reading = false; - msgStart = 0; - byteCount = 0; - - readRollingCode(this->store_.doorState, this->store_.lightState, this->store_.lockState, this->store_.motionState, this->store_.obstructionState); + void stopDoor(){ + if(this->doorStates[this->store_.doorState] == "opening" || doorStates[this->store_.doorState] == "closing"){ + toggleDoor(); + }else{ + Serial.print("The door is not moving."); } } - } - - void RATGDOComponent::statusUpdateLoop(){ - // initialize to unknown - static uint8_t previousDoorState = 0; - static uint8_t previousLightState = 2; - static uint8_t previousLockState = 2; - static uint8_t previousObstructionState = 2; - - if(this->store_.doorState != previousDoorState) sendDoorStatus(); - if(this->store_.lightState != previousLightState) sendLightStatus(); - if(this->store_.lockState != previousLockState) sendLockStatus(); - if(this->store_.obstructionState != previousObstructionState) sendObstructionStatus(); - - if(this->store_.motionState == 1){ - sendMotionStatus(); - this->store_.motionState = 0; + void toggleDoor() + { + getRollingCode("door1"); + transmit(this->txRollingCode); + delay(40); + getRollingCode("door2"); + transmit(this->txRollingCode); + this->pref_.save(&this->rollingCodeCounter); + } - previousDoorState = this->store_.doorState; - previousLightState = this->store_.lightState; - previousLockState = this->store_.lockState; - previousObstructionState = this->store_.obstructionState; - } - - void RATGDOComponent::sendDoorStatus(){ - ESP_LOGD(TAG, "Door state %d", this->store_.doorState); - this->status_door_pin_->digital_write(this->store_.doorState == 1); - } - - void RATGDOComponent::sendLightStatus(){ - ESP_LOGD(TAG, "Light state %d", this->store_.lightState); - } - - void RATGDOComponent::sendLockStatus(){ - ESP_LOGD(TAG, "Lock state %d", this->store_.lockState); - } - - void RATGDOComponent::sendMotionStatus(){ - ESP_LOGD(TAG, "Motion state %d", this->store_.motionState); - this->store_.motionState = 0; // reset motion state - } - - void RATGDOComponent::sendObstructionStatus(){ - ESP_LOGD(TAG, "Obstruction state %d", this->store_.obstructionState); - this->status_obst_pin_->digital_write(this->store_.obstructionState == 0); - } - - /************************* 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(const unsigned char * payload) - { - 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->swSerial.write(payload, CODE_LENGTH); - } - - void RATGDOComponent::sync() - { - getRollingCode("reboot1"); - transmit(this->txRollingCode); - delay(65); - - getRollingCode("reboot2"); - transmit(this->txRollingCode); - delay(65); - - getRollingCode("reboot3"); - transmit(this->txRollingCode); - delay(65); - - getRollingCode("reboot4"); - transmit(this->txRollingCode); - delay(65); - - getRollingCode("reboot5"); - transmit(this->txRollingCode); - delay(65); - - getRollingCode("reboot6"); - transmit(this->txRollingCode); - delay(65); - - this->pref_.save(&this->rollingCodeCounter); - } - - void RATGDOComponent::openDoor() - { - if(this->doorStates[this->store_.doorState] == "open" || doorStates[this->store_.doorState] == "opening"){ - ESP_LOGD(TAG, "The door is already %s", this->doorStates[this->store_.doorState]); - return; + void lightOn(){ + if(this->lightStates[this->store_.lightState] == "on"){ + ESP_LOGD(TAG, "already on"); + }else{ + toggleLight(); + } } - toggleDoor(); - } - void RATGDOComponent::closeDoor() - { - if(this->doorStates[this->store_.doorState] == "closed" || doorStates[this->store_.doorState] == "closing"){ - ESP_LOGD(TAG, "The door is already %s", this->doorStates[this->store_.doorState]); - return; + void lightOff(){ + if(this->lightStates[this->store_.lightState] == "off"){ + ESP_LOGD(TAG, "already off"); + }else{ + toggleLight(); + } } - toggleDoor(); - } - void RATGDOComponent::stopDoor(){ - if(this->doorStates[this->store_.doorState] == "opening" || doorStates[this->store_.doorState] == "closing"){ - toggleDoor(); - }else{ - Serial.print("The door is not moving."); + void toggleLight(){ + sendCommand("light"); + } + + // Lock functions + void lock(){ + if(this->lockStates[this->store_.lockState] == "locked"){ + ESP_LOGD(TAG, "already locked"); + }else{ + toggleLock(); + } + } + + void unlock(){ + if(this->lockStates[this->store_.lockState] == "unlocked"){ + ESP_LOGD(TAG, "already unlocked"); + }else{ + toggleLock(); + } + } + + void toggleLock(){ + sendCommand("lock"); + } + + void sendCommand(const char* command){ + getRollingCode(command); + transmit(this->txRollingCode); + this->pref_.save(&this->rollingCodeCounter); } } - - void RATGDOComponent::toggleDoor() - { - getRollingCode("door1"); - transmit(this->txRollingCode); - delay(40); - getRollingCode("door2"); - transmit(this->txRollingCode); - this->pref_.save(&this->rollingCodeCounter); - - } - - void RATGDOComponent::lightOn(){ - if(this->lightStates[this->store_.lightState] == "on"){ - ESP_LOGD(TAG, "already on"); - }else{ - toggleLight(); - } - } - - void RATGDOComponent::lightOff(){ - if(this->lightStates[this->store_.lightState] == "off"){ - ESP_LOGD(TAG, "already off"); - }else{ - toggleLight(); - } - } - - void RATGDOComponent::toggleLight(){ - sendCommand("light"); - } - - // Lock functions - void RATGDOComponent::lock(){ - if(this->lockStates[this->store_.lockState] == "locked"){ - ESP_LOGD(TAG, "already locked"); - }else{ - toggleLock(); - } - } - - void RATGDOComponent::unlock(){ - if(this->lockStates[this->store_.lockState] == "unlocked"){ - ESP_LOGD(TAG, "already unlocked"); - }else{ - toggleLock(); - } - } - - void RATGDOComponent::toggleLock(){ - sendCommand("lock"); - } - - void RATGDOComponent::sendCommand(const char* command){ - getRollingCode(command); - transmit(this->txRollingCode); - this->pref_.save(&this->rollingCodeCounter); - } - } // namespace ratgdo } // namespace esphome