Ralenti ou travail ? Une ligne de JEXL tranche

TL;DR. Un camion à l'arrêt, moteur allumé, c'est soit du carburant gaspillé, soit un travail facturable entraîné par la prise de force — et la vitesse affiche zéro dans les deux cas. Une seule ligne d'expression IoT Logic lit le bit du mot d'état qui distingue les deux. Dans ce tutoriel, un agent assemble toute la règle via l'API — il lit le schéma en direct, construit le graphe, l'active, envoie de la télémétrie —, puis un canal indépendant confirme que la règle calcule bien ce que vous vouliez. Le canevas visuel reste la place de l'humain pour relire, approuver et déboguer.
Un camion reste à l'arrêt dix minutes, moteur allumé. Gaspillage ou travail ? Le chauffeur réchauffe peut-être la cabine en brûlant du diesel pour rien. Ou alors le moteur entraîne la prise de force (PTO) — une pompe, une grue — pour un travail que la flotte facture.
La vitesse ne permet pas de distinguer les deux cas : elle affiche zéro dans les deux. La consommation de carburant n'aide guère plus, elle se ressemble aussi. La différence se cache dans un seul bit d'un mot d'état que la passerelle du véhicule envoie.
Voici l'astuce, avant les détails : une expression IoT Logic lit ce bit et transforme « à l'arrêt, moteur allumé » en deux verdicts opposés — et un flux indépendant, celui qui n'a jamais écrit la règle, prouve qu'elle calcule bien ce que vous vouliez.
Une précision d'abord. IoT Logic offre un éditeur visuel en glisser-déposer : vous placez des nœuds sur un canevas — pratique, une vraie force. Mais la plateforme expose aussi un flux typé, lisible et modifiable via l'API REST ; la documentation propose un guide de génération de flux par IA, et un serveur MCP en lecture seule permet de l'auditer. Cette surface est ce qui permet à un agent de travailler contre un contrat plutôt que face à un écran.
Dans l'exécution ci-dessous, l'agent effectue toute la boucle sur un compte de test jetable : il lit le schéma en direct, assemble le graphe, active le flux, envoie de la télémétrie, puis le désactive. Le canevas ne disparaît pas pour autant — un humain ouvre ce même flux et le Data Stream Analyzer pour relire le graphe, approuver l'activation en production, vérifier l'installation sur le camion, et déboguer. L'agent assemble ; l'humain garde la main sur l'activation et sur la vérification.
La réponse tient dans un bit du mot d'état
Voici ce qui arrive sur le fil — un entier, un mot d'état empaqueté :
can_status_word = 4 # 0b100 — PTO off
can_status_word = 5 # 0b101 — PTO engaged (bit 0 set)
Ce nombre arrive dans la plateforme comme un champ de télémétrie numérique ordinaire. C'est la passerelle qui empaquette le mot d'état — l'analyse du bus et cet empaquetage se font sur l'appareil —, si bien qu'à l'intérieur de la règle vous manipulez directement la valeur reçue, sans firmware ni service externe.
Ce mot d'état est synthétique, empaqueté comme le ferait une passerelle réelle ; prenez la disposition réelle des bits dans le contrat de votre appareil ou son DBC, pas dans cet article. Le bit 0 n'est qu'une position illustrative, choisie pour montrer la technique — à vous d'y mettre le décalage de votre propre signal PTO.
util:checkBit — tout le décodage en une seule ligne
IoT Logic dispose de son propre langage d'expression — le même JEXL que vous avez déjà croisé dans une dizaine d'autres outils, avec en plus quelques fonctions utilitaires pour les bits. Extraire le bit qu'il vous faut ressemble à ceci :
util:checkBit(can_status_word, 0)
Ajoutez la vitesse, et vous obtenez trois attributs calculés. Le sens de chacun tient en une phrase, à droite :
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 production, vous combineriez par un ET logique un signal de contact ou de moteur allumé avec speed < 3, pour que « à l'arrêt » signifie vraiment que le moteur tourne ; ici, speed < 3 fait l'affaire à sa place, pour garder l'attention sur le bit PTO — la part que la vitesse, seule, ne peut pas vous donner.
Voilà tout le « décodeur » : trois expressions dans un nœud de règle, sans microservice ni analyseur backend à maintenir. Chacune produit un booléen sur lequel le flux se ramifie — wasteful_idle à vrai est la condition sur laquelle vous agiriez. Transformer ce booléen en notification reste une étape séparée (un capteur ou une règle en plus) ; ce flux ne fait que calculer et router. La syntaxe complète des opérations bit à bit se trouve dans la référence des expressions Navixy.
La règle elle-même est un simple graphe à quatre nœuds, construit via l'API REST : une source de données, un nœud de calcul d'attributs, un nœud de logique, et un point de sortie. Elle ne porte aucune action ni webhook — elle calcule et route, mais ne commande rien. La première écriture se fait avec enabled:false, si bien qu'un graphe même correct ne touche à aucune donnée avant une activation séparée et vérifiée.
L'agent construit le graphe ; vous l'ouvrez pour vérifier
Le même graphe que l'agent a assemblé via l'API s'ouvre dans l'éditeur visuel comme un flux ordinaire — nœud par nœud :
Personne n'a glissé le moindre nœud. Mais rien n'est caché non plus : un humain ouvre cet écran, voit les quatre mêmes nœuds et la ramification, en modifie n'importe lequel, ou désactive le flux d'un seul interrupteur. Le canevas, c'est l'endroit où le travail de l'agent devient vérifiable.
Un bit inverse le verdict à vitesse nulle
Construire le graphe ne suffit pas — il faut encore voir qu'il calcule ce que vous avez voulu. Que le graphe ait survécu à l'écriture, cela se vérifie en le relisant ; comment la règle se comporte sur des données réelles relève d'un canal séparé, celui du Data Stream Analyzer (DSA). Abonnez-vous au flux WebSocket du DSA, envoyez trois paquets de télémétrie — un par état, chacun avec sa propre vitesse et son propre mot d'état —, et le DSA affiche, de façon indépendante, ce que la règle a calculé.
| Ce qu'un paquet a envoyé | Ce que le DSA a montré sur le même tick |
|---|---|
speed=45, can_status_word=4 — en mouvement, PTO coupée |
pto=false, wasteful=false, productive=false, flagged=false |
speed=0, can_status_word=4 — à l'arrêt, PTO coupée |
pto=false, wasteful=true, productive=false, flagged=true |
speed=0, can_status_word=5 — à l'arrêt, PTO enclenchée |
pto=true, wasteful=false, productive=true, flagged=false |
Lisez de haut en bas. En mouvement, ce n'est déjà plus du ralenti, donc rien n'est signalé. Le camion s'arrête, PTO coupée — wasteful passe à vrai, et flagged avec lui : voilà le ralenti à vide. Changez un seul bit du mot d'état, gardez la vitesse à zéro, et le tableau s'inverse : flagged retombe, productive passe à vrai. Même immobilité, verdict opposé — exactement la différence que la vitesse ne peut pas voir.
Un détail transforme ceci en preuve, et non en coïncidence. Chaque paquet porte un identifiant unique, et le contrôle ne cherche qu'un seul tick du DSA portant cet identifiant, puis compare, à l'intérieur de ce tick, les champs envoyés et les champs calculés. La vitesse d'un message ne peut pas se retrouver, par accident, collée au mot d'état d'un autre. C'est l'habitude qui porte tout ici : la preuve vient d'un canal qui n'a jamais rien écrit.
Voici toute l'exécution ramenée à quatre valeurs — une exécution synthétique sur un compte de test jetable, trois états vérifiés chacun sur son tick, la règle laissée désactivée après le contrôle :
{
"status": "succeeded",
"dsa_verified": true,
"final_disabled_verified": true,
"inventory_verified": true
}
Qui fait quoi : l'agent écrit, le canevas vérifie
Chaque acteur tient sa part, si bien qu'aucune réponse ne repose sur la seule confiance pour toutes les autres :
- L'agent, via REST, écrit la configuration puis confirme, en la relisant, que le graphe et
enabled:trueont bien persisté. - NGP accepte la télémétrie ; son code HTTP 200 ne parle que de la livraison.
- DSA montre, de façon indépendante, le résultat calculé sur le flux.
- User MCP reste du côté lecture — le serveur User MCP le lit et l'audite, tandis que toute modification passe par l'API REST.
- L'humain travaille dans l'éditeur visuel : il valide le flux construit par l'agent, approuve l'activation, vérifie l'installation sur le camion, débogue via le DSA, et détient la clé. C'est le point de contrôle — l'humain dans la boucle, au-dessus de l'agent.
En pratique, la règle que je garderais est celle-ci : une règle fonctionne non pas quand create répond avec succès, mais quand un canal qui n'a pas écrit la règle montre le résultat attendu. La voie directe par REST a aussi un cousin déjà intégré au produit — le Navixy AI Assistant, où l'assistant assemble le flux et un humain confirme. Les deux aboutissent au même objet, sur le même canevas.
Quand il n'est pas utile de décoder un bit
Cette technique ne se justifie que dans un cas précis. Si votre passerelle expose déjà un indicateur « PTO active » tout fait, comme son propre champ, prenez ce champ tel quel et ne décodez rien. Si la question ne se pose qu'une fois et que le volume de données reste faible, un export vers une feuille de calcul et dix minutes de travail feront mieux que n'importe quelle règle.
Décoder un bit dans IoT Logic mérite sa place quand le signal arrive empaqueté, en flux continu, et que vous voulez distinguer les états à la volée plutôt que de les reconstituer après coup à partir des journaux.
Votre signal : ce qu'il faut changer, ce qu'il faut garder
Remplacez can_status_word et le bit de démonstration par un champ numérique réel de votre traceur ou de votre passerelle, et indiquez le décalage que le contrat de votre appareil ou son DBC attribue au signal qui vous intéresse. Gardez le reste de l'ordre : le schéma en direct d'abord, puis la construction avec enabled:false, la relecture, une mise à jour complète pour l'activation, et un contrôle DSA rattaché à un identifiant unique.
La seule commande à lancer à la main d'abord, c'est le contrôle préalable — lire le schéma en direct pour confirmer que votre déploiement dispose des types de nœuds nécessaires. La clé se crée une seule fois dans Paramètres du compte → Clés API, et se lit depuis une variable d'environnement :
curl -fsS \
-H "Authorization: NVX ${NAVIXY_API_KEY}" \
-H 'Accept: application/json' \
'https://api.us.navixy.com/v2/iot/logic/flow/schema'
Ensuite viennent les trois expressions vues plus haut, avec une relecture après chaque écriture. La relecture confirme que le flux a persisté tel qu'écrit ; le contrôle DSA indépendant confirme qu'il calcule les états que vous avez voulus.
Tout ceci reste une suite d'appels distincts, avec relecture et contrôle DSA, pour une raison précise : chaque étape obtient un résultat vérifiable par une machine — une correspondance sur un identifiant, un tick du DSA portant son identifiant unique, un enabled:false confirmé par une lecture. Le schéma typé, le guide de génération de flux par IA et le MCP en lecture seule existent pour qu'un agent puisse exécuter cette boucle.
L'éditeur reste la façon la plus familière de construire un flux, et c'est bien commode. Mais je parierais que l'assemblage des graphes continue de glisser vers les agents, tandis que le canevas et le DSA restent l'endroit où un humain valide, vérifie l'installation et débogue — ne laissant qu'une seule opération non délégable : créer la clé, puis la révoquer.
- La réponse tient dans un bit du mot d'état
- util:checkBit — tout le décodage en une seule ligne
- L'agent construit le graphe ; vous l'ouvrez pour vérifier
- Un bit inverse le verdict à vitesse nulle
- Qui fait quoi : l'agent écrit, le canevas vérifie
- Quand il n'est pas utile de décoder un bit
- Votre signal : ce qu'il faut changer, ce qu'il faut garder