La connexion à un broker MQTT Définition dans le serveur Dans tous les logiciels modernes, il est possible de publier des données pouvant être utilisées par d'autres applications. Dans QuickView, nous avons opter pour l'utilisation de MQTT. MQTT est une manière de publier des données selon un protocole standard (voir MQTT sur wikipedia ). Création d'un "UNS" (Unified Name Space) L'utilisation de MQTT doit se faire d'une manière standardisée en appliquant les standards ISA-95 dans l'architecture d'un UNS: Exemple d'un Unified Name Space: Dans l'exemple ci-dessus, ENTREPRISE, SITE et AREA correspondent à "Base Name". PRODUCTION LINE correspond à "Group Name". La configuration La configuration de la connexion se fait dans VKServer.ini. Une nouvelle section [ MQTT ] doit être créée. Il faut auparavant avoir obtenu la licence pour permettre cette connexion. La licence correspond à AMConnector car elle est aussi utilisée par VK A&M pour importer des données depuis QuickView. Exemple de configuration: [MQTT] Enabled=1 Host=192.168.11.31 Port=8883 SSlEnable=1 ClientID=VKQuickView GroupName=A34002 RefreshRate=30 Hierarchical=1 ForceIOType=0 AutoRestart=1 PublishRectifiers=1 PublishMachine=1 PublishCounters=1 PublishDailyData=1 ValueStyle=1 DecimalCount=2 La section [MQTT] Les mots clef suivants peuvent être définis: Mot clef Type Valeur par défaut Description Enabled Boolean 0 Doit être activé pour que la connexion soit créée. Host String vide Adresse du broker MQTT Port Integer 1883 Numéro du port TCP SSLEnable Boolean 0 Vrai si la connexion utilise Open SSL (TLSv1.1) pour une connexion sécurisée. Pour pouvoir travailler en mode SSL sécurisé, il faut placer les dll d'OpenSSL dans le même répertoire que QuickView (version 32bits, version testée: 1.0.2.18) ClientID String GUID Nom du client MQTT KeepAlive Integer 60 Temps en secondes pour garder la connexion en vie lorsqu'il n'y a pas de communication RefreshRate Integer 30 Temps en secondes pour l'exécution d'un rafraîchissement des variables Retain Boolean 0 Vrai si le contenu des variables doit être préservé sur le broker après la déconnexion. Si ce flag est activé, alors des messages seront renvoyés à tous les clients lors de leur connexion au broker. BaseName String VKQV Nom de base des topics. GroupName String MachineName Nom de publication du groupe. En général correspond au code de la machine par exemple: A34002 ForceIOType Boolean 1 Vrai si le type défini dans les I/O doit être respecté. Si faux alors le système utilise le type des registres des databanks. Hierarchical Boolean 0 Vrai pour forcer une hiérarchie dans la publication des variables par exemple: VKQV\23\Température actuelle. Si faux alors le système n'utilise pas le nom de la variable mais son numéro exemple: VKQV\924 PublishMachine Boolean 0 Vrai pour forcer la publication de la machine et des tableaux correspondants comme les redresseurs, les pompes doseuses. AutoRestart Boolean 1 Vrai pour forcer la reconnexion et le démarrage de la publication après une perte de connexion. ValueStyle Integer 1 Format des valeurs des variables: 0: (ISA-95) Tous les changement de variable sont envoyés dans le même topic soit: BaseName/GroupName/ToVKAM . Le format utilisé sera: { "Type":1, "Items":[{ "LB": "A34001/23/Température actuelle", "V": 12.4, "U":"°C","T":"Double"},{...}], "TS": "2019-04-06T13:46:15.145"}   1: (Legacy) {"V":12.4,"U":"°C","T":"Double","TS":"2019-04-06T13:46:15.145"} V=Value, U=Units, T=Type, TS=TimeStamp DecimalCount Integer 2 Nombre de décimales affichées dans les valeurs réelles UserName String vide Nom de l'utilisateur lorsqu'un login est demandé par le broker Password String vide Mot de passe lorsqu'un login est demandé par le broker Language Integer 0 Langue utilisée pour les textes des alarmes et messages PublishAlarm Boolean 0 Vrai pour forcer la publication des alarmes et des messages UsePosNumber Boolean 0 Vrai pour utiliser la valeur "display" de la position à la place de son index dans le nom des variables publiées. PublishIOs Boolean 0 Publie les IO dans l'items 'IOs' si le style ISA-95 est utilisé ItemValueOnly Boolean 0 Lorsque les I/O sont publiées avec le style ISA-95, si ce mot clef est activé alors les données des I/O seront publiées en valeurs numériques (sans TS, T et U) PublishDailyData Boolean 0 Vrai pour publier les données de fonctionnement journalier WillTopic String vide Nom du topic du will (utilisé seulement lorsque ValueStyle=1) Will String vide Contenu du will (utilisé seulement lorsque ValueStyle=1) QoS Integer 0 Qualité se service (0:At most once, 1: At least once, 2: Exactly once) La définition des variables dans QuickView Les variables sont définies dans les IO de QuickView. Le flag 'Q' doit être ajouté à toutes les variables devant être publiées vers MQTT. Ceci se fait soit manuellement dans le fichier IO.ini soit en utilisant le navigateur d'équipement de VKClient10. Exemple de définition dans [IO.INI]: ; Températures ; ============ 300=1,Actual Temperature A,W,RQ,15,0,$FFFF,10,100 301=1,Actual Temperature B,W,RQ,15,1,$FFFF,10,100 302=3,Actual Temperature,W,RQ,15,2,$FFFF,10,100 303=4,Actual Temperature,W,RQ,15,3,$FFFF,10,100 304=5,Actual Temperature,W,RQ,15,4,$FFFF,10,100 La publication des variables Le système publiera les I/O qui sont définies comme pouvant être publiées dans la définition ci-dessus. Il publiera également les valeurs globales de la machine comme par exemple la définition machine ou les redresseurs à condition que le mot clef "PublishMachine" soit activé. Les variables sont publiées sous forme d'un enregistrement au format JSON. Exemple: {"V":12.4,"U":"°C","T":"Double","TS":"2019-04-06T13:46:15.145"} Les topics de publication dépendent du mot clef "ValueStyle". 2 styles sont définis: 0-ISA-95: Style utilisé avec VKAM ayant une version > 3.0.0.2. et 1-Legacy: Style utilisé avec VKAM ayant une version <= 3.0.0.2 VariableStyle=ISA-95 Ce style utilise des topics prédéfinis dont voici la liste: Topics Description BaseName/GroupName/VKQV/Datas Topic dans lequel les changements des variables sont envoyés. Le format du topic sera le suivant:   {    "Type": int,    "Items": Array [                              {                                "LB": string,                                "V": object,                                "U": string,                                "T": string,                                "S": string                               },                              {                               ....                               }                            ],     "TS" : string }         Type: Type de message. Toujours 1 pour l'instant LB : Label de la variable V  : valeur de la variable U : unité de la variable T: type de la variable S: source de la variable TS: Timestamp   Exemple: { "Type":1, "Items":[{ "LB": "A34001/23/Température actuelle", "V": 12.4, "U":"°C", "T":"Double"},{"LB":"A34001/78/Conductivité", "V":2.44, "U":"mS", "T":"Double"}], "TS": "2019-04-06T13:46:15.145"} BaseName/GroupName/VKQV/Apps Topic dans lequel les clients se connectent à QuickView BaseName/GroupName/VKQV/Apps/ClientID Topic dans lequel le client ClientID publie ses commandes. BaseName/GroupName/VKQV/Apps/ClientID/Status Statut de la connexion avec le client ClientID. BaseName/GroupName/VKQV/Apps/ClientID/Status/Connection Topic dans lequel le client ClientID publie le statut de sa connexion. Exemple: {"TS":"2023-12-27T10:54:40.646125Z","T":"String","V":"Connected"} Ce topic est également désigné comme Last Will Topic lors de la connexion du client. BaseName/GroupName/VKQV/Apps/ClientID/Status/Watchdog Topic dans lequel ClientID va écrire de temps en temps pour indiquer que la connexion est valide. Exemple: {"Id":"Server_92881d83-d3a0-4edf-8720-e8e700340346","Date":"2023-12-28T12:40:45.6958696+01:00"} BaseName/GroupName/VKQV/Apps/ClientID/Login Topic dans lequel ClientID va s'authentifier. Exemple: {"Id":"Server_92881d83-d3a0-4edf-8720-e8e700340346", "UserName":"MyUserName","Password":"MyPassword"}  Lorsque VKQV constate qu'un client s'authentifie, il remplace le contenu par les informations de connexion: Exemple: {"jwtoken":"MyToken"} Si le login n'aboutit pas alors la réponse sera: {"Error":"Login fail !"} Si le login aboutit alors il contient un jwt de connexion qui devra être utilisé à chaque commande vers VKQV. Le client lit la réponse, l'enregistre puis efface le contenu du topic. BaseName/GroupName/VKQV/Apps/ClientID/Commands Topic dans lequel ClientID envoie des commandes à VKQV. Exemple: {"jwtoken":"MyToken", "Commands": [{"Cmd":"WriteBit", "Addr":"20,4,2", "Value": true}] } Lorsque VKQV accepte la commande, il l'execute si le jwtoken est valide puis efface le contenu. BaseName/GroupName/VKQV/Status/Watchdog Topic dans lequel VKQV va écrire à chaque rafraîchissement des variables. VKQV s'abonne à ce topic pour vérifier que le broker soit bien fonctionnel. Si celui-ci fonctionne correctement, il devrait renvoyer ce que VKQV a écrit. La liaison est déclarée comme dégradée si ce topic n'est pas envoyé par le broker après 5 fois le temps de rafraichissement. Dans ce cas, la liaison est interrompue et une nouvelle connexion est tentée.   Exemple du contenu envoyé par VKQV: {"V":269,"T":"Int","TS":"2022-06-03T10:28:01.936"}   BaseName/GroupName/VKQV/Status/Machine Statut de la machine. Pour chaque position de la machine, un statut est envoyé dans un json array: "V": {         "positions": [             {                 "pos": 1,                 "jn": 3,                 "js": 0,                 "jp": 0,                 "rdy": 1,                 "ala": false             },             {                 "pos": 2,                 "rdy": 1,                 "ala": false             },             {                 "pos": 3,                 "jn": 1,                 "js": 0,                 "jp": 0,                 "ena": true,                 "rdy": 1,                 "ala": false             }, ...     ],         "hoists": [             {                 "hoist": 1,                 "rdy": true,                 "blockingala": 0,                 "ala": 0,                 "height": 0,                 "destheight": 0,                 "position": 0,                 "destpos": 0,                 "origin": 0,                 "destination": 0,                 "mode": 0,                 "moveHforward": false,                 "moveHbackward": false,                 "moveVup": false,                 "moveVdown": false             },             {                 "hoist": 2,                 "rdy": true,                 "blockingala": 0,                 "ala": 0,                 "height": 0,                 "destheight": 0,                 "position": 0,                 "destpos": 0,                 "origin": 0,                 "destination": 0,                 "mode": 0,                 "moveHforward": false,                 "moveHbackward": false,                 "moveVup": false,                 "moveVdown": false             }          ]     },     "T": "MachineStatus",     "TS": "2024-04-26T06:55:30.333" }   Les positions sont composées des topics suivants: pos : int  -> numéro de position jn : int  -> numéro du rack dans la position js : int -> Statut du rack dans la position jp: int -> numéro de programme du rack ena: boolean -> position en/hors service rdy: boolean -> position prête (mode machine) ala: boolean -> position en alarme   Les robots sont composés des topics suivants: hoist:int -> numéro du robot rdy:boolean -> indique si le robot est prêt blockingala:int -> mot de statut des alarmes bloquantes ala:int -> mot de statut des alarmes non bloquantes height:int -> hauteur actuelle du robot destheight:int -> hauteur de destination position:int -> position actuelle destpos:int -> position de destination origin:int -> position d'origine lors d'un mouvement complet destination:int -> position de destination lors d'un mouvement mode:int -> mode de fonctionnement du robot moveHforward:boolean -> le robot se déplace horizontalement en avant moveHbackward:boolean -> le robot se déplace horizontalement en arrière moveVup:boolean -> le robot se déplace verticalement vers le haut moveVdown:boolean -> le robot se déplace verticalement vers le bas.   BaseName/GroupName/VKQV/Status/Alarms Statut des alarmes: {     "V": {         "alarms": [             {                 "evt": 2,                 "num": 50,                 "time": "07:16:19",                 "type": "Programme",                 "group": "Général",                 "mess": "Programme en mode STOP",                 "tnum": 1,                 "gnum": 150,                 "mnum": 2             },             {                 "evt": 2,                 "num": 897,                 "time": "07:16:19",                 "type": "Communication",                 "group": "M5Stack",                 "mess": "Erreur de communication avec l'automate",                 "tnum": 14,                 "gnum": 148,                 "mnum": 35             },             {                 "evt": 3,                 "num": 2,                 "time": "07:16:20",                 "type": "Système",                 "group": "HMI",                 "mess": "Watchdog communication avec automate",                 "tnum": 2,                 "gnum": 140,                 "mnum": 37             }         ]     },     "T": "AlarmStatus",     "TS": "2024-04-26T07:16:46.639" } Les alarmes contiennent les topics suivants:   evt:int -> événement ALA/ACK/RTN num:int -> numéro de l'alarme. time:Time -> heure/minute/seconde de l'alarme type:string -> type de l'alarme mess:string -> message de l'alarme group:string -> groupe de l'alarme tnum:int -> numéro du type de l'alarme gnum:int -> numéro du groupe de l'alarme mnum:int -> numéro du message de l'alarme val:num -> valeur associée à l'alarme.   BaseName/GroupName/VKQV/Status/Messages Même chose que ci-dessus pour les messages BaseName/GroupName/VKQV/Status/DailyData Données de production et d'efficacité: { "V": {         "DateOfData": "20240426",         "Date": "26.04.2024",         "BatchesIn": 0,         "BatchesOut": 0,         "IdleTime": 0,         "ErrorStopTime": 0,         "ErrorWarningTime": 28,         "ManuModeTime": 28,         "SafetyDoorTime": 0,         "PowerOnTime": 28,         "Utilization": 100,         "Reliability": 100,         "24hours": [             {                 "Hour": 9,                 "BachesIn": 0,                 "BachesOut": 0,                 "Reliability": 0,                 "Utilization": 0             },             {                 "Hour": 10,                 "BachesIn": 0,                 "BachesOut": 0,                 "Reliability": 0,                 "Utilization": 0             },             { ...     },     "T": "DailyData",     "TS": "2024-04-26T07:23:31.594" } BaseName/GroupName/VKQV/Status/Rectifiers Statut des redresseurs:   {     "V": {         "rectifiers": [             {                 "rectifier": 1,                 "position": 13,                 "name": "",                 "status": 128,                 "step": 0,                 "ahamn": 1,                 "surface": 0,                 "density": 0,                 "current": 0,                 "voltage": 0,                 "Q": 0,                 "QTheo": 0,                 "QTheoAct": 0,                 "QTotal": 1406.11250237337,                 "setpoint": 0,                 "reverse": 0,                 "maxU": 15,                 "maxI": 100,                 "minU": 0,                 "minI": 100,                 "pcsetpoint": 100,                 "alternation": 0,                 "flag0": 0,                 "flag1": 1,                 "flag2": 0,                 "surfaceflag": 7,                 "currentform": 0             },             { ...             }         ]     },     "T": "RectifiersStatus",     "TS": "2024-04-26T06:55:30.353" } BaseName/GroupName/VKQV/Status/PositionsStat Statut d'utilisation des positions de la machine et des barres:   {     "V": {         "positions": [             {                 "pos": 1,                 "time": 13,                 "load": "",                 "surftotal": 128,                 "surfmetal": 0,                 "entrainment": 1             },             { ...             }         ]       "jigs":[          {               "jig": 1,               "loaded": 45,               "total": 234          },          {          ...          }          ]    },     "T": "RectifiersStatus",     "TS": "2024-04-26T06:55:30.353" } BaseName/GroupName/VKQV/Status/Connection Statut de la connexion VKQV. Lorsque VKQV démarre, il écrit le statut de la connexion soit: {"V":"Connected","T":"String","TS":"2022-06-02T09:20:00.642"}. Avant de se déconnecter, il écrit: {"V":"Disconnected","T":"String","TS":"2022-06-02T10:24:35.123"}. Ce topic est également désigné comme Last Will Topic lors de la connexion. BaseName/GroupName/VKQV/Status/Databanks/{#} Liste des databanks de l'application. Le contenu de chaque databank est contenu dans le topic ayant comme nom le numéro du databank. Exemple: {"DB":1,"Device":1,"Channel":1,"Regi":0,"Regf":13,"Registers":[{"R":0,"T":"Int","V":0},{"R":1,"T":"Int","V":0},{"R":2,"T":"Int","V":0},{"R":3,"T":"Int","V":0},{"R":4,"T":"Int","V":0},{"R":5,"T":"Int","V":0},{"R":6,"T":"Int","V":0},{"R":7,"T":"Int","V":0},{"R":8,"T":"Int","V":0},{"R":9,"T":"Int","V":0},{"R":10,"T":"Int","V":0},{"R":11,"T":"Int","V":0},{"R":12,"T":"Int","V":0},{"R":13,"T":"Int","V":0}],"TS":"2023-12-28T11:22:22.923"} BaseName/Messaging/ Service d'envoi de message BaseName/Messaging/Status/Connection/ Statut de la connexion de VKSMSMessaging. Lorsque ce programme démarre, il écrit le statut de la connexion soit: {"V":"Connected","T":"String","TS":"2022-06-02T09:20:00.642"}. Avant de se déconnecter, il écrit: {"V":"Disconnected","T":"String","TS":"2022-06-02T10:24:35.123"}. Ce topic est également désigné comme Last Will Topic lors de la connexion. BaseName/Messaging/Status/Watchdog/ Topic dans lequel VKSMSMessaging va écrire à chaque rafraîchissement des variables. VKSMSMessaging s'abonne à ce topic pour vérifier que le broker soit bien fonctionnel. Si celui-ci fonctionne correctement, il devrait renvoyer ce que VKSMSMessaging a écrit. La liaison est déclarée comme dégradée si ce topic n'est pas envoyé par le broker après 5 fois le temps de rafraichissement. Dans ce cas, la liaison est interrompue et une nouvelle connexion est tentée.   Exemple du contenu envoyé par VKSMSMessaging: {"V":269,"T":"Int","TS":"2022-06-03T10:28:01.936"} BaseName/Messaging/SMS/{messages} Topic contenant les messages à envoyer par SMS. Ce topic contiendra des sous-topic nommer par un GUID. Chaque sous-topic correspondra à un message à envoyer. L'application qui s'occupera de l'envoi des SMS devra s'abonner au topic .../SMS/#. Chaque fois que l'application recevra un topic, il l'analysera, enverra le SMS correspondant puis effacera le topic. Le contenu du topic sera composé d'un json. Exemple: {"Recipient":"+41219683128", "Sender":"VKVision", "Message" : "Température max. chaudière", "TS":"2023-12-28T11:22:22.923"} Si le temps entre le TS et l'heure de réception du topic est plus grand qu'un temps pré-défini, le message est effacé sans être envoyé. BaseName/GroupName/VKQV/Datas/ Changement des I/O de la machine: {"Type":1,"Items":[{"LB":"A44003/3/Température actuelle","V":38.1,"T":"Double","U":"°C"}],"TS":"2024-04-26T07:32:31.852"}   Toutes les I/O qui ont changées d'état depuis la dernière analyse sont  transmit dans cet array.   BaseName/GroupName/VKQV/Datas/{#position} Liste des I/O par position. Le nom des I/O est modifié pour ne pas interférer dans les noms de topics: les espaces, /, \,# sont remplacés par _ Par exemple, l'I/O "Compteur d'Amin" de la cuve 33: Topic: 33 Topic: Compteur_Amin {"V":135.44,"TS":"2024-04-16T08:48:16.256","T":"Double","U":"Amin"}   BaseName/GroupName/VKQV/Configuration/Machine Définition de la machine: {     "V": {         "positioncount": 65,         "hoistcount": 4,         "positions": [             {                 "pos": 1,                 "name": "01 - Charge",                 "flag": 2,                 "addr": 1,                 "group": 0,                 "tank": 1,                 "disable": false,                 "width": 0,                 "process": 1,                 "dist": 200,                 "branch": 0,                 "num": 1,                 "layout": 0             },             {                 "pos": 2,                 "name": "02 - Transfert 1",                 "flag": 10,                 "addr": 2,                 "group": 0,                 "tank": 2,                 "disable": false,                 "width": 0,                 "process": 2,                 "dist": 200,                 "branch": 0,                 "num": 2,                 "layout": 0             },             { ..             }         ],         "hoists": [             {                 "hoist": 1,                 "type": 13,                 "driptray": true,                 "halfup": true,                 "pmin": 1,                 "pmax": 26             },             {                 "hoist": 2,                 "type": 13,                 "driptray": true,                 "halfup": true,                 "pmin": 12,                 "pmax": 36             },             {                 "hoist": 3,                 "type": 13,                 "driptray": true,                 "halfup": true,                 "pmin": 37,                 "pmax": 56             },             {                 "hoist": 4,                 "type": 13,                 "driptray": true,                 "halfup": true,                 "pmin": 45,                 "pmax": 65             }         ]     },     "T": "MachineDefinition",     "TS": "2024-04-26T06:54:58.864" } BaseName/GroupName/VKQV/Configuration/Graphics/{#NomduSynoptique} Pages graphiques de l'application publiées sous forme de winjson BaseName/GroupName/VKQV/Status/TimeTable Positions avec une charge: { "V": { "timetable": [ { "rack": 5, "num": 2, "posnumber": 112, "name": "112 - Stockage", "status": 3, "reference": "APEP30100", "progname": "G-APEP30100", "prognum": 255, "tmin": 0, "tmax": 1800000, "in": "2026-07-20T08:17:50.000" }, { "rack": 4, "num": 4, "posnumber": 114, "name": "114 - Stockage", "status": 3, "reference": "APCC30100", "progname": "G-APCC30100", "prognum": 255, "tmin": 0, "tmax": 1800000, "in": "2026-07-20T08:15:32.000" }, { "rack": 7, "num": 14, "posnumber": 207, "name": "207 - Dégrais. 2.1", "status": 1, "reference": "BCBD30035", "progname": "G-BCBD30035", "prognum": 255, "tmin": 900, "tmax": 930, "in": "2026-07-20T09:34:33.000" Pub/Sub Il est possible de définir des variables en publication ou en souscription indépendamment du système d'I/O de QuickView. Ces variables sont définies dans 2 sections de IO.ini: [MQTTSub] et [MQTTPub]. MQTTSub Dans cette section il est possible de définir jusqu'à 100 souscriptions à des topics MQTT. ;************************************************************************* ;Souscription à des variables MQTT ;1..100=nom de la variable,Type (IO/DB),N°I/O, Var type,N°DB, N°Reg, N°Bit ;************************************************************************* [MQTTSub] 1=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_recyclée_20uS,DB,0,F,36,90 2=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_recyclée_20uS,DB,0,F,36,91 3=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/pH_eau_recyclée_20uS,DB,0,F,36,92 4=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Turbidité_eau_recyclée_20uS,DB,0,F,36,93 5=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_recyclée_5uS,DB,0,F,36,94 6=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_recyclée_5uS,DB,0,F,36,95 7=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/pH_eau_recyclée_5uS,DB,0,F,36,96 8=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Turbidité_eau_recyclée_5uS,DB,0,F,36,97 9=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_DI,DB,0,F,36,98 10=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_DI,DB,0,F,36,99 Il est possible de souscrire à des topics MQTT et de les stocker dans des registres de databank. Il est possible de souscrire jusqu'à 100 topics. La définition se fait de la manière suivante: Section [MQTTSub] n=Nom du topic, type de donnée, n° de l'I/O, type de variable, n° du DB, n° du registre, n° du bit n : numéro de souscription(1..100) Nom du topic: nom du topic dans MQTT type de donnée: IO => correspond à un numéro d'I/O  DB => correspond à un DB,Reg,Bit n° d'I/O: si le type de donnée = IO alors indique le numéro d'I/O à utiliser pour stocker les données sinon pas utilisé type de variable: 'F' => float, 'B' => boolean, 'W' => integer n° du DB: numéro du databank si le type de donnée = DB sinon pas utilisé n° du registre: numéro du registre du databank si type de donnée = DB sinon pas utilisé n° du bit: numéro du bit du registre du databank si type de donnée = DB sinon pas utilisé MQTTPub Dans cette section il est possible de définir jusqu'à 100 publications dans des topics MQTT. ;******************************************************************************************************************************* ;Publication de variables vers MQTT ;1..100=nom du topic,Min time between refresh (sec),Force Refresh after (sec),Type (IO/DB),N° d'I/O,Var type, N°DB, N°Reg, N°Bit ;******************************************************************************************************************************* [MQTTPub] 1=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_recyclée_20uS,5,600,DB,0,F,36,121 2=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_recyclée_20uS,5,600,DB,0,F,36,122 3=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/pH_eau_recyclée_20uS,5,600,DB,0,F,36,123 4=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Turbidité_eau_recyclée_20uS,5,600,DB,0,F,36,124 5=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_recyclée_5uS,5,600,DB,0,F,36,125 6=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_recyclée_5uS,5,600,DB,0,F,36,126 7=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/pH_eau_recyclée_5uS,5,600,DB,0,F,36,127 8=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Turbidité_eau_recyclée_5uS,5,600,DB,0,F,36,128 9=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Conductivité_eau_DI,5,600,DB,0,F,36,129 10=Rolex/Bienne/Galvano_BB/A34003/VKQV/Pub/STEP/Température_eau_DI,5,600,DB,0,F,36,130 Il est possible de publier le contenu de DB ou d'I/O dans des topics MQTT. Il est possible de définir jusqu'à 100 publications. La définition se fait de la manière suivante: Section [MQTTPub] n=Nom du topic, Min time between refresh, Force refresh after, n° de l'I/O, type de donnée, type de variable, n° du DB, n° du registre, n° du bit n : numéro de publication (1..100) Nom du topic: nom du topic dans MQTT Min time between refresh: correspond au temps minimum entre chaque publication si la variable à changée. Le temps est exprimé en secondes. Force refresh after: correspond au temps minimum entre chaque publication quelque soit le valeur de la variable. Le temps est exprimé en secondes. type de donnée: IO => correspond à un numéro d'I/O  DB => correspond à un DB,Reg,Bit n° d'I/O: si le type de donnée = IO alors indique le numéro d'I/O à utiliser pour stocker les données sinon pas utilisé type de variable: 'F' => float, 'B' => boolean, 'W' => integer n° du DB: numéro du databank si le type de donnée = DB sinon pas utilisé n° du registre: numéro du registre du databank si type de donnée = DB sinon pas utilisé n° du bit: numéro du bit du registre du databank si type de donnée = DB sinon pas utilisé Définition dans le client Il est possible de définir une connexion MQTT dans le programme client. Cette connexion peut être utilisée pour échanger avec un ERP ou pour l'utilisation d'un lecteur de codes à barres partagé sur plusieurs PC ou pour faire un login/logout sur plusieurs PC en même temps. La définition se fait dans le fichier VKWinQV.ini dans la section [MQTT]. Par exemple: [MQTT] Enabled=1 Host=wss://google.com Port=xxxx GroupName=A11191 WatchdogTopic=WatchDog BaseName=VK_Vision_SA/Villeneuve/Galvano_BA BarCodeReaderTopic=VK_Vision_SA/Villeneuve/Galvano_BA/A11191/BarcodeReader_PDC1 LoginTopic= SSLEnable=1 ValueStyle=0 UserName= Password= RefreshRate=10 ClientName=PC_Poste_de_charge_1 La section [MQTT] Les mots clef suivants peuvent être définis: Mot clef Type Valeur par défaut Description Enabled Boolean 0 Doit être activé pour que la connexion soit créée. Host String vide Adresse du broker MQTT Port Integer 1883 Numéro du port TCP SSLEnable Boolean 0 Vrai si la connexion utilise Open SSL (TLSv1.1) pour une connexion sécurisée. Pour pouvoir travailler en mode SSL sécurisé, il faut placer les dll d'OpenSSL dans le même répertoire que QuickView (version 32bits, version testée: 1.0.2.18) ClientID String GUID Nom du client MQTT KeepAlive Integer 60 Temps en secondes pour garder la connexion en vie lorsqu'il n'y a pas de communication RefreshRate Integer 30 Temps en secondes pour l'exécution d'un rafraîchissement des variables. Ce temps, multiplié par 5, est également utilisé pour l'attente du watchdog. Lorsque le topic watchdog est défini, celui-ci doit être reçu par le programme client pour confirmer sa connexion avec MQTT. Passé ce temps, une reconnexion automatique est effectuée. Retain Boolean 0 Vrai si le contenu des variables doit être préservé sur le broker après la déconnexion. Si ce flag est activé, alors des messages seront renvoyés à tous les clients lors de leur connexion au broker. BaseName String VKQV Nom de base des topics. GroupName String MachineName Nom de publication du groupe. En général correspond au code de la machine par exemple: A34002 AutoRestart Boolean 1 Vrai pour forcer la reconnexion et le démarrage de la publication après une perte de connexion. ValueStyle Integer 0 Format des valeurs des variables: 0: (ISA-95)   UserName String vide Nom de l'utilisateur lorsqu'un login est demandé par le broker Password String vide Mot de passe lorsqu'un login est demandé par le broker QoS Integer 0 Qualité se service (0:At most once, 1: At least once, 2: Exactly once) ClientName String vide Nom lisible du client utilisé par la connexion à un ERP LoginTopic String vide Nom du topic utilisé lors d'un partage de login/logout par les clients BarcodeReaderTopic String vide Nom du topic utilisé lorsqu'un lecteur de codes à barres est partagé entre plusieurs PC Login/Logout sur plusieurs PC Le LoginTopic n'est pas basé sur le BaseName, il est définissable n'importe où dans l'espace MQTT. Si un LoginTopic est défini, il est utilisé lorsqu'un utilisateur effectue un login ou un logout. Lorsqu'il effectue un login, le topic est rempli avec le json suivant: { "Command": "Login", "User": "Crypted user name", "Pwd": "Crypted password" } Lorsqu'il effectue un logout, le topic est rempli avec le json suivant: { "Command": "Logout", "User": "Crypted user name" }  Le client s'abonne au LoginTopic. Lorsque ce dernier change, le programme exécute le login ou le logout selon les données reçues. Bien s¹r, le nom d'utilisateur et le mot de passe doivent être définis et correspondre. Lecteur de barres codes partagé Le BarcodeReaderTopic n'est pas basé sur le BaseName, il est définissable n'importe où dans l'espace MQTT. Ce topic possède 2 sous-topics : In et Out. Le topic "In" correspond à la valeur lue par le lecteur de codes à barres. Le topic "Out" permet l'envoi de données à afficher sur le lecteur. Il peut également correspondre à une commande permettant de faire beeper le lecteur. Lorsque la section [Barcode]ReaderType=MQTT, le programme s'abonne au topic BarcodeReaderTopic et lorsque son contenu change, il prend la valeur contenu dans le sous-topic "In" pour l'utiliser sur le poste de charge. Echanges entre QuickView et un ERP Les échanges entre QuickView et un ERP peuvent être réalisés en passant par MQTT. QuickView fait la demande en publiant une demande sur MQTT. Un agent spécialisé s'occupe de l'échange avec l'ERP et retourne la réponse en publiant cette réponse à MQTT. QuickView récupère la réponse et effectue la commande correspondante. Pour fonctionner avec MQTT, la section [Exchange] doit être défini  doit être définie avec les valeurs suivantes: [Exchange] Enabled=1 Mode=8 Timeout=10 Lorsque le mode d'échange est = 8, le client s'abonne au topic suivant: BaseName/GroupName /ERP/Clients/ ClientName/ Request/#.  L'agent (VKQV_NCOM ou VKQV_SAPDB ou autre) souscrit au topic  BaseName/GroupName /ERP/Clients/#  et répondra aux requêtes des différents clients dans /Request/Result  ou /Request/Error ou /Request/File. Lorsque l'agent démarre, il publie son statut dans le topic BaseName/GroupName /ERP/Status/Connection  pour que les clients connectés sachent que l'agent est actif. Il publie également le type d'agent dans BaseName/GroupName/ ERP/Status/AgentType  pour que les clients puissent modifier l'interprétation des données car tous les ERP ne fonctionnent pas de la même manière. NCOM NCOM est un échange entre Flexnet et QuickView. Le nom de l'agent est VKQV-NCOM. Les échanges ci-dessous sont pris en compte: SAPDM L'échange entre SAPDM et QuickView est réalisé à l'aide de l'agent VKQV-SAPDM. Les échanges ci-dessous sont pris en compte: Mosquitto Eclipse Mosquitto est un courtier de messages open source (sous licence EPL/EDL) qui implémente les versions 5.0, 3.1.1 et 3.1 du protocole MQTT. Mosquitto est léger et convient à une utilisation sur tous les appareils, des ordinateurs monocarte à faible consommation aux serveurs complets. Le protocole MQTT fournit une méthode légère pour effectuer la messagerie à l'aide d'un modèle de publication/abonnement. Cela le rend adapté à la messagerie de l'Internet des objets, par exemple avec des capteurs de faible puissance ou des appareils mobiles tels que des téléphones, des ordinateurs embarqués ou des microcontrôleurs. Télécharger le programme ici : https://mosquitto.org/download/ puis l'installer selon les instructions. Il faut modifier le fichier de configuration de Mosquitto (mosquitto.conf) en y ajoutant les "listener" disponibles: #Si pas de mot de passe nécessaire allow_anonymous true #Web socket ws:// listener 9000 protocol websockets socket_domain ipv4 #Web socket sécurisé wss:// listener 9001 protocol websockets cafile C:\Metier\mosquitto\certs\ca_certificat.crt certfile C:\Metier\mosquitto\certs\certificat.crt keyfile C:\Metier\mosquitto\certs\certificat.key #accès standard mqtt:// listener 1883 protocol mqtt require_certificate false #accès sécurisé mqtts:// listener 8883 protocol mqtt cafile C:\Metier\mosquitto\certs\ca_certificat.crt certfile C:\Metier\mosquitto\certs\certificat.crt keyfile C:\Metier\mosquitto\certs\certificat.key Pour permettre l'utilisation depuis une application web, un listener Web socket doit être activé (ws:// ou wss://) Configuration de l'ACL (Access Control List) dans Mosquitto Par défaut Mosquitto autorise la connexion sans login / mot de passe.   J'ai parlé de ce point dans l'article sur son installation Une fois connecté chaque utilisateur (ou client) peut écrire ou écouter n'importe quel topic sans aucune restriction. C'est ici que l'ACL intervient ! Dans le fichier de configuration de votre Mosquitto, il est nécessaire de configurer l'emplacement de votre acl_file. acl_file /etc/mosquitto/acl "Lexique" #  û Wildcard, il donne accès à tout le topic de façon récursive. +  û Wildcard, il donne accès à tout le topic sur le même niveau. $SYS  û est réservé au broker, il communique ses statistiques,... Vous pouvez laisser l'accès en lecture ou non aux clients via un pattern par exemple. user  û Permet de définir l'utilisateur concerné. topic  û Permet de définir le topic concerné. pattern  û Permet de définir un topic à tous utilisateurs ou clients. read  û Permet de lire le topic. write  û Permet d'écrire sur le topic. readwrite  û Permet de lire et d'écrire sur le topic. %c  û ID du client. %u  û Nom de l'utilisateur. Il est possible de connecter plusieurs clients avec un ID différent avec le même utilisateur. Dans un premier temps limitez-vous à un client = un utilisateur car cela peut vite poser des soucis. Clients & Users Dans l'exemple suivant l'utilisateur  cuisine  à le droit d'écrire et de lire dans tout le topic maison/cuisine et à aussi le droit de lire tout le topic maison. l'utilisateur  toto   lui à uniquement le droit de lire maison/cuisine/temperature. user cuisine topic readwrite maison/cuisine/# topic read maison/# user toto topic read maison/cuisine/temperature Patterns Dans l'exemple suivant tous les utilisateurs peuvent lire les informations du broker $SYS. Chaque client et utilisateur ont le droit d'écrire et de lire dans " leur espace ?. Donc l'utilisateur  toto  à son topic maison/user/toto de façon récursive, pareil pour l'utilisateur  cuisine . pattern read $SYS/# pattern readwrite maison/id/%c/# pattern readwrite maison/user/%u/# Ressource :  https://mosquitto.org/man/mosquitto-conf-5.html Sources: https://iooner.io/configuration-acl-mosquitto/ SparkPlugB Sparkplug B est une spécification qui standardise la façon dont les données sont structurées et échangées sur MQTT dans un contexte industriel (IIoT/SCADA), pour éviter que chaque fournisseur ait son propre format. Points clés : Topic namespace : les messages suivent une arborescence fixe spBv1.0/group_id/message_type/edge_node_id/device_id , où message_type indique le type de message (NBIRTH, NDEATH, DBIRTH, DDEATH, NDATA, DDATA, etc.). Payload en Protobuf : contrairement au MQTT classique souvent en JSON, Sparkplug B encode les données en Protocol Buffers, ce qui réduit la taille des messages et impose un schéma strict (métriques avec nom, type, valeur, timestamp, alias). Gestion d'état (birth/death) : à la connexion, un nœud publie un message NBIRTH (Node Birth) listant toutes ses métriques avec leurs valeurs initiales. Le broker MQTT garde en réserve un message NDEATH (via le mécanisme Last Will and Testament) qui est publié automatiquement si le nœud se déconnecte anormalement. Cela permet aux abonnés de connaître l'état de santé (« online »/« stale ») du réseau à tout instant. Rapport par exception (RBE) : après le message de naissance complet, seules les valeurs qui changent sont republiées (NDATA/DDATA), ce qui limite la bande passante. Séquencing : chaque message porte un numéro de séquence (0-255) qui permet de détecter des messages perdus et de déclencher une resynchronisation. En résumé, Sparkplug B ajoute par-dessus MQTT une convention de topics, un format de payload binaire, et un cycle de vie (birth/death/data) qui garantit un état cohérent et interopérable entre tous les appareils du réseau.