Connectivité des moyens industriels : la démo!

Un article rapide pour présenter une vidéo qui donne vie aux différents sujets que j'ai pu aborder dans mes précédents articles. Enjoy!


Fichier(s) joint(s) :



Connecter un automate à un serveur OPC/UA sous Linux

J'ai déjà présenté dans de précédents articles le couteau suisse de la connectivité OT/IT : KEPServerEX. Indispensable pour exposer les données d'une grande variété de machines via un serveur OPC/UA. Il est prévu pour fonctionner sous un environnement Windows.

Nous allons voir ici comment utiliser son pendant pour serveurs Linux : ThingWorx Kepware Edge.

Pour les besoins de cet article, nous utiliserons de nouveau notre PLC Siemens Logo! 8.

Contrairement à la version pour Windows, celle-ci ne dispose pas d'interface graphique. En revanche, elle expose une interface REST très complète et très bien documentée dans le ThingWorx Kepware Edge User Manual disponible en téléchargement. Elle est même autodocumentée, via des APIs spécifiques. Par exemple :

Définition des drivers/channels spécifiques

La requête suivante renvoie les éléments nécessaires à la création de channels dédiés au type de machine/équipement à connecter :

GET https://localhost:57513/config/v1/doc/drivers/Siemens%20TCP%2FIP%20Ethernet/channels

Réponse :

{
    "type_definition": {
        "name": "Channel",
        "collection": "channels",
        "namespace": "servermain",
        "can_create": true,
        "can_delete": true,
        "can_modify": true,
        "auto_generated": false,
        "requires_driver": true,
        "access_controlled": true,
        "child_collections": [
            "devices",
            "phonebooks"
        ]
    },
    "property_definitions": [
        {
            "symbolic_name": "common.ALLTYPES_NAME",
            "display_name": "Name",
            "display_description": "Specify the identity of this object.",
            "read_only": false,
            "type": "String",
            "default_value": null,
            "minimum_length": 1,
            "maximum_length": 256
        },
        {
            "symbolic_name": "common.ALLTYPES_DESCRIPTION",
            "display_name": "Description",
            "display_description": "Provide a brief summary of this object or its use.",
            "read_only": false,
            "type": "String",
            "default_value": null,
            "minimum_length": 0,
            "maximum_length": 255
        },
        {
            "symbolic_name": "servermain.MULTIPLE_TYPES_DEVICE_DRIVER",
            "display_name": "Driver",
            "display_description": "",
            "read_only": true,
            "type": "String",
            "default_value": "Siemens TCP/IP Ethernet",
            "minimum_length": 0,
            "maximum_length": -1
        },
        {
            "symbolic_name": "servermain.CHANNEL_DIAGNOSTICS_CAPTURE",
            "display_name": "Diagnostics Capture",
            "display_description": "Select whether or not to make the channel's diagnostic information available to an OPC application.",
            "read_only": false,
            "type": "EnableDisable",
            "default_value": false
        },
        {
            "symbolic_name": "servermain.CHANNEL_UNIQUE_ID",
            "display_name": "Unique Id",
            "display_description": "Unique identifier associated with this object.",
            "read_only": false,
            "type": "Integer",
            "default_value": 422613010,
            "minimum_value": null,
            "maximum_value": null
        },
        {
            "symbolic_name": "servermain.CHANNEL_ETHERNET_COMMUNICATIONS_NETWORK_ADAPTER_STRING",
            "display_name": "Network Adapter",
            "display_description": "Specify the name of a network adapter to bind or allow the OS to select the default.",
            "read_only": false,
            "type": "StringWithBrowser",
            "default_value": null,
            "minimum_length": 0,
            "maximum_length": -1,
            "hints": [
                "",
                "wlp3s0",
                "eno1"
            ]
        },
        ...
    ]
}

Définition des devices

La requête suivante renvoie les éléments nécessaires à la création de devices dédiés au type de machine/équipement à connecter :

GET https://localhost:57513/config/v1/doc/drivers/Siemens%20TCP%2FIP%20Ethernet/devices

Réponse :

{
    "type_definition": {
        "name": "Device",
        "collection": "devices",
        "namespace": "servermain",
        "can_create": true,
        "can_delete": true,
        "can_modify": true,
        "auto_generated": false,
        "requires_driver": true,
        "access_controlled": true,
        "child_collections": [
            "services",
            "tag_groups",
            "tags"
        ]
    },
    "property_definitions": [
        {
            "symbolic_name": "common.ALLTYPES_NAME",
            "display_name": "Name",
            "display_description": "Specify the identity of this object.",
            "read_only": false,
            "type": "String",
            "default_value": null,
            "minimum_length": 1,
            "maximum_length": 256
        },
        {
            "symbolic_name": "common.ALLTYPES_DESCRIPTION",
            "display_name": "Description",
            "display_description": "Provide a brief summary of this object or its use.",
            "read_only": false,
            "type": "String",
            "default_value": null,
            "minimum_length": 0,
            "maximum_length": 255
        },
        {
            "symbolic_name": "servermain.MULTIPLE_TYPES_DEVICE_DRIVER",
            "display_name": "Driver",
            "display_description": "",
            "read_only": true,
            "type": "String",
            "default_value": "Siemens TCP/IP Ethernet",
            "minimum_length": 0,
            "maximum_length": -1
        },
        {
            "symbolic_name": "servermain.DEVICE_MODEL",
            "display_name": "Model",
            "display_description": "Select the specific type of device associated with this ID. Options depend on the type of communications in use.",
            "read_only": false,
            "type": "Enumeration",
            "default_value": null,
            "enumeration": {
                "S7-200": 0,
                "S7-300": 1,
                "S7-400": 2,
                "S7-1200": 3,
                "S7-1500": 4,
                "NetLink: S7-300": 5,
                "NetLink: S7-400": 6
            }
        },
        {
            "symbolic_name": "servermain.DEVICE_UNIQUE_ID",
            "display_name": "Unique Id",
            "display_description": "Unique identifier associated with this object.",
            "read_only": false,
            "type": "Integer",
            "default_value": 4145021575,
            "minimum_value": null,
            "maximum_value": null
        },
        {
            "symbolic_name": "servermain.DEVICE_ID_FORMAT",
            "display_name": "ID Format",
            "display_description": "Indicate the format of the device ID (set by the driver by default).",
            "read_only": false,
            "type": "Enumeration",
            "default_value": 0,
            "enumeration": {
                "Octal": 0,
                "Decimal": 1,
                "Hex": 2
            }
        },
        ...
    ]
}

Munissez-vous donc d'un client d'API comme Postman, d'un client OPC/UA comme UAExpert, et c'est parti!

Les endpoints

La documentation ThingWorx Kepware Edge Quick Start décrit les étapes nécessaires pour connecter un premier client UAExpert au serveur OPC/UA, via le endpoint créé par défaut par l'installation standard. Ce dernier est sécurisé et requiert une validation manuelle pour accepter la connexion du client au serveur.

Mais il est fréquent que le client qui sera utilisé dans une application (que vous découvrirez dans un prochain article ;) ne supporte pas ce mécanisme d'authentification. Il devient donc nécessaire de créer en premier lieu un nouveau endpoint "non sécurisé".

Ceci peut donc être fait via l'API REST de Kepware Edge :

POST https://localhost:57513/config/v1/admin/ua_endpoints

Body :

{
    "common.ALLTYPES_NAME": "UnsecureEndpoint",
    "common.ALLTYPES_DESCRIPTION": "Available adapters: Default; wlp3s0:192.168.1.94; vboxnet0:192.168.56.1; eno1:; localhost",
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_ENABLE": true,
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_ADAPTER": "Default",
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_PORT": 49331,
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_URL": "opc.tcp://localhost:49331",
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_SECURITY_NONE": true,
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_SECURITY_BASIC128_RSA15": 0,
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_SECURITY_BASIC256": 0,
    "libadminsettings.UACONFIGMANAGER_ENDPOINT_SECURITY_BASIC256_SHA256": 0
}

Il sera nécessaire de redémarrer le serveur pour prendre en compte cette modification. Ce nouveau endpoint apparaitra donc dans le client OPC/UA :

Le Channel

En s'appuyant sur la documentation récupérée plus haut, nous pouvons créer le channel spécifique à notre PLC Siemens :

POST https://localhost:57513/config/v1/project/channels

Body :

{
    "common.ALLTYPES_NAME": "SiemensChannel",
    "servermain.MULTIPLE_TYPES_DEVICE_DRIVER": "Siemens TCP/IP Ethernet",
    "servermain.CHANNEL_DIAGNOSTICS_CAPTURE": false,
    "servermain.CHANNEL_WRITE_OPTIMIZATIONS_METHOD": 2,
    "servermain.CHANNEL_WRITE_OPTIMIZATIONS_DUTY_CYCLE": 10,
    "servermain.CHANNEL_NON_NORMALIZED_FLOATING_POINT_HANDLING": 0,
    "servermain.CHANNEL_ETHERNET_COMMUNICATIONS_NETWORK_ADAPTER_STRING":"wlp3s0"
}

Le Device

Nous pouvons maintenant associer à notre Channel un Device représentant notre Logo! 8 :

POST https://localhost:57513/config/v1/project/channels/SiemensChannel/devices

Body :

{
    "common.ALLTYPES_NAME": "Logo8",
    "servermain.DEVICE_ID_STRING": "192.168.1.13",
    "servermain.MULTIPLE_TYPES_DEVICE_DRIVER": "Siemens TCP/IP Ethernet",
    "servermain.DEVICE_MODEL": 0,
    "servermain.DEVICE_ID_FORMAT": 0,
    "servermain.DEVICE_ID_HEXADECIMAL": 0,
    "servermain.DEVICE_ID_DECIMAL": 0,
    "servermain.DEVICE_ID_OCTAL": 0,
    "servermain.DEVICE_DATA_COLLECTION": true,
    "servermain.DEVICE_SIMULATED": false,
    "servermain.DEVICE_SCAN_MODE": 0,
    "servermain.DEVICE_SCAN_MODE_RATE_MS": 1000,
    "servermain.DEVICE_SCAN_MODE_PROVIDE_INITIAL_UPDATES_FROM_CACHE": false,
    "servermain.DEVICE_CONNECTION_TIMEOUT_SECONDS": 3,
    "servermain.DEVICE_REQUEST_TIMEOUT_MILLISECONDS": 2000,
    "servermain.DEVICE_RETRY_ATTEMPTS": 2,
    "servermain.DEVICE_INTER_REQUEST_DELAY_MILLISECONDS": 0,
    "servermain.DEVICE_AUTO_DEMOTION_ENABLE_ON_COMMUNICATIONS_FAILURES": false,
    "servermain.DEVICE_AUTO_DEMOTION_DEMOTE_AFTER_SUCCESSIVE_TIMEOUTS": 3,
    "servermain.DEVICE_AUTO_DEMOTION_PERIOD_MS": 10000,
    "servermain.DEVICE_AUTO_DEMOTION_DISCARD_WRITES": false,
    "servermain.DEVICE_TAG_GENERATION_ON_STARTUP": 1,
    "servermain.DEVICE_TAG_GENERATION_DUPLICATE_HANDLING": 0,
    "servermain.DEVICE_TAG_GENERATION_GROUP": "",
    "servermain.DEVICE_TAG_GENERATION_ALLOW_SUB_GROUPS": true,
    "siemens_tcpip_ethernet.DEVICE_COMMUNICATIONS_PORT_NUMBER": 102,
    "siemens_tcpip_ethernet.DEVICE_COMMUNICATIONS_MPI_ID": 0,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_MAX_PDU": 960,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_200_LOCAL_TSAP": 200,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_200_REMOTE_TSAP": 200,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_300_400_1200_1500_LINK_TYPE": 3,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_CPU_RACK": 0,
    "siemens_tcpip_ethernet.DEVICE_S7_COMMUNICATIONS_CPU_SLOT": 2,
    "siemens_tcpip_ethernet.DEVICE_ADDRESSING_BYTE_ORDER": 0,
    "siemens_tcpip_ethernet.DEVICE_TAG_IMPORT_TYPE": 0,
    "siemens_tcpip_ethernet.DEVICE_TAG_IMPORT_CODE_PAGE": 4294967295,
    "siemens_tcpip_ethernet.DEVICE_TAG_IMPORT_STEP_7_PROJECT_FILE": "",
    "siemens_tcpip_ethernet.DEVICE_TAG_IMPORT_PROGRAM_PATH": "",
    "siemens_tcpip_ethernet.DEVICE_TAG_IMPORT_TIA_EXPORT_FILE": ""
}

Toutes ces informations correspondent à ce qui est demandé par l'assistant de configuration dans la version Windows.

Les Tags

Terminons par le plus important, exposer les informations de l'automate via les tags OPC/UA :

POST https://localhost:57513/config/v1/project/channels/SiemensChannel/devices/Logo8/tags

Body :

[
    {
        "common.ALLTYPES_NAME": "Entree1",
        "servermain.TAG_ADDRESS": "I0.0",
        "servermain.TAG_DATA_TYPE": 1,
        "servermain.TAG_READ_WRITE_ACCESS": 1,
        "servermain.TAG_SCAN_RATE_MILLISECONDS": 100,
        "servermain.TAG_SCALING_TYPE": 0
    },
    {
        "common.ALLTYPES_NAME": "EntreeReseau1",
        "servermain.TAG_ADDRESS": "V0.0",
        "servermain.TAG_DATA_TYPE": 1,
        "servermain.TAG_READ_WRITE_ACCESS": 1,
        "servermain.TAG_SCAN_RATE_MILLISECONDS": 100,
        "servermain.TAG_SCALING_TYPE": 0
    },
    {
        "common.ALLTYPES_NAME": "Output1",
        "servermain.TAG_ADDRESS": "Q0.0",
        "servermain.TAG_DATA_TYPE": 1,
        "servermain.TAG_READ_WRITE_ACCESS": 1,
        "servermain.TAG_SCAN_RATE_MILLISECONDS": 100,
        "servermain.TAG_SCALING_TYPE": 0
    }
]

Et voilà! Notre serveur est prêt à être utilisé :

Pour aller plus loin

Si vous avez besoin de configuration spécifique, avec des attributs particuliers, pour ne pas avoir à fouiller dans toute la documentation, il est possible d'exporter un projet déjà existant sous Kepware version Windows au format JSON : vous retrouverez ainsi tout le contenu nécessaire pour appeler les APIs REST!

Récupération des logs

Les logs du serveur, habituellement visibles sous Windows dans la console, peuvent être récupérés via cette interface :

GET https://localhost:57513/config/v1/event_log

Fichier(s) joint(s) :