Azure IoT Hub et .NET nanoFramework avec ESP32

Encore un nouvel article pour parler d’IoT Hub vous allez me dire ? Et bien non, aujourd’hui je ne ferai pas de focus sur IoT Hub, mais plutôt sur .NET nanoFramework !

Nous allons pouvoir voir ensemble comment ce framework s’utilise pour écrire des applications à destination d’appareils embarqués.

.NET nanoFramework

L’histoire de .NET nanoFramework débute par sa création en 2016 par une équipe de passionnés faisant pour certain parti de l’équipe de développement de Microsoft .NET Micro Framework, projet initié par Microsoft. Ce nouveau framework se distingue alors par son indépendance vis-à-vis de Microsoft et sa communauté qui continue de contribuer à ce projet Open Source qui compte maintenant parmi les projets soutenus par la .NET Fundation

Comme je vous le disais, il offre maintenant la possibilité de développer des applications embarquées en .NET (et on sait que beaucoup qui de ceux qui me liront seront contents de ne pas avoir à lire du C ou C++ dans ce billet pour une fois) …

Composition du Framework

Ce framework s’appuie sur ChibiOS qui est un RTOS (Real Time OS) afin de bénéficier de sa HAL et ainsi être supporté par de nombreuses cartes comme ST Micro Electronics ou ESP 32… Il intègre également une version réduite de la CLR (Common Language Runtime) avec un sous ensemble de classes .NET nécessaires pour éxécuter les scénarii d’applications embarquées.

Il possède également les classes nécessaires à l’exécution de Azure IoT Device dans votre application.

Dans l’ensemble, et c’est aussi intéressant, les APIs exposés par .NET nanoFramework sont alignés (depuis peu) avec les APIs des classes .NET Standard, ce qui offre la possibilité de développer son programme embarqué sur .NET Core Standard puis de le migrer sur un appareil encore plus contraint …

Leur approche a été aussi de découper au maximum les packages, ainsi dès que vous aurez besoins d’une fonctionnalité non « core », il vous faudra installer le package NuGet correspondant (GPIO, button, DeviceClient, …), de cette manière nanoFramework assure une taille de votre application réduite au maximum en fonction de vos besoins.

Je ne vais pas vous détailler ici toutes les capacités de ce framework ni ses compatibilités avec les hardware, en effet, la documentation disponible sur le site de la communauté est suffisamment bien fournie et restera à jour ! (.NET nanoFramework | nanoFramework Documentation), mais on peut retenir qu’il supporte :

  • STM32
  • ESP32
  • NXP
  • M5Stack,

Cela fait une multitude de plateforme hardware disponible et également un grand nombre de sensors qui ont été développés pour pouvoir les intégrer rapidement : List and category of devices | nanoFramework Documentation

Regardons maintenant comment cela fonctionne dans le cadre d’un développement sur un ESP 32 …

Prérequis

Pour démarrer avec .NET nanoFramework, vous devrez installer l’extension .NET nanoFramework pour votre éditeur (actuellement pour Visual Studio 2019 et 2022 inclus et VSCode).

.NET nanoFramework Extension – Visual Studio Marketplace

Attention cependant, il y a encore quelques limitations pour la version VS Code qui ne permet pas, par exemple, de débugger dans votre programme en plus des limitations de l'OS et de l'architecture processeur. Je vous recommande donc d'utiliser l'extension disponible dans Visual Studio. 

Installation du firmware

Comme je vous l’ai expliqué, ce produit s’appuie sur un RTOS et un ensemble de librairies (un Firmare en sommes) qui seront déployés sur votre appareil. L’équipe .NET nanoFramework nous facilite alors les choses en nous proposant d’installer une fois pour toute le firmware sur votre appareil puis de vous concentrer sur votre code applicatif.

Commençons alors par là. Une simple commande suffit à réaliser l’installation.

nanoff --platform esp32 --serialport COM5 --update [--preview] [--baud 115200]

Et voilà le Firmware est maintenant installé sur l’appareil, je vais maintenant pouvoir commencer à développer mon application.

Développer son application

C’est parti maintenant pour réaliser le programme embarqué en C#. Pour cela j’ouvre mon plus beau IDE (Visual Studio 2022) et je démarre un nouveau projet nanoFramework:

Je sélectionne alors un « Blank Application (nanoFramework) pour démarrer et je supprime le contenu par défaut de la méthode main (oui on ne va pas s’arrêter à un simple Hello World non plus…).

Configuration WiFi

La première étape que je vous propose est de configurer la connectivité Wifi de l’appareil. J’ai deux possibilités, le configurer dans le code, par exemple :

void ConnectToWifi()
{
    // As we are using TLS, we need a valid date & time
    // We will wait maximum 1 minute to get connected and have a valid date
    CancellationTokenSource cs = new(sleepTimeMinutes);
    var success = NetworkHelper.ConnectWifiDhcp(Ssid, Password, setDateTime: true, token: cs.Token);
    if (!success)
    {
        GoToSleep();
    }
}

Il est également possible de le configurer directement au travers de Visual Studio et ainsi vous pouvez enregistrer les paramètres dans la configuration du firmware nanoFramework que nous avons installés.

Pour cette option :

  • ouvrez la fenêtre de Device Explorer (View -> Other Windows -> Device Explorer),
  • sélectionnez l’appareil que vous avez connecté,
  • cliquez sur « Edit Network Connection »

Vous aurez ainsi la possibilité de manipuler directement toute la configuration de la connectivité de votre appareil :

Packages NuGet

Nous allons maintenant pouvoir installer les packages NuGet nous permettant de bénéficier de la connectivité avec la plateforme Azure IoT.

dotnet add package nanoFramework.Azure.Devices.Client

Application

public static void Main()
        {
            X509Certificate azureCert = new X509Certificate(baltimoreRootCA);

            var provisioningClient = ProvisioningDeviceClient.Create(
                globalDeviceEndpoint: DPSServiceEndpoint,
                idScope: DPSScopeId,
                registrationId: DeviceId,
                securityProvider: DeviceSasKey,
                azureCert: azureCert);

            var registerResult = provisioningClient.Register(null, CancellationToken.None);

            if (registerResult.Status != ProvisioningRegistrationStatusType.Assigned)
            {
                return;
            }

            var device = new DeviceClient(
                iotHubName: registerResult.AssignedHub, 
                deviceId: registerResult.DeviceId,
                sasKey: DeviceSasKey,
                qosLevel: nanoFramework.M2Mqtt.Messages.MqttQoSLevel.AtMostOnce, 
                azureCert: azureCert);

            if (!device.Open())
            {
                return;
            }

            Debug.WriteLine($"Device connected to {registerResult.AssignedHub}.");

            Debugger.Break();
        }

Bon voilà, j’ai le code qui me permet de me connecter à Azure IoT Hub (en effectuant l’enregistrement dans le DPS.

Regardons maintenant comment cela fonctionne dans Visual Studio en Debug …

Le résultat que nous constatons est que nous pouvons nous attacher en point à point sans aucune configuration sur l’appareil ou dans Visual Studio.

J’ai attaché des watch dans le debugger me permettant de confirmer que les opérations se sont bien passées, mon appareil s’est provisionné dans le DPS puis connecté dans IoT Hub.

On remarque également qu’il est possible de bénéficier des de l’output tout simplement comme n’importe quelle application .NET que nous avons l’habitude de réaliser.

Et si je voulais maintenant jouer un peu avec les Pins de mon ESP32 comment cela se passe avec nanoFramework ?

Utilisation des GPIOs

nanoFramework dispose également de packages NuGet que vous pouvez installer pour manipuler vos pin GPIO sur vos cartes. De ce fait l’utilisation reste assez simple…

dotnet add package nanoFramework.System.Device.Gpio

Puis je peux maintenant réaliser l’ouverture de mon GPIO correspondant à la LED interne et l’allumer :

var gpioController = new GpioController();

GpioPin ledPin = gpioController.OpenPin(2);
ledPin.SetPinMode(PinMode.Output);
ledPin.Write(PinValue.High);

C’est aussi simple que cela, comme vous le remarquez, les APIs à consommer sont assez proches des APIs natives ESP, on s’y retrouve donc facilement.

Déclenchement du bouton

L’ESP 32 dispose également d’un bouton, voyons comment cela fonctionne pour l’utiliser avec nanoFramework.

dotnet add package nanoFramework.Iot.Device.Button

Vous pouvez retrouver ici la documentation de la classe Button ainsi disponible : Button | nanoFramework Documentation

GpioButton button = new GpioButton(buttonPin: 0);

button.ButtonDown += ButtonPressedReleasedHandler;
button.ButtonUp += ButtonPressedReleasedHandler;

private static void ButtonPressedReleasedHandler(object sender, EventArgs e)
{
    GpioButton button = (GpioButton)sender;

    Debug.WriteLine($"buttondown IsPressed={button.IsPressed}");
}

Dans cet exemple, je créée une instance du bouton sur la pin GPIO 0 (bouton BOOT de l’ESP32) et je m’abonne aux évènements ButtonDown, ButtonUp pour déclencher un évènement.

On se rend compte par cet exemple concret que l’utilisation des boutons est tout aussi simple. Chose également intéressante, la classe GpioButton possède déjà la possibilité de s’abonner à des évènements liés à des comportements plus haut niveau (Press, DoublePress, Holding), rendant son utilisation encore plus simple.

Conclusions

Comme nous le constatons, le nanoFramework s’avère un merveilleux outil pour réaliser votre propre application embarquée. Utiliser un langage de haut niveau dans de l’embarqué n’est pas nouveau, mais tout de même pour le coup c’est assez novateur de pouvoir le faire sur un MCU aussi bon marché que l’ESP 32 est.

Personnellement, j’apprécie le fait de pouvoir me dire que nous (développeurs lambda), nous avons également la possibilité d’intervenir et de rester maître de l’application embarquée que nous souhaitons réaliser.

Je n’ai pas abordé ces points dans cet article mais nanoFramework fournit aussi des packages NuGet permettant de réaliser des tests unitaires codés de l’application. Encore une fois un atout majeur de cette solution, vous pouvez ainsi intégrer toutes les pratiques de Quality Gates (Unit Tests, Code Coverage, …) pour une application embarquée, dans votre plateforme d’intégration continue que vous maîtrisez sans avoir à créer d’usine à gaz !

Je vous le rappel, nanoFramework est un projet OpenSource, soutenu par la .NET Fundation, et donc à ce titre bénéficie d’une communauté très active sur le sujet !

Vous le constatez, ce n’est donc pas une solution de « garage » pour pouvoir s’amuser, mais bel et bien une vraie solution qui n’a pas son égal et qui est également ready-to-production (plusieurs déploiements en production à son actif)

Si vous souhaitez en savoir plus sur .NET nanoFramework, je peux aussi vous conseiller d’aller faire un tour et profiter de quelques vidéos en ligne par Olivier Bloch (on ne le présente plus dnas le monde de l’IoT chez Microsoft) et Laurent Ellerbach, l’un des developpeurs les plus actifs sur ce projet (cocorico, ce sont deux Français 😉 ) :

Votre commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l’aide de votre compte WordPress.com. Déconnexion /  Changer )

Image Twitter

Vous commentez à l’aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l’aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s