Un gateway es un dispositivo que se conecta a CORE-M en nombre de otros dispositivos que
no pueden alcanzar la plataforma por sí mismos. El caso clásico es un bus industrial: una
docena de sensores Modbus RTU cuelgan de un único segmento RS-485, y un gateway de borde
habla Modbus con ellos y CORE-M con la nube. El gateway se autentica una vez y hace
fan-in de la telemetry de todos sus hijos, cada uno de los cuales aparece en CORE-M como su propio
dispositivo de primera clase.
Los hijos detrás de un gateway no tienen credencial directa ni ruta directa a
CORE-M. El gateway proporciona ambas: es el uplink autenticado, y CORE-M
mapea el nombre local de cada hijo a un device_id real para que la telemetry del hijo se
almacene, se procese por reglas y se ancle exactamente como si se hubiera conectado directamente.
La route key ata la identidad local de un hijo (un índice de slot, un número de serie o un nombre
lógico) a su dispositivo en la plataforma, acotada al gateway y al tenant propietarios.
Registra el gateway. Aprovisiona el dispositivo de borde normalmente. Recibe un
device_id y una API key; esta es la única credencial que los hijos necesitan.
Conecta cada hijo. El gateway llama a GatewayConnectDevice con un
child_name estable. CORE-M crea (o busca) el dispositivo hijo y devuelve su
child_device_id. Esto establece la ruta para ese hijo.
Envía telemetry. El gateway llama a GatewaySubmitTelemetry con un lote
de puntos, cada uno direccionado por child_name. CORE-M resuelve cada nombre a un dispositivo
hijo y publica un punto de telemetry en bruto por hijo.
GatewayConnectDevice es idempotente: llamarlo de nuevo con el mismo child_name
devuelve el mismo hijo. Internamente el hijo se almacena con un hardware ID de la
forma gw:{gateway_device_id}:{child_name}, que es lo que hace estable la búsqueda.
GatewaySubmitTelemetry hace fan-in de un lote. Cada punto lleva el child_name,
un timestamp opcional (el servidor usa ahora si está ausente) y las lecturas
numéricas/de texto. CORE-M resuelve cada nombre y publica un punto en bruto por hijo,
atribuido al device_id del hijo para almacenamiento, reglas y anchoring.
La respuesta cuenta los puntos a lo largo del lote, con la misma forma accepted / rejected
que la ingesta directa:
{
"accepted": 2,
"rejected": 0
}
sequenceDiagram
participant GW as Gateway G1
participant CM as CORE-M gateway :8080
participant Reg as Registro de dispositivos
participant RP as Redpanda telemetry.raw.{tenant}
GW->>CM: POST /api/v1/gateway/G1/telemetry (lote por child_name)
CM->>CM: Verificar device_id del invocador == G1
loop cada punto
CM->>Reg: Resolver {tenant}:G1:child_name → device_id
alt la ruta existe (o auto_create)
CM->>RP: Publicar punto como device_id del hijo
else hijo desconocido, auto_create=false
CM->>CM: Rechazar (corem_gateway_child_rejections_total +1)
end
end
CM-->>GW: { accepted, rejected }
Lo que ocurre cuando llega telemetry para un child_name que aún no tiene ruta
depende de la bandera auto_create:
auto_create = true — CORE-M crea el dispositivo hijo al vuelo a partir de la
primera telemetry, así puedes omitir el paso explícito GatewayConnectDevice.
auto_create = false — la telemetry para un hijo desconocido se rechaza, y
corem_gateway_child_rejections_total{reason="unknown_child"} se incrementa.
Usa esto cuando quieras que los hijos existan solo tras un connect deliberado.
Los hijos de un gateway comparten su suerte en el uplink. Si la política del profile dice que
el estado del hijo sigue al del gateway, entonces cuando el gateway pasa a offline, el
verificador de desconexión marca también offline a todos los hijos enrutados a través de él, y publica un
evento device.status por cada hijo afectado. Esto mantiene el panel honesto — un bus
de sensores no aparece como online cuando lo único que puede alcanzarlos se ha
caído.
De forma independiente, cada hijo aún cambia a online con su propia primera telemetry,
y a offline tras el umbral de desconexión (por defecto 120 segundos) de silencio.