Actions

L'éditeur d'action : identité et emplacement, le bloc de script, ce qu'un script peut lire et écrire, chaque message de validation, le verbe Exécuter et sa journalisation, qui a déclenché la dernière exécution, ce qui exécute l'action, Activer et Désactiver, Copier et Supprimer, et les limites d'une exécution.

Afficher en Markdown

Une action est un bloc d'instructions JavaScript qui lit l'espace d'adressage et écrit des variables mémoire et des tags. Les actions sont le chemin d'écriture de Logic : elles s'exécutent à la demande (Exécuter), sur un déclencheur, depuis un Bouton de tableau de bord qui leur est associé, ou au démarrage ou à la fin d'un essai de Process, par une commande d'action Logic. Sélectionnez une action sous la section Actions de la colonne Logic, ou appuyez sur Ouvrir sur sa ligne dans le tableau de son dossier ou de la racine de sa section, pour ouvrir son éditeur (une action créée avec Nouveau… > Nouvelle action ne s'ouvre pas, elle est mise en évidence dans ce tableau, voir Créer et copier); lire demande Voir Logic, modifier Configurer Logic, exécuter Piloter Logic.

L'en-tête montre la marque de l'action, le nom, la ligne « Un script que vous exécutez à la demande, ou qu'un déclencheur exécute pour vous, en écrivant des variables et des tags. » et un badge Désactivée tant que l'action est éteinte. La colonne du formulaire porte IDENTITÉ, SCRIPT DE L'ACTION et Utilisé par; le rail porte DERNIÈRE EXÉCUTION.

Identité

Champ Ce que c'est Valeurs et valeur par défaut Effet
Nom Le nom affiché et le libellé sous lequel une exécution est journalisée. Texte libre; une nouvelle action s'appelle ActionN; un nom vide s'enregistre comme Action. S'enregistre automatiquement à chaque frappe. Les actions sont référencées par identité : le renommage ne réécrit rien et ne casse rien.
Ligne d'emplacement Où l'action est classée, en toutes lettres : Actions / Startup / Walk setpoint. Lecture seule. Une action n'a pas d'adresse; la ligne est un endroit, jamais quelque chose à taper dans une expression. Changez-la avec Déplacer vers dans l'arborescence.
Description (facultative) Texte libre. Vide par défaut. Aucun.

Script de l'action

La carte SCRIPT DE L'ACTION est l'éditeur de script, avec l'indication « Instructions JavaScript (let, if, for, fonctions). Écrivez les variables mémoire par affectation (Variables.Setpoint = 21.5;) et les tags avec Connector.Driver.Device.Tag.Write(value). Les lectures ne sont pas filtrées par la qualité : vérifiez .State() et protégez les manques avec?? avant tout calcul. » Le script s'enregistre automatiquement à chaque frappe et est validé toutes les demi-secondes; le message apparaît sous l'indication. La validation n'exécute jamais le script.

Un script est du JavaScript ordinaire en mode strict (variables locales, if, boucles, fonctions, Math, Date, JSON) sur le même espace d'adressage et la même surface de lecture que les expressions, avec deux différences. Les lectures ne passent pas la barrière de qualité : un vide se lit comme null, alors vérifiez .State() et protégez le calcul avec ??; traiter une mauvaise lecture est justement ce à quoi servent les actions. Et un script peut lire des variables d'expression (leur valeur publiée); seule une expression ne peut pas les référencer.

Un point en direct (un tag, une variable, une alarme, un canal de Process) est le point, pas sa valeur : lisez donc sa valeur par un membre, if (Variables.Start.ValueToBool()), Variables.Level.ValueToReal() > 80, if (Alarms.High.IsActive). Écrit nu dans le test de if, while, do, for ou ?:, comme opérande de !, && ou ||, dans une comparaison ou dans l'arithmétique (+= et les autres affectations composées compris), il compterait toujours comme vrai ou ne lirait jamais sa valeur : if (Variables.Start) { … } exécuterait son bloc à chaque exécution, quelle que soit la valeur de la variable. La validation le refuse et nomme le membre à lire à la place (Ce que la validation refuse). Un point passé à une fonction, et tout membre d'un point, reste tel qu'il est écrit. Il en va de même pour un switch sur un point nu ou un case qui en nomme un (lisez .Value), pour le côté gauche de ?? (lisez .Value) et pour un emplacement ${…} d'un gabarit littéral (lisez .ValueToString()). Une affectation composée à une variable (Variables.Total += 1, -=, ||= et les autres) lit la variable comme le point avant d'écrire, elle est donc refusée avec l'affectation simple qui fonctionne : Variables.Total = Variables.Total.ValueToReal() + 1.

Ce qu'une action peut écrire

Exactement deux constructions modifient l'installation, et les deux passent par le canal d'écriture journalisé :

Écriture Forme Cible
Affectation en mémoire Variables.Setpoint = 21.5; ou Variables.Forno.Setpoint = 21.5; Une variable mémoire, niveaux de dossier compris. La valeur est convertie vers le type de sortie de la variable et marquée pour la rémanence quand la variable est rémanente. Elle s'applique aussitôt : la ligne suivante du même script relit donc ce qu'elle vient d'écrire.
Écriture de tag Connector.Simulated.Pump.Cmd.Write(true); ou …Cmd.WriteAndWait(true); Un tag vivant. La valeur est une valeur physique : elle remonte à l'envers la chaîne de conversion du tag jusqu'à la valeur brute que l'équipement accepte, et le canal la remet à la file d'acheminement propre à cet équipement, où les valeurs dues à cet équipement partent une à une, dans l'ordre d'arrivée.

Un tag porte deux verbes d'écriture, et le script choisit selon qu'il a besoin de la réponse :

Verbe Arguments Omis Renvoie Attend l'équipement
Write(value) La valeur. Rien à omettre. Rien. Non. La valeur est remise à la file de l'équipement et la ligne suivante s'exécute.
WriteAndWait(value, timeoutMs, continueOnFailure) La valeur, combien de millisecondes l'attendre, et s'il faut poursuivre quand elle échoue. timeoutMs : le temps d'attente propre au pilote sert à sa place. continueOnFailure : true. true seulement quand l'équipement a pris la valeur; false pour tout le reste, une valeur devancée comprise. Oui, jusqu'à l'accusé de réception ou à l'épuisement du temps d'attente.

L'attente se fait sur la voie des actions : un équipement lent ne retient donc que les actions derrière celle-ci, et elle ne retire jamais l'écriture; une valeur qui n'est pas confirmée à temps voyage encore, et son accusé de réception est journalisé à son arrivée. C'est ce que dit la réponse, en toutes lettres : « « Cmd » n'a pas été confirmé en 2000 ms; la valeur est encore en route vers l'équipement. » Avec continueOnFailure omis ou à true, le verbe répond false et le script poursuit; avec false, l'exécution se termine à cette ligne, en nommant la cible et la raison.

Aucune écriture n'interrompt un script à elle seule. Une écriture refusée avant tout envoi et une écriture que l'équipement refuse ou à laquelle il ne répond jamais échouent toutes deux seules : le reste du script s'exécute, et l'exécution se termine comme une exécution réussie avec des écritures en échec. Rien n'est défait non plus : ce qui s'est appliqué avant une écriture en échec reste appliqué, et le journal montre chaque écriture de l'ancienne vers la nouvelle valeur sous la source Action. Les raisons dans lesquelles se lit un refus :

  • « L'écriture dans « X » a été rejetée: la valeur n'est pas finie. » (NaN ou infini)
  • « « Tag » n'est pas matérialisé dans le connecteur. » (un équipement désactivé, ou un tag que le Connector ne porte pas)
  • « « valeur » n'a pas pu être converti pour « Tag ». »
  • « « X » est protégé en écriture par « <qui la retient> ». » (une recette en cours ou un verrouillage retient la source)
  • « « Cmd » n'a pas été écrit : l'équipement n'est pas connecté. » (l'équipement est déjà connu pour être hors service, alors rien n'est mis en file pour lui)
  • « L'écriture dans « Tag » a échoué : le Connector ne fonctionne pas. »
  • « La variable « X » est introuvable. » et « « Variables.X » est une variable d'expression : elle est calculée, jamais écrite. »
  • Ce que l'équipement ou son pilote a répondu, dans ses propres mots, quand le refus est venu du fil.

Une valeur qu'une écriture plus récente sur le même tag a devancée dans la file de l'équipement n'est pas un échec : « « Cmd » a été remplacé par une valeur plus récente avant l'envoi. » est exactement ce qui s'est passé, c'est la valeur la plus récente qui est dite à l'équipement, et rien n'en est rapporté nulle part sauf à un WriteAndWait, qui répond false parce que cette valeur n'est pas celle qui est partie.

Ce qui met fin à une exécution : une erreur du script lui-même (une erreur de syntaxe, une adresse qui ne nomme rien, une exception), un WriteAndWait(…, false) dont l'écriture a échoué, et les limites d'exécution décrites sous Exécuter.

Les échecs que l'exécution peut elle-même rapporter découlent de qui a attendu. Un Write refusé avant tout envoi l'est pendant que le script tourne encore : l'exécution le compte et le journal des actions le dit; un Write que l'équipement refuse ensuite reçoit sa réponse bien après la fin de l'exécution, alors c'est la console Événements, sous le nom de l'action, qui le porte, et jamais l'exécution. Un WriteAndWait est resté pour la réponse : il la compte donc dans un sens comme dans l'autre.

Ce que la validation refuse

Message Cause
« Un script est obligatoire. » L'éditeur est vide.
« Erreur de script : … » Le texte ne s'analyse pas.
« Les adresses doivent être statiques : « Root » est atteint par un segment calculé. » Variables[name] ou tout segment qui n'est pas un littéral.
« Adresse incomplète « … ». » Une référence trop courte pour nommer un point.
« « X » est introuvable. » Une lecture, ou une cible d'affectation, qui ne se résout vers rien.
« « X » est une valeur : lisez-la sans .Value. » Un membre de point en direct (.Value, .ValueToBool(), .State(), …) lu sur un point qui entre dans le script comme sa valeur : System.StartTime.Value ou Process.Oven_soak.Oven_1.Procedure.Running.ValueToBool(). Le message nomme le membre écrit.
« « X » est le point lui-même, pas sa valeur : comme condition, il compte toujours comme vrai. Lisez sa valeur avec X.ValueToBool(). » Un point en direct écrit nu là où il est testé comme vrai ou faux : le test de if, while, do, for ou ?:, ou un opérande de !, && ou \|\| (if (Variables.Start)). Sur une alarme, le message nomme .IsActive.
« « X » est le point lui-même, pas sa valeur : une comparaison ou un calcul ne lit jamais sa valeur. Lisez sa valeur avec X.ValueToReal(). » Un point en direct écrit nu dans une comparaison ou dans l'arithmétique (Variables.Level > 80, total += Variables.Level). Pour ==, !=, === et !==, le message nomme .Value, et sur une alarme .IsActive. Un switch sur un point nu, ou un case qui en nomme un, reçoit le message avec .Value.
« « X » est le point lui-même, pas sa valeur : il n'est jamais vide, donc ?? le garde toujours. Lisez sa valeur avec X.Value. » Un point en direct écrit nu à gauche de ?? (Variables.Level ?? 0). Sur une alarme, le message nomme .IsActive.
« « X » est le point lui-même, pas sa valeur : écrit dans un texte, il n'y montre jamais sa valeur. Lisez sa valeur avec X.ValueToString(). » Un point en direct écrit nu dans un emplacement ${…} d'un gabarit littéral. Sur une alarme, le message nomme .IsActive.
« « += » lit X comme le point lui-même, pas sa valeur, avant d'écrire. Utilisez X = X.ValueToReal() + 1. » Une affectation composée à une variable : +=, -=, *=, /=, %=, **=, celles bit à bit, &&=, \|\|= et ??=. Le message nomme l'opérateur écrit et l'affectation simple qui fait ce qu'il dit, avec le côté droit tel qu'il est écrit : .ValueToReal() pour l'arithmétique, .ValueToInteger() pour celles bit à bit, .ValueToBool() pour &&= et \|\|=, .Value pour ??=.
« Affectez la variable elle-même : Variables.Name = value. » La partie gauche du = nomme un membre, ou descend plus bas que ne va l'adresse d'une variable.
« « X » est une variable d'expression : elle est calculée, jamais écrite. » Une affectation à une variable d'expression.
« Les points « Connector » sont en lecture seule. Écrivez les tags avec Connector.Driver.Device.Tag.Write(value). » Une affectation à une racine autre que Variables (Process a son propre message).
« Les points Process sont en lecture seule dans les actions; les commandes d'essai et les écritures de préparation ne sont pas prises en charge par les scripts. » Une affectation à un point Process, ou un appel de Write sur un point Process.
« Les commandes d'essai de Process ne peuvent pas être appelées depuis les actions; les points de commande exposent des valeurs de disponibilité en lecture seule. » L'appel de Process.<Model>.<Unit>.Commands.Start() ou de tout autre point de commande; un point Commands ne fait que dire si la commande pourrait s'exécuter maintenant.
« Les opérateurs ++ et -- ne sont pas pris en charge sur les points. Utilisez Variables.Name = Variables.Name.ValueToReal() + 1. » Variables.N++.
« Write(value) est l'écriture du tag : Connector.Driver.Device.Tag.Write(value). » Write appelé sur autre chose qu'une adresse de tag. La phrase nomme le verbe employé : WriteAndWait reçoit donc la même, avec son propre nom aux deux endroits.
« Le temps d'attente de WriteAndWait doit être un nombre de millisecondes : WriteAndWait(value, 2000). » Le deuxième argument est écrit et n'est pas un nombre.
« Le « continuer en cas d'échec » de WriteAndWait doit être true ou false : WriteAndWait(value, 2000, false). » Le troisième argument est écrit et n'est ni true ni false.
« WriteAndWait prend au plus trois arguments : la valeur, le temps d'attente en millisecondes et s'il faut continuer en cas d'échec. » Un quatrième argument.

Les trois messages de WriteAndWait jugent ce que dit le texte lui-même. Un argument que l'éditeur ne peut pas trancher à la lecture (une variable, une expression calculée) est jugé au moment où l'appel a lieu, et la même phrase met alors fin à l'exécution à cette ligne.

Les variables locales de JavaScript (let x = 1; x = x + 1;) ne sont touchées par aucune de ces règles.

Exécuter

Exécuter est le verbe de tête de la barre au-dessus d'une action ouverte; il n'est dessiné que pour un rôle qui détient Piloter Logic et il est grisé avec « Runtime arrêté » pendant que la station est en lecture seule (le verrou d'ingénierie ne le grise pas : exécuter est du pilotage, pas de la configuration). Quand le rôle détient aussi Configurer Logic, le brouillon de l'éditeur est enregistré d'abord et l'exécution porte sur la définition enregistrée; sans cette permission, l'exécution porte sur la définition durable (les champs sont en lecture seule, donc les deux ne diffèrent jamais).

Chaque exécution se fait sur la voie des actions avec un moteur de script neuf : aucun état ne fuit d'une exécution à l'autre, et deux scripts ne tournent jamais en même temps, ils s'exécutent un à la fois, dans l'ordre où ils ont été demandés. La voie n'est pas le cycle de 100 ms. Les expressions, les alarmes, les acquittements et les écritures qui arrivent d'ailleurs continuent pendant qu'un script tourne : un cycle peut donc tomber au milieu d'un script et deux lectures d'un même script voir des cycles différents; en échange, une action qui s'arrête pour attendre un équipement ne retarde que les actions en file derrière elle, et rien d'autre dans la station.

Une exécution est interrompue au-delà de 500 ms (« Le script a été interrompu : il a dépassé la limite de temps de 500 ms (boucle infinie?). »), de 100 000 instructions ou de 4 MB de mémoire, chacune avec un message qui nomme la limite. Les 500 ms mesurent le script en train de s'exécuter : le décompte est suspendu tant qu'un WriteAndWait attend un équipement et reprend ensuite, si bien qu'un script correct n'est jamais blâmé pour la lenteur de l'équipement. Une action désactivée échoue sans s'exécuter (« L'action est désactivée. »); un runtime arrêté répond « Le runtime de la logique n'est pas en service. »

Le journal des actions signale « Exécution réussie en 12 ms. » quand chaque écriture est passée, « Exécution réussie en 12 ms, 1 écriture en échec : Cmd : « Cmd » n'a pas été écrit : l'équipement n'est pas connecté. » quand le script lui-même est allé au bout et qu'une écriture non (avec « Exécution réussie en 12 ms, 3 écritures en échec, la première : Cmd : « Cmd » n'a pas été écrit : l'équipement n'est pas connecté. » à partir du deuxième échec), ou « Échec de l'exécution : <raison> » quand c'est l'exécution elle-même qui s'est mal terminée.

L'exécution en échec parvient à la console Événements, sous le nom de l'action et avec ce qui l'a lancée : Manuel pour le verbe, Dashboard pour un Bouton, MCP pour l'agent, le nom du déclencheur pour une exécution planifiée, et Process · <unit> · <action> pour un essai de Process. Il est journalisé comme un avertissement la première fois, résumé tant qu'il échoue pour la même cause, et noté une fois encore au rétablissement, et cette ligne de rétablissement est la seule entrée qu'une exécution réussie y écrive jamais. Une écriture refusée parvient à la console de la même façon et sous le même nom, et pour la même raison c'est l'action qui est nommée et non l'exécution : la réponse de l'équipement peut arriver des secondes après la fin de l'exécution, et il ne reste plus d'exécution à faire échouer. Une exécution qui réussit simplement, et chaque valeur qu'elle écrit, ne vont qu'à la capture détaillée : un script qui écrit à chaque cycle produit des valeurs par milliers, et une console qui en est pleine est une console où personne ne lit les nouvelles de la station.

Le rail DERNIÈRE EXÉCUTION montre quand l'action s'est exécutée pour la dernière fois (ou « Jamais exécutée. »), « Durée : N ms », qui l'a déclenchée (ci-dessous), la dernière erreur dans une note de prudence, les écritures en échec de cette exécution dans une note de prudence à elles (la même phrase que portait le journal des actions, si bien qu'une exécution qui a réussi en laissant quand même une consigne là où elle était le dit aussi ici), et le rappel « Les exécutions se font sur la voie des actions, une à la fois. Seule une exécution en échec parvient à la console des événements; une exécution réussie, et chaque valeur qu'elle écrit, est conservée pour la capture détaillée. Les déclencheurs appellent les actions selon leur planification. » Le rail appartient à l'action vivante : un enregistrement automatique ne le vide jamais; un redémarrage du runtime, si.

Déclenchée par

Sous la durée, la ligne « Déclenchée par : … » dit ce qui a exécuté l'action en dernier :

Ce qui l'a exécutée La ligne indique
Exécuter sur cette page « Déclenchée par : Exécution depuis cette page »
Un Bouton de tableau de bord « Déclenchée par : Un bouton de tableau de bord »
L'agent (action_run) « Déclenchée par : Agent logiciel »
Un déclencheur Le nom du déclencheur : « Déclenchée par : Heater off when too hot ».
Une commande d'action Logic d'un essai de Process L'unité et le groupe d'actions : « Déclenchée par : Process · Oven 1 · After soak ».

Utilisé par

La carte Utilisé par liste tout ce qui, dans la station, exécute l'action (« Tout ce qui, dans la station, exécute cette action. »), lue à l'ouverture de l'action : une ligne par commande de Process qui la déclenche, par déclencheur qui lui est associé et par Bouton de tableau de bord qui l'exécute.

Nature Emplacement Nom
Commande Process Le modèle. Le groupe d'actions et le moment : After soak · Fin.
Déclencheur Vide. Le déclencheur, sous ses dossiers.
Bouton Le tableau de bord. Le libellé du Bouton.

Sans rien, elle dit « Rien dans la station n'exécute cette action. »; quand les références ne peuvent pas être lues, « Cette action est peut-être encore utilisée. Réessayez avant de la supprimer ou de la renommer. » avec Réessayer. La carte ne fait que lire, donc chaque rôle la voit, y compris quand la station est verrouillée en ingénierie. Lisez-la avant de désactiver ou de supprimer une action : une commande de Process dont l'action a disparu n'exécute rien et le dit sur sa propre page.

Lire l'essai qui l'a déclenchée

Une action qu'un essai de Process déclenche à la fin lit cet essai sous la branche LastRun de l'unité, qui le porte déjà quand l'action s'exécute; une action déclenchée au démarrage lit les métadonnées de l'essai qui commence sous Procedure.Metadata. Les points de Process se lisent comme des valeurs brutes, sans .Value après eux, contrairement aux variables, et un point que l'essai ne porte pas se lit null, donc protégez-le :

if (Process.Oven_soak.Oven_1.LastRun.Verdict === "Ok") {
  Variables.Last_serial = Process.Oven_soak.Oven_1.LastRun.Metadata.Serial;
}
const peak = Process.Oven_soak.Oven_1.LastRun.Evaluations.Soak_check.Temperature_in_range.MaxValue;
if (peak !== null) {
  Variables.Last_peak = peak;
}

Les adresses s'écrivent en entier, comme toute adresse d'un script : une adresse ne peut pas se construire à partir d'une variable.

Commandes

Commande Ce qu'elle fait Grisée quand Non dessinée quand
Exécuter Enregistre le brouillon (avec Configurer Logic) et met une exécution en file. Runtime arrêté. Le rôle n'a pas Piloter Logic.
Activer / Désactiver Bascule Activée; une action désactivée refuse Exécuter et laisse inactif chaque déclencheur qui lui est associé, et une commande de Process qui la déclenche est refusée à chaque fois et passe À vérifier. Station verrouillée ou en lecture seule. Le rôle n'a pas Configurer Logic.
Copier Duplique l'action à la racine Actions sous un nom libre et met la copie en évidence dans le tableau de cette racine au lieu de l'ouvrir (Créer et copier); la copie n'a aucune exécution enregistrée et aucun déclencheur associé. Station verrouillée ou en lecture seule. Le rôle n'a pas Configurer Logic.
Supprimer l'action Demande « Supprimer « X »? Cela retire l'action. Cette action est irréversible. » Un déclencheur qui lui était associé reste sans action, il n'est pas supprimé; une commande de Process qui l'exécute reste, n'exécute rien et passe À vérifier. Station verrouillée ou en lecture seule. Le rôle n'a pas Configurer Logic.

Le volet de la racine Actions liste chaque action avec son état dans la colonne Valeur : « Activée · dernière exécution <quand> », avec « · erreur » quand la dernière exécution a échoué, « · écriture en échec » quand elle a réussi et qu'une de ses écritures non, ou « Désactivée ».

Ce que les actions ne font pas

Elles ne lancent pas les commandes d'essai de Process, ne préparent pas une procédure et n'ajoutent pas de commentaire d'essai (ces points ne sont que des valeurs de disponibilité et de préparation, en lecture seule); elles n'acquittent pas les alarmes; elles ne s'exécutent pas en parallèle; elles ne gardent aucun état d'une exécution à l'autre et ne partagent aucune fonction; et elles ne partent ni sur un changement de valeur, ni sur une condition, mais seulement par Exécuter, par l'intervalle d'un déclencheur, par un bouton de tableau de bord, par l'agent ou par la commande d'un essai de Process. Un essai de Process n'attend jamais l'action qu'il déclenche, et le résultat de l'action n'est jamais écrit dans l'essai.