| README.md | ||
UpsBox
Firmware para ESP32-C3 SuperMini (board lolin_c3_mini, framework Arduino /
PlatformIO) que actúa como puente WiFi ↔ serie transparente para depurar la
comunicación con un UPS APC BX1100CI.
El C3 se conecta por UART TTL 3.3V directo a la placa del UPS (en los pines que iban al conversor USB, ya retirado): no hay RS232 ni level shifter. El puente pasa bytes crudos en ambos sentidos — no parsea el protocolo — para poder descubrir a mano qué habla el UPS (APC "smart" de comandos de una letra + CR, o Microlink binario).
Conexionado (UART1)
| C3 SuperMini | UPS | Notas |
|---|---|---|
| GPIO0 (RX) | TX del UPS | entra al C3 |
| GPIO1 (TX) | RX del UPS | sale del C3 hacia el UPS |
| GND | GND del UPS | masa común imprescindible |
Parámetros: 2400 8N1. Pines y baudios son configurables en
include/config.h (UPS_RX_PIN, UPS_TX_PIN, UPS_BAUD).
El UART1 del UPS es independiente del USB CDC (
Serial) que se usa para el log de diagnóstico: nunca se mezclan.
Puertos de red
:23→ puente Telnet crudo ↔ UART del UPS (el núcleo).telnet upsbox.local.:2323→ consola de logs de diagnóstico (WiFi/IP, OTA, cliente conectado…).nc upsbox.local 2323. También sale por el USB CDC nativo.:80→ web de estado (http://upsbox.local/).
Arquitectura del código
- Puente serie (serial_bridge): TCP:23 ↔ UART1.
Filtra la negociación Telnet (IAC/
0xFF) para que no contamine el stream serie y pide al cliente modo carácter/raw (sin line-buffering ni eco local). Un cliente a la vez (el más nuevo gana). Reconexión sin resetear la placa. - WiFi (wifi_conn): station, única fase bloqueante al
boot +
setAutoReconnect(true); si se cuelga reinicia la radio, no el chip. - OTA (ota):
ArduinoOTA,upsbox.localcon password. Se atiende en cadaloop()aunque haya un cliente Telnet conectado. - Log remoto (remote_log) y web (web).
- Secretos:
secrets.ymlcifrado con ansible-vault, inyectado como macros-Den el build (scripts/inject_secrets.py). Las credenciales no viven en el fuente.
Setup de secretos
cp secrets.yml.example secrets.yml
# ...editar wifi_ssid / wifi_pass / ota_password (tg_* opcional)...
ansible-vault encrypt secrets.yml
# password del vault: archivo .vault_pass (gitignoreado) o ANSIBLE_VAULT_PASSWORD_FILE
Flashear la primera vez (por USB)
pio run -t upload # usa upload_port = /dev/ttyACM0 (ajustar si hace falta)
pio device monitor # ver el log por USB CDC (115200): IP, OTA listo, etc.
El platformio.ini ya trae ARDUINO_USB_CDC_ON_BOOT=1 para que el USB CDC del C3
hable desde el arranque.
Flashear las siguientes (por OTA)
Una vez que la placa está en la red (mirá la IP en el monitor o en http://upsbox.local/):
pio run -t upload --upload-port upsbox.local # o la IP; pide la ota_password
espota/ArduinoOTA queda anunciado como upsbox.local. Podés fijarlo en el
platformio.ini con upload_protocol = espota y upload_port = upsbox.local.
Conectarse a la consola del UPS (Telnet)
telnet upsbox.local # o telnet <ip>
El firmware negocia modo carácter, así que cada tecla se manda al UPS al toque. Todo lo que llega del UPS se imprime crudo.
Mandar comandos con CR intacto
Los comandos APC "smart" terminan en CR (\r, 0x0D), no en LF. El método más
determinístico para probar un comando y ver la respuesta es un disparo con nc:
printf 'Q\r' | nc -w2 upsbox.local 23 # manda exactamente Q + CR, espera 2s la respuesta
printf 'Y\r' | nc -w2 upsbox.local 23 # "smart mode" (respuesta esperada: SM)
printf 'A\r' | nc -w2 upsbox.local 23 # self-test de front panel
nc no negocia Telnet, así que el byte sale tal cual: no hay IAC de por medio.
Interactivo con telnet: al presionar Enter, muchos clientes mandan CR-LF o
CR-NUL. El puente lo pasa crudo por defecto (TELNET_EOL_MODE 0) — el CR llega,
pero puede ir seguido de un LF/NUL. Si querés que cualquier Enter mande un
solo CR limpio (cómodo para tantear a mano, también hace que el LF de nc
interactivo se traduzca a CR), poné en config.h:
#define TELNET_EOL_MODE 1
UPS binario (Microlink)
Si el UPS resulta hablar binario, TELNET_ESCAPE_IAC 1 (default) escapa los
0xFF para no romper el cliente Telnet. Para verlo tal cual con nc, poné
TELNET_ESCAPE_IAC 0 en config.h.
Tips de diagnóstico
- Si no ves nada del UPS: revisá GND común y probá cruzar RX/TX (TX del UPS debe entrar al RX=GPIO0 del C3).
- El log (
nc upsbox.local 2323o USB) te avisa cuándo se conecta/desconecta el cliente Telnet y el estado de WiFi/OTA.