Module opcua
Le module opcua permet de communiquer avec des serveurs OPC UA (Unified Architecture) pour lire et écrire des données industrielles.
Import
Pour importer le module en Lua :
Configuration YAML
Le module opcua nécessite une configuration dans le fichier YAML de l'agent :
iot:
modules:
opcua:
- name: opcua1 # nom unique de l'instance
endpoint: "opc.tcp://localhost:4840" # URL du serveur OPC UA
cert_file: "/etc/alemca/opcua/client.pem" # certificat client (optionnel)
key_file: "/etc/alemca/opcua/client.key" # clé privée RSA (optionnel)
trusted_dir: "/etc/alemca/opcua/trusted" # dossier certs serveur fiables (optionnel)
username: "" # nom d'utilisateur (optionnel)
password: "" # mot de passe (optionnel)
timeout: 30 # timeout en secondes (optionnel, défaut: 30)
persistent: true # garde la session ouverte (recommandé en production)
# idle_timeout: 60 # agent >= 3.3.0, sans effet si persistent: true
# namespace_uri: "urn:vendor:model" # namespace du SERVEUR, voir plus bas
Détails de la configuration
- name : Nom unique de l'instance du module. Utilisé pour l'import en Lua.
- endpoint : URL complète du serveur OPC UA (format
opc.tcp://host:port). L'agent utilise toujours cette URL comme cible de connexion, même si le serveur annonce une URL différente pendant la découverte — utile derrière un NAT ou dans des déploiements conteneurisés. - cert_file : Chemin vers le certificat client au format PEM. Quand fourni (avec
key_file), active le SecureChannel chiffré et signé. La policy et le mode sont auto-négociés avec le serveur (typiquementBasic256Sha256+SignAndEncrypt). Le certificat doit contenir unApplicationURIdans lesSubject Alternative Names(exigence OPC UA). - key_file : Chemin vers la clé privée RSA au format PEM (PKCS#1 ou PKCS#8). Doit correspondre à
cert_file. Permissions recommandées :0600(un warning est loggé sinon). - trusted_dir : Dossier optionnel contenant les certificats serveur de confiance (
*.pem,*.crt). Si renseigné, seuls les serveurs dont le certificat vérifie contre ce pool sont acceptés ; sinon, tout certificat serveur est accepté. - username / password : Authentification utilisateur optionnelle.
- timeout : Délai d'attente pour les opérations, en secondes (défaut: 30).
- persistent : Garde une seule session ouverte en permanence, quels que soient les appels à
connect()etdisconnect(). Recommandé en production, surtout avec un certificat client : sans cette clé, chaque nouvelle session rejoue une poignée de main de sécurité complète (calcul RSA), coûteuse sur une passerelle ARM. - idle_timeout (agent 3.3.0 et suivants) : En mode non persistant, délai en secondes après lequel une session inutilisée est fermée (défaut : 60). Sans effet avec
persistent: true. - namespace_uri : URI d'un namespace du serveur OPC UA, utilisée pour résoudre les browse paths et les tags symboliques qui ne précisent pas d'index
ns=. Inutile quand on ne manipule que des NodeId complets (ns=2;s=...). Un avertissementconfigured namespace_uri ... not found on serverest journalisé à la connexion si le serveur ne la connaît pas.
Ne pas confondre avec l'URI du certificat client
L'ApplicationURI du certificat client (urn:alemca:agent dans l'exemple ci-dessous) est l'identité de l'agent auprès du serveur. Ce n'est pas un namespace du serveur : la reporter dans namespace_uri, ici ou dans une table d'échange input_opcua du bridge, rend tous les points concernés introuvables, sans erreur visible au niveau info. Les namespaces réels du serveur se lisent avec la commande de découverte opcua_discover du bridge, ou dans un client OPC UA (nœud Server > NamespaceArray).
Génération d'un certificat client
Le serveur OPC UA exige qu'un ApplicationURI soit présent dans le SAN du certificat client. Exemple avec OpenSSL :
openssl req -x509 -newkey rsa:2048 \
-keyout client.key -out client.pem \
-days 3650 -nodes \
-subj "/CN=alemca-agent" \
-addext "subjectAltName=URI:urn:alemca:agent"
chmod 600 client.key
Déposez ensuite client.pem dans la trust list du serveur OPC UA (la procédure dépend du serveur : souvent un dossier pki/trusted/ avec redémarrage du service).
L'URI urn:alemca:agent saisie ici identifie le client uniquement. Elle apparaît dans le journal de l'agent (loaded client cert CN="alemca-agent" URI="urn:alemca:agent") mais ne doit jamais servir de namespace_uri.
Migration depuis les anciennes versions
Les champs security_policy et security_mode ne sont plus reconnus. Ils sont silencieusement ignorés dans les anciennes configurations. Pour activer la sécurité, fournissez désormais cert_file et key_file : la policy et le mode sont auto-négociés à partir des endpoints que le serveur annonce.
API Lua
Liste des fonctions
| Fonction | Signature Lua | Rôle | Retour (succès) | Retour (échec) |
|---|---|---|---|---|
connect |
bool, err = opcua.connect() |
Connecte au serveur OPC UA. | true, nil |
nil, "msg" |
disconnect |
bool, err = opcua.disconnect() |
Ferme la connexion. | true, nil |
nil, "msg" |
read |
value, err = opcua.read(nodeId) |
Lit la valeur d'un noeud. | string, nil |
nil, "msg" |
write |
bool, err = opcua.write(nodeId, value) |
Écrit une valeur dans un noeud. | true, nil |
nil, "msg" |
| Champs | opcua.name, opcua.type |
Métadonnées du module. | – | – |
opcua.connect()
Établit une connexion avec le serveur OPC UA.
- Paramètres : Aucun
- Retour :
truesi la connexion est réussie.nilet un message d'erreur en cas d'échec.
local opcua = require("opcua1")
local ok, err = opcua.connect()
if not ok then
print("Erreur de connexion : " .. err)
return
end
print("Connecté au serveur OPC UA")
opcua.disconnect()
Libère la connexion avec le serveur OPC UA.
Session partagée entre scripts
Une instance opcua est partagée par tous les scripts Lua qui la requièrent (télémétrie EdgeControl, régulation, input_opcua du bridge...).
- Agent 3.3.0 et suivants :
disconnect()ne ferme plus la session. Elle est fermée par un chien de garde aprèsidle_timeoutsecondes sans utilisation, jamais en modepersistent. - Agent antérieur à 3.3.0 :
disconnect()ferme réellement la session, y compris pendant qu'un autre script l'utilise. Un script périodique ne doit donc pas l'appeler à chaque exécution : préférezpersistent: truesur l'instance et n'appelez pasdisconnect().
- Paramètres : Aucun
- Retour :
truesi la déconnexion est réussie.nilet un message d'erreur en cas d'échec.
local opcua = require("opcua1")
local ok, err = opcua.disconnect()
if not ok then
print("Erreur de déconnexion : " .. err)
end
opcua.read(nodeId)
Lit la valeur d'un noeud OPC UA.
- Paramètres :
-
nodeId(string) : Identifiant du noeud à lire (ex.ns=2;s=Temperature). -
Retour :
- La valeur du noeud (convertie en string).
nilet un message d'erreur en cas d'échec.
local opcua = require("opcua1")
opcua.connect()
-- Lecture d'un noeud par son NodeId
local value, err = opcua.read("ns=2;s=Temperature")
if not value then
print("Erreur de lecture : " .. err)
else
print("Température : " .. value)
end
opcua.disconnect()
opcua.write(nodeId, value)
Écrit une valeur dans un noeud OPC UA.
- Paramètres :
nodeId(string) : Identifiant du noeud à écrire.-
value(string) : Valeur à écrire. -
Retour :
truesi l'écriture est réussie.nilet un message d'erreur en cas d'échec.
local opcua = require("opcua1")
opcua.connect()
-- Écriture d'une valeur
local ok, err = opcua.write("ns=2;s=Setpoint", "25.5")
if not ok then
print("Erreur d'écriture : " .. err)
else
print("Valeur écrite avec succès")
end
opcua.disconnect()
Exemple complet
Script périodique (déclenché par trigger) sur une instance déclarée avec persistent: true. Il ne ferme pas la session, que d'autres scripts peuvent utiliser en même temps (voir opcua.disconnect()).
Télémétrie EdgeControl et bridge
Pour remonter des mesures OPC UA vers la plateforme ou EdgeControl, inutile d'écrire un script : utilisez une table d'échange input_opcua du bridge. Ce script sert à tester une connexion ou à un besoin spécifique.
local opcua = require("opcua1")
local json = require("json")
local alemca = require("alemca")
-- Connexion au serveur
local ok, err = opcua.connect()
if not ok then
printError("Connexion OPC UA échouée : " .. err)
return
end
-- Lecture de plusieurs noeuds
local nodes = {
"ns=2;s=Temperature",
"ns=2;s=Humidity",
"ns=2;s=Pressure"
}
local data = {}
for _, nodeId in ipairs(nodes) do
local value, err = opcua.read(nodeId)
if value then
data[nodeId] = tonumber(value) or value
else
printError("Erreur lecture " .. nodeId .. " : " .. err)
end
end
-- Publication des données
alemca.publish(json.encode(data), "opcua_data")
-- Pas de disconnect() : la session est partagée avec les autres scripts
Formats de NodeId
Les NodeId OPC UA peuvent être spécifiés dans plusieurs formats :
| Format | Exemple | Description |
|---|---|---|
| Numérique | ns=0;i=2258 |
Identifiant numérique |
| String | ns=2;s=Temperature |
Identifiant texte |
| GUID | ns=1;g=09087e75-8e5e-499b-954f-f2a9603db28a |
Identifiant GUID |
| Opaque | ns=1;b=M/RbKBsRVkePCePcx24oRA== |
Identifiant opaque (base64) |
Champs Lua associés
opcua.name: Retourne le nom de l'instance du module.opcua.type: Retourne le type du module ("opcua").