Remove obstruction detection using the obstruction signal and use flag provided by opener
This commit is contained in:
parent
49487afde1
commit
f0b8380fa5
|
@ -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:
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue