Integración con MCU

Descripción general

VBatPower acepta datos de telemetría desde cualquier dispositivo capaz de realizar peticiones HTTP POST. El formato de datos es intencionadamente simple: un CSV plano que se puede generar con printf en cualquier MCU de 8 bits.

El flujo típico:

  1. Crea un proyecto en la aplicación VBatPower
  2. Genera una clave de API en Ajustes > API
  3. Envía telemetría desde tu MCU a POST /api/v1/telemetry
  4. Visualiza gráficos y análisis en la aplicación

Arduino / ESP32

Usando el cliente HTTP por WiFi para enviar datos de telemetría:

// Global state
uint32_t nonce = 0;
uint32_t runid = 1;

// Read sensors and send data
void sendTelemetry() {
    float batteryV = analogRead(VBAT_PIN) * 3.3 / 4095.0 * 2.0;
    float currentMA = readINA219();
    uint32_t elapsed = millis();
    nonce++;

    String json = "{\"records\":[";
    // Battery voltage (type: v = value measurement)
    json += "{\"id\":\"0\",\"type\":\"v\",\"value\":";
    json += String(batteryV, 3);
    json += ",\"unit\":\"V\",\"nonce\":";
    json += String(nonce);
    json += ",\"runid\":";
    json += String(runid);
    json += "},";
    // State execution duration (type: t = telemetry timing)
    json += "{\"id\":\"0.0.0\",\"type\":\"t\",\"value\":";
    json += String(500);  // execution duration in ms
    json += ",\"unit\":\"ms\",\"nonce\":";
    json += String(nonce);
    json += ",\"runid\":";
    json += String(runid);
    json += "},";
    // Current draw (type: v = value measurement)
    json += "{\"id\":\"0.0.0\",\"type\":\"v\",\"value\":";
    json += String(currentMA, 2);
    json += ",\"unit\":\"mA\",\"nonce\":";
    json += String(nonce);
    json += ",\"runid\":";
    json += String(runid);
    json += "},";
    // Elapsed time from boot (type: n = elapsed-time measurement)
    json += "{\"id\":\"0.0.0\",\"type\":\"n\",\"value\":";
    json += String(elapsed);
    json += ",\"unit\":\"ms\",\"nonce\":";
    json += String(nonce);
    json += ",\"runid\":";
    json += String(runid);
    json += "}]}";

    HTTPClient http;
    http.begin("https://api.vbatpower.com/api/v1/telemetry");
    http.addHeader("Content-Type", "application/json");
    http.addHeader("Authorization", "Bearer " + String(API_KEY));
    int code = http.POST(json);
    http.end();
}

STM32 (bare metal / HAL)

Para STM32 con un módulo UART-a-WiFi (comandos AT de ESP8266) o Ethernet, formatea la carga útil JSON con snprintf:

char buf[512];
int len = snprintf(buf, sizeof(buf),
    "{\"records\":["
    "{\"id\":\"0.0.0\",\"type\":\"t\","
    "\"value\":%lu,\"unit\":\"ms\","
    "\"nonce\":%lu,\"runid\":%lu},"
    "{\"id\":\"0.0.0\",\"type\":\"v\","
    "\"value\":%.2f,\"unit\":\"mA\","
    "\"nonce\":%lu,\"runid\":%lu},"
    "{\"id\":\"0.0.0\",\"type\":\"n\","
    "\"value\":%lu,\"unit\":\"ms\","
    "\"nonce\":%lu,\"runid\":%lu}"
    "]}",
    exec_duration_ms, nonce, runid,
    current_ma, nonce, runid,
    HAL_GetTick(), nonce, runid
);

Envía buf como cuerpo de la petición HTTP POST a /api/v1/telemetry con las cabeceras Content-Type: application/json y Authorization: Bearer your-key.

Recolección sin conexión

Si tu MCU carece de conectividad de red, registra los datos en una tarjeta SD o por serial en formato CSV:

// Print CSV to Serial or SD file
void logSample(uint32_t nonce, uint32_t runid) {
    float vbat = readBattery();
    float current = readCurrent();
    uint32_t elapsed = millis();

    Serial.printf("0,v,%.3f,V,%lu,%lu\n", vbat, nonce, runid);
    Serial.printf("0.0.0,t,500,ms,%lu,%lu\n", nonce, runid);
    Serial.printf("0.0.0,v,%.2f,mA,%lu,%lu\n", current, nonce, runid);
    Serial.printf("0.0.0,n,%lu,ms,%lu,%lu\n", elapsed, nonce, runid);
}

Captura la salida serial a un archivo .csv e impórtalo en la página de Datos.

Estrategia de nonce

El nonce es un contador monótonamente creciente que agrupa las mediciones tomadas en el mismo instante. Reglas:

  • Incrementa una vez por ciclo de medición (no por registro)
  • Todos los registros de un ciclo comparten el mismo nonce
  • Nunca lo reinicies dentro de una ejecución: usa runid para separar experimentos
  • Usa un entero sin signo de 32 bits: a 1 muestra/segundo, se desborda al cabo de 136 años

Consejos

  • Subidas por lotes — almacena varios nonces en búfer y envíalos en un único POST para reducir los despertares del WiFi y ahorrar energía.
  • MCU de 8 bits — el formato CSV no requiere ningún análisis de JSON en el lado del dispositivo. Usa printf para formatear filas y súbelas como archivo más tarde.
  • Múltiples estados — mide distintos modos de funcionamiento (sueño, activo, TX) asignando cada uno a un ID de estado diferente (p. ej. 0.0.0 para sueño, 0.0.1 para activo).
  • Monitoreo de batería — incluye una medición de voltaje en el nivel 1 (p. ej. 0,v,3.28,V,...) para rastrear la descarga a lo largo del tiempo.