For the complete documentation index, see llms.txt. This page is also available as Markdown.

Référence CEL

Référence de syntaxe CEL pour les règles Kilo IoT — Common Expression Language utilisée dans les passerelles, scripts et alarmes.

Le moteur de règles utilise CEL (Common Expression Language) pour les expressions à l’intérieur de l’éditeur visuel de workflow — conditions des passerelles, calculs des tâches de script, messages d’alarme, recherches d’enrichissement et définitions des entrées/sorties. CEL est un langage d’expression rapide et sûr, conçu à l’origine par Google pour évaluer des conditions dans des politiques de sécurité et des systèmes d’infrastructure. La spécification complète du langage est disponible sur GitHub.

CEL n’est pas un langage de programmation à usage général. Il évalue des expressions et renvoie des résultats. Il ne peut pas accéder au système de fichiers, effectuer des appels réseau, créer des boucles ni modifier l’état externe. Cela permet d’exécuter en toute sécurité des expressions définies par l’utilisateur, sans risque pour la plateforme ni pour les autres règles.

La plupart des règles Kilo n’utilisent que quelques expressions courtes. La structure du workflow reste visuelle et basée sur BPMN ; CEL est la couche de précision qui rend ces workflows utiles dans de vrais scénarios de production.


Données disponibles

Chaque expression du moteur de règles a accès aux variables de processus via l’ vars . Les données disponibles dépendent de l’endroit de la règle où l’expression s’exécute.

Les champs dans vars peuvent être accessibles avec la notation par point ou la notation entre crochets:

vars.temperature        // notation par point — fonctionne pour les identifiants simples
vars["sensor_id"]       // notation entre crochets — fonctionne pour n’importe quel nom
vars["my-sensor"]       // notation entre crochets requise — tiret dans le nom

La notation par point est pratique pour la plupart des noms de champ. La notation entre crochets est requise lorsqu’un nom de champ contient des tirets, des espaces ou d’autres caractères spéciaux, ou lorsque le nom du champ est calculé dynamiquement à partir d’une autre expression.

Disponible après l’événement de démarrage

Ce que fournit l’événement de démarrage dépend de sa source de démarrage, donc vérifiez de quel type de règle il s’agit avant d’utiliser une variable.

Source de démarrage : lecture du capteur

Variable
Type
Description

vars.value

Varie selon le capteur

La lecture du capteur qui a déclenché la règle. Peut être un nombre (température, humidité), une chaîne (état de la porte) ou un booléen (mouvement détecté).

vars.sensor_id

chaîne

L’identifiant unique du capteur qui a déclenché la règle.

vars.timestamp

horodatage

Le moment où la lecture du capteur a été enregistrée.

Source de démarrage : condition de déclenchement

Variable
Type
Description

vars.device_name

chaîne

Le nom de l’appareil qui a satisfait la condition. Sur une déclencheur règle surveillant plusieurs appareils, cela identifie celui qui s’est déclenché.

vars.subject_kind

chaîne

Le type de ressource surveillée. Il s’agit actuellement de appareil.

vars.subject_id

chaîne

L’identifiant de l’appareil surveillé qui a satisfait la condition.

vars.sensor_id

chaîne

L’identifiant du capteur utilisé pour associer l’exécution et toute alarme à l’appareil surveillé.

vars.detector_id

chaîne

L’identifiant du déclencheur qui a démarré la règle.

vars.timestamp

int

L’heure du signal de déclenchement en secondes Unix.

vars.value n’existe pas dans une règle déclenchée par un déclencheur. Un déclencheur signale une transition de condition plutôt que de fournir à la règle un événement de capteur normalisé. Cela vaut à la fois pour les déclencheurs immédiats et de durée. Une expression faisant référence à vars.value échouera à chaque signal de déclenchement — vérifiez cela en premier lors de la conversion d’une règle existante depuis Lecture du capteur.

Disponible après les tâches de script

Si une tâche de script renvoie une map, chaque clé est fusionnée dans vars. Par exemple, après une tâche de script avec l’expression {"level": "critical", "delta": 15.2}, les nœuds en aval peuvent accéder à vars.level et vars.delta.

Les sorties de la tâche de script, de la passerelle, de Définir l’alarme, d’Enrichissement et de l’événement de démarrage peuvent également publier des valeurs nommées dans vars après l’exécution de ce nœud.

Disponible après l’enrichissement

Après qu’un nœud d’enrichissement stocke des données sous un nom de variable (par ex. : outdoor_temp), les données enrichies sont accessibles comme un objet imbriqué :

Variable
Type
Description

vars.outdoor_temp.value

Varie

La lecture la plus récente du capteur enrichi.

vars.outdoor_temp.sensor_id

chaîne

L’identifiant du capteur enrichi.

vars.outdoor_temp.type

chaîne

Le type de données du capteur enrichi.

vars.outdoor_temp.timestamp_ms

int

Horodatage de la lecture en millisecondes.

Variables personnalisées

Les expressions d’entrée et de sortie sur les événements de démarrage, les passerelles exclusives, les tâches de script, les nœuds Définir l’alarme et les nœuds d’enrichissement permettent de nommer une valeur calculée. Choisissez entre elles selon la distance que la valeur doit parcourir :

  • Sorties ajoutent le nom au contexte du workflow. Il est accessible sous la forme vars.<name> dans chaque nœud exécuté ensuite.

  • Entrées restent sur le nœud sur lequel vous les avez définies. Elles sont calculées avant l’exécution de ce nœud et ses propres expressions peuvent les utiliser — les entrées d’une passerelle sont disponibles pour les conditions de flux de cette passerelle — mais les nœuds suivants ne peuvent pas les lire.

Si une valeur calculée sur un nœud est nécessaire plus loin dans la règle, faites-en une sortie. Voir Référence des nœuds pour un exemple.


Système de types

CEL prend en charge les types suivants. Toute valeur dans une expression se résout en l’un de ceux-ci.

Type
Description
Exemple

bool

Booléen vrai ou faux

true, vars.value > 30

int

Entier signé

42, -7

uint

Entier non signé

42u

double

Nombre à virgule flottante

30.5, -0.7

chaîne

Texte

"critical", "Alerte de température"

bytes

Séquence d’octets

b"\x00\xff"

list

Collection ordonnée

[1, 2, 3], ["a", "b"]

map

Paires clé-valeur

{"level": "high", "count": 5}

null_type

Valeur nulle

null

horodatage

Un instant précis

vars.timestamp

duration

Une durée

duration("5m")

Conversions de type

Utilisez les fonctions de conversion intégrées pour convertir entre les types :

Fonction
Description
Exemple

int()

Convertir en entier

int(vars.value)

uint()

Convertir en entier non signé

uint(42)

double()

Convertir en double

double(vars.value)

string()

Convertir en chaîne

string(vars.value)

type()

Renvoie le type d’une valeur

type(vars.value)

La conversion en chaîne est particulièrement importante lors de la création de messages de motivation d’alarme, car CEL exige une conversion explicite des nombres en chaînes pour la concaténation.


Opérateurs

Opérateurs de comparaison

Opérateur
Signification
Exemple

==

Égal à

vars.value == 0

!=

Différent de

vars.status != "offline"

>

Supérieur à

vars.value > 30.0

>=

Supérieur ou égal à

vars.value >= 100

<

Inférieur à

vars.value < 5

<=

Inférieur ou égal à

vars.value <= 25.0

Opérateurs logiques

Opérateur
Signification
Exemple

&&

ET logique

vars.value > 30 && vars.value < 50

||

OU logique

vars.value < 0 || vars.value > 100

!

NON logique

!has(vars.humidity)

Opérateurs arithmétiques

Opérateur
Signification
Exemple

+

Addition

vars.value + 10

-

Soustraction

vars.value - vars.outdoor_temp.value

*

Multiplication

vars.value * 1.8 + 32

/

Division

vars.value / 100.0

%

Modulo

vars.value % 10

Opérateur ternaire

L’opérateur ternaire ? : renvoie l’une de deux valeurs en fonction d’une condition :

Les expressions ternaires peuvent être imbriquées pour une classification à plusieurs niveaux :

Opérateurs et fonctions de chaîne

Opération
Syntaxe
Exemple

Concaténation

+

"Temp : " + string(vars.value)

Longueur

size()

vars.name.size() > 0

Contient

contains()

vars.status.contains("error")

Commence par

startsWith()

vars.zone.startsWith("warehouse")

Se termine par

endsWith()

vars.device_id.endsWith("-prod")

Correspondance regex

matches()

vars.device_id.matches("^WH-[0-9]+$")

Fonctions de collection

Fonction
Description
Exemple

x dans la liste

Vérification d’appartenance

vars.zone in ["A", "B", "C"]

clé dans la map

La clé existe dans la map

"humidity" in vars

list.exists(x, expr)

Vrai si un élément satisfait l’expression

[10, 25, 40].exists(t, t > 30)

list.all(x, expr)

Vrai si tous les éléments satisfont l’expression

[10, 25, 40].all(t, t > 0)

list.filter(x, expr)

Renvoie les éléments qui satisfont l’expression

[10, 25, 40].filter(t, t > 20)[25, 40]

list.map(x, expr)

Transforme chaque élément

[1, 2, 3].map(x, x * 10)[10, 20, 30]

list.exists_one(x, expr)

Vrai si exactement un élément satisfait

[10, 25, 40].exists_one(t, t > 30)true

Variables intermédiaires avec cel.bind

Utilisez cel.bind() pour définir une variable temporaire à l’intérieur d’une expression, en évitant un calcul redondant :

Le premier argument nomme la variable, le second calcule sa valeur, et le troisième est l’expression qui l’utilise.

Vérification d’existence

Fonction
Description
Exemple

has()

Renvoie true si le champ existe

has(vars.humidity)

Utilisez has() avant d’accéder à une variable qui pourrait ne pas exister. Après un nœud d’enrichissement avec un événement d’erreur de frontière, par exemple, les données enrichies ne sont disponibles que si l’enrichissement a réussi.


Modèles d’expressions courants

Vérification de seuil

Le modèle le plus simple et le plus courant. Utilisé dans les conditions de passerelle pour brancher sur une seule valeur.

Renvoie true si la lecture du capteur dépasse 30. Fonctionne dans les conditions de passerelle exclusive pour orienter le flux.

Vérification d’intervalle

Tester si une lecture se situe dans une plage acceptable.

Utile pour la conformité CVC, la surveillance de la chaîne du froid ou tout scénario où les bornes supérieure et inférieure comptent.

Vérification multi-condition

Combinez les vérifications sur plusieurs variables. Ce modèle apparaît souvent après l’enrichissement, lorsque des données provenant de plus d’un capteur sont disponibles.

Utilisez toujours has() avant de référencer des variables provenant de sources optionnelles (enrichissement, tâches de script précédentes avec sorties conditionnelles).

Classification de la gravité (tâche de script)

Renvoie une map depuis une tâche de script pour classer une lecture en catégories. Chaque clé devient une variable de processus distincte.

Après cette tâche de script, vars.level est disponible pour les conditions de passerelle ou les messages d’alarme.

Message d’alarme dynamique (Définir l’alarme)

Construisez une chaîne lisible par l’humain qui inclut des données de capteur en temps réel. Le champ de message de motivation dans un nœud Définir l’alarme utilise ce modèle.

N’oubliez pas d’utiliser string() pour convertir les valeurs numériques — CEL ne convertit pas implicitement les nombres en chaînes lors de la concaténation.

Vérification des données enrichies (après enrichissement)

Référencez une valeur récupérée par un nœud d’enrichissement. Le nom de variable utilisé dans la configuration d’enrichissement devient la clé sous vars.

Valeurs dérivées calculées (tâche de script)

Calculez de nouvelles valeurs à partir de plusieurs entrées et stockez-les pour une utilisation en aval.

Après cette tâche de script, la passerelle peut vérifier vars.needs_alarm directement, et le message d’alarme peut faire référence à vars.delta pour le contexte.

Combiner la classification avec des valeurs calculées

Une seule tâche de script peut effectuer plusieurs calculs à la fois.


Où CEL est utilisé

Les expressions CEL apparaissent à plusieurs endroits dans le moteur de règles. Le contexte détermine ce que l’expression doit renvoyer.

Emplacement
Type de retour attendu
Objectif

Événement de démarrage — Entrées

N’importe quel type

Créer des valeurs d’aide locales lorsque l’événement de capteur entre dans la règle.

Événement de démarrage — Sorties

N’importe quel type

Publier des valeurs nommées dans le contexte partagé du workflow.

Tâche de script — Script

N’importe quel type (map de préférence)

Transformer ou classer des données. Les clés de la map fusionnent dans les variables de processus.

Tâche de script — Entrées

N’importe quel type

Créer des valeurs d’aide locales avant l’exécution du script.

Tâche de script — Sorties

N’importe quel type

Publier des valeurs nommées supplémentaires après l’exécution de la tâche.

Passerelle exclusive — Condition

bool

Orienter l’exécution. Doit renvoyer true ou false.

Passerelle exclusive — Entrées

N’importe quel type

Préparer les valeurs locales utilisées par les conditions de branche.

Passerelle exclusive — Sorties

N’importe quel type

Publier des valeurs après la décision d’orientation.

Définir l’alarme — Message de motivation

chaîne

Décrire pourquoi l’alarme a été déclenchée. Affiché aux intervenants.

Définir l’alarme — Entrées

N’importe quel type

Préparer les valeurs avant l’exécution de l’action d’alarme.

Définir l’alarme — Sorties

N’importe quel type

Publier des valeurs après l’exécution du nœud d’alarme.

Enrichissement — ID du capteur

chaîne

Identifier le capteur à partir duquel récupérer les données.

Enrichissement — Entrées

N’importe quel type

Préparer les valeurs avant l’exécution de la recherche.

Enrichissement — Sorties

N’importe quel type

Publier des valeurs après que le résultat de l’enrichissement est disponible.

Portée des entrées et sorties

Les entrées et sorties sur un nœud servent à des fins différentes et ont une visibilité différente :

  • Entrées créent locales des variables limitées au nœud actuel uniquement. Elles ne modifient pas le contexte partagé du workflow. Les expressions d’entrée sont évaluées par rapport à l’état vars actuel. Utilisez-les pour préparer des valeurs d’aide ou pré-calculer des résultats intermédiaires avant l’exécution de la logique principale du nœud.

  • Sorties écrivent des valeurs dans le partagé contexte du workflow (vars). Les expressions de sortie sont évaluées dans la portée locale du nœud — qui inclut à la fois l'original vars et tous les locaux définis par l'entrée. Les valeurs publiées par les sorties persistent et sont accessibles à tous les nœuds en aval.

Conséquence pratique : Si vous définissez une entrée nommée threshold sur une passerelle exclusive, les nœuds en aval ne peuvent pas voir vars.threshold — elle n'existe que pendant l'évaluation de la condition de cette passerelle. Pour rendre une valeur calculée disponible en aval, définissez-la plutôt comme une sortie.


Sécurité et bac à sable

CEL est isolé par conception. Les expressions s'exécutent dans un environnement restreint sans accès à :

  • Le système de fichiers

  • Les ressources réseau

  • Les horloges système (sauf via les variables d'horodatage fournies)

  • Les services externes

  • L'état mutable en dehors de la propre évaluation de l'expression

Une expression ne peut pas créer de boucles infinies, allouer une mémoire illimitée ou affecter d'autres règles. Si une expression échoue (erreur de type, division par zéro, référence à une variable manquante sans has() garde), le nœud qui la contient lève une erreur. Attachez un événement d'erreur de frontière pour gérer ces échecs avec élégance.


Fonctions de la plateforme

En plus de la bibliothèque CEL standard, le moteur de règles fournit deux fonctions spécifiques à la plateforme.

error(message)

Prend un argument de type chaîne et produit toujours une valeur d'erreur. Lorsqu'une expression de tâche de script s'évalue à une erreur, le moteur vérifie la présence d'un événement d'erreur de frontière attaché. S'il en existe un, l'exécution emprunte le chemin d'erreur. Sinon, l'erreur arrête la règle.

Utilisez error() pour une défaillance conditionnelle délibérée — des situations où une condition de données spécifique doit déclencher le chemin de traitement des erreurs plutôt que de poursuivre l'exécution normale.

Dans cet exemple, les températures supérieures à 200 font volontairement échouer la tâche de script. Si un événement d'erreur de frontière est attaché, le chemin d'erreur s'exécute (peut-être en déclenchant une alarme d'urgence). En dessous de 200, la tâche de script produit {"status": "ok"} comme normal.

random()

Renvoie un nombre à virgule flottante pseudo-aléatoire dans l'intervalle [0.0, 1.0). Utile pour l'échantillonnage probabiliste, le routage basé sur un pourcentage ou la génération d'identifiants aléatoires.


Conseils pratiques

Gardez des expressions ciblées. Une seule expression doit faire une seule chose. Si vous devez classifier une mesure, calculer un delta et construire un message, utilisez plusieurs tâches de script plutôt qu'une seule expression complexe. Cela rend la règle plus facile à lire, à déboguer et à maintenir.

Privilégiez d'abord la structure visuelle. Utilisez le canevas pour montrer le workflow, puis utilisez CEL dans les champs pertinents. Un diagramme BPMN lisible avec quelques expressions claires est plus facile à auditer qu'une règle qui cache trop de logique dans une seule immense expression.

Utilisez has() avant les champs facultatifs. Toute variable provenant d'un enrichissement, de tâches de script conditionnelles ou d'entrées facultatives peut ne pas exister. Y accéder sans has() et l'expression lève une erreur.

Convertissez explicitement les types. CEL n'effectue pas de conversion de type implicite. Lorsque vous construisez des messages d'alerte, convertissez les nombres avec string(). Lors d'opérations arithmétiques, assurez-vous que les deux opérandes sont du même type numérique — mélanger int et double peut produire des résultats inattendus.

Utilisez des maps pour les sorties à plusieurs valeurs. Retourner une map depuis une tâche de script est la manière standard de rendre plusieurs valeurs calculées disponibles en aval. Chaque clé devient une variable de processus indépendante.

Testez les expressions sur des cas limites. Réfléchissez à ce qui se passe lorsqu'un capteur renvoie zéro, une valeur négative ou un nombre anormalement élevé. Les conditions de passerelle doivent gérer toute la plage des entrées possibles sans orienter vers une branche non souhaitée.

Nommez les variables de façon descriptive. Lorsque vous définissez des noms de variables d'enrichissement ou des clés de sortie de tâche de script, utilisez des noms qui décrivent les données — outdoor_temp, humidity_reading, severity_level — pas x, val2, ou tmp. Vos collègues les liront lorsqu'ils examineront ou modifieront la règle.

Mis à jour