diff --git a/base.yaml b/base.yaml index 05a998b..2a0164f 100644 --- a/base.yaml +++ b/base.yaml @@ -10,7 +10,6 @@ ratgdo: id: ${id_prefix} input_gdo_pin: ${uart_rx_pin} output_gdo_pin: ${uart_tx_pin} - input_obst_pin: ${input_obst_pin} remote_id: 0x539 sensor: diff --git a/components/ratgdo/__init__.py b/components/ratgdo/__init__.py index f59ebcb..f4766eb 100644 --- a/components/ratgdo/__init__.py +++ b/components/ratgdo/__init__.py @@ -19,8 +19,6 @@ CONF_INPUT_GDO = "input_gdo_pin" DEFAULT_INPUT_GDO = ( "D2" # D2 red control terminal / GarageDoorOpener (UART1 RX) pin is D2 on D1 Mini ) -CONF_INPUT_OBST = "input_obst_pin" -DEFAULT_INPUT_OBST = "D7" # D7 black obstruction sensor terminal CONF_REMOTE_ID = "remote_id" DEFAULT_REMOTE_ID = 0x539 @@ -36,9 +34,6 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional( CONF_INPUT_GDO, default=DEFAULT_INPUT_GDO ): pins.gpio_input_pin_schema, - cv.Optional( - CONF_INPUT_OBST, default=DEFAULT_INPUT_OBST - ): pins.gpio_input_pin_schema, cv.Optional( CONF_REMOTE_ID, default=DEFAULT_REMOTE_ID ): cv.uint64_t, @@ -64,8 +59,6 @@ async def to_code(config): cg.add(var.set_output_gdo_pin(pin)) pin = await cg.gpio_pin_expression(config[CONF_INPUT_GDO]) cg.add(var.set_input_gdo_pin(pin)) - pin = await cg.gpio_pin_expression(config[CONF_INPUT_OBST]) - cg.add(var.set_input_obst_pin(pin)) cg.add(var.set_remote_id(config[CONF_REMOTE_ID])) cg.add_library( diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 173ba8c..b66ea5a 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -25,15 +25,6 @@ namespace ratgdo { static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 3; static const uint32_t FLASH_WRITE_INTERVAL = 10000; - void IRAM_ATTR HOT RATGDOStore::isrObstruction(RATGDOStore* arg) - { - if (arg->input_obst.digital_read()) { - arg->lastObstructionHigh = millis(); - } else { - arg->obstructionLowCount++; - } - } - void RATGDOComponent::setup() { this->pref_ = global_preferences->make_preference(734874333U); @@ -43,18 +34,12 @@ namespace ratgdo { this->output_gdo_pin_->setup(); this->input_gdo_pin_->setup(); - this->input_obst_pin_->setup(); - - this->store_.input_obst = this->input_obst_pin_->to_isr(); 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->input_obst_pin_->attach_interrupt(RATGDOStore::isrObstruction, &this->store_, gpio::INTERRUPT_ANY_EDGE); - // save counter to flash every 10s if it changed set_interval(FLASH_WRITE_INTERVAL, std::bind(&RATGDOComponent::saveCounter, this, 1)); @@ -66,7 +51,6 @@ namespace ratgdo { void RATGDOComponent::loop() { - obstructionLoop(); gdoStateLoop(); statusUpdateLoop(); } @@ -76,7 +60,6 @@ namespace ratgdo { ESP_LOGCONFIG(TAG, "Setting up RATGDO..."); LOG_PIN(" Output GDO Pin: ", this->output_gdo_pin_); LOG_PIN(" Input GDO Pin: ", this->input_gdo_pin_); - LOG_PIN(" Input Obstruction Pin: ", this->input_obst_pin_); ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", this->rollingCodeCounter); ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id); } @@ -133,6 +116,8 @@ namespace ratgdo { uint16_t RATGDOComponent::readRollingCode() { + static bool have_obstruction_status_retry = false; + uint32_t rolling = 0; uint64_t fixed = 0; uint32_t data = 0; @@ -171,11 +156,39 @@ namespace ratgdo { 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 - // this->obstructionState = static_cast((byte1 >> 6) & 1); - ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", + this->obstructionState = ((byte2 >> 2) & 1) == 1 ? ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED : ObstructionState::OBSTRUCTION_STATE_CLEAR; + uint8_t motorEnabled = (byte1 >> 6) & 1; // motor enabled? bit that gets cleared about 4s after an obstruction and is set after the obstruction clears + + if (motorEnabled && !this->motorEnabled) { + // if motor is enabled after having been disabled, clear obstruction flag + this->obstructionState = ObstructionState::OBSTRUCTION_STATE_CLEAR; + } + this->motorEnabled = motorEnabled; + + if (this->obstructionState == ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED) { + // no status sent when onstruction is cleared, + // query status with back-off until obstruction is cleared + if (!have_obstruction_status_retry) { + set_retry("obstruction_status", 1000, 100, [=] (uint8_t call){ + ESP_LOGD(TAG, "Get obstruction status: %d", call); + transmit(command::GET_STATUS); + return RetryResult::RETRY; + }, 1.5); + have_obstruction_status_retry = true; + } + } else { + if (have_obstruction_status_retry) { + ESP_LOGD(TAG, "Cancel get obstruction status"); + cancel_retry("obstruction_status"); + have_obstruction_status_retry = false; + } + } + + ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s obstruction=%s", door_state_to_string(this->doorState), light_state_to_string(this->lightState), - lock_state_to_string(this->lockState)); + lock_state_to_string(this->lockState), + obstruction_state_to_string(this->obstructionState)); } else if (cmd == command::LIGHT) { if (nibble == 0) { this->lightState = LightState::LIGHT_STATE_OFF; @@ -272,42 +285,6 @@ namespace ratgdo { 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 bool reading_msg = false; diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index e47fd86..fd72b44 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -98,15 +98,6 @@ namespace ratgdo { }; } - struct RATGDOStore { - ISRInternalGPIOPin input_obst; - - int obstructionLowCount = 0; // count obstruction low pulses - long lastObstructionHigh = 0; // count time between high pulses from the obst ISR - - static void IRAM_ATTR HOT isrObstruction(RATGDOStore* arg); - }; - class RATGDOComponent : public Component { public: void setup() override; @@ -124,6 +115,8 @@ namespace ratgdo { 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 motorEnabled { 1 }; + DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; DoorState doorState { DoorState::DOOR_STATE_UNKNOWN }; @@ -147,7 +140,6 @@ namespace ratgdo { void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; }; void set_input_gdo_pin(InternalGPIOPin* pin) { this->input_gdo_pin_ = pin; }; - void set_input_obst_pin(InternalGPIOPin* pin) { this->input_obst_pin_ = pin; }; void set_remote_id(uint64_t remote_id) { this->remote_id = remote_id & 0xffffff; }; // not sure how large remote_id can be, assuming not more than 24 bits /********************************** FUNCTION DECLARATION @@ -157,7 +149,6 @@ namespace ratgdo { void sync(); void gdoStateLoop(); - void obstructionLoop(); void statusUpdateLoop(); void saveCounter(int threshold); @@ -176,7 +167,7 @@ namespace ratgdo { void toggleLock(); void lock(); void unlock(); - + void query_status(); void query_openings(); @@ -195,11 +186,9 @@ namespace ratgdo { std::vector children_; bool rollingCodeUpdatesEnabled_ { true }; bool forceUpdate_ { false }; - RATGDOStore store_ {}; InternalGPIOPin* output_gdo_pin_; InternalGPIOPin* input_gdo_pin_; - InternalGPIOPin* input_obst_pin_; uint64_t remote_id; }; // RATGDOComponent diff --git a/static/v2board_esp32_d1_mini.yaml b/static/v2board_esp32_d1_mini.yaml index 70199b0..d23c169 100644 --- a/static/v2board_esp32_d1_mini.yaml +++ b/static/v2board_esp32_d1_mini.yaml @@ -4,7 +4,6 @@ substitutions: friendly_name: "RATGDOv2" uart_tx_pin: D4 uart_rx_pin: D2 - input_obst_pin: D7 status_door_pin: D0 status_obstruction_pin: D8 dry_contact_open_pin: D5 diff --git a/static/v2board_esp8266_d1_mini_lite.yaml b/static/v2board_esp8266_d1_mini_lite.yaml index 939c174..3e67d55 100644 --- a/static/v2board_esp8266_d1_mini_lite.yaml +++ b/static/v2board_esp8266_d1_mini_lite.yaml @@ -4,7 +4,6 @@ substitutions: friendly_name: "ratgdov2" uart_tx_pin: D4 uart_rx_pin: D2 - input_obst_pin: D7 status_door_pin: D0 status_obstruction_pin: D8 dry_contact_open_pin: D5