Saltar a contenido

Stack tecnológico

Elecciones

Capa Elección Estado
Lenguaje TypeScript, un solo proyecto firme (D-04)
Runtime Node LTS firme
Servidor Modbus jsmodbus o modbus-serial sin verificar (PEND-21)
UDP node:dgram firme, sin dependencia
WebSocket ws firme
Registro de eventos SQLite con better-sqlite3, modo WAL firme
Validación de configuración JSON Schema con Ajv firme
Interfaz SPA ligera servida por el mismo proceso firme
Despliegue Docker Swarm + cloudflared firme (D-05)
Documentación MkDocs Material firme

Por qué un solo proceso y un solo lenguaje

Núcleo, servidor Modbus, emisor UDP, servidor WebSocket e interfaz viven en el mismo proceso Node (D-01). Un salto de red entre el adaptador Modbus y el núcleo añadiría jitter que no existe en el radar real, y el banco existe para medir jitter.

El riesgo técnico principal

Múltiples unit IDs sobre una sola conexión TCP

El diseño exige que el servidor atienda diez unit IDs sobre la misma conexión TCP, porque las direcciones de los módulos ADAM colisionan entre sí y la resolución es un unit ID por módulo físico (Modbus TCP).

jsmodbus y modbus-serial anuncian modo servidor, pero no está verificado que ninguna de las dos lo soporte correctamente. Es un requisito duro: si ninguna lo cumple, hay que implementar el servidor Modbus TCP a mano sobre node:net, lo cual es viable —el subconjunto de códigos de función es pequeño— pero cambia la estimación de la fase 1.

Es lo primero que hay que probar, antes de escribir cualquier otra cosa.

Además del multi-unit, la prueba de concepto debe verificar dos cosas más de la librería candidata: que permite responder excepción ante una escritura sobre una coil de solo lectura, y que expone el instante de recepción de cada trama con resolución suficiente para el registro.

Códigos de función a implementar

Solo seis, por cómo Advantech usa los espacios de direcciones:

FC Función Uso
01 Read Coils DI y DO
03 Read Holding Registers AI y AO
05 Write Single Coil DO
06 Write Single Register AO
15 Write Multiple Coils DO
16 Write Multiple Registers AO

FC02 y FC04 no se usan: las entradas digitales viven en 0X y las analógicas en 4X. Ver Modbus TCP.

Estructura del repositorio

rd100s-emu/
├── src/
│   ├── core/          # estado, tick, grafo, modos de señal
│   ├── config/        # esquema, validación, carga
│   ├── adapters/
│   │   ├── modbus/    # servidor, mapeo, conversión de crudo
│   │   ├── udp/       # emisor de encoder y degradaciones
│   │   └── ws/        # telemetría, eventos, órdenes
│   ├── log/           # SQLite, sesiones, descarga
│   ├── blocks/        # biblioteca de comportamiento (fase 2)
│   └── ui/            # SPA
├── config/            # rd100s.json y otras configuraciones
├── scenarios/         # escenarios y aserciones (fase 3)
├── docs/              # este sitio
├── stack.yml
└── mkdocs.yml

El núcleo no importa nada de adapters/. La dependencia va en un solo sentido y conviene imponerlo con una regla de lint, no solo por convención: es lo que mantiene el modelo independiente de los transportes.

Convenciones

  • Reloj monótono en todo lo que se registre o se emita. Nunca hora de pared.
  • Marcado // PEND-nn en cada punto donde se use un valor provisional.