Ir al contenido

← Datalogging en SD con ficheros diarios en un PLC ESP32

Monitorización textil (tejeduría)ESP32 PLCSDDatalogging

Datalogging en SD con ficheros diarios en un PLC ESP32 — ejemplo completo

Datalogging en tarjeta SD en un PLC ESP32 con un fichero JSON por día: nombres por RTC, remontaje en caliente, búfer offline y recuperación de datos pendientes.

Programa completo y ejecutable para el ESP32 PLC (sd-daily-file-datalogging.ino): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

/*
 * COMPLETE EXAMPLE — SD datalogging with daily file and offline buffering
 *
 * Hardware: ESP32 PLC (Industrial Shields, with microSD slot + RTC)
 * Based on: textile monitoring project, modul_SD.h
 *
 * Wiring / hardware:
 *   microSD  formatted FAT32, in the PLC slot
 *   RTC      integrated chip of the PLC (valid time even without network)
 *
 * Offline-first architecture:
 *   1. Every JSON message is appended to /YYYY-MM-DD.json (one file per day)
 *   2. The file name comes from the hardware RTC -> automatic rotation
 *      at midnight without extra logic
 *   3. The SD write ALWAYS happens before the network send: if MQTT
 *      or WiFi go down, the data stays on the card
 *   4. Inventory function that lists the pending files so the HTTP
 *      upload module can recover them later
 *
 * Works together with other catalog examples:
 *   - rtc-ntp-synchronization.ino (correct time for the file names)
 *   - sd-file-upload-http-post.ino (recovery)
 *   - mqtt-events-sd-buffering.ino (source of the messages)
 */

#include 
#include           // integrated RTC of the PLC (Industrial Shields library)

const int PLC_ID = 1;

bool sdAvailable = false;
uint32_t tDemo = 0;
uint32_t demoCounter = 0;

// ------------------------------------------------- Daily file name
// The RTC rules: without a valid time, data goes to a fallback file
String dailyFileName() {
  if (!RTC.read()) return "/error_date.json";
  char n[20];
  sprintf(n, "/%04d-%02d-%02d.json", RTC.getYear(), RTC.getMonth(), RTC.getMonthDay());
  return String(n);
}

// ------------------------------------------------- Append write
// Returns true if the record was persisted; the caller decides whether to retry
bool saveToSD(const String &json) {
  if (!sdAvailable) {
    sdAvailable = SD.begin();         // hot remount retry
    if (!sdAvailable) return false;
  }
  File f = SD.open(dailyFileName(), FILE_APPEND);
  if (!f) { sdAvailable = false; return false; }
  f.println(json);
  f.close();
  return true;
}

// ------------------------------------------------- History inventory
// Lists the .json files in the root: this is what the MQTT "list" command
// returns and what the HTTP upload module walks to recover pending days
void listFiles() {
  File root = SD.open("/");
  if (!root) return;
  Serial.println("--- Files on SD ---");
  File f = root.openNextFile();
  while (f) {
    if (!f.isDirectory() && String(f.name()).endsWith(".json")) {
      Serial.print(f.name());
      Serial.print("  ");
      Serial.print(f.size());
      Serial.println(" bytes");
    }
    f = root.openNextFile();
  }
  root.close();
}

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

  RTC.begin();                        // in production: synchronized via NTP
  sdAvailable = SD.begin();
  Serial.println(sdAvailable ? "SD mounted" : "SD NOT available");

  listFiles();                        // which days are still pending upload
}

void loop() {
  // Demo: generate one record every 5 s, like the production snapshot would
  if (millis() - tDemo >= 5000) {
    tDemo = millis();
    demoCounter++;

    String json = "{\"id\":" + String(PLC_ID) +
                  ",\"ts\":" + String(RTC.getTime()) +
                  ",\"sample\":" + String(demoCounter) + "}";

    if (saveToSD(json)) {
      Serial.println("OK  -> " + dailyFileName() + " : " + json);
    } else {
      Serial.println("SD FAILURE (check card): " + json);
      // In production the message is also attempted over MQTT, so that
      // SD and network cover each other (two-way offline-first)
    }
  }

  delay(20);
}
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales