dummybot/docs/FIRMWARE.md
javiservices 3a80d5e76b
Some checks failed
Deploy DummyBot / Build & Deploy to ${{ env.DEPLOY_HOST }} (push) Has been cancelled
docs: documentar deploy automático + firmware ESP32
2026-06-18 12:32:35 +02:00

6.2 KiB

Firmware del ESP32

Firmware para el bot físico DummyBot. ESP32 + OLED SSD1306 128x64 + WiFi

  • polling backend.

Hardware

  • ESP32-D0WD-V3 (DevKitC / WROOM-32, 4 MB flash)
  • Pantalla OLED SSD1306 0.96" (128x64, I2C)
  • 3 botones (NEXT / DONE / SNOOZE)
  • 1 motor vibrador 1027 (3V DC, MOSFET en GPIO 25)

Pinout

Función GPIO Notas
OLED SDA 21 I2C data
OLED SCL 22 I2C clock
OLED addr 0x3C I2C address
Botón NEXT 26 INPUT_PULLDOWN, flanco ascendente
Botón DONE 27 INPUT_PULLDOWN, flanco ascendente
Botón SNOOZE 14 INPUT_PULLDOWN, flanco ascendente
Vibrador 25 OUTPUT, MOSFET gate
BOOT (reset cfg) 0 INPUT_PULLUP, mantener 5s al arrancar

Cableado OLED

ESP32 (WROOM-32)            OLED SSD1306 0.96"
─────────────────────       ─────────────────────
3V3          ───────▶       VDD
GND          ───────▶       GND
GPIO 22      ───────▶       SCK (I2C SCL)
GPIO 21      ───────▶       SDA (I2C SDA)

Cableado botones

Los botones se conectan entre GND y el GPIO correspondiente. Con INPUT_PULLDOWN interno del ESP32, el GPIO lee LOW en reposo y HIGH al pulsar. El firmware detecta el flanco ascendente con debounce de 200 ms.

ESP32          Botón (entre pin y GND)
─────          ─────
GPIO 26 ──────▶ Siguiente
GPIO 27 ──────▶ Hecha
GPIO 14 ──────▶ Snooze 5 min
GND     ──────▶ Común

Cableado vibrador

ESP32          MOSFET (AO3400 / 2N7000)         Vibrador 1027
─────          ──────                            ─────
GPIO 25 ──[100Ω]──▶ Gate
                       │
                       ├──▶ Source ──▶ GND
                       │
                       └──▶ Drain ──▶ Vibrador ──▶ 3V3

Si solo se dispone de NPN (BC547 / 2N2222 / S8050), esquema alternativo: motor entre 3V3 y colector, resistencia 1kΩ en base.

Build flags (platformio.ini)

build_flags =
    -DCORE_DEBUG_LEVEL=3
    -DUSER_SETUP_LOADED=1
    -DDEFAULT_WIFI_SSID=\"PHARMACO\"
    -DDEFAULT_WIFI_PASS=\"arnoldgym2010\"
    -DBACKEND_URL=\"http://157.180.77.232:18080\"
    -DDEFAULT_DEVICE_TOKEN=\"<token-del-bot>\"

Build y flasheo

# Compilar
pio run

# Flashear
pio run -t upload --upload-port /dev/ttyUSB0

# Monitor serie
pio device monitor --port /dev/ttyUSB0 --baud 115200

Configuración en runtime (captive portal)

Si no hay config WiFi válida en NVS, el bot abre un AP DummyBot-Setup (pass dummybot) en 192.168.4.1. Desde el móvil, configurar WiFi y token del dispositivo. El bot se reinicia automáticamente y conecta.

Para resetear la config: mantener pulsado el botón BOOT (GPIO 0) durante 5 segundos al arrancar.

Comandos serie (debug)

Conectar a 115200 baud:

Comando Acción
S Imprime estado (WiFi, IP, tarea actual)
B0 Simula pulsación botón NEXT (GPIO 26)
B1 Simula pulsación botón DONE (GPIO 27)
B2 Simula pulsación botón SNOOZE (GPIO 14)
P Lee estado actual de los 3 pines de botón
A Lectura continua del ADC en GPIO 34 (60s)
C Calibración guiada de umbrales ADC (3 botones)
W Watch: monitor rápido de cambios en pines

Arquitectura del firmware

// Namespace principales
namespace Config    { void load(); void save(); void clear(); }
namespace UI        { showBoot, showConnecting, showIdle, showTask, showPortal }
namespace Vib       { buzz(), tick()  patrón 2-buzz al recibir tarea nueva }
namespace Api       { pollPending(), markDone(), snooze() }
namespace Input     { tick()  polling 3 botones con debounce por flanco }
namespace Portal    { start(), stop(), tick()  AP + DNS + WebServer }
namespace Wifi      { wifiStartSTA(), wifiTick()  máquina de estados }

Máquina de estados WiFi

BOOT → CONNECTING (timeout 20s)
        ├─ OK → CONNECTED (poll cada 30s)
        └─ FAIL → PORTAL (AP DummyBot-Setup)

CONNECTED
        └─ WiFi perdido → CONNECTING

PORTAL
        └─ ESP.restart() al guardar config

Flujo de polling

CONNECTED
  → Api::pollPending() cada 30s
    → GET /api/device/tasks/pending
    → Si tiene tareas: muestra primera en OLED
    → Si cambia id: buzz (vibrador)

Troubleshooting

WiFi no conecta

  • Verificar SSID y password (son case-sensitive).
  • Si el router está en 5 GHz, el ESP32 solo soporta 2.4 GHz.
  • Si la red bloquea nuevos dispositivos (MAC filtering), añadir la MAC del ESP32 (visible en el log de WiFi.status()).

Botones no responden

  • Verificar que el botón hace contacto entre el GPIO y GND.
  • Comandos serie P muestra el estado actual de los pines. Pulsar y ver si cambia de 0 a 1.
  • Si el botón usa active-low (HIGH en reposo, LOW al pulsar), cambiar a INPUT_PULLUP y la lógica de flanco a descendente.

OLED no enciende

  • Verificar 3V3 en VDD del OLED.
  • Verificar SDA (GPIO 21) y SCL (GPIO 22) — pines fijos I2C del ESP32.
  • I2C addr por defecto 0x3C. Si la OLED es 0x3D, cambiar OLED_ADDR.

API no responde

  • Verificar que el bot tiene acceso a internet (ping al backend desde el ESP32 con el comando serie S).
  • Si el backend usa HTTPS con cert auto-firmado, hay que añadir el cert al firmware (más complejo) o usar HTTP plano.

Versiones

  • v6.1 (actual): producción, sin botones (pendiente nueva placa). Funcionalidad core: WiFi, OLED, polling, portal cautivo.
  • v6.0 (legacy): intentona con ADC para matriz de botones, no funcionó en hardware del usuario.
  • v5 (legacy): SPIFFS en lugar de NVS, varios bugs en defaults WiFi.