Hi,
I have built a simple circuit to upgrade my standard doorbell to send a MQTT message when it is rung. It takes an 18v AC voltage that is sent when the doorbell is pressed, drops the voltage, sends it via a diode and then to an optocoupler then on to an ESP32 board. I am fairly sure (but I could be wrong) that the hardware side is fine but I have an issue with the software I have written.
The doorbell works wonderfully, but about every 24 hours (could be more frequent) it locks up and required me to restart the ESP board, it then continues to work fine.
I have worked around this by using a watchdog interrupt which reboots the board if it cannot loop for more than 6 seconds. This is not ideal as it is not getting to the heart of the problem, I was wondering if anyone can help me understand why this maybe locking up and what I can do to resolve this.
Thank you.
Schematic
Here is the schematic for the hardware, (the Wemos D1 mini is an ESP32 dev board now but the schematic is effectively the same).
Environment
It sits above a consumer unit (switch board) I don't know if that would have any impact.
Programming Environment
I am using PlatformIO inside VS Code on a Mac with the latest official ESP32 library.
Code
Here is the main.cpp, showing the code that handles the interrupts and the door press. I also pull in some standard files i use to setup Wifi, OTA and MQTT. I have not included these but can do if needed (these are almost identical to my other projects that are working fine).
#include <Arduino.h>
#include <config.h>
#include <connections.h>
#include "esp_system.h"
config cfg;
const int wdtTimeout = 6000; //time in ms to trigger the watchdog
hw_timer_t *timer = NULL;
void IRAM_ATTR resetModule() {
ets_printf("watchdog reboot\n");
esp_restart();
}
const unsigned long debounceInterval = 1000;
unsigned long currentTime;
struct Doorbell{
const uint8_t PIN;
bool pressed;
unsigned long lastRung;
};
Doorbell frontDoor = {34, false, 0};
void IRAM_ATTR rintEvent(){
if(currentTime - frontDoor.lastRung >= debounceInterval){
frontDoor.pressed = true;
frontDoor.lastRung = currentTime;
}
}
void setup() {
pinMode(frontDoor.PIN, INPUT);
attachInterrupt(frontDoor.PIN, rintEvent, FALLING);
Serial.begin(115200);
cfg.load();
setupWiFi(cfg);
setupOTA(cfg);
setupMQTT(cfg);
timer = timerBegin(0, 80, true); //timer 0, div 80
timerAttachInterrupt(timer, &resetModule, true); //attach callback
timerAlarmWrite(timer, wdtTimeout * 1000, false); //set time in us
timerAlarmEnable(timer); //enable interrupt
}
void loop() {
timerWrite(timer, 0); //reset timer (feed watchdog)
currentTime = millis();
ArduinoOTA.handle();
if (!MQTTclient.connected())
{
connectMQTT(cfg);
}
if(frontDoor.pressed){
Serial.println("RING");
publishDoorbellRing(cfg);
frontDoor.pressed = false;
}
MQTTclient.loop();
}
Code - Without Watchdog
Here is a code version (as requested) without the watchdog code.
#include <Arduino.h>
#include <config.h>
#include <connections.h>
config cfg;
const unsigned long debounceInterval = 1000;
unsigned long currentTime;
struct Doorbell{
const uint8_t PIN;
bool pressed;
unsigned long lastRung;
};
Doorbell frontDoor = {34, false, 0};
void IRAM_ATTR rintEvent(){
if(currentTime - frontDoor.lastRung >= debounceInterval){
frontDoor.pressed = true;
frontDoor.lastRung = currentTime;
}
}
void setup() {
pinMode(frontDoor.PIN, INPUT);
attachInterrupt(frontDoor.PIN, rintEvent, FALLING);
Serial.begin(115200);
cfg.load(); //Load config (from SPIFS) and create config class
setupWiFi(cfg); //WiFi Setup
setupOTA(cfg); //OTA Setup
setupMQTT(cfg); //MQTT Setup
}
void loop() {
currentTime = millis();
ArduinoOTA.handle();
if (!MQTTclient.connected())
{
connectMQTT(cfg);
}
if(frontDoor.pressed){
Serial.println("RING");
publishDoorbellRing(cfg);
frontDoor.pressed = false;
}
MQTTclient.loop();
}
