Remove obstruction detection using the obstruction signal and use flag provided by opener

This commit is contained in:
Marius Muja 2023-06-24 22:35:26 -07:00
parent 49487afde1
commit f0b8380fa5
6 changed files with 36 additions and 80 deletions

View File

@ -10,7 +10,6 @@ ratgdo:
id: ${id_prefix} id: ${id_prefix}
input_gdo_pin: ${uart_rx_pin} input_gdo_pin: ${uart_rx_pin}
output_gdo_pin: ${uart_tx_pin} output_gdo_pin: ${uart_tx_pin}
input_obst_pin: ${input_obst_pin}
remote_id: 0x539 remote_id: 0x539
sensor: sensor:

View File

@ -19,8 +19,6 @@ CONF_INPUT_GDO = "input_gdo_pin"
DEFAULT_INPUT_GDO = ( DEFAULT_INPUT_GDO = (
"D2" # D2 red control terminal / GarageDoorOpener (UART1 RX) pin is D2 on D1 Mini "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" CONF_REMOTE_ID = "remote_id"
DEFAULT_REMOTE_ID = 0x539 DEFAULT_REMOTE_ID = 0x539
@ -36,9 +34,6 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional( cv.Optional(
CONF_INPUT_GDO, default=DEFAULT_INPUT_GDO CONF_INPUT_GDO, default=DEFAULT_INPUT_GDO
): pins.gpio_input_pin_schema, ): pins.gpio_input_pin_schema,
cv.Optional(
CONF_INPUT_OBST, default=DEFAULT_INPUT_OBST
): pins.gpio_input_pin_schema,
cv.Optional( cv.Optional(
CONF_REMOTE_ID, default=DEFAULT_REMOTE_ID CONF_REMOTE_ID, default=DEFAULT_REMOTE_ID
): cv.uint64_t, ): cv.uint64_t,
@ -64,8 +59,6 @@ async def to_code(config):
cg.add(var.set_output_gdo_pin(pin)) cg.add(var.set_output_gdo_pin(pin))
pin = await cg.gpio_pin_expression(config[CONF_INPUT_GDO]) pin = await cg.gpio_pin_expression(config[CONF_INPUT_GDO])
cg.add(var.set_input_gdo_pin(pin)) 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(var.set_remote_id(config[CONF_REMOTE_ID]))
cg.add_library( cg.add_library(

View File

@ -25,15 +25,6 @@ namespace ratgdo {
static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 3; static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 3;
static const uint32_t FLASH_WRITE_INTERVAL = 10000; 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() void RATGDOComponent::setup()
{ {
this->pref_ = global_preferences->make_preference<int>(734874333U); this->pref_ = global_preferences->make_preference<int>(734874333U);
@ -43,18 +34,12 @@ namespace ratgdo {
this->output_gdo_pin_->setup(); this->output_gdo_pin_->setup();
this->input_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->output_gdo_pin_->pin_mode(gpio::FLAG_OUTPUT);
this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); 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->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 // save counter to flash every 10s if it changed
set_interval(FLASH_WRITE_INTERVAL, std::bind(&RATGDOComponent::saveCounter, this, 1)); set_interval(FLASH_WRITE_INTERVAL, std::bind(&RATGDOComponent::saveCounter, this, 1));
@ -66,7 +51,6 @@ namespace ratgdo {
void RATGDOComponent::loop() void RATGDOComponent::loop()
{ {
obstructionLoop();
gdoStateLoop(); gdoStateLoop();
statusUpdateLoop(); statusUpdateLoop();
} }
@ -76,7 +60,6 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, "Setting up RATGDO..."); ESP_LOGCONFIG(TAG, "Setting up RATGDO...");
LOG_PIN(" Output GDO Pin: ", this->output_gdo_pin_); LOG_PIN(" Output GDO Pin: ", this->output_gdo_pin_);
LOG_PIN(" Input GDO Pin: ", this->input_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, " Rolling Code Counter: %d", this->rollingCodeCounter);
ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id); ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id);
} }
@ -133,6 +116,8 @@ namespace ratgdo {
uint16_t RATGDOComponent::readRollingCode() uint16_t RATGDOComponent::readRollingCode()
{ {
static bool have_obstruction_status_retry = false;
uint32_t rolling = 0; uint32_t rolling = 0;
uint64_t fixed = 0; uint64_t fixed = 0;
uint32_t data = 0; uint32_t data = 0;
@ -171,11 +156,39 @@ namespace ratgdo {
this->lockState = static_cast<LockState>(byte2 & 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->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->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); this->obstructionState = ((byte2 >> 2) & 1) == 1 ? ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED : ObstructionState::OBSTRUCTION_STATE_CLEAR;
ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", 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), door_state_to_string(this->doorState),
light_state_to_string(this->lightState), 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) { } else if (cmd == command::LIGHT) {
if (nibble == 0) { if (nibble == 0) {
this->lightState = LightState::LIGHT_STATE_OFF; this->lightState = LightState::LIGHT_STATE_OFF;
@ -272,42 +285,6 @@ namespace ratgdo {
this->txRollingCode[18]); 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() void RATGDOComponent::gdoStateLoop()
{ {
static bool reading_msg = false; static bool reading_msg = false;

View File

@ -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 { class RATGDOComponent : public Component {
public: public:
void setup() override; void setup() override;
@ -124,6 +115,8 @@ namespace ratgdo {
uint16_t previousOpenings { 0 }; // number of times the door has been opened uint16_t previousOpenings { 0 }; // number of times the door has been opened
uint16_t openings { 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 previousDoorState { DoorState::DOOR_STATE_UNKNOWN };
DoorState doorState { 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_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_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 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 /********************************** FUNCTION DECLARATION
@ -157,7 +149,6 @@ namespace ratgdo {
void sync(); void sync();
void gdoStateLoop(); void gdoStateLoop();
void obstructionLoop();
void statusUpdateLoop(); void statusUpdateLoop();
void saveCounter(int threshold); void saveCounter(int threshold);
@ -176,7 +167,7 @@ namespace ratgdo {
void toggleLock(); void toggleLock();
void lock(); void lock();
void unlock(); void unlock();
void query_status(); void query_status();
void query_openings(); void query_openings();
@ -195,11 +186,9 @@ namespace ratgdo {
std::vector<RATGDOClient*> children_; std::vector<RATGDOClient*> children_;
bool rollingCodeUpdatesEnabled_ { true }; bool rollingCodeUpdatesEnabled_ { true };
bool forceUpdate_ { false }; bool forceUpdate_ { false };
RATGDOStore store_ {};
InternalGPIOPin* output_gdo_pin_; InternalGPIOPin* output_gdo_pin_;
InternalGPIOPin* input_gdo_pin_; InternalGPIOPin* input_gdo_pin_;
InternalGPIOPin* input_obst_pin_;
uint64_t remote_id; uint64_t remote_id;
}; // RATGDOComponent }; // RATGDOComponent

View File

@ -4,7 +4,6 @@ substitutions:
friendly_name: "RATGDOv2" friendly_name: "RATGDOv2"
uart_tx_pin: D4 uart_tx_pin: D4
uart_rx_pin: D2 uart_rx_pin: D2
input_obst_pin: D7
status_door_pin: D0 status_door_pin: D0
status_obstruction_pin: D8 status_obstruction_pin: D8
dry_contact_open_pin: D5 dry_contact_open_pin: D5

View File

@ -4,7 +4,6 @@ substitutions:
friendly_name: "ratgdov2" friendly_name: "ratgdov2"
uart_tx_pin: D4 uart_tx_pin: D4
uart_rx_pin: D2 uart_rx_pin: D2
input_obst_pin: D7
status_door_pin: D0 status_door_pin: D0
status_obstruction_pin: D8 status_obstruction_pin: D8
dry_contact_open_pin: D5 dry_contact_open_pin: D5