Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial Internet of Things >> Embarqué

Implémentation d'un client MQTT pour les systèmes réactifs

MQTT-Reactive est un client MQTT v3.1.1 dérivé de la bibliothèque MQTT-C de LiamBindle. L'objectif de MQTT-Reactive est de fournir un client MQTT portable et non bloquant écrit en C afin d'être utilisé dans des systèmes embarqués réactifs. Tout d'abord, cet article explique ce qu'est un système réactif. Ensuite, il décrit comment concevoir une structure logicielle appropriée pour ce type de système. Enfin, l'article montre comment utiliser la bibliothèque MQTT-Reactive dans un système réactif en utilisant une machine à états et le paradigme événementiel. Pour ce faire, l'article utilise un véritable appareil IoT comme exemple démonstratif à partir duquel l'article explique sa structure logicielle et son comportement basé sur l'état en utilisant des diagrammes UML tels que la machine à états, l'interaction et la structure. L'article fournit également des directives pour implémenter le client MQTT-Reactive de l'appareil IoT en langage C.

De nombreux systèmes embarqués sont réactifs, c'est-à-dire qu'ils réagissent à des événements internes ou externes. Une fois ces réactions terminées, le logiciel revient en arrière pour attendre le prochain événement. C'est pourquoi les systèmes événementiels sont également appelés systèmes réactifs.

La programmation événementielle, ou programmation réactive, est l'un des paradigmes de programmation les plus appropriés pour obtenir un logiciel flexible, prévisible et maintenable pour les systèmes réactifs. Dans ce paradigme, le déroulement du programme est déterminé par les événements. Fréquemment, la structure du logiciel réactif est composée de plusieurs unités concurrentes, appelées objets actifs, qui attendent et traitent différents types d'événements. Chaque objet actif possède un thread de contrôle et une file d'attente d'événements à travers lesquels il traite ses événements entrants. Dans les systèmes réactifs, les objets actifs ont généralement un comportement basé sur l'état défini dans un diagramme d'états transitions.

Afin d'explorer comment utiliser la bibliothèque MQTT-Reactive dans un système réactif avec des tâches multiples et simultanées et en utilisant à la fois une machine d'état et le paradigme piloté par les événements, nous utilisons un appareil IoT comme exemple.

L'idée d'utiliser le protocole MQTT est née alors qu'un appareil IoT était en cours de développement pour une entreprise ferroviaire. Cet appareil était un système réactif clair qui était capable de :

  1. détecter et stocker les modifications de plusieurs entrées numériques
  2. acquérir, filtrer et stocker plusieurs signaux analogiques
  3. envoyer périodiquement des informations stockées à un serveur distant
  4. envoyer et recevoir des informations via le protocole MQTT sur le réseau GSM

MQTT a été choisi car il s'agit d'un protocole de messagerie léger basé sur l'éditeur et l'abonné qui est couramment utilisé dans les applications IoT et de réseau où des liaisons à haute latence et à faible débit de données sont attendues, comme les réseaux GSM.

La capacité MQTT pour le périphérique IoT mentionné a été réalisée en utilisant une version modifiée du MQTT-C de LiamBindle. Le logiciel de cet appareil ayant été conçu comme un logiciel réactif, MQTT-C a dû être modifié pour le communiquer avec le reste du système en échangeant des événements asynchrones. Ces événements étaient utilisés pour recevoir et envoyer du trafic sur le réseau ainsi que pour connecter et publier des informations sensibles sur un serveur. La bibliothèque de logiciels résultante s'appelait MQTT-Reactive.

Machine d'état

MQTT-Reactive a été utilisé via une machine à états, comme le montre la figure 1, qui modélise le comportement de base d'un client MQTT-Reactive. C'était un objet actif appelé MqttMgr (MQTT Manager). Les actions de la machine à états de la figure 1 montrent comment la bibliothèque MQTT-Reactive peut être utilisée à partir d'une machine à états. Même si le langage C a été utilisé comme langage d'action dans la figure 1, n'importe quel langage informatique ou formel peut être utilisé.

cliquez pour agrandir l'image

Figure 1. Machine à états d'un client MQTT-Reactive (Source :VortexMakes)

La machine d'état de la figure 1 démarre dans l'état WaitingForNetConnection. Une fois qu'une connexion réseau est établie avec un serveur, WaitingForNetConnection reçoit l'événement Activate, puis la machine d'état passe à l'état WaitingForSync. Ce n'est que dans cet état que la machine d'état peut organiser des messages MQTT à envoyer au courtier, tels que CONNECT ou PUBLISH via les événements Connect et Publish respectivement. L'état Sync utilise un mécanisme spécial d'UML pour différer l'événement Publish qui est spécifié par le mot-clé defer inclus dans le compartiment interne de l'état Sync. Si l'événement de publication se produit lorsque la synchronisation est l'état actuel, il sera enregistré (différé) pour un traitement futur jusqu'à ce que le SM entre dans un état dans lequel l'événement de publication ne figure pas dans sa liste d'événements différés, comme WaitingForSync ou WaitingForNetConnection. Lors de l'entrée dans de tels états, la machine d'état rappellera automatiquement tout événement de publication enregistré et consommera ou supprimera cet événement en fonction de l'état cible de la transition.

Toutes les millisecondes SyncTime, la machine d'état passe à l'état composite Sync, qui effectue l'envoi et la réception réels du trafic du réseau en publiant des événements de réception et d'envoi au gestionnaire de réseau. C'est une entité concurrente qui s'occupe des problèmes de réseau.

Même si le MqttMgr introduit ne prend en charge que les paquets CONNECT et PUBLIER, il pourrait prendre en charge le paquet SUBSCRIBE avec des modifications assez simples.

Les actions de la machine d'état accèdent aux paramètres de l'événement consommé en utilisant le mot clé params. Par exemple, dans la transition suivante, l'événement Connect porte deux paramètres, clientId et keepAlive, dont les valeurs sont utilisées pour mettre à jour les attributs de l'objet MqttMgr correspondant :

Connect(clientId, keepAlive)/    me->clientId =params->clientId ; moi->keepAlive =params->keepAlive; me->operRes =mqtt_connect(&me->client, me->clientId, NULL, NULL, 0,                               NULL, NULL, 0, me->keepAlive);

Dans cet exemple, l'événement Connect(clientId, keepAlive) est le déclencheur de la transition et l'appel mqtt_connect() fait partie de l'action exécutée en conséquence. En d'autres termes, lorsque l'objet MqttMgr reçoit un événement Connect(clientId, keepAlive) avec les paramètres de 'publishing_client' et '400', Connect("publishing_client", 400), les attributs clientId et keepAlive de MqttMgr sont mis à jour avec les valeurs ' Publishing_client' et '400' par conséquent.

Afin de créer et d'envoyer des événements, les actions de la machine d'état utilisent la macro GEN(). Par exemple, l'instruction suivante envoie un événement Receive à l'objet Collector, qui est référencé en tant qu'attribut d'objet MqttMgr par son pointeur Collector :

GEN(me->itsCollector, Receive());

Le premier argument de l'instruction GEN() est l'objet qui reçoit l'événement, tandis que le deuxième argument est l'événement envoyé, y compris les arguments d'événement (s'il y en a). Les arguments doivent être en accord avec les paramètres de l'événement. Par exemple, l'instruction suivante génère un événement ConnRefused(code) et l'envoie à l'objet Collector en passant le code renvoyé par le courtier en tant que paramètre d'événement :

GEN(me->itsCollector, ConRefused(code));

L'idée d'utiliser le mot-clé params pour accéder aux paramètres de l'événement consommé et la macro GEN() pour générer des événements à partir d'actions a été adoptée à partir du générateur de code de Rational Rhapsody Developer à des fins purement illustratives.

L'action par défaut de la machine d'état dans la figure 1 définit le rappel qui est appelé par MQTT-Reactive chaque fois qu'une acceptation de connexion est reçue du courtier. Ce rappel doit être implémenté dans le code MqttMgr. Ce rappel doit générer des événements ConnAccepted ou ConnRefused(code) pour être envoyé à l'objet Collector comme indiqué ci-dessous.

statique  vide connack_response_callback (énumération MQTTConnackReturnCode return_code){    /*...*/    if (return_code ==MQTT_CONNACK_ACCEPTED)    {        GEN(me->itsCollector, ConnAccepted()); }    autre {        GEN(me->itsCollector, ConnRefused(return_code)); }}

Mise en œuvre du modèle

Le modèle de la figure 1 peut être implémenté en C ou C++ en utilisant soit votre outil logiciel préféré, soit simplement votre propre implémentation de machine d'état. Il existe différents outils disponibles sur Internet pour le faire, tels que le framework RKH, le framework QP, Yakindu Statechart Tool ou Rational Rhapsody Developer, entre autres. Tous prennent en charge les Statecharts et les langages C/C++. De plus, certains d'entre eux incluent un outil pour dessiner un diagramme Statechart et générer du code à partir de celui-ci.

Cette machine à états était exécutée à partir d'un objet actif appelé MqttMgr (MQTT Manager), qui fournissait une encapsulation stricte du code MQTT-Reactive et c'était la seule entité autorisée à appeler une fonction MQTT-Reactive ou à accéder aux données MQTT-Reactive. Les autres entités concurrentes du système ainsi que tous les ISR n'ont pu utiliser MQTT-Reactive qu'indirectement en échangeant des événements avec MqttMgr. L'utilisation de ce mécanisme pour synchroniser des entités concurrentes et partager des données entre elles évite de faire face aux dangers des mécanismes de blocage traditionnels comme les sémaphores, les mutex, les retards ou les indicateurs d'événement. Ces mécanismes pourraient provoquer des dysfonctionnements inattendus, difficiles et fastidieux à diagnostiquer et à réparer.

L'objet actif MqttMgr encapsule ses attributs sous la forme d'un ensemble d'éléments de données. Un élément de données désigne une variable avec un nom et un type, où le type est en fait un type de données. Un élément de données pour l'objet MqttMgr est mappé à un membre de la structure de l'objet. Le nom et le type du membre sont les mêmes que ceux des données de l'objet. Par exemple, l'attribut client du type d'objet MqttMgr est incorporé par valeur en tant que membre de données à l'intérieur de la structure MqttMgr :

struct MqttMgr {    /* ... */ struct mqtt_client client; /* attribut client */ LocalRecvAll localRecv; /* attribut localRecv */ } ;

Les données de l'objet MqttMgr sont accessibles et modifiées directement sans utiliser d'opérations d'accesseur ou de mutateur. Par exemple, client et localRecv sont accessibles via le pointeur me, qui pointe vers une instance de MqttMgr.

mqtt_recvMsgError(&me->client, &me->localRecv);

Le MqttMgr a la liste des attributs indiqués dans le tableau 1.

Tableau 1. Attributs MqttMgr

La structure de la figure 2 est utile pour garder à l'esprit les relations entre les acteurs concernés. Ce sont :l'objet Collector, qui veut envoyer des informations au courtier; l'objet NetMgr, qui s'occupe du réseau; et l'objet MqttMgr.


Figure 2. Ébauche de la structure du système IoT (Source :VortexMakes)

Le diagramme de séquence de la figure 3 montre comment l'objet MqttMgr interagit avec le reste du système lorsqu'il est nécessaire d'ouvrir une session avec un serveur MQTT. Dans ce diagramme, l'état MqttMgr et les messages asynchrones échangés sont exposés entre les acteurs Collector, MqttMgr et NetMgr.


Figure 3. Connexion à un courtier MQTT (Source :VortexMakes)

Une fois qu'une connexion réseau est établie par l'objet NetMgr à un courtier, le premier paquet envoyé de MqttMgr à un serveur MQTT doit être un paquet CONNECT. Ainsi, l'acteur Collector envoie un événement Connect(clientId, keepAlive) à l'acteur MqttMgr. Cet événement doit porter l'identifiant du client et l'intervalle de temps de maintien en vie. Si le serveur accepte la demande de connexion, l'acteur MqttMgr enverra un événement ConnAccepted à l'acteur Collector pour notifier cette situation. Dès lors, l'acteur Collector peut publier des messages d'information à destination de ce courtier.

Si le serveur rejette la demande de connexion, l'acteur MqttMgr enverra un événement ConnRefused à l'acteur Collector. Cet événement comporte un code qui notifie la cause du rejet, comme illustré à la Figure 4. Voir MQTT v3.1.1 section 3.2.2.3.


Figure 4. Le courtier rejette une demande de connexion (Source :VortexMakes)

La figure 5 montre le flux d'interaction lorsqu'un message est publié. Pour ce faire, l'acteur Collector envoie un événement Publish(data, size, topic, qos), qui porte les informations à publier (data), la longueur des informations en octets (size), le nom du topic auquel les informations seront publiées (sujet) et le niveau d'assurance pour transmettre ce message (qos). Dans l'appareil IoT mentionné précédemment, les informations publiées ont été formatées à l'aide de la spécification JSON. Il s'agit d'un format standard ouvert qui contient des objets de données avec des paires attribut-valeur dans un texte lisible par l'homme. Ce format a été réalisé en utilisant jWrite, qui est une bibliothèque simple et légère écrite en C.


Figure 5. Publication de données vers un courtier (Source :VortexMakes)

La figure 6 montre un scénario dans lequel la réception et l'envoi de messages MQTT au réseau échouent. Si le gestionnaire de réseau ne peut pas recevoir le trafic du réseau, il enverra un acteur ReceiveFail à MqttMgr. De même, si le gestionnaire de réseau ne peut pas envoyer de données au réseau, il enverra un acteur SendFail à MqttMgr.


Figure 6. Défaillances du réseau (Source :VortexMakes)

Le tableau 2 résume les événements impliqués dans les scénarios indiqués.

Tableau 2. Événements

Conclusion

En évitant les dangers des mécanismes de blocage traditionnels - comme les sémaphores, les mutex, les délais ou les indicateurs d'événement - la bibliothèque MQTT-Reactive, la machine d'état et l'architecture logicielle proposées dans cet article permettent aux systèmes embarqués réactifs d'implémenter un client MQTT dans un roman chemin. Il est obtenu en encapsulant du code MQTT-Reactive dans une unité de concurrence appelée objet actif , dont le comportement basé sur l'état est défini dans la machine à états suggérée. Cet objet actif communique avec le reste du système en échangeant des événements asynchrones utilisés :non seulement pour recevoir et envoyer du trafic sur le réseau, mais également pour se connecter et publier des informations sur un serveur pour les applications Internet des objets.


Embarqué

  1. Une taxonomie pour l'IIoT
  2. Construire des systèmes de fabrication flexibles pour l'industrie 4.0
  3. Würth Elektronik eiSos présentera de nouveaux composants pour les systèmes intelligents
  4. Conception de commandes de moteurs pour systèmes robotiques
  5. Syslogic :ordinateurs durcis et systèmes IHM pour engins de chantier
  6. Kontron et SYSGO :plate-forme informatique SAFe-VX pour les systèmes critiques pour la sécurité
  7. Configuration de l'état souhaité pour les circuits
  8. Les entreprises fixent des délais pour les systèmes intelligents
  9. Top 10 des flux de travail pour les fabricants