Ir al contenido

← Sincronizar el RTC del PLC ESP32 desde un smartphone por BLE

Piso móvil hidráulico (app BLE)ESP32 PLC 38RBLEInfraestructura

Sincronizar el RTC del PLC ESP32 desde un smartphone por BLE — ejemplo completo

Pon en hora el reloj del PLC ESP32 desde un smartphone por Bluetooth LE, sin NTP ni internet. Ejemplo Arduino con trama de timestamp y settimeofday.

Programa completo y ejecutable para el ESP32 PLC 38R (rtc-sync-over-ble-38r.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 — RTC synchronization from the mobile app (BLE)
 *
 * Hardware:  ESP32 PLC 38R (Industrial Shields)
 * Based on:  hydraulic moving floor project, AppLink.cpp ([D] command)
 *
 * Wiring: none — BLE only. The PLC advertises a Nordic UART service.
 *
 * Logic:
 *   - The equipment works without internet (mobile machine): NTP is not
 *     an option.
 *   - The smartphone DOES have the correct time, so the app sends it on
 *     connect with the [D]timestamp_ms* frame (Unix epoch in milliseconds).
 *   - The PLC sets its clock with settimeofday(); from then on events
 *     and logs carry the real date/time.
 *   - To test without the app: nRF Connect -> write "[D]1765532800000*"
 *     to the RX characteristic.
 *
 * Integration with other catalog modules:
 *   - Same BLE UART server as the equipment control
 *     (see ejemplos/piso-movil/ble-mobile-app-control-38r.ino).
 *   - The synchronized time makes it possible to timestamp the counters
 *     persisted in NVS (see ejemplos/piso-movil/nvs-persistent-counters-38r.ino).
 */

#include 
#include 
#include 
#include 
#include 

#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHAR_RX_UUID "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHAR_TX_UUID "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

BLECharacteristic *txChar;
bool deviceConnected = false;
bool rtcSynced = false;

// Sets the ESP32 internal clock from an epoch in milliseconds
void setRTC(uint64_t epochMs) {
  struct timeval tv;
  tv.tv_sec  = (time_t)(epochMs / 1000ULL);
  tv.tv_usec = (suseconds_t)((epochMs % 1000ULL) * 1000ULL);
  settimeofday(&tv, NULL);
  rtcSynced = true;
  Serial.println("RTC synchronized from the mobile app");
}

class ServerCB : public BLEServerCallbacks {
  void onConnect(BLEServer *s)    { deviceConnected = true; }
  void onDisconnect(BLEServer *s) { deviceConnected = false; s->startAdvertising(); }
};

class RxCB : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *c) {
    String cmd = String(c->getValue().c_str());   // e.g. "[D]1765532800000*"
    if (cmd.startsWith("[D]")) {
      int end = cmd.indexOf('*');
      if (end > 3) {
        // strtoull because the epoch in ms does not fit in a 32-bit int
        uint64_t epochMs = strtoull(cmd.substring(3, end).c_str(), NULL, 10);
        if (epochMs > 1600000000000ULL) {         // sanity check: > year 2020
          setRTC(epochMs);
        }
      }
    }
  }
};

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

  BLEDevice::init("PLC-HIDRAULICO");
  BLEServer *server = BLEDevice::createServer();
  server->setCallbacks(new ServerCB());

  BLEService *svc = server->createService(SERVICE_UUID);
  txChar = svc->createCharacteristic(CHAR_TX_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  txChar->addDescriptor(new BLE2902());
  BLECharacteristic *rxChar =
      svc->createCharacteristic(CHAR_RX_UUID, BLECharacteristic::PROPERTY_WRITE);
  rxChar->setCallbacks(new RxCB());

  svc->start();
  server->getAdvertising()->start();
  Serial.println("BLE advertising. Waiting for [D]timestamp_ms* frame ...");
}

void loop() {
  // Every 5 s print the PLC time (and notify it if an app is connected)
  static uint32_t tLast = 0;
  if (millis() - tLast > 5000) {
    tLast = millis();

    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    char buf[32];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", t);

    String line = String(rtcSynced ? "[RTC OK] " : "[RTC NOT SYNCED] ") + buf;
    Serial.println(line);

    if (deviceConnected) {
      txChar->setValue(line.c_str());
      txChar->notify();
    }
  }

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