Scripts et Formules

L'application Serveur dispose d'un moteur intégré pour exécuter des scripts utilisateurs. Les scripts sont utilisés pour calculer les valeurs et statuts des canaux, ainsi que pour calculer les valeurs des commandes.

Les scripts sont écrits dans la table Scripts de la base de données de configuration. Un projet créé à l'aide d'un modèle contient déjà un ensemble initial de scripts qui peuvent être utilisés comme exemples pour développer vos propres scripts. Les variables et fonctions implémentées dans la table Scripts sont ensuite appelées dans les colonnes Formule d'Entrée et Formule de Sortie de la table Canaux. Pour effectuer des calculs de formule pour un canal, sélectionnez la case dans la colonne Formule Activée.

Règles de Création de Scripts

Règles générales pour écrire et utiliser des scripts :

  1. Les scripts sont écrits selon la syntaxe du langage C#. Diverses classes du framework .NET sont disponibles, telles que Math, DateTime et File.
  2. De nouvelles constantes, champs, propriétés et méthodes sont ajoutés à la table Scripts et deviennent disponibles dans les formules des canaux.
  3. Si au moins un script ou une formule contient une erreur, le fonctionnement du Serveur est impossible. Les informations sur les erreurs dans les scripts sont écrites dans le journal d'application du Serveur.

Règles pour le calcul des formules des canaux :

  1. Une formule d'entrée pour les canaux des types Entrée et Entrée/Sortie est calculée uniquement lorsque le Serveur reçoit de nouvelles données pour ces canaux. Utilisez ces types de canaux si les données proviennent de dispositifs.
  2. Une formule d'entrée pour les canaux des types Calculé et Calculé/Sortie est calculée en continu à chaque itération de la boucle principale du Serveur. La séquence de calcul va du numéro de canal le plus petit au plus grand.
  3. Une formule de sortie pour les canaux des types Entrée/Sortie, Calculé/Sortie et Sortie est calculée lorsqu'une commande est envoyée au canal correspondant.
  4. Un statut de canal après le calcul d'une formule d'entrée pour les types Entrée et Entrée/Sortie est égal au statut des données transférées au Serveur, sauf si le calcul du statut est explicitement spécifié dans la formule.
  5. Pour les canaux des types Calculé et Calculé/Sortie, le statut est défini sur Défini si le calcul du statut n'est pas explicitement spécifié dans la formule.
  6. Si une formule d'entrée contient le symbole ";", elle est divisée en deux parties : la première calcule la valeur du canal, et la seconde calcule le statut du canal.
  7. Si un canal a des limites spécifiées, le statut du canal est recalculé en tenant compte des limites après le calcul de la formule d'entrée du canal.
  8. Les formules doivent retourner des valeurs de types de données spécifiques, décrits ci-dessous.

Les formules d'entrée des canaux retournent des données des types suivants :

Type de Données Description
double Valeur du canal
CnlData Valeur et statut du canal
long Valeur entière 64 bits d'un canal dont le type de données est défini sur Entier dans la table Canaux
string Valeur texte d'un canal dont le type de données est défini sur Chaîne ASCII ou Chaîne Unicode dans la table Canaux

Si une formule d'entrée retourne un type de données autre que ceux listés ci-dessus, la valeur retournée par la formule est convertie au type approprié basé sur le type de données du canal. La partie de la formule d'entrée du canal qui calcule le statut du canal doit retourner une valeur entière de type int.

Les formules de sortie des canaux retournent des données des types suivants :

Type de Données Description
double Valeur de commande. Pour annuler une commande, la formule doit retourner double.NaN
CnlData Valeur de commande. Pour annuler une commande, la formule doit retourner CnlData.Empty
byte[] Données binaires de commande. Pour annuler une commande, la formule doit retourner null
string Données de commande sous forme de chaîne. Converties par le Serveur en un tableau de bytes

Variables Disponibles

Le moteur de script fournit les variables intégrées suivantes :

Variable Type de Données Description
Timestamp DateTime Horodatage des données traitées (UTC)
IsCurrent bool Indique si les données traitées sont des données actuelles
CnlNum int Numéro du canal pour lequel la formule est calculée
Channel Cnl Propriétés du canal pour lequel la formule est calculée
ArrIdx int Index de l'élément du tableau traité
Cnl, CnlVal double Valeur du canal transmise au Serveur avant le calcul
CnlStat int Statut du canal transmis au Serveur avant le calcul
CnlData CnlData Données du canal transmises au Serveur avant le calcul
Cmd, CmdVal double Valeur de commande transmise au Serveur avant le calcul
CmdData byte[] Données de commande transmises au Serveur
CmdDataStr string Données de commande sous forme de chaîne

Fonctions Disponibles

Le moteur de script fournit les fonctions intégrées suivantes :

Fonction Type de Données Description
N(n) int Retourne le numéro du canal n. Utilisé dans le clonage de canaux
Val() double Valeur actuelle du canal pour la formule
Val(n) double Valeur actuelle du canal n
SetVal(n, val) double Définit la valeur actuelle du canal n
Stat() int Statut actuel du canal pour la formule
Stat(n) int Statut actuel du canal n
SetStat(n, stat) int Définit le statut actuel du canal n
Data() CnlData Données actuelles du canal pour la formule
Data(n) CnlData Données actuelles du canal n
SetData(n, val, stat) double Définit la valeur et le statut actuels du canal n
SetData(n, cnlData) double Définit les données actuelles du canal n
NewData(val, stat) CnlData Crée une nouvelle instance de données de canal
PrevVal() double Valeur précédente du canal pour la formule
PrevVal(n) double Valeur précédente du canal n
PrevStat() int Statut précédent du canal pour la formule
PrevStat(n) int Statut précédent du canal n
PrevData() CnlData Données précédentes du canal pour la formule
PrevData(n) CnlData Données précédentes du canal n
Time() DateTime Horodatage actuel du canal pour la formule
Time(n) DateTime Horodatage actuel du canal n
PrevTime() DateTime Horodatage précédent du canal pour la formule
PrevTime(n) DateTime Horodatage précédent du canal n
Deriv(n) double Dérivée temporelle du canal n

Fonctions du Modèle de Projet

Dans un projet créé à partir d'un modèle standard, la table Scripts contient les fonctions suivantes :

Fonction Type de Données Description
GetBit(val, n) double Retourne le nème bit de la valeur spécifiée
GetBit(cnlData, val) CnlData Retourne les données du canal composées du nème bit de la valeur et du statut du canal
SetBit(val, n, isOn) double Définit le nème bit de la valeur spécifiée
SetBit(cnlData, n, isOn) CnlData Définit le nème bit de la valeur du canal, tout en conservant le statut du canal
GetByte(val, n) double Retourne le nème octet de la valeur spécifiée
DataRel(offset) CnlData Données du canal relatives au canal actuel
SetData() double Définit les données actuelles du canal en fonction de la valeur de commande
Now() double La date et l'heure actuelles sous forme de nombre à virgule flottante. Utilise le fuseau horaire du serveur
UtcNow() double La date et l'heure actuelles sous forme de nombre à virgule flottante. Utilise le fuseau horaire universel (UTC)
UnixTime() long Heure Unix actuelle en secondes
EncodeDate(dateTime) double Convertit la date et l'heure spécifiées en une valeur de canal de type Double
DecodeDate(val) DateTime Convertit la valeur du canal en une date et une heure
EncodeAscii(s) double Convertit une chaîne ASCII de 8 caractères maximum en un nombre à virgule flottante
EncodeUnicode(s) double Convertit une chaîne Unicode de 4 caractères maximum en un nombre à virgule flottante
DecodeAscii(val) string Convertit la valeur spécifiée en une chaîne ASCII de 8 caractères maximum
DecodeUnicode(val) string Convertit la valeur spécifiée en une chaîne Unicode de 4 caractères maximum
Substring(s, startIndex, length) string Extrait une sous-chaîne de la chaîne avec vérification des limites
SplitAscii(getStringFunc) string Divise une chaîne ASCII pour être stockée dans plusieurs canaux
SplitUnicode(getStringFunc) string Divise une chaîne Unicode pour être stockée dans plusieurs canaux
EverySec(getDataFunc) CnlData Exécute la fonction spécifiée toutes les secondes
EveryMin(getDataFunc) CnlData Exécute la fonction spécifiée toutes les minutes
EveryHour(getDataFunc) CnlData Exécute la fonction spécifiée toutes les heures
CountPulse(cnlNum) double Compte les impulsions du canal spécifié
HourStarted() bool Indique qu'une nouvelle heure a commencé. Le résultat est vrai une fois pour chaque canal
DayStarted() bool Indique qu'un nouveau jour a commencé. Le résultat est vrai une fois pour chaque canal
MonthStarted() bool Indique qu'un nouveau mois a commencé. Le résultat est vrai une fois pour chaque canal

Des scripts supplémentaires, notamment pour le calcul de moyennes, sont disponibles sur GitHub.

Débogage des Scripts

Lors du développement de vos propres scripts, suivez les règles de syntaxe et vérifiez que les scripts fonctionnent correctement. Si le service Serveur ne parvient pas à compiler les scripts au démarrage, les informations sur les erreurs s'affichent dans le journal des opérations du Serveur ScadaServer.log, et le code source compilé est disponible dans le fichier CalcEngine.cs, situé dans le répertoire des journaux du Serveur. Pour développer des formules complexes, nous recommandons d'utiliser Microsoft Visual Studio ou Visual Studio Code.

Exemples de Formules

Exemple 1 : Transformation linéaire de la valeur d'un canal reçue d'un dispositif. La formule est utilisée pour un canal de type Entrée.

10 * Cnl + 1

Exemple 2 : La somme des valeurs des canaux 101 et 102. Le statut est extrait du canal 101. La formule est utilisée pour un canal de type Calculé.

Val(101) + Val(102); Stat(101)

Exemple 3 : La formule utilisée pour un canal de type calcul extrait le 0ème bit des données du canal 105.

GetBit(Data(105), 0)

Exemple 4 : La formule incrémente le compteur d'une unité chaque minute, en réinitialisant le compteur au début de chaque heure.

EveryMin(() => HourStarted() ? 0 : Val() + 1)