Exercício – escrever código para telemetria de vibração

Concluído

No final desta unidade, estará a enviar e a receber telemetria.

Criar uma aplicação para enviar telemetria

  1. Para utilizar C# no Visual Studio Code, verifique se o .NET Coree a Extensão C# estão instalados.

  2. Abra um terminal no Visual Studio Code e crie uma pasta chamada “vibrationdevice” (introduza mkdir vibrationdevice). Navegue até à pasta vibrationdevice.

  3. Introduza o comando a seguir no terminal: dotnet new console. Este comando cria um ficheiro Program.cs na pasta, juntamente com um ficheiro de projeto.

  4. Introduza dotnet restore no terminal. Este comando fornece à aplicação acesso aos pacotes .NET necessários.

  5. No terminal, instale as bibliotecas necessárias. Introduza:

    • dotnet adicionar pacote Microsoft.Azure.Devices.Client
    • dotnet adicionar pacote Newtonsoft.Json
  6. A partir do menu Ficheiro, abra o ficheiro .cs Programa e elimine o conteúdo predefinido.

  7. Depois de ter introduzido o seguinte código no ficheiro Program.cs, pode executar a aplicação com o comando dotnet run . Este comando vai executar o ficheiro Program.cs na pasta atual.

  1. Abra o Visual Studio e crie um novo projeto Visual C#/Windows Desktop. Selecione Aplicação da Consola (.NET Framework).

  2. Dê ao projeto um nome amigável, como “VibrationDevice”.

  3. Em Ferramentas/NuGet Package Manager, selecione Gerir Pacotes NuGet para Solução. Instale as bibliotecas a seguir:

    • Microsoft.Azure.Devices.Client
    • Newtonsoft.Json
  4. Elimine os conteúdos predefinidos do ficheiro Program.cs.

  5. Adicione todo o código que se segue ao ficheiro Program.cs.

Nota

Este módulo não requer a transferência de código. No entanto, todo o código está disponível em GitHub/MicrosoftDocs/mslearn-data-anomaly-detection-using-azure-iot-hub, caso necessário.

Adicionar código para enviar telemetria

A seguinte aplicação simula um tapete rolante e envia relatórios dos dados do sensor de vibração a cada dois segundos.

  1. Abra o ficheiro Program.cs da aplicação de dispositivo.

  2. Copie e cole o código a seguir.

    // Copyright (c) Microsoft. All rights reserved.
    // Licensed under the MIT license. See LICENSE file in the project root for full license information.
    
    using System;
    using Microsoft.Azure.Devices.Client;
    using Newtonsoft.Json;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace vibration_device
    {
        class SimulatedDevice
        {
            // Telemetry globals.
            private const int intervalInMilliseconds = 2000;                                // Time interval required by wait function.
            private static readonly int intervalInSeconds = intervalInMilliseconds / 1000;  // Time interval in seconds.
    
            // Conveyor belt globals.
            enum SpeedEnum
            {
                stopped,
                slow,
                fast
            }
            private static int packageCount = 0;                                        // Count of packages leaving the conveyor belt.
            private static SpeedEnum beltSpeed = SpeedEnum.stopped;                     // Initial state of the conveyor belt.
            private static readonly double slowPackagesPerSecond = 1;                   // Packages completed at slow speed/ per second
            private static readonly double fastPackagesPerSecond = 2;                   // Packages completed at fast speed/ per second
            private static double beltStoppedSeconds = 0;                               // Time the belt has been stopped.
            private static double temperature = 60;                                     // Ambient temperature of the facility.
            private static double seconds = 0;                                          // Time conveyor belt is running.
    
            // Vibration globals.
            private static double forcedSeconds = 0;                                    // Time since forced vibration started.
            private static double increasingSeconds = 0;                                // Time since increasing vibration started.
            private static double naturalConstant;                                      // Constant identifying the severity of natural vibration.
            private static double forcedConstant = 0;                                   // Constant identifying the severity of forced vibration.
            private static double increasingConstant = 0;                               // Constant identifying the severity of increasing vibration.
    
            // IoT Hub global variables.
            private static DeviceClient s_deviceClient;
    
            // The device connection string to authenticate the device with your IoT hub.
            private readonly static string s_deviceConnectionString = "<your device connection string>";
    
            private static void colorMessage(string text, ConsoleColor clr)
            {
                Console.ForegroundColor = clr;
                Console.WriteLine(text);
                Console.ResetColor();
            }
            private static void greenMessage(string text)
            {
                colorMessage(text, ConsoleColor.Green);
            }
    
            private static void redMessage(string text)
            {
                colorMessage(text, ConsoleColor.Red);
            }
    
            // Async method to send simulated telemetry.
            private static async void SendDeviceToCloudMessagesAsync(Random rand)
            {
                // Simulate the vibration telemetry of a conveyor belt.
                double vibration;
    
                while (true)
                {
                    // Randomly adjust belt speed.
                    switch (beltSpeed)
                    {
                        case SpeedEnum.fast:
                            if (rand.NextDouble() < 0.01)
                            {
                                beltSpeed = SpeedEnum.stopped;
                            }
                            if (rand.NextDouble() > 0.95)
                            {
                                beltSpeed = SpeedEnum.slow;
                            }
                            break;
    
                        case SpeedEnum.slow:
                            if (rand.NextDouble() < 0.01)
                            {
                                beltSpeed = SpeedEnum.stopped;
                            }
                            if (rand.NextDouble() > 0.95)
                            {
                                beltSpeed = SpeedEnum.fast;
                            }
                            break;
    
                        case SpeedEnum.stopped:
                            if (rand.NextDouble() > 0.75)
                            {
                                beltSpeed = SpeedEnum.slow;
                            }
                            break;
                    }
    
                    // Set vibration levels.
                    if (beltSpeed == SpeedEnum.stopped)
                    {
                        // If the belt is stopped, all vibration comes to a halt.
                        forcedConstant = 0;
                        increasingConstant = 0;
                        vibration = 0;
    
                        // Record how much time the belt is stopped, in case we need to send an alert.
                        beltStoppedSeconds += intervalInSeconds;
                    }
                    else
                    {
                        // Conveyor belt is running.
                        beltStoppedSeconds = 0;
    
                        // Check for random starts in unwanted vibrations.
    
                        // Check forced vibration.
                        if (forcedConstant == 0)
                        {
                            if (rand.NextDouble() < 0.1)
                            {
                                // Forced vibration starts.
                                forcedConstant = 1 + 6 * rand.NextDouble();             // A number between 1 and 7.
                                if (beltSpeed == SpeedEnum.slow)
                                    forcedConstant /= 2;                                // Lesser vibration if slower speeds.
                                forcedSeconds = 0;
                                redMessage($"Forced vibration starting with severity: {Math.Round(forcedConstant, 2)}");
                            }
                        }
                        else
                        {
                            if (rand.NextDouble() > 0.99)
                            {
                                forcedConstant = 0;
                                greenMessage("Forced vibration stopped");
                            }
                            else
                            {
                                redMessage($"Forced vibration: {Math.Round(forcedConstant, 1)} started at: {DateTime.Now.ToShortTimeString()}");
                            }
                        }
    
                        // Check increasing vibration.
                        if (increasingConstant == 0)
                        {
                            if (rand.NextDouble() < 0.05)
                            {
                                // Increasing vibration starts.
                                increasingConstant = 100 + 100 * rand.NextDouble();     // A number between 100 and 200.
                                if (beltSpeed == SpeedEnum.slow)
                                    increasingConstant *= 2;                            // Longer period if slower speeds.
                                increasingSeconds = 0;
                                redMessage($"Increasing vibration starting with severity: {Math.Round(increasingConstant, 2)}");
                            }
                        }
                        else
                        {
                            if (rand.NextDouble() > 0.99)
                            {
                                increasingConstant = 0;
                                greenMessage("Increasing vibration stopped");
                            }
                            else
                            {
                                redMessage($"Increasing vibration: {Math.Round(increasingConstant, 1)} started at: {DateTime.Now.ToShortTimeString()}");
                            }
                        }
    
                        // Apply the vibrations, starting with natural vibration.
                        vibration = naturalConstant * Math.Sin(seconds);
    
                        if (forcedConstant > 0)
                        {
                            // Add forced vibration.
                            vibration += forcedConstant * Math.Sin(0.75 * forcedSeconds) * Math.Sin(10 * forcedSeconds);
                            forcedSeconds += intervalInSeconds;
                        }
    
                        if (increasingConstant > 0)
                        {
                            // Add increasing vibration.
                            vibration += (increasingSeconds / increasingConstant) * Math.Sin(increasingSeconds);
                            increasingSeconds += intervalInSeconds;
                        }
                    }
    
                    // Increment the time since the conveyor belt app started.
                    seconds += intervalInSeconds;
    
                    // Count the packages that have completed their journey.
                    switch (beltSpeed)
                    {
                        case SpeedEnum.fast:
                            packageCount += (int)(fastPackagesPerSecond * intervalInSeconds);
                            break;
    
                        case SpeedEnum.slow:
                            packageCount += (int)(slowPackagesPerSecond * intervalInSeconds);
                            break;
    
                        case SpeedEnum.stopped:
                            // No packages!
                            break;
                    }
    
                    // Randomly vary ambient temperature.
                    temperature += rand.NextDouble() - 0.5d;
    
                    // Create two messages:
                    // 1. Vibration telemetry only, that is routed to Azure Stream Analytics.
                    // 2. Logging information, that is routed to an Azure storage account.
    
                    // Create the telemetry JSON message.
                    var telemetryDataPoint = new
                    {
                        vibration = Math.Round(vibration, 2),
                    };
                    var telemetryMessageString = JsonConvert.SerializeObject(telemetryDataPoint);
                    var telemetryMessage = new Message(Encoding.ASCII.GetBytes(telemetryMessageString));
    
                    // Add a custom application property to the message. This is used to route the message.
                    telemetryMessage.Properties.Add("sensorID", "VSTel");
    
                    // Send an alert if the belt has been stopped for more than five seconds.
                    telemetryMessage.Properties.Add("beltAlert", (beltStoppedSeconds > 5) ? "true" : "false");
    
                    Console.WriteLine($"Telemetry data: {telemetryMessageString}");
    
                    // Send the telemetry message.
                    await s_deviceClient.SendEventAsync(telemetryMessage);
                    greenMessage($"Telemetry sent {DateTime.Now.ToShortTimeString()}");
    
                    // Create the logging JSON message.
                    var loggingDataPoint = new
                    {
                        vibration = Math.Round(vibration, 2),
                        packages = packageCount,
                        speed = beltSpeed.ToString(),
                        temp = Math.Round(temperature, 2),
                    };
                    var loggingMessageString = JsonConvert.SerializeObject(loggingDataPoint);
                    var loggingMessage = new Message(Encoding.ASCII.GetBytes(loggingMessageString));
    
                    // Add a custom application property to the message. This is used to route the message.
                    loggingMessage.Properties.Add("sensorID", "VSLog");
    
                    // Send an alert if the belt has been stopped for more than five seconds.
                    loggingMessage.Properties.Add("beltAlert", (beltStoppedSeconds > 5) ? "true" : "false");
    
                    Console.WriteLine($"Log data: {loggingMessageString}");
    
                    // Send the logging message.
                    await s_deviceClient.SendEventAsync(loggingMessage);
                    greenMessage("Log data sent\n");
    
                    await Task.Delay(intervalInMilliseconds);
                }
            }
    
            private static void Main(string[] args)
            {
                Random rand = new Random();
                colorMessage("Vibration sensor device app.\n", ConsoleColor.Yellow);
    
                // Connect to the IoT hub using the MQTT protocol.
                s_deviceClient = DeviceClient.CreateFromConnectionString(s_deviceConnectionString, TransportType.Mqtt);
    
                // Create a number between 2 and 4, as a constant for normal vibration levels.
                naturalConstant = 2 + 2 * rand.NextDouble();
    
                SendDeviceToCloudMessagesAsync(rand);
                Console.ReadLine();
            }
        }
    }
    

    Importante

    Dedice alguns minutos e leia os comentários no código. Observe como a matemática da vibração que se encontrava na descrição do cenário durante a introdução nos acompanhou até ao código. A secção de código mais importante para aprender sobre mensagens IoT começa com o comentário de duas mensagens Create.

  3. Substitua a < cadeia de ligação do dispositivo > com a cadeia de ligação do dispositivo que guardou na unidade anterior. Não é necessário alterar mais linhas de código.

  4. Guarde o ficheiro Program.cs.

Testar o código para enviar telemetria

  1. Executar a aplicação no terminal com o comando dotnet run . Este comando vai executar o ficheiro Program.cs na pasta atual.
  1. Execute a aplicação ao selecionar Depurar/Iniciar sem Depurar.
  1. Deverá obter rapidamente um ecrã de consola semelhante à seguinte imagem. Note a utilização de texto verde para mostrar que as coisas estão a funcionar como deviam e texto vermelho quando estão a acontecer erros. Se não obtiver um ecrã semelhante a esta imagem, comece por verificar a cadeia de ligação do dispositivo.

    Screenshot mostrando as mensagens de telemetria de vibração.

  2. Observe a telemetria por um curto período e confirme que está a fornecer vibrações nos intervalos esperados.

    Pode deixar essa aplicação em execução, uma vez que é necessária para a próxima secção.

Verificar se o Hub IoT está a receber telemetria

  1. Para verificar se o seu Hub IoT está a receber a telemetria, abra o painel de visão geral para o centro. Desloque-se para baixo até à parte inferior da página. Altere o intervalo de tempo para uma hora. O desenho Mensagens de dispositivos para a cloud deve mostrar alguma atividade.

    Screenshot mostrando a contagem de mensagens de telemetria recebidas pelo IoT Hub.

  2. Se não aparecer atividade, espere um pouco, já que há alguma latência.

Com o dispositivo a emitir telemetria e o Hub a recebê-la, o próximo passo é encaminhar as mensagens para os pontos finais corretos.