A4A : MQTT et le Cloud

Bonjour,

Avec Gnoga votre application avait déjà la tête dans les nuages, embarquant un serveur web pour fournir une interface homme-machine web comme évoqué précédemment.

Parmi les sujets chauds du moment on trouve donc le nuage, le fameux Cloud, et ce que le marketing nous annonce comme la prochaine déferlante, le non moins fameux aujourd’hui Internet des Objets ou IoT, Industrial IoT, Industry 4.0 et autres petits noms qu’on lui donne.

Le nuage met à notre disposition, moyennant finances, une architecture permettant de bénéficier de machines virtuelles à géométrie et capacité variables, ce qu’on a coutume d’appeler l’infrastructure en tant que service ou IaaS, sur lesquelles on peut faire tourner différents systèmes d’exploitation, avec un lot de serveurs divers tels que serveurs web ou base de données, la plate-forme en tant que service ou PaaS, et par dessus des applications tout aussi diverses, soit le Software en tant que service, SaaS.

On peut par exemple imaginer que nous investissions dans une machine virtuelle d’un cloud public, que nous y installions une Debian du jour et que l’on y installe également une application « Ada for Automation » avec une interface web et une communication en Modbus TCP avec notre partie opérative pour le contrôle-commande de celle-ci.

Bon, ça risque de fonctionner mais il y a un point faible, la communication entre l’application de contrôle-commande et la partie opérative, avec cette dernière qui passera en repli en cas de problème de communication, si c’est bien réalisé.
On préférera bien sûr que notre application de contrôle-commande reste pas trop loin de notre partie opérative, sur une machine bien physique en local, surtout si on utilise une carte de communication Hilscher au lieu de Modbus TCP.

Par contre, pour une application permettant par exemple de surveiller les consommations d’une ou plusieurs installations, ou d’afficher différents indicateurs de production, de qualité ou de performance, une telle architecture pourrait faire sens.

L’un des protocoles concourant dans le domaine de l’IoT est MQTT et on en trouve toute l’information sur le web, comme dans l’excellent article de Framboise 314 avec un exemple de mise en œuvre sur Raspberry Pi.

Il se trouve que le non moins excellent Monsieur Per Sandberg a eu le bon goût d’en réaliser un binding pour Ada, mosquitto-ada qui fournira donc un client permettant de publier et souscrire auprès d’un serveur Mosquitto implémentant le protocole MQTT et connectant de ce fait votre application au nuage tant vanté, cf. IoT, Industry 4.0, etc…

Ainsi notre application tournant sur notre machine physique locale pourra transmettre ou recevoir des données du broker tandis que nos applications cloud consommerons ces données ou enverrons des informations diverses :
Cloud

Inkscape, c’est bon ! Mangez en !

Pour mémoire, je rappelle que j’espère bien vous voir à ces 17èmes Journées du Logiciel Libre
Les Gentils Organisateurs ayant bien voulu m’accorder la faveur insigne d’un stand pour la présentation du projet « Ada for Automation », n’hésitez pas à venir nous rendre visite pour échanger.

A priori, le stand se tiendra dans l’espace DIY.
Il est également prévu un atelier en Salle Musique le Dimanche 3 Mars de 10h00 à 11h00.

JDLL2016

Cordialement,
Stéphane

A4A : IHM Web et Gnoga

Bonjour,

Il est question dans les articles précédents d’Interface homme Machine basée sur les technologies web que le framework Gnoga permet de relier à une application écrite dans le langage Ada de façon simple.
Dans ce qui suit, passé les considérations générales sur cette solution, nous décortiquerons les principes mis en œuvre pour équiper « Ada for Automation » d’une telle IHM Web.

Considérations générales

Les avantages des technologies web sont nombreux.
On peut citer rapidement :

  • accès local ou distant et de manière sécurisée éventuellement via SSL,
  • solution multiplateforme, indépendante donc du matériel ou de l’OS et du navigateur en théorie,
  • interface statique et / ou dynamique,
  • adaptabilité en fonction du terminal, ou responsive design,
  • compétences requises disponibles chez de nombreux développeurs,
  • pléthore de bibliothèques tierces pour tous usages, frameworks JavaScript ou CSS…

Gnoga permet de créer à partir d’un embryon de page web un site complet entièrement depuis l’application en Ada.

Le développeur principal, Monsieur David BOTTON, indique dans l’un des échanges que nous avons eus sur la liste comp.lang.ada qu’en théorie il n’est pas nécessaire de connaître les technologies web que sont HTML 5, CSS3, SVG et JavaScript mais que « la connaissance c’est le pouvoir ».
Je serai sans doute plus catégorique que lui : je pense qu’il est indispensable d’être familier avec ces technologies afin de pouvoir envisager un développement dépassant le stade de simple exercice.
Cependant, ces technologies sont maintenant incontournables et il est assurément profitable pour tout développeur d’en avoir une bonne connaissance.

Et puis ce n’est pas non plus très compliqué et c’est assez ludique !

Ce blog n’a pas vocation d’héberger un tutoriel sur ces technologies et d’autres le font très bien comme Monsieur Jenkov ou chez W3Schools.com.
C’est d’ailleurs chez eux que j’ai bien appris, je les en remercie bien.

Les technologies web ont été prévues au départ pour créer et distribuer des documents. C’est l’aspect interaction ajouté par la suite qui permet de rendre ce document vivant et de le transformer en Interface Homme Machine.

S’il est donc possible de créer l’interface web de toutes pièces depuis l’application Ada, je pense qu’une approche mixte, combinant développement web classique pour la structure générale, les feuilles de style et en général pour tout l’aspect statique et, pour les aspects dynamiques la modification du document depuis le code Ada, permet de profiter de tous les avantages de ce mix technologique.

Ce que j’apprécie particulièrement dans les technologies web c’est l’aspect déclaratif. On pose les éléments du document dans un simple fichier texte et on peut visualiser tout de suite le résultat dans son navigateur préféré. Pas besoin de code, de compilation…

Comme, quand c’est bien fait, on peut dissocier structure, contenu et mise en forme, on peut faire évoluer l’IHM séparément de l’application.
De même on pourra faire intervenir un designer pour l’ergonomie ou le style qui n’aura pas besoin d’apprendre Ada pour œuvrer.

Bien sûr, cela représente beaucoup de compétences à acquérir mais elles sont réutilisables dans nombre de contextes et passionnantes !
En fait, cela permet d’envisager tout type d’application depuis l’embarqué en passant par le PC et plus si besoin.

Et vous avez sans aucun doute entendu parler de l’Internet des Objets ou (IoT : Internet of Things) et autres buzz words comme Industry 4.0 je présume.

Principes de mise en œuvre

Dans l’exemple qui suit, un unique document intègre la structure (HTML 5), le contenu (HTML et SVG), la mise en forme (feuille de style CSS intégrée) et JavaScript pour un peu d’interactivité.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <div>
      <svg  xmlns="http://www.w3.org/2000/svg" width="300" height="400" >

        <style type="text/css" >
          <![CDATA[

           .a4a-class-valve {
             stroke: #ff0000;
             stroke-width: 2px;
             stroke-linejoin: round;
           }

           .a4a-class-valve:hover {
             stroke-width: 5px;
           }

           .a4a-class-valve[status="open"] {
             fill:   #00ff00;
           }

           .a4a-class-valve[status="closed"] {
             fill:   #0000ff;
           }
           
         ]]>
        </style>

        <rect id="my_valve" x="100" y="100" height="100" width="150"
         class="a4a-class-valve" status="closed"
         onclick="Thing_Clicked(evt)"/>

      </svg>
    </div>
    <script>
      function Thing_Clicked(evt) {
        var thing = evt.target;
        console.log("Thing " + thing.getAttribute("id") + " Clicked !");
        var thing_status = thing.getAttribute("status");
        if (thing_status == "closed")
            thing.setAttribute("status", "open");
        else
            thing.setAttribute("status", "closed");
      }

    </script>
  </body>
</html>

Notre contenu est un peu fruste mais vous pourrez imaginer bien plus complexe par la suite grâce à Inkscape.
C’est un simple rectangle qui pourra changer de couleur en fonction de son état, état piloté par la souris et un peu de JavaScript.
Avec Gnoga, l’interaction se fait en Ada, les fonctions JavaScript sont remplacées par l’équivalent en Ada.

On peut tester en direct :
rectangle0.html

A ce stade, normalement vous utilisez un bon navigateur comme Firefox et vous disposez des outils de développement intégrés qui permettent notamment de naviguer dans la structure du document, d’en sélectionner les éléments, voir la sortie console et autres.

Les feuilles de style permettent d’associer couleur, taille, position, animation… à des éléments du document en fonction de leur type, de leur classe ou autres caractéristiques comme les attributs.
En définissant une classe et un attribut « status » pour notre rectangle nous pouvons lui affecter des propriétés telles la couleur.
En faisant varier son statut notre rectangle va changer de couleur conformément à la définition.

Donc, depuis l’application Ada on va associer un objet View à un élément à animer comme notre rectangle grâce à son identifiant (id) et connecter des gestionnaires d’événements si besoin.

Ainsi par exemple dans le cas de « A4A_Piano », (cf. a4a-web-web_server.adb) :

      App_Data.LED1_View.Attach_Using_Parent (App_Data.View, "led1");
      App_Data.LED1_View.On_Click_Handler
        (LED_Views.On_Click'Unrestricted_Access);

Je vous invite à en parcourir le code pour le détail d’implémentation.

Cordialement,
Stéphane

A4A : Changement de licence

Bonjour,

« Ada for Automation » était jusqu’à présent distribué sous la licence « GMGPL : GNAT Modified General Public License « .

Les bibliothèques mises en œuvre dans « Ada for Automation », GtkAda et Gnoga, étant passées à la GPL V3 + GCC RUNTIME LIBRARY EXCEPTION, j’ai également procédé au changement de licence dans les mêmes termes car cela me semble cohérent.

Bien sûr, il vous appartient de juger si cette licence convient à votre utilisation.

Pour le côté pratique, d’habitude, quand je veux modifier une ligne dans une série de fichiers, j’invoque ce bon vieux « sed » comme ceci par exemple :

cd Ada/A4A
find . -name "*.ad*" -exec sed -i 's/Copyright (C) 2012-2014/Copyright (C) 2012-2015/g' {} \;

Cela fonctionne bien avec une ligne à remplacer mais c’est plus laborieux avec plusieurs…

Comme je suis un peu fainéant et que « sed » n’avait pas l’air d’être conçu pour le cas, j’ai préféré apprendre un peu de Python que de me taper tous les fichiers un par un et ça a donné le script « ChangeLicense.py » :

#!/usr/bin/env python
# ChangeLicense.py
# cd Ada/A4A
# find . -name "*.ad*" -exec sed -i 's/Copyright (C) 2012-2014/Copyright (C) 2012-2015/g' {} \;
# find . -name "*.ad*" -execdir python ~/Ada/ChangeLicense.py {} \;

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("file", help="the file to operate on")
args = parser.parse_args()
print(args.file)

old = """
-----------------------------------------------------------------------
--                       Ada for Automation                          --
--                                                                   --
--              Copyright (C) 2012-2015, Stephane LOS                --
--                                                                   --
-- This library is free software; you can redistribute it and/or     --
-- modify it under the terms of the GNU General Public               --
-- License as published by the Free Software Foundation; either      --
-- version 2 of the License, or (at your option) any later version.  --
--                                                                   --
-- This library is distributed in the hope that it will be useful,   --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of    --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU --
-- General Public License for more details.                          --
--                                                                   --
-- You should have received a copy of the GNU General Public         --
-- License along with this library; if not, write to the             --
-- Free Software Foundation, Inc., 59 Temple Place - Suite 330,      --
-- Boston, MA 02111-1307, USA.                                       --
--                                                                   --
-- As a special exception, if other files instantiate generics from  --
-- this unit, or you link this unit with other files to produce an   --
-- executable, this  unit  does not  by itself cause  the resulting  --
-- executable to be covered by the GNU General Public License. This  --
-- exception does not however invalidate any other reasons why the   --
-- executable file  might be covered by the  GNU Public License.     --
-----------------------------------------------------------------------
"""


new = """
------------------------------------------------------------------------------
--                            Ada for Automation                            --
--                                                                          --
--                   Copyright (C) 2012-2016, Stephane LOS                  --
--                                                                          --
-- This library is free software;  you can redistribute it and/or modify it --
-- under terms of the  GNU General Public License  as published by the Free --
-- Software  Foundation;  either version 3,  or (at your  option) any later --
-- version. This library is distributed in the hope that it will be useful, --
-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                            --
--                                                                          --
-- As a special exception under Section 7 of GPL version 3, you are granted --
-- additional permissions described in the GCC Runtime Library Exception,   --
-- version 3.1, as published by the Free Software Foundation.               --
--                                                                          --
-- You should have received a copy of the GNU General Public License and    --
-- a copy of the GCC Runtime Library Exception along with this program;     --
-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
-- <http://www.gnu.org/licenses/>.                                          --
--                                                                          --
------------------------------------------------------------------------------
"""


file_content = ''
with open(args.file) as infile:
    for line in infile:
        file_content = file_content + line

file_content = file_content.replace(old, new)

with open(args.file, 'w') as outfile:
    outfile.write(file_content)

Et ça s’utilise presque pareil :

find . -name "*.ad*" -execdir python ~/Ada/ChangeLicense.py {} \;

Bon, je ne suis pas devenu un pro de Python avec ceci mais j’ai bien aimé l’expérience.

Ce script peut sans doute être utilisé pour d’autres cas en adaptant les chaînes.
Si ça peut vous servir je vous l’offre.

Cordialement,
Stéphane

A4A : Modbus TCP Server + Web HMI = A4A_Piano

Bonjour,

J’évoquais ce tantôt en fin d’article une application mêlant un serveur Modbus TCP et une IHM Web pour constituer un « piano » pour mes essais et démonstrations.

Cette application s’appuie donc sur le framework Gnoga qui permet de réaliser des IHM Web entre autres. Gnoga, de Monsieur David Botton, intègre également les Simple Components de Monsieur Dmitry Kasakov qui fournissent entre autres le serveur web embarqué dans l’application.

Gnoga permet la création dynamique de contenu web et l’animation des pages depuis une application écrite en Ada.

En ce moment je joue beaucoup avec Inkscape qui permet plein de fantaisie dans l’édition au format SVG de graphiques vectoriels.
C’est bien sûr intéressant pour dessiner des synoptiques que l’on pourra animer relativement facilement et cela permet aussi de faire un beau schéma :

Structure de l'application A4A_Piano
Structure de l’application A4A_Piano

L’application « A4A_Piano » met en œuvre le noyau « kernel0 » qui intègre seulement un serveur Modbus TCP, fourni par libmodbus, et une tâche principale ainsi qu’une tâche périodique.
Le noyau gère les échanges entre les tâches et le serveur Modbus TCP, la tâche principale appelle la fonction principale du programme utilisateur, la tâche périodique appelle la fonction périodique du programme utilisateur.
Le programme utilisateur est en charge de la gestion des échanges entre les zones mémoire E/S et les objets utilisateur ainsi que du traitement de ces objets.
C’est de l’histoire ancienne.

L’IHM Web est composée d’une part des vues affichées dans le / les navigateurs, ces vues étant constituées naturellement de technologies Web telles HTML 5, CSS, SVG et JavaScript, et d’une contrepartie en Ada fondée sur le patron de conception Modèle-Vue-Contrôleur un peu bricolé.

Tel que réalisé dans « A4A_Piano », le code HTML est juste une amorce, le SVG et le CSS ont été écrits à la main, je vous conseille la lecture des tutoriels de Monsieur Jenkov, courts et efficaces.
Avec un peu d’habitude on arrive à faire de belles choses avec SVG et Inkscape et on peut alors penser plus grand.

En fait, plutôt que de tout piloter d’un côté ou de l’autre, j’ai pris le parti de laisser l’aspect graphique côté technologies Web et de n’agir que sur un attribut d’état. En fonction de l’état, le CSS fait le reste pour l’animation.

Chaque objet de synoptique HTML ou SVG que l’on souhaite animer dispose d’un identifiant dont on pourra se servir pour le connecter à un pendant « View », un objet dérivé des objets fournis par Gnoga.
Pour chaque connexion on va instancier une collections d’objets « View » ainsi qu’une tâche gérant le rafraîchissement.

Ces objets « View » gèrent la mise à jour des objets HTML ou SVG auxquels on les a connectés à la création de la connexion ainsi que l’interaction avec l’utilisateur, c’est à dire les « Cliques » souris par exemple.
D’un autre côté on les a également connectés avec un objet « Controller » dont le rôle est d’une part de servir de proxy aux objets « View » et de gérer l’accès en lecture / écriture des données utilisateur.
La tâche « Scanner » va piloter elle le rafraîchissement des « Controllers ».

Le code n’est sans doute pas optimal mais il est quand même disponible dans le dépôt comme d’habitude.

Pour information, j’espère bien vous voir à ces 17èmes Journées du Logiciel Libre…
D’autant plus que les Gentils Organisateurs ont bien voulu m’accorder la faveur insigne d’un stand pour la présentation du projet « Ada for Automation » !

JDLL2016

Cordialement,
Stéphane

A4A : Exemple d’application 6 : Modbus TCP Client / Serveur + deux canaux Hilscher

Bonjour,

Comme je l’indiquais récemment l’application « app6_gui » offre :

  • un serveur Modbus TCP pour y connecter par exemple un SCADA du marché,
  • une fonction IO Scanning avec une tâche client Modbus TCP par serveur d’E/S,
  • deux canaux cifX Hilscher, pour gérer deux cartes, par exemple une PROFIBUS DP Maitre et une EtherCAT Maitre, ou pour gérer une carte à deux canaux comme par exemple un PROFIBUS DP Maitre et un CANopen Maitre,
  • une interface graphique avec GtkAda, permettant de consulter l’état des communications et de l’application et de démarrer ou arrêter les programmes utilisateur,
  • l’intégration du « cifX TCP Server » permettant la configuration et le diagnostic des cartes par SYCON.net via une connexion TCP/IP.

Je voulais faire un article à part pour cette application, avec des images. J’ai donc monté la manipulation suivante :

Manip-2016-01-08

On a donc un PC, sous Debian Jessie et un noyau Linux 64 bit standard, avec deux cartes Hilscher PCI, une cifX 50-DP configurée en Maître PROFIBUS DP et une cifX 50-RE configurée en Maître EtherCAT :

PC+2cifX50

Comme Esclave PROFIBUS DP j’ai une carte Hilscher CB-AB32-DPS, un « piano » avec deux octets en entrée et autant en sortie qui permet de monter une manipulation en deux secondes et demie :

CB-AB32-DPS

Pour EtherCAT, j’ai également un « piano », le NXIO 500-RE, qui reçoit sa fonctionnalité en insérant la carte MMC qui convient, ici EtherCAT Esclave, avec toujours deux octets d’E/S :

NXIO-500-RE

Le client Modbus TCP qui interroge le serveur de l’application 6 est Modbus Poll dont j’ai déjà fait mention il y a longtemps.

Quant au client Modbus TCP, ce que certains appellent IO Scanning, il est configuré pour exécuter deux requêtes sur un serveur d’un genre particulier sur lequel je reviendrai plus tard.

Je vous épargne la trace laissée par l’application dans le terminal depuis lequel elle est lancée, qui est certes informative, voire même didactique, mais un peu indigeste.

La fenêtre principale s’ouvre et l’on y trouve les onglets suivants.

La vue « Identité », (remarquez la version !) :

A4A-App6-Identity

La vue « Etat général » en deux bouts :

A4A-App6-GeneralStatus1

A4A-App6-GeneralStatus2

On notera la présence des informations d’état des deux tâches « Fieldbus ».

On trouve ensuite la vue d’état du serveur Modbus TCP qui affiche les compteurs de requêtes, et bien évidemment celui qui bouge est celui de la fonction 3 configurée côté Modbus Poll :

A4A-App6-ModbusTCPServer

La vue « Client Modbus TCP » affiche les informations d’état concernant les deux requêtes configurées pour le serveur secret pour le moment, le second client étant désactivé :

A4A-App6-ModbusTCPClients

Notez que lorsque l’on rajoute des requêtes au niveau de la configuration des clients, la vue d’état est bien sûr adaptée automatiquement.

Puis viennent les deux vues d’état des canaux Hilscher cifX.

L’un est donc PROFIBUS DP Maître :

A4A-App6-ProfibusDPMaster

Et l’autre est EtherCAT Maître :

A4A-App6-EtherCATMaster

Le programme utilisateur à l’œuvre dans les trois tâches est très sensiblement identique :

   procedure Process_IO is

      Elapsed_TON_1 : Ada.Real_Time.Time_Span;

   begin

      if First_Cycle then

         Output_Byte := Pattern_Byte;

         First_Cycle := False;

      end if;

      Tempo_TON_1.Cyclic (Start   => not TON_1_Q,
                          Preset  => Ada.Real_Time.Milliseconds (500),
                          Elapsed => Elapsed_TON_1,
                          Q       => TON_1_Q);

      if TON_1_Q then

         case Cmd_Byte is

         when 0 =>
            Output_Byte := ROR (Value => Output_Byte, Amount => 1);

         when 1 =>
            Output_Byte := ROL (Value => Output_Byte, Amount => 1);

         when others => Output_Byte := Pattern_Byte;

         end case;

      end if;

   end Process_IO;

On trouve aussi dans « Ada for Automation » une application exemple 5, « app5 », identique à « app6 » mais qui ne gère elle qu’un seul canal Hilscher cifX.

Mais quel est donc ce serveur Modbus TCP secret dont je vous entretiens depuis le début ?
La NXIO 500-RE ne pourrait-elle faire l’affaire avec une MMC ad hoc ? Sans doute, mais pour des raisons qui m’échappent ce firmware n’existe pas…

Aussi, je me suis dit que je n’avais qu’à utiliser le « kernel 0 », issu de « app1simu », et qui fournit un serveur Modbus TCP.
Oui mais, et les boutons et LEDs ? GtkAda aurait bien sûr pu convenir mais comme je jouais avec Gnoga…

Taa taan ! Voilà un « piano » piloté depuis le navigateur !

A4A-App6-A4A-Piano-Local

Comme c’est du SVG, donc du vectoriel, même depuis un mobile ça se pilote.

Et en plus l’application supporte les connexions multiples ! On peut jouer à plusieurs ! J’adore…
Promis, dès que mon code est un peu plus propre je l’envoie sur le dépôt.

Cordialement,
Stéphane