Exercice : Utiliser les bibliothèques IoT .NET

Effectué

Dans cette unité, vous utilisez les bibliothèques IoT .NET pour écrire du code qui interagit avec votre appareil de surveillance de grotte. Bien que le kit de développement logiciel (SDK) .NET soit pris en charge sur Raspberry Pi et d’autres cartes IoT, l’utilisation d’un ordinateur est recommandée. Le recours à un ordinateur vous permet d’utiliser des IDE et des éditeurs complets, comme Visual Studio et Visual Studio Code.

Créer l’application

Effectuez les étapes suivantes à partir d’un interpréteur de commandes sur votre ordinateur de développement.

  1. Créent une application console nommée cheesecave.net.

    dotnet new console -o cheesecave.net
    cd ./cheesecave.net
    

    Les commandes précédentes :

    • Créent une application console .NET dans un dossier nommé cheesecave.net.
    • Définissent l’emplacement actuel sur le dossier cheesecave.net.
  2. Ajoutez les bibliothèques IoT .NET au projet.

    dotnet add package System.Device.Gpio --version 2.1.0
    dotnet add package IoT.Device.Bindings --version 2.1.0
    

    Les commandes précédentes :

    • Ajoutent les packages System.Device.Gpio et Iot.Device.Bindings au projet.
    • Spécifient que la version 2.1.0 est ajoutée pour les deux packages.

Ajout de code

  1. À l’aide de l’IDE ou éditeur de votre choix, remplacez le contenu de Program.cs par le code suivant :

    using System;
    using System.Device.Gpio;
    using System.Device.Gpio.Drivers;
    using System.Device.I2c;
    using Iot.Device.Bmxx80;
    using Iot.Device.Bmxx80.ReadResult;
    
    bool _fanOn = false;
    bool _exit = false;
    int _pin = 21;
    
    // Initialize the GPIO controller
    using GpioController gpio = new GpioController();
    
    // Open the GPIO pin for output
    gpio.OpenPin(_pin, PinMode.Output);
    gpio.Write(_pin, PinValue.Low);
    
    // Get a reference to a device on the I2C bus
    var i2cSettings = new I2cConnectionSettings(1, Bme280.DefaultI2cAddress);
    using I2cDevice i2cDevice = I2cDevice.Create(i2cSettings);
    
    // Create a reference to the BME280
    using var bme280 = new Bme280(i2cDevice);
    
    // Write the fan, temperature, and humidity statuses to the console
    WriteStatus();
    
    // Main control loop
    while (!_exit)
    {
        string commandText = Console.ReadLine() ?? string.Empty;
        DoCommand(commandText);
    }
    
    // Close the pin before exit
    gpio.ClosePin(_pin);
    
    // Exit
    return;
    
    void DoCommand(string commandText)
    {
        switch (commandText)
        {
            case "exit":
                Console.WriteLine("Exiting!");
                _exit = true;
                break;
    
            case "fan":
                if (!_fanOn)
                {
                    // Turn on the fan
                    gpio.Write(_pin, PinValue.High);
                    Console.WriteLine("Turned fan on!");
                }
                else 
                {
                    // Turn off the fan
                    gpio.Write(_pin, PinValue.Low);
                    Console.WriteLine("Turned fan off!");
                }
                _fanOn = !_fanOn;
                WriteStatus();
                break;
    
            case "status":
                WriteStatus();
                break;
    
            default:
                Console.WriteLine("Command not recognized! Try again.");
                return;
        }
    }
    
    void WriteStatus()
    {
        // Read the BME280
        Bme280ReadResult output = bme280.Read();
        double temperatureF = output.Temperature?.DegreesFahrenheit ?? double.NaN;
        double humidityPercent = output.Humidity?.Percent ?? double.NaN;
    
        // Print statuses
        Console.WriteLine();
        Console.WriteLine("DEVICE STATUS");
        Console.WriteLine("-------------");
        Console.WriteLine($"Fan: {(_fanOn ? "ON" : "OFF")}");
        Console.WriteLine($"Temperature: {temperatureF:0.#}°F");
        Console.WriteLine($"Relative humidity: {humidityPercent:#.##}%");
        Console.WriteLine();
        Console.WriteLine("Enter command (status/fan/exit):");
    }
    
  2. Examinez le code pour comprendre comment il interagit avec la broche GPIO. Dans le code précédent :

    • Une instance de GpioController est créée pour être utilisée dans des opérations GPIO.

    • La broche 21 est ouverte avec gpio.OpenPin(). La broche est ouverte pour la sortie avec PinMode.Output.

    • La valeur de la broche 21 est définie sur PinValue.Low. Cette valeur représente la tension la plus faible que la broche peut émettre. Pour allumer la LED, PinValue.Low représente éteinte et PinValue.Highallumée. Par conséquent, la LED qui représente le ventilateur est éteinte.

    • Le code allume et éteint le ventilateur/la LED en écrivant PinValue.Low et PinValue.High.

      Conseil

      De nombreux relais réels utilisent PinValue.High pour éteint et PinValue.Low pour allumé. C’est l’opposé de ce que vous implémentez pour la LED qui représente le relais du ventilateur dans cet exercice.

    • Avant que le code ne se termine, la broche 21 est fermée avec gpio.ClosePin().

  3. Examinez le code pour comprendre comment il interagit avec le capteur BME280. Dans le code précédent :

    • Une instance de I2cConnectionSettings est créée. Le premier paramètre de constructeur, busId, a la valeur 1, l’ID du bus I2C sur le Raspberry Pi. Le deuxième paramètre de constructeur, deviceAddress, a la valeur Bme280.DefaultI2cAddress.

      Avertissement

      Certaines cartes BME280 utilisent Bme280.SecondaryI2cAddress pour l’adresse de l’appareil. Si votre application lève System.IO.IOException: Error 121 performing I2C data transfer., essayez cette valeur à la place.

    • Une instance de I2cDevice est créée à l’aide de l’objet I2cConnectionSettings.

    • Une instance de Bme280 est créée à l’aide de l’objet I2cDevice. Cet objet représente le capteur BME280 physique.

    • Dans la méthode WriteStatus(), un objet Bme280ReadResult est créé en appelant Bme280.Read().

    • L’objet Bme280ReadResult contient les propriétés Temperature et Humidity.

      • Les propriétés Temperature et Humidity peuvent toutes deux accepter la valeur Null, ce qui signifie qu’elles peuvent contenir null. En conséquence, l’opérateur conditionnel null ?. est utilisé pour accéder à leurs membres.
      • Les propriétés proprement dites exposent des propriétés qui effectuent des conversions d’unités automatiques, notamment DegreesFahrenheit et Percent.
      • Dans les deux cas, l’opérateur de coalescence nulle ?? vérifie la valeur renvoyée. Si la valeur est null, il le remplace par double.NaN.

    Conseil

    Si vous avez besoin d’aide pour comprendre la sécurité Null, consultez Sécurité Null en C#.

Générer l’application

Exécutez la commande suivante pour générer l’application.

dotnet build

La génération se termine sans erreurs ni avertissements.

Dans l’unité suivante, vous déployez votre application sur le Raspberry Pi et vous la testez.