fix
This commit is contained in:
parent
74b7f08551
commit
c1c7f16769
|
@ -34,6 +34,109 @@ namespace ratgdo {
|
|||
static const unsigned char LIGHT_CODE[] = { 0x55, 0x01, 0x00, 0x94, 0x3f, 0xef, 0xbc, 0xfb, 0x7f, 0xbe,
|
||||
0xff, 0xa6, 0x1a, 0x4d, 0xa6, 0xda, 0x8d, 0x76, 0xb1 };
|
||||
|
||||
|
||||
|
||||
/*************************** DRY CONTACT CONTROL OF LIGHT & DOOR
|
||||
* ***************************/
|
||||
void IRAM_ATTR HOT RATGDOStore::isrDoorOpen(RATGDOStore *arg) {
|
||||
unsigned long currentMillis = millis();
|
||||
// Prevent ISR during the first 2 seconds after reboot
|
||||
if (currentMillis < 2000)
|
||||
return;
|
||||
|
||||
if (!arg->trigger_open.digital_read()) {
|
||||
// save the time of the falling edge
|
||||
arg->lastOpenDoorTime = currentMillis;
|
||||
} else if (currentMillis - arg->lastOpenDoorTime > 500 && currentMillis - arg->lastOpenDoorTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
arg->dryContactDoorOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT RATGDOStore::isrDoorClose(RATGDOStore *arg) {
|
||||
unsigned long currentMillis = millis();
|
||||
// Prevent ISR during the first 2 seconds after reboot
|
||||
if (currentMillis < 2000)
|
||||
return;
|
||||
|
||||
if (!this->trigger_close.digital_read()) {
|
||||
// save the time of the falling edge
|
||||
arg->lastCloseDoorTime = currentMillis;
|
||||
} else if (currentMillis - arg->lastCloseDoorTime > 500 && currentMillis - arg->lastCloseDoorTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
arg->dryContactDoorClose = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT RATGDOStore::isrLight(RATGDOStore *arg) {
|
||||
unsigned long currentMillis = millis();
|
||||
// Prevent ISR during the first 2 seconds after reboot
|
||||
if (currentMillis < 2000)
|
||||
return;
|
||||
|
||||
if (!arg->trigger_light.digital_read()) {
|
||||
// save the time of the falling edge
|
||||
arg->lastToggleLightTime = currentMillis;
|
||||
} else if (currentMillis - arg->lastToggleLightTime > 500 && currentMillis - arg->lastToggleLightTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
arg->dryContactToggleLight = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire on RISING edge of RPM1
|
||||
void IRAM_ATTR HOT RATGDOStore::isrRPM1(RATGDOStore *arg) { arg->rpm1Pulsed = true; }
|
||||
|
||||
// Fire on RISING edge of RPM2
|
||||
// When RPM1 HIGH on RPM2 rising edge, door closing:
|
||||
// RPM1: __|--|___
|
||||
// RPM2: ___|--|__
|
||||
|
||||
// When RPM1 LOW on RPM2 rising edge, door opening:
|
||||
// RPM1: ___|--|__
|
||||
// RPM2: __|--|___
|
||||
void IRAM_ATTR HOT RATGDOStore::isrRPM2(RATGDOStore *arg)
|
||||
{
|
||||
// The encoder updates faster than the ESP wants to process, so by sampling
|
||||
// every 5ms we get a more reliable curve The counter is behind the actual
|
||||
// pulse counter, but it doesn't matter since we only need a reliable linear
|
||||
// counter to determine the door direction
|
||||
if (millis() - arg->lastPulse < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In rare situations, the rotary encoder can be parked so that RPM2
|
||||
// continuously fires this ISR. This causes the door counter to change value
|
||||
// even though the door isn't moving To solve this, check to see if RPM1
|
||||
// pulsed. If not, do nothing. If yes, reset the pulsed flag
|
||||
if (arg->rpm1Pulsed) {
|
||||
arg->rpm1Pulsed = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
arg->lastPulse = millis();
|
||||
|
||||
// If the RPM1 state is different from the RPM2 state, then the door is
|
||||
// opening
|
||||
if (arg->input_rpm1.digital_read()) {
|
||||
arg->doorPositionCounter--;
|
||||
} else {
|
||||
arg->doorPositionCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR HOT RATGDOStore::isrObstruction()
|
||||
{
|
||||
if (this->input_obst.digital_read()) {
|
||||
arg->lastObstructionHigh = millis();
|
||||
} else {
|
||||
this->obstructionLowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void RATGDOComponent::setup()
|
||||
{
|
||||
this->pref_ = global_preferences->make_preference<int>(734874333U);
|
||||
|
@ -42,13 +145,21 @@ namespace ratgdo {
|
|||
}
|
||||
|
||||
this->output_gdo_pin_->setup();
|
||||
this->store_.output_gdo = this->output_gdo_pin_->to_isr();
|
||||
this->trigger_open_pin_->setup();
|
||||
this->store_.trigger_open = this->trigger_open_pin_->to_isr();
|
||||
this->trigger_close_pin_->setup();
|
||||
this->store_.trigger_close = this->trigger_close_pin_->to_isr();
|
||||
this->trigger_light_pin_->setup();
|
||||
this->store_.trigger_light = this->trigger_light_pin_->to_isr();
|
||||
this->status_door_pin_->setup();
|
||||
this->store_.status_door = this->status_door_pin_->to_isr();
|
||||
this->status_obst_pin_->setup();
|
||||
this->store_.status_obst = this->status_obst_pin_->to_isr();
|
||||
this->input_rpm1_pin_->setup();
|
||||
this->store_.input_rpm1 = this->input_rpm1_pin_->to_isr();
|
||||
this->input_rpm2_pin_->setup();
|
||||
this->store_.input_rpm2 = this->input_rpm2_pin_->to_isr();
|
||||
this->input_obst_pin_->setup();
|
||||
|
||||
this->swSerial.begin(9600, SWSERIAL_8N2, -1, this->output_gdo_pin_->get_pin(), true);
|
||||
|
@ -166,12 +277,12 @@ namespace ratgdo {
|
|||
// bounces
|
||||
if (!rotaryEncoderDetected) {
|
||||
if (!this->input_rpm1_pin_->digital_read()) {
|
||||
if (doorState != "reed_closed") {
|
||||
if (this->doorState != "reed_closed") {
|
||||
ESP_LOGD(TAG, "Reed switch closed");
|
||||
this->doorState = "reed_closed";
|
||||
this->status_door_pin_->digital_write(true);
|
||||
}
|
||||
} else if (doorState != "reed_open") {
|
||||
} else if (this->doorState != "reed_open") {
|
||||
ESP_LOGD(TAG, "Reed switch open");
|
||||
this->doorState = "reed_open";
|
||||
this->status_door_pin_->digital_write(false);
|
||||
|
@ -189,7 +300,7 @@ namespace ratgdo {
|
|||
}
|
||||
|
||||
// Wait 5 pulses before updating to door opening status
|
||||
if (doorPositionCounter - lastDirectionChangeCounter > 5) {
|
||||
if (this->doorPositionCounter - lastDirectionChangeCounter > 5) {
|
||||
if (this->doorState != "opening") {
|
||||
ESP_LOGD(TAG, "Door Opening...");
|
||||
}
|
||||
|
@ -225,135 +336,31 @@ namespace ratgdo {
|
|||
lastDoorPositionCounter = doorPositionCounter;
|
||||
}
|
||||
|
||||
/*************************** DRY CONTACT CONTROL OF LIGHT & DOOR
|
||||
* ***************************/
|
||||
void IRAM_ATTR RATGDOComponent::isrDebounce(const char* type)
|
||||
{
|
||||
static unsigned long lastOpenDoorTime = 0;
|
||||
static unsigned long lastCloseDoorTime = 0;
|
||||
static unsigned long lastToggleLightTime = 0;
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
// Prevent ISR during the first 2 seconds after reboot
|
||||
if (currentMillis < 2000)
|
||||
return;
|
||||
|
||||
if (strcmp(type, "openDoor") == 0) {
|
||||
if (!this->trigger_open_pin_->digital_read()) {
|
||||
// save the time of the falling edge
|
||||
lastOpenDoorTime = currentMillis;
|
||||
} else if (currentMillis - lastOpenDoorTime > 500 && currentMillis - lastOpenDoorTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
this->dryContactDoorOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(type, "closeDoor") == 0) {
|
||||
if (!this->trigger_close_pin_->digital_read()) {
|
||||
// save the time of the falling edge
|
||||
lastCloseDoorTime = currentMillis;
|
||||
} else if (currentMillis - lastCloseDoorTime > 500 && currentMillis - lastCloseDoorTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
this->dryContactDoorClose = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(type, "toggleLight") == 0) {
|
||||
if (!this->trigger_light_pin_->digital_read()) {
|
||||
// save the time of the falling edge
|
||||
lastToggleLightTime = currentMillis;
|
||||
} else if (currentMillis - lastToggleLightTime > 500 && currentMillis - lastToggleLightTime < 10000) {
|
||||
// now see if the rising edge was between 500ms and 10 seconds after the
|
||||
// falling edge
|
||||
this->dryContactToggleLight = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR RATGDOComponent::isrDoorOpen() { isrDebounce("openDoor"); }
|
||||
|
||||
void IRAM_ATTR RATGDOComponent::isrDoorClose() { isrDebounce("closeDoor"); }
|
||||
|
||||
void IRAM_ATTR RATGDOComponent::isrLight() { isrDebounce("toggleLight"); }
|
||||
|
||||
// Fire on RISING edge of RPM1
|
||||
void IRAM_ATTR RATGDOComponent::isrRPM1() { this->rpm1Pulsed = true; }
|
||||
|
||||
// Fire on RISING edge of RPM2
|
||||
// When RPM1 HIGH on RPM2 rising edge, door closing:
|
||||
// RPM1: __|--|___
|
||||
// RPM2: ___|--|__
|
||||
|
||||
// When RPM1 LOW on RPM2 rising edge, door opening:
|
||||
// RPM1: ___|--|__
|
||||
// RPM2: __|--|___
|
||||
void IRAM_ATTR RATGDOComponent::isrRPM2()
|
||||
{
|
||||
// The encoder updates faster than the ESP wants to process, so by sampling
|
||||
// every 5ms we get a more reliable curve The counter is behind the actual
|
||||
// pulse counter, but it doesn't matter since we only need a reliable linear
|
||||
// counter to determine the door direction
|
||||
static unsigned long lastPulse = 0;
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
if (currentMillis - lastPulse < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In rare situations, the rotary encoder can be parked so that RPM2
|
||||
// continuously fires this ISR. This causes the door counter to change value
|
||||
// even though the door isn't moving To solve this, check to see if RPM1
|
||||
// pulsed. If not, do nothing. If yes, reset the pulsed flag
|
||||
if (this->rpm1Pulsed) {
|
||||
this->rpm1Pulsed = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPulse = millis();
|
||||
|
||||
// If the RPM1 state is different from the RPM2 state, then the door is
|
||||
// opening
|
||||
if (this->input_rpm1_pin_->digital_read()) {
|
||||
this->doorPositionCounter--;
|
||||
} else {
|
||||
this->doorPositionCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
// handle changes to the dry contact state
|
||||
void RATGDOComponent::dryContactLoop()
|
||||
{
|
||||
if (this->dryContactDoorOpen) {
|
||||
if (this->store_.dryContactDoorOpen) {
|
||||
ESP_LOGD(TAG, "Dry Contact: open the door");
|
||||
this->dryContactDoorOpen = false;
|
||||
this->store_.dryContactDoorOpen = false;
|
||||
openDoor();
|
||||
}
|
||||
|
||||
if (this->dryContactDoorClose) {
|
||||
if (this->store_.dryContactDoorClose) {
|
||||
ESP_LOGD(TAG, "Dry Contact: close the door");
|
||||
this->dryContactDoorClose = false;
|
||||
this->store_.dryContactDoorClose = false;
|
||||
closeDoor();
|
||||
}
|
||||
|
||||
if (this->dryContactToggleLight) {
|
||||
if (this->store_.dryContactToggleLight) {
|
||||
ESP_LOGD(TAG, "Dry Contact: toggle the light");
|
||||
this->dryContactToggleLight = false;
|
||||
this->store_.dryContactToggleLight = false;
|
||||
toggleLight();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************** OBSTRUCTION DETECTION ***************************/
|
||||
void IRAM_ATTR RATGDOComponent::isrObstruction()
|
||||
{
|
||||
if (this->input_obst_pin_->digital_read()) {
|
||||
this->lastObstructionHigh = millis();
|
||||
} else {
|
||||
this->obstructionLowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RATGDOComponent::obstructionLoop()
|
||||
{
|
||||
|
|
|
@ -56,6 +56,43 @@ static const uint8_t D10 = 1;
|
|||
namespace esphome {
|
||||
namespace ratgdo {
|
||||
|
||||
class RATGDOComponent;
|
||||
|
||||
struct RATGDOStore {
|
||||
ISRInternalGPIOPin output_gdo;
|
||||
ISRInternalGPIOPin trigger_open;
|
||||
ISRInternalGPIOPin trigger_close;
|
||||
ISRInternalGPIOPin trigger_light;
|
||||
ISRInternalGPIOPin status_door;
|
||||
ISRInternalGPIOPin status_obst;
|
||||
ISRInternalGPIOPin input_rpm1;
|
||||
ISRInternalGPIOPin input_rpm2;
|
||||
ISRInternalGPIOPin input_obst;
|
||||
|
||||
volatile unsigned long lastOpenDoorTime{0};
|
||||
volatile unsigned long lastCloseDoorTime{0};
|
||||
volatile unsigned long lastToggleLightTime{0};
|
||||
volatile unsigned long lastPulse{0};
|
||||
volatile int doorPositionCounter{0}; // calculate the door's movement and position
|
||||
volatile bool rpm1Pulsed{false}; // did rpm1 get a pulse or not - eliminates an issue when the
|
||||
// sensor is parked on a high pulse which fires rpm2 isr
|
||||
|
||||
volatile int obstructionLowCount = 0; // count obstruction low pulses
|
||||
volatile long lastObstructionHigh = 0; // count time between high pulses from the obst ISR
|
||||
|
||||
volatile bool doorIsObstructed{false};
|
||||
volatile bool dryContactDoorOpen{false};
|
||||
volatile bool dryContactDoorClose{false};
|
||||
volatile bool dryContactToggleLight{false};
|
||||
|
||||
static void IRAM_ATTR isrDoorOpen(RATGDOStore *arg);
|
||||
static void IRAM_ATTR isrDoorClose(RATGDOStore *arg);
|
||||
static void IRAM_ATTR isrLight(RATGDOStore *arg);
|
||||
static void IRAM_ATTR isrObstruction(RATGDOStore *arg);
|
||||
static void IRAM_ATTR isrRPM1(RATGDOStore *arg);
|
||||
static void IRAM_ATTR isrRPM2(RATGDOStore *arg);
|
||||
};
|
||||
|
||||
class RATGDOComponent : public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
|
@ -64,22 +101,10 @@ namespace ratgdo {
|
|||
* *****************************************/
|
||||
unsigned int rollingCodeCounter;
|
||||
SoftwareSerial swSerial;
|
||||
byte rollingCode[CODE_LENGTH];
|
||||
unsigned char * rollingCode[CODE_LENGTH];
|
||||
String doorState = "unknown"; // will be
|
||||
// [online|offline|opening|open|closing|closed|obstructed|clear|reed_open|reed_closed]
|
||||
|
||||
unsigned int obstructionLowCount = 0; // count obstruction low pulses
|
||||
unsigned long lastObstructionHigh = 0; // count time between high pulses from the obst ISR
|
||||
|
||||
bool useRollingCodes = true; // use rolling codes or not
|
||||
bool doorIsObstructed = false;
|
||||
bool dryContactDoorOpen = false;
|
||||
bool dryContactDoorClose = false;
|
||||
bool dryContactToggleLight = false;
|
||||
int doorPositionCounter = 0; // calculate the door's movement and position
|
||||
bool rpm1Pulsed = false; // did rpm1 get a pulse or not - eliminates an issue when the
|
||||
// sensor is parked on a high pulse which fires rpm2 isr
|
||||
|
||||
void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; };
|
||||
void set_trigger_open_pin(InternalGPIOPin* pin) { this->trigger_open_pin_ = pin; };
|
||||
void set_trigger_close_pin(InternalGPIOPin* pin) { this->trigger_close_pin_ = pin; };
|
||||
|
@ -110,19 +135,12 @@ namespace ratgdo {
|
|||
void printRollingCode();
|
||||
void getRollingCode(const char* command);
|
||||
|
||||
/********************************** INTERRUPT SERVICE ROUTINES
|
||||
* ***********************************/
|
||||
void IRAM_ATTR isrDebounce(const char* type);
|
||||
void IRAM_ATTR isrDoorOpen();
|
||||
void IRAM_ATTR isrDoorClose();
|
||||
void IRAM_ATTR isrLight();
|
||||
void IRAM_ATTR isrObstruction();
|
||||
void IRAM_ATTR isrRPM1();
|
||||
void IRAM_ATTR isrRPM2();
|
||||
|
||||
protected:
|
||||
ESPPreferenceObject pref_;
|
||||
bool useRollingCodes_;
|
||||
bool useRollingCodes_{true};
|
||||
RATGDOStore store_{};
|
||||
|
||||
InternalGPIOPin* output_gdo_pin_;
|
||||
InternalGPIOPin* trigger_open_pin_;
|
||||
InternalGPIOPin* trigger_close_pin_;
|
||||
|
|
Loading…
Reference in New Issue