Need help with ESP32 project: standalone database write worked, but code fails when all sensors are connected

Hi everyone,

I’m working on a project for school/college where I’m building a “smart box” integrated with a database and a mobile app.

The main idea of the system is to interact seamlessly with the database:

Marcador It reads data/instructions from the database.

Marcador It detects events using sensors and writes those detection logs back to the database.

Marcador The mobile app communicates through this database to monitor and interact with the box.

The Issue:

I did an isolated test earlier where the ESP connected directly to the database and successfully recorded data by itself (without sensor input). However, when I connect all the sensors together and run the full code, it stops working completely and throws errors.

I’ve already checked and double-checked all the wiring/hardware setup. I also asked all my professors, but unfortunately, no one has been able to figure out what’s causing the issue.

Below is the code I’m currently using. Could anyone take a look and point out what might be going wrong or help me troubleshoot this?

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <FirebaseJson.h>
#include <time.h>
#include <string.h>
#include “secrets.h”

#ifndef WIFI_SSID
#define WIFI_SSID “”
#endif

#ifndef WIFI_PASSWORD
#define WIFI_PASSWORD “”
#endif

// REMOVED HTTPS URL TO PREVENT NEW USER LINK LIMITATION
#define DATABASE_URL “YOUR_FIREBASE_URL_HERE”

constexpr int PIN_IR = 5;
constexpr int PIN_SOS = 27;
constexpr int PIN_BUZZER = 18;
constexpr int PIN_REED = 4;
constexpr int PIN_SDA = 21;
constexpr int PIN_SCL = 22;

constexpr int IR_DETECTED_LEVEL = HIGH;
constexpr int SOS_ACTIVE_LEVEL = LOW;

constexpr unsigned long ROUTINE_CHECK_MS = 15000;
constexpr unsigned long HEARTBEAT_INTERVAL_MS = 60000;
constexpr unsigned long WIFI_RETRY_INTERVAL_MS = 10000;
constexpr unsigned long EVENT_RETRY_INTERVAL_MS = 5000;
constexpr unsigned long BUZZER_STEP_MS = 250;
constexpr unsigned long DEBOUNCE_MS = 50;

LiquidCrystal_I2C lcd(0x27, 16, 2);

const String medicinesPath = “/cuidaPlus/medicamentos”;
const String historyPath = “/cuidaPlus/historico”;
const String sosPath = “/cuidaPlus/sos”;
const String deviceStatusPath = “/cuidaPlus/status”;

String medicineId;
String medicineName;
String scheduledTime;
String scheduledDate;
String lastCheckedMinute;
String pendingSosEventId;
String pendingSosTimestamp;
String doseEventId;

WiFiClientSecure secureClient;

bool alarmActive = false;
bool lidWasOpened = false;
bool handDetectedAfterOpening = false;
bool lidIsClosed = true;
bool lastButtonReading = false;
bool stableButtonState = false;
bool handStateInitialized = false;
bool lastHandSent = false;
bool sosPending = false;
bool firebaseReadyAnnounced = false;
bool firebaseConfigValid = false;

unsigned long lastRoutineCheck = 0;
unsigned long lastHeartbeat = 0;
unsigned long nextWifiRetry = 0;
unsigned long nextEventRetry = 0;
unsigned long lastBuzzerStep = 0;
unsigned long lastDoseRetry = 0;
unsigned long lastButtonChange = 0;

uint8_t buzzerStep = 0;

const bool ACTIVE_BUZZER_PATTERN = {true, false, true, false, true, false, false, false};

String twoDigits(int value) {
return value < 10 ? “0” + String(value) : String(value);
}

bool firebaseRequest(const String &method, const String &path, const String &payload, String &response) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println(“Wi-Fi desconectado.”);
return false;
}

HTTPClient http;
String url = String(DATABASE_URL) + path + “.json”;

secureClient.setInsecure();

if (!http.begin(secureClient, url)) {
Serial.println(“Falha ao iniciar HTTP.”);
return false;
}

http.addHeader(“Content-Type”, “application/json”);

int httpCode = -1;

if (method == “GET”) {
httpCode = http.GET();
} else if (method == “PUT”) {
httpCode = http.PUT(payload);
} else {
http.end();
return false;
}

if (httpCode > 0) {
response = http.getString();
Serial.printf(“Firebase HTTP: %d\n”, httpCode);
} else {
Serial.printf(“Erro HTTP: %s\n”, http.errorToString(httpCode).c_str());
}

http.end();

return httpCode >= 200 && httpCode < 300;
}

bool firebaseRead(const String &path, String &response) {
return firebaseRequest(“GET”, path, “”, response);
}

bool firebaseWrite(const String &path, const String &json) {
String response;
return firebaseRequest(“PUT”, path, json, response);
}

String jsonString(const String &value) {
String result = “”";

for (size_t i = 0; i < value.length(); i++) {
char c = value[i];
if (c == ‘"’) result += “\”";
else if (c == ‘\’) result += “\\”;
else if (c == ‘\n’) result += “\n”;
else if (c == ‘\r’) result += “\r”;
else if (c == ‘\t’) result += “\t”;
else result += c;
}

result += “”";
return result;
}

bool firebaseWriteString(const String &path, const String &value) {
return firebaseWrite(path, jsonString(value));
}

bool getDateTime(String &date, String &timeText) {
struct tm info;
if (!getLocalTime(&info, 100)) return false;

date = String(info.tm_year + 1900) + “-” + twoDigits(info.tm_mon + 1) + “-” + twoDigits(info.tm_mday);
timeText = twoDigits(info.tm_hour) + “:” + twoDigits(info.tm_min);

return true;
}

String timestampNow() {
struct tm info;
if (!getLocalTime(&info, 100)) return “”;

char timestamp[80];
snprintf(timestamp, sizeof(timestamp), “%04d-%02d-%02dT%02d:%02d:%02d-03:00”,
info.tm_year + 1900, info.tm_mon + 1, info.tm_mday,
info.tm_hour, info.tm_min, info.tm_sec);

return String(timestamp);
}

String newEventId() {
return String(static_cast<uint32_t>(ESP.getEfuseMac() >> 32), HEX) + “_” + String(millis(), HEX);
}

bool writeDeviceStatus(const String &state) {
FirebaseJson status;
status.set(“online”, true);
status.set(“lastSeen”, static_cast(time(nullptr)) * 1000.0);
status.set(“state”, state);
status.set(“wifiRssi”, WiFi.RSSI());

if (medicineId.length()) status.set(“medicineId”, medicineId);
if (medicineName.length()) status.set(“medicineName”, medicineName);

String json;
status.toString(json, true);

if (!firebaseWrite(deviceStatusPath, json)) {
Serial.println(“Erro ao gravar status do dispositivo.”);
return false;
}

return true;
}

bool writeEvent(const String &collection, const String &eventId, const String &title, const String &type, const String &eventTimestamp, const String &subtitle = “”) {
if (eventTimestamp.length() == 0) return false;

FirebaseJson event;
event.set(“timestamp”, eventTimestamp);
event.set(“date”, eventTimestamp.substring(0, 10));
event.set(“title”, title);
event.set(“type”, type);
event.set(“source”, “esp32”);
event.set(“eventId”, eventId);

if (subtitle.length()) event.set(“subtitle”, subtitle);

String json;
event.toString(json, true);

String path = collection == “sos” ? sosPath : historyPath;

if (!firebaseWrite(path + “/” + eventId, json)) {
Serial.printf(“Erro ao gravar evento: %s\n”, collection.c_str());
return false;
}

return true;
}

bool writeSosEvent(const String &eventId, const String &eventTimestamp) {
const String title = “SOS do dispositivo”;
bool sosSaved = writeEvent(“sos”, eventId, title, “warning”, eventTimestamp);
bool historySaved = writeEvent(“historico”, eventId, title, “warning”, eventTimestamp, “Alerta enviado pelo botão SOS do ESP32.”);
bool statusSaved = writeDeviceStatus(“sos”);

return sosSaved && historySaved && statusSaved;
}

String currentDeviceState() {
if (!alarmActive) return “online”;
if (lidWasOpened && handDetectedAfterOpening && !lidIsClosed) return “ir_detected”;
if (lidWasOpened && !lidIsClosed) return “lid_open”;
return “reminder”;
}

void showDisplay() {
lcd.clear();
if (alarmActive) {
lcd.setCursor(0, 0);
lcd.print(“HORA REMEDIO”);
lcd.setCursor(0, 1);
String line = medicineName;
if (line.length() > 16) line = line.substring(0, 16);
lcd.print(line);
} else {
lcd.setCursor(0, 0);
lcd.print(“Cuida conectado”);
lcd.setCursor(0, 1);
lcd.print(“Aguardando hora”);
}
}

void startReminder(const String &name, const String &date, const String &timeText) {
medicineName = name;
scheduledDate = date;
scheduledTime = timeText;
doseEventId = newEventId();

alarmActive = true;
lidWasOpened = false;
handDetectedAfterOpening = false;

buzzerStep = 0;
lastBuzzerStep = millis();

writeDeviceStatus(“reminder”);
showDisplay();

Serial.printf(“Lembrete: %s - %s %s\n”, medicineName.c_str(), scheduledDate.c_str(), scheduledTime.c_str());
}

void checkRoutine() {
if (WiFi.status() != WL_CONNECTED || alarmActive) return;

String date, timeText;
if (!getDateTime(date, timeText)) return;

String minuteKey = date + " " + timeText;
if (minuteKey == lastCheckedMinute) return;

String response;
if (!firebaseRead(medicinesPath, response)) {
Serial.println(“Erro ao ler medicamentos.”);
return;
}

lastCheckedMinute = minuteKey;

FirebaseJson medicines;
medicines.setJsonData(response);

size_t count = medicines.iteratorBegin();
FirebaseJson::IteratorValue entry;

for (size_t index = 0; index < count; index++) {
entry = medicines.valueAt(index);
if (entry.type != FirebaseJson::JSON_OBJECT) continue;

FirebaseJson medication;
medication.setJsonData(entry.value);

FirebaseJsonData value;
medication.get(value, "time");
String medicineTime = value.success ? value.stringValue : "";

medication.get(value, "name");
String name = value.success ? value.stringValue : "";

medication.get(value, "status");
String status = value.success ? value.stringValue : "";

medication.get(value, "lastTakenDate");
String lastTakenDate = value.success ? value.stringValue : "";

bool due = status == "Pendente" || (status == "Tomado" && lastTakenDate != date);

if (medicineTime != timeText || name.length() == 0 || !due || lastTakenDate == date) {
  continue;
}

medicineId = entry.key;
medicines.iteratorEnd();
startReminder(name, date, timeText);
return;

}

medicines.iteratorEnd();
}

void confirmMedicationInteraction() {
if (WiFi.status() != WL_CONNECTED || !alarmActive || millis() - lastDoseRetry < EVENT_RETRY_INTERVAL_MS) {
return;
}

lastDoseRetry = millis();
const String takenAt = timestampNow();
if (takenAt.length() == 0) return;

const String medicationPath = medicinesPath + “/” + medicineId;

bool statusOk = firebaseWriteString(medicationPath + “/status”, “Tomado”);
bool takenAtOk = firebaseWriteString(medicationPath + “/lastTakenAt”, takenAt);
bool dateOk = firebaseWriteString(medicationPath + “/lastTakenDate”, scheduledDate);

String timing = “on_time”;
String takenTime = takenAt.substring(11, 16);
if (takenTime > scheduledTime) timing = “late”;

FirebaseJson event;
event.set(“date”, scheduledDate);
event.set(“timestamp”, takenAt);
event.set(“title”, medicineName + " confirmado");
event.set(“subtitle”, “Confirmado pelo ESP32”);
event.set(“type”, “success”);
event.set(“timing”, timing);
event.set(“scheduledTime”, scheduledTime);
event.set(“medicineId”, medicineId);
event.set(“medicineName”, medicineName);
event.set(“source”, “esp32”);
event.set(“eventId”, doseEventId);

String eventJson;
event.toString(eventJson, true);

bool historyOk = firebaseWrite(historyPath + “/” + doseEventId, eventJson);

if (statusOk && takenAtOk && dateOk && historyOk) {
alarmActive = false;
lidWasOpened = false;
handDetectedAfterOpening = false;
medicineId = “”;
doseEventId = “”;

writeDeviceStatus("dose_taken");
showDisplay();
Serial.println("Medicamento confirmado no Firebase.");

} else {
Serial.println(“Falha ao registrar a tomada. Tentarei novamente.”);
}
}

void retryPendingSos() {
if (!sosPending || WiFi.status() != WL_CONNECTED || millis() < nextEventRetry) return;

nextEventRetry = millis() + EVENT_RETRY_INTERVAL_MS;

if (pendingSosTimestamp.length() == 0) {
pendingSosTimestamp = timestampNow();
if (pendingSosTimestamp.length() == 0) {
Serial.println(“SOS aguardando horario NTP.”);
return;
}
}

if (writeSosEvent(pendingSosEventId, pendingSosTimestamp)) {
sosPending = false;
Serial.println(“SOS gravado no Firebase.”);
}
}

void checkSensors() {
bool closedNow = digitalRead(PIN_REED) == LOW;
bool handNow = digitalRead(PIN_IR) == IR_DETECTED_LEVEL;

if (closedNow != lidIsClosed) {
lidIsClosed = closedNow;
if (alarmActive && !closedNow) {
lidWasOpened = true;
handDetectedAfterOpening = false;
Serial.println(“Tampa aberta.”);
writeDeviceStatus(“lid_open”);
} else if (closedNow) {
writeDeviceStatus(alarmActive ? “reminder” : “online”);
}
}

if (!handStateInitialized) {
lastHandSent = handNow;
handStateInitialized = true;
} else if (handNow != lastHandSent) {
lastHandSent = handNow;
}

if (alarmActive && lidWasOpened && !lidIsClosed && handNow && !handDetectedAfterOpening) {
handDetectedAfterOpening = true;
Serial.println(“Sensor IR detectou retirada.”);
writeDeviceStatus(“ir_detected”);
}

if (alarmActive && lidWasOpened && handDetectedAfterOpening && lidIsClosed) {
confirmMedicationInteraction();
}

bool buttonReading = digitalRead(PIN_SOS) == SOS_ACTIVE_LEVEL;

if (buttonReading != lastButtonReading) {
lastButtonChange = millis();
lastButtonReading = buttonReading;
}

if (millis() - lastButtonChange >= DEBOUNCE_MS && buttonReading != stableButtonState) {
stableButtonState = buttonReading;
if (stableButtonState) {
pendingSosEventId = newEventId();
pendingSosTimestamp = timestampNow();
sosPending = true;
Serial.println(“Botao SOS pressionado.”);
}
}
}

void handleBuzzer() {
if (!alarmActive) {
digitalWrite(PIN_BUZZER, LOW);
return;
}

if (millis() - lastBuzzerStep >= BUZZER_STEP_MS) {
lastBuzzerStep = millis();
buzzerStep = (buzzerStep + 1) % (sizeof(ACTIVE_BUZZER_PATTERN) / sizeof(ACTIVE_BUZZER_PATTERN[0]));
}

digitalWrite(PIN_BUZZER, ACTIVE_BUZZER_PATTERN[buzzerStep] ? HIGH : LOW);
}

void setup() {
Serial.begin(115200);

pinMode(PIN_IR, INPUT);
pinMode(PIN_SOS, INPUT_PULLUP);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_REED, INPUT_PULLUP);

stableButtonState = digitalRead(PIN_SOS) == SOS_ACTIVE_LEVEL;
lastButtonReading = stableButtonState;
lastButtonChange = millis();

digitalWrite(PIN_BUZZER, LOW);

Wire.begin(PIN_SDA, PIN_SCL);

lcd.init();
lcd.backlight();
lcd.print(“Iniciando Cuida”);

firebaseConfigValid = strlen(WIFI_SSID) > 0 && strlen(WIFI_PASSWORD) > 0;

if (!firebaseConfigValid) {
Serial.println(“Configure Wi-Fi em secrets.h.”);
lcd.clear();
lcd.print(“Configurar Wi-Fi”);
lcd.setCursor(0, 1);
lcd.print(“secrets.h”);
return;
}

WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

configTzTime(“BRT3”, “pool.ntp.org”, “time.google.com”);

lidIsClosed = digitalRead(PIN_REED) == LOW;
showDisplay();

Serial.println(“Cuida+ iniciado.”);
Serial.println(“Firebase sera acessado pelo caminho /cuidaPlus.”);
}

void loop() {
if (!firebaseConfigValid) {
delay(1000);
return;
}

if (WiFi.status() != WL_CONNECTED && millis() >= nextWifiRetry) {
nextWifiRetry = millis() + WIFI_RETRY_INTERVAL_MS;
Serial.println(“Tentando reconectar ao Wi-Fi.”);
WiFi.reconnect();
}

bool connected = WiFi.status() == WL_CONNECTED;

if (connected && !firebaseReadyAnnounced) {
firebaseReadyAnnounced = true;
Serial.println(“Wi-Fi conectado.”);
Serial.println(“Acessando Firebase pelo REST.”);
writeDeviceStatus(currentDeviceState());
lastHeartbeat = millis();
}

if (!connected && firebaseReadyAnnounced) {
firebaseReadyAnnounced = false;
Serial.println(“Wi-Fi desconectado.”);
}

if (connected) {
retryPendingSos();
if (millis() - lastHeartbeat >= HEARTBEAT_INTERVAL_MS) {
lastHeartbeat = millis();
writeDeviceStatus(currentDeviceState());
}
}

checkSensors();
handleBuzzer();

if (millis() - lastRoutineCheck >= ROUTINE_CHECK_MS) {
lastRoutineCheck = millis();
checkRoutine();
}

delay(20);
}

Thanks in advance for any help or guidance!

Could you please provide details on the following points? This information is essential for understanding the situation.

  1. What is the exact model number of the ESP32 chip or development board you are using?
  2. Could you share the contents of your platformio.ini file? (This is very important information.)
  3. Regarding the statement, “it stops working completely and throws errors”:
  • Could you provide more context? What exactly happens when it “stops working completely”?
  • What specific errors are occurring? (Please include the exact error messages, as well as information on which component is reporting the error and to whom it is being reported.)
  1. Have you tried having an AI proficient in code analysis examine the code you provided?
    If there are any logical contradictions that could lead to a deadlock, an AI skilled in code analysis (such as Claude) might be able to identify them.
  2. Is this related to your other post (ESP32 + PlatformIO: Upload succeeds but Serial Monitor cannot open port (COM4) + Firebase stopped working - #6 by ito_giken)?