¿Ralentí o trabajo? Una línea de JEXL lo distingue

TL;DR. Un camión detenido con el motor encendido puede significar dos cosas: combustible desperdiciado o trabajo facturable de toma de fuerza (PTO); la velocidad marca cero en ambos casos y no distingue cuál es cuál. Una sola línea de expresión en IoT Logic lee el bit de estado que sí marca la diferencia. En este recorrido, un agente ensambla toda la regla a través de la API —lee el esquema en vivo, construye el grafo, lo habilita, transmite la telemetría— y un canal independiente confirma después que la regla calculó justo lo que usted esperaba. El lienzo visual se mantiene como el lugar donde la persona revisa, aprueba y depura.
Un camión permanece detenido diez minutos con el motor encendido. ¿Desperdicio o trabajo? Puede ser que el conductor esté calentando la cabina, quemando diésel para nada. O puede ser que el motor esté impulsando una toma de fuerza (PTO), moviendo una bomba o haciendo girar una grúa: trabajo facturable que le pagan a la flotilla.
La velocidad no permite distinguir entre los dos casos: en ambos marca cero. El consumo de combustible tampoco ayuda mucho, porque se ve casi igual. La diferencia está escondida en un solo bit de la palabra de estado que envía el gateway del vehículo.
Antes de entrar en detalles, el truco completo es este: una sola expresión de IoT Logic lee ese bit y convierte "detenido, motor encendido" en dos veredictos opuestos, y una transmisión independiente —la que nunca escribió la regla— demuestra que la regla calcula justo lo que usted quiso decir.
Primero, un punto importante. IoT Logic tiene un editor visual de arrastrar y soltar, donde usted coloca nodos en un lienzo y los conecta: es cómodo, y es una ventaja real.
Pero también tiene una superficie programática documentada: un flujo es un esquema tipado que se lee y se escribe por REST, la documentación incluye una guía de generación de flujos con IA, y la plataforma expone un servidor MCP de solo lectura para auditoría. Esa superficie es lo que permite que un agente trabaje contra un contrato, no contra una pantalla.
En la corrida que sigue, el agente ejecuta todo el ciclo sobre una cuenta de prueba descartable: lee el esquema en vivo, ensambla el grafo, habilita el flujo para la prueba, transmite telemetría y lo vuelve a deshabilitar. El lienzo no desaparece: una persona abre ese mismo flujo y el Data Stream Analyzer para revisar el grafo, aprobar la habilitación en producción, verificar la instalación en el camión y depurar. El agente ensambla; la persona conserva la compuerta de habilitación y la verificación.
La respuesta está en un bit de la palabra de estado
Esto es lo que llega por el cable: un entero, una palabra de estado empaquetada:
can_status_word = 4 # 0b100 — PTO off
can_status_word = 5 # 0b101 — PTO engaged (bit 0 set)
El número llega a la plataforma como un campo numérico de telemetría más. El gateway empaqueta la palabra de estado (el análisis y el empaquetado del bus ocurren en el dispositivo), así que dentro de la regla usted trabaja con el valor ya entregado: sin firmware y sin ningún servicio externo.
Esta es una palabra de estado sintética, empaquetada como la empaquetaría un gateway real; tome la distribución de bits real del contrato de su dispositivo o del DBC, no de esta publicación. El bit 0 es una posición ilustrativa, elegida para mostrar la técnica: ahí es donde usted coloca el desplazamiento de su propia señal real de PTO.
util:checkBit: toda la decodificación en una sola línea
IoT Logic tiene su propio lenguaje de expresiones: el mismo JEXL que usted ya conoce de otras herramientas, más algunos ayudantes para trabajar con bits. Extraer el bit que necesita se ve así:
util:checkBit(can_status_word, 0)
Agregue la velocidad y obtiene tres atributos calculados. El significado de cada uno va en el comentario de la derecha:
pto_engaged = util:checkBit(can_status_word, 0)
wasteful_idle = speed < 3 && !util:checkBit(can_status_word, 0) # parked, PTO off
productive_idle = speed < 3 && util:checkBit(can_status_word, 0) # parked, PTO on
En producción, usted combinaría mediante AND una señal de encendido o de motor-encendido con speed < 3, de manera que "detenido" signifique que el motor esté realmente encendido; aquí speed < 3 funciona como sustituto, para mantener el foco en el bit de PTO: la parte que la velocidad no le puede dar.
Ese es el "decodificador" completo: tres expresiones dentro de un nodo de regla, sin microservicio ni analizador de backend que mantener. Cada una produce un booleano sobre el que el flujo se ramifica: que wasteful_idle sea true es la condición sobre la que usted actuaría. Convertir un booleano en una notificación real es un paso aparte (un sensor o una regla adicional); este flujo solo calcula y enruta. La sintaxis completa y la lista de operaciones con bits están en la referencia de expresiones de Navixy.
La regla en sí es un grafo simple de cuatro nodos, construido por REST: una fuente de datos, un nodo de atributos calculados, un nodo de lógica y un único punto de salida. No lleva ninguna acción ni webhook: la regla calcula y enruta, pero no ordena nada. La primera escritura entra con enabled:false, de modo que incluso un grafo correcto no toca ningún dato hasta una habilitación aparte y verificada.
El agente construye el grafo; usted lo abre para revisarlo
El mismo grafo que el agente ensambló por la API se abre en el editor visual como un flujo normal, nodo por nodo:
Nadie arrastró un solo nodo. Pero tampoco hay nada oculto: una persona abre esta misma pantalla, ve los mismos cuatro nodos y la ramificación, edita cualquiera de ellos, o deshabilita el flujo con un solo interruptor. El lienzo es donde el trabajo del agente se vuelve revisable.
Un bit invierte el veredicto a velocidad cero
Construir el grafo no es suficiente: hay que comprobar que calcula lo que usted quiso. Si el grafo sobrevivió a la escritura se confirma leyéndolo de vuelta; cómo se comporta la regla con datos en vivo es un canal distinto, el Data Stream Analyzer (DSA). Usted se suscribe a la transmisión WebSocket del DSA, envía tres paquetes de telemetría —uno por cada estado, cada uno con su propia velocidad y palabra de estado— y el DSA muestra, de forma independiente, lo que la regla calculó.
| Lo que envió un paquete | Lo que mostró el DSA en el mismo tick |
|---|---|
speed=45, can_status_word=4 — en movimiento, PTO apagado |
pto=false, wasteful=false, productive=false, flagged=false |
speed=0, can_status_word=4 — detenido, PTO apagado |
pto=false, wasteful=true, productive=false, flagged=true |
speed=0, can_status_word=5 — detenido, PTO encendido |
pto=true, wasteful=false, productive=true, flagged=false |
Léalo de arriba hacia abajo. Moverse no es ralentí en absoluto, así que nada se marca. El camión se detiene con el PTO apagado: wasteful pasa a true, y flagged con él: ahí está el ralentí vacío. Cambie un solo bit de la palabra de estado, mantenga la velocidad en cero, y el panorama se invierte: flagged se limpia y productive pasa a true. Mismo punto muerto, veredicto opuesto: exactamente la diferencia que la velocidad no puede ver.
Un detalle es lo que convierte esto en prueba y no en coincidencia. Cada paquete lleva un marcador único, y la verificación busca exactamente un tick del DSA con ese marcador, y ahí compara los campos enviados con los calculados. La velocidad de un mensaje no puede quedar pegada por accidente a la palabra de estado de otro. Ese es el hábito que sostiene todo esto: la prueba viene de un canal que nunca escribió nada.
Esto es toda la corrida reducida a cuatro valores: una corrida sintética sobre una cuenta de prueba descartable, con los tres estados coincididos en sus respectivos ticks, y la regla otra vez deshabilitada después de la verificación:
{
"status": "succeeded",
"dsa_verified": true,
"final_disabled_verified": true,
"inventory_verified": true
}
Quién hace qué: el agente escribe, el lienzo verifica
Cada actor es responsable de una parte, así que ninguna respuesta se acepta por fe para todas las demás:
- El agente, mediante REST, escribe la configuración y confirma, leyéndola de vuelta, que el grafo y
enabled:truede verdad quedaron guardados. - NGP recibe la telemetría; su HTTP 200 solo confirma la entrega.
- DSA muestra, de forma independiente, el resultado calculado sobre la transmisión.
- User MCP se queda del lado de la lectura: el servidor de User MCP lo lee y lo audita, mientras que cada cambio pasa por REST.
- La persona trabaja en el editor visual: valida el flujo que construyó el agente, aprueba la habilitación, revisa los datos en el camión ya instalado, depura por medio del DSA, controla el interruptor y es dueña de la clave. Ese es el punto de control: una persona en el circuito, por encima del agente.
En la práctica, el criterio que yo mantendría es este: una regla no funciona cuando create responde con éxito, sino cuando un canal que no participó en la escritura muestra el resultado que usted esperaba. La ruta directa por REST tiene además una contraparte dentro del propio producto: el Navixy AI Assistant, donde el asistente ensambla el flujo y una persona lo confirma. Las dos rutas terminan en el mismo objeto, sobre el mismo lienzo.
Cuándo no hace falta decodificar un bit
Esta técnica vale la pena en un caso concreto y acotado. Si su gateway ya expone una bandera lista de "PTO encendido" como campo propio, tome ese campo tal cual y no decodifique nada. Si la pregunta es puntual y los datos son pocos, exportar a una hoja de cálculo le tomará diez minutos y le ganará a cualquier regla.
Decodificar bits en IoT Logic se justifica cuando la señal llega empaquetada, en una transmisión continua, y usted necesita distinguir los estados al vuelo, en lugar de reconstruirlos después a partir de los registros.
Su señal: qué cambiar, qué conservar
Sustituya can_status_word y el bit de la demostración por un campo numérico real de su rastreador o gateway, y coloque el desplazamiento que el contrato de su dispositivo o el DBC le asigna a la señal que le interesa. Conserve el resto del orden: primero el esquema en vivo, luego construir con enabled:false, leer de vuelta, una actualización completa al habilitar, y una verificación en el DSA con un marcador único.
El único comando que vale la pena correr a mano primero es la revisión previa: leer el esquema en vivo y confirmar que su implementación tiene los tipos de nodo que necesita. La clave se crea una sola vez en Account Settings → API Keys y se lee desde una variable de entorno:
curl -fsS \
-H "Authorization: NVX ${NAVIXY_API_KEY}" \
-H 'Accept: application/json' \
'https://api.us.navixy.com/v2/iot/logic/flow/schema'
Después de eso, vienen las tres expresiones de arriba y una lectura de verificación después de cada escritura. La lectura de vuelta confirma que el flujo quedó guardado tal como se escribió; la verificación independiente en el DSA confirma que calcula los estados que usted quiso.
Todo esto se mantiene como llamadas separadas, con lectura de vuelta y verificación en el DSA, por una razón concreta: así, cada paso tiene un resultado que una máquina puede verificar como correcto o incorrecto —una coincidencia en una búsqueda por etiqueta, un tick del DSA con su marcador único, un enabled:false final confirmado con una lectura. El esquema tipado, la guía de generación de flujos con IA y el MCP de solo lectura existen precisamente para que un agente pueda correr ese ciclo.
El editor es la manera conocida de construir un flujo, y eso es cómodo. Pero yo apostaría a que ensamblar grafos va a seguir moviéndose hacia los agentes, mientras el lienzo y el DSA se quedan como el lugar donde una persona valida, revisa la instalación y depura —dejando una sola operación que usted no puede delegar: crear la clave, y revocarla.
- La respuesta está en un bit de la palabra de estado
- util:checkBit: toda la decodificación en una sola línea
- El agente construye el grafo; usted lo abre para revisarlo
- Un bit invierte el veredicto a velocidad cero
- Quién hace qué: el agente escribe, el lienzo verifica
- Cuándo no hace falta decodificar un bit
- Su señal: qué cambiar, qué conservar