You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/it/2-farm/lessons/4-migrate-your-plant-to-the.../wio-terminal-connect-hub.md

13 KiB

Collega il tuo dispositivo IoT al cloud - Wio Terminal

In questa parte della lezione, collegherai il tuo Wio Terminal al tuo IoT Hub per inviare telemetria e ricevere comandi.

Collega il tuo dispositivo a IoT Hub

Il prossimo passo è collegare il tuo dispositivo a IoT Hub.

Attività - collegamento a IoT Hub

  1. Apri il progetto soil-moisture-sensor in VS Code.

  2. Apri il file platformio.ini. Rimuovi la dipendenza della libreria knolleary/PubSubClient. Questa veniva utilizzata per connettersi al broker MQTT pubblico e non è necessaria per connettersi a IoT Hub.

  3. Aggiungi le seguenti dipendenze di libreria:

    seeed-studio/Seeed Arduino RTC @ 2.0.0
    arduino-libraries/AzureIoTHub @ 1.6.0
    azure/AzureIoTUtility @ 1.6.1
    azure/AzureIoTProtocol_MQTT @ 1.6.0
    azure/AzureIoTProtocol_HTTP @ 1.6.0
    azure/AzureIoTSocket_WiFi @ 1.0.2
    

    La libreria Seeed Arduino RTC fornisce il codice per interagire con un orologio in tempo reale nel Wio Terminal, utilizzato per tenere traccia del tempo. Le altre librerie consentono al tuo dispositivo IoT di connettersi a IoT Hub.

  4. Aggiungi quanto segue alla fine del file platformio.ini:

    build_flags =
        -DDONT_USE_UPLOADTOBLOB
    

    Questo imposta un flag del compilatore necessario per compilare il codice di Arduino IoT Hub.

  5. Apri il file header config.h. Rimuovi tutte le impostazioni MQTT e aggiungi la seguente costante per la stringa di connessione del dispositivo:

    // IoT Hub settings
    const char *CONNECTION_STRING = "<connection string>";
    

    Sostituisci <connection string> con la stringa di connessione del tuo dispositivo che hai copiato in precedenza.

  6. La connessione a IoT Hub utilizza un token basato sul tempo. Questo significa che il dispositivo IoT deve conoscere l'ora corrente. A differenza dei sistemi operativi come Windows, macOS o Linux, i microcontrollori non sincronizzano automaticamente l'ora corrente tramite Internet. Questo significa che dovrai aggiungere del codice per ottenere l'ora corrente da un server NTP. Una volta ottenuta l'ora, può essere memorizzata in un orologio in tempo reale nel Wio Terminal, consentendo di richiedere l'ora corretta in un secondo momento, a meno che il dispositivo non perda alimentazione. Aggiungi un nuovo file chiamato ntp.h con il seguente codice:

    #pragma once
    
    #include "DateTime.h"
    #include <time.h>
    #include "samd/NTPClientAz.h"
    #include <sys/time.h>
    
    static void initTime()
    {
        WiFiUDP _udp;
        time_t epochTime = (time_t)-1;
        NTPClientAz ntpClient;
    
        ntpClient.begin();
    
        while (true)
        {
            epochTime = ntpClient.getEpochTime("0.pool.ntp.org");
    
            if (epochTime == (time_t)-1)
            {
                Serial.println("Fetching NTP epoch time failed! Waiting 2 seconds to retry.");
                delay(2000);
            }
            else
            {
                Serial.print("Fetched NTP epoch time is: ");
    
                char buff[32];
                sprintf(buff, "%.f", difftime(epochTime, (time_t)0));
                Serial.println(buff);
                break;
            }
        }
    
        ntpClient.end();
    
        struct timeval tv;
        tv.tv_sec = epochTime;
        tv.tv_usec = 0;
    
        settimeofday(&tv, NULL);
    }
    

    I dettagli di questo codice sono al di fuori dello scopo di questa lezione. Definisce una funzione chiamata initTime che ottiene l'ora corrente da un server NTP e la utilizza per impostare l'orologio sul Wio Terminal.

  7. Apri il file main.cpp e rimuovi tutto il codice MQTT, inclusi il file header PubSubClient.h, la dichiarazione della variabile PubSubClient, i metodi reconnectMQTTClient e createMQTTClient, e qualsiasi chiamata a queste variabili e metodi. Questo file dovrebbe contenere solo il codice per connettersi al WiFi, ottenere l'umidità del suolo e creare un documento JSON con questi dati.

  8. Aggiungi le seguenti direttive #include all'inizio del file main.cpp per includere i file header delle librerie IoT Hub e per impostare l'ora:

    #include <AzureIoTHub.h>
    #include <AzureIoTProtocol_MQTT.h>
    #include <iothubtransportmqtt.h>
    #include "ntp.h"
    
  9. Aggiungi la seguente chiamata alla fine della funzione setup per impostare l'ora corrente:

    initTime();
    
  10. Aggiungi la seguente dichiarazione di variabile all'inizio del file, appena sotto le direttive include:

    IOTHUB_DEVICE_CLIENT_LL_HANDLE _device_ll_handle;
    

    Questo dichiara un IOTHUB_DEVICE_CLIENT_LL_HANDLE, un handle per una connessione a IoT Hub.

  11. Sotto questa, aggiungi il seguente codice:

    static void connectionStatusCallback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void *user_context)
    {
        if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED)
        {
            Serial.println("The device client is connected to iothub");
        }
        else
        {
            Serial.println("The device client has been disconnected");
        }
    }
    

    Questo dichiara una funzione di callback che verrà chiamata quando la connessione a IoT Hub cambia stato, ad esempio durante la connessione o la disconnessione. Lo stato viene inviato alla porta seriale.

  12. Sotto questa, aggiungi una funzione per connettersi a IoT Hub:

    void connectIoTHub()
    {
        IoTHub_Init();
    
        _device_ll_handle = IoTHubDeviceClient_LL_CreateFromConnectionString(CONNECTION_STRING, MQTT_Protocol);
    
        if (_device_ll_handle == NULL)
        {
            Serial.println("Failure creating Iothub device. Hint: Check your connection string.");
            return;
        }
    
        IoTHubDeviceClient_LL_SetConnectionStatusCallback(_device_ll_handle, connectionStatusCallback, NULL);
    }
    

    Questo codice inizializza il codice della libreria IoT Hub, quindi crea una connessione utilizzando la stringa di connessione nel file header config.h. Questa connessione si basa su MQTT. Se la connessione fallisce, questo viene inviato alla porta seriale - se vedi questo nell'output, controlla la stringa di connessione. Infine, viene configurato il callback dello stato della connessione.

  13. Chiama questa funzione nella funzione setup sotto la chiamata a initTime:

    connectIoTHub();
    
  14. Come per il client MQTT, questo codice viene eseguito su un singolo thread e necessita di tempo per elaborare i messaggi inviati dall'hub e all'hub. Aggiungi quanto segue all'inizio della funzione loop per fare ciò:

    IoTHubDeviceClient_LL_DoWork(_device_ll_handle);
    
  15. Compila e carica questo codice. Vedrai la connessione nel monitor seriale:

    Connecting to WiFi..
    Connected!
    Fetched NTP epoch time is: 1619983687
    Sending telemetry {"soil_moisture":391}
    The device client is connected to iothub
    

    Nell'output puoi vedere l'ora NTP che viene recuperata, seguita dalla connessione del client del dispositivo. Potrebbero essere necessari alcuni secondi per connettersi, quindi potresti vedere l'umidità del suolo nell'output mentre il dispositivo si sta connettendo.

    💁 Puoi convertire l'ora UNIX dell'NTP in una versione più leggibile utilizzando un sito web come unixtimestamp.com

Invia telemetria

Ora che il tuo dispositivo è connesso, puoi inviare telemetria a IoT Hub invece che al broker MQTT.

Attività - invia telemetria

  1. Aggiungi la seguente funzione sopra la funzione setup:

    void sendTelemetry(const char *telemetry)
    {
        IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromString(telemetry);
        IoTHubDeviceClient_LL_SendEventAsync(_device_ll_handle, message_handle, NULL, NULL);
        IoTHubMessage_Destroy(message_handle);
    }
    

    Questo codice crea un messaggio IoT Hub da una stringa passata come parametro, lo invia all'hub, quindi pulisce l'oggetto del messaggio.

  2. Chiama questo codice nella funzione loop, subito dopo la riga in cui la telemetria viene inviata alla porta seriale:

    sendTelemetry(telemetry.c_str());
    

Gestisci i comandi

Il tuo dispositivo deve gestire un comando dal codice server per controllare il relè. Questo viene inviato come una richiesta di metodo diretto.

Attività - gestisci una richiesta di metodo diretto

  1. Aggiungi il seguente codice prima della funzione connectIoTHub:

    int directMethodCallback(const char *method_name, const unsigned char *payload, size_t size, unsigned char **response, size_t *response_size, void *userContextCallback)
    {
        Serial.printf("Direct method received %s\r\n", method_name);
    
        if (strcmp(method_name, "relay_on") == 0)
        {
            digitalWrite(PIN_WIRE_SCL, HIGH);
        }
        else if (strcmp(method_name, "relay_off") == 0)
        {
            digitalWrite(PIN_WIRE_SCL, LOW);
        }
    }
    

    Questo codice definisce un metodo di callback che la libreria IoT Hub può chiamare quando riceve una richiesta di metodo diretto. Il metodo richiesto viene inviato nel parametro method_name. Questa funzione stampa il metodo chiamato sulla porta seriale, quindi accende o spegne il relè a seconda del nome del metodo.

    💁 Questo potrebbe anche essere implementato in un singolo metodo diretto, passando lo stato desiderato del relè in un payload che può essere passato con la richiesta del metodo e disponibile dal parametro payload.

  2. Aggiungi il seguente codice alla fine della funzione directMethodCallback:

    char resultBuff[16];
    sprintf(resultBuff, "{\"Result\":\"\"}");
    *response_size = strlen(resultBuff);
    *response = (unsigned char *)malloc(*response_size);
    memcpy(*response, resultBuff, *response_size);
    
    return IOTHUB_CLIENT_OK;
    

    Le richieste di metodo diretto necessitano di una risposta, e la risposta è composta da due parti: una risposta come testo e un codice di ritorno. Questo codice creerà un risultato come il seguente documento JSON:

    {
        "Result": ""
    }
    

    Questo viene quindi copiato nel parametro response, e la dimensione di questa risposta viene impostata nel parametro response_size. Questo codice quindi restituisce IOTHUB_CLIENT_OK per indicare che il metodo è stato gestito correttamente.

  3. Collega il callback aggiungendo quanto segue alla fine della funzione connectIoTHub:

    IoTHubClient_LL_SetDeviceMethodCallback(_device_ll_handle, directMethodCallback, NULL);
    
  4. La funzione loop chiamerà la funzione IoTHubDeviceClient_LL_DoWork per elaborare gli eventi inviati da IoT Hub. Questo viene chiamato solo ogni 10 secondi a causa del delay, il che significa che i metodi diretti vengono elaborati solo ogni 10 secondi. Per rendere questo più efficiente, il ritardo di 10 secondi può essere implementato come molti ritardi più brevi, chiamando IoTHubDeviceClient_LL_DoWork ogni volta. Per fare ciò, aggiungi il seguente codice sopra la funzione loop:

    void work_delay(int delay_time)
    {
        int current = 0;
        do
        {
            IoTHubDeviceClient_LL_DoWork(_device_ll_handle);
            delay(100);
            current += 100;
        } while (current < delay_time);
    }
    

    Questo codice eseguirà un ciclo ripetutamente, chiamando IoTHubDeviceClient_LL_DoWork e ritardando di 100ms ogni volta. Lo farà tante volte quanto necessario per ritardare per il tempo specificato nel parametro delay_time. Questo significa che il dispositivo aspetta al massimo 100ms per elaborare le richieste di metodo diretto.

  5. Nella funzione loop, rimuovi la chiamata a IoTHubDeviceClient_LL_DoWork e sostituisci la chiamata delay(10000) con il seguente codice per chiamare questa nuova funzione:

    work_delay(10000);
    

💁 Puoi trovare questo codice nella cartella code/wio-terminal.

😀 Il tuo programma per il sensore di umidità del suolo è connesso al tuo IoT Hub!

Disclaimer:
Questo documento è stato tradotto utilizzando il servizio di traduzione automatica Co-op Translator. Sebbene ci impegniamo per garantire l'accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.