Main Content

Questa pagina è stata tradotta con la traduzione automatica. Fai clic qui per vedere l'ultima versione in inglese.

Raccogliere dati agricoli su The Things Network

Questo esempio mostra come impostare la raccolta dati da tre sensori collegati a una scheda a microprocessore con una radio LoRa®.

Questa configurazione permette la realizzazione di una rete di sensori distribuiti su una vasta area. I sensori inviano i dati a The Things Network, che viene poi inoltrato a ThingSpeak™ per l'analisi e la visualizzazione. Nell'esempio, costruisci un dispositivo prototipo, ti connetti a The Things Network e integri la raccolta dati con ThingSpeak. Il dispositivo mostrato qui raccoglie dati su temperatura, umidità del suolo e GPS.

Panoramica

L'esempio è composto da tre passaggi principali. L'integrazione The Things Network è ulteriormente suddivisa in diversi sottofasi. Il passaggio più impegnativo è la costruzione del dispositivo. Per completare l'esempio, è necessario un account ThingSpeak e un account su The Things Network. Su ThingSpeak crei un nuovo canale. Su Things Network crei un'applicazione e registri un dispositivo. Quindi crei un decoder del payload e aggiungi l'integrazione che inoltra i dati a ThingSpeak.

1) Configura un canale ThingSpeak per raccogliere dati

2) Configura Things Network

  • Crea applicazione

  • Registra dispositivo

  • Crea formato Payload

  • Aggiungi integrazione

3) Crea dispositivo

  • Hardware utilizzato per creare il nodo sensore

  • Schema e connessioni

4) Dispositivo di programma

  • Impostazione della programmazione

  • Codice

Configura un canale ThingSpeak per raccogliere dati

1) Creare un canale ThingSpeak, come mostrato in Collect Data in a New Channel. Registra la chiave API di scrittura e l'ID del canale per il tuo nuovo canale.

2) Passare alla pagina Impostazioni canale. Impostare le etichette dei campi come segue.

  • Campo 1: Counter

  • Campo 2: Soil Moisture

  • Campo 3: Temperature F

3) Fai clic su Salva canale in basso per salvare le impostazioni.

Configura l'applicazione The Things Network

Crea un account su The Things Network, e quindi accedi a The Things Network Console.

Crea applicazione

1) Seleziona Applicazioni.

2) Selezionare Aggiungi applicazione.

3) Crea un ID applicazione, quindi aggiungi una Descrizione. Seleziona la Registrazione dell'handler in base alla tua posizione.

Registra un dispositivo

1) Fare clic sulla scheda Dispositivi e registrare un dispositivo. Per ulteriori informazioni, vedere Device Registration.

2) Creare un ID dispositivo. Inserisci l'IUE del dispositivo se il tuo dispositivo ne ha uno. In caso contrario, seleziona il pulsante a sinistra del campo Device EUI per generare automaticamente l'IUE.

3) Fare clic su Registrati. Il browser ti riporta alla scheda Panoramica.

4) Selezionare la scheda Impostazioni.

5) Nelle impostazioni, seleziona ABP come metodo di attivazione. Per facilitare il debug, puoi facoltativamente disabilitare i Frame Counter Checks nella parte inferiore della pagina.

6) Registrare l'Indirizzo del dispositivo, la Chiave di sessione di rete e la Chiave di sessione dell'app. Questa informazione è necessaria nel codice del tuo dispositivo.

Crea formattatore di payload

Il formattatore del payload utilizza i byte inviati all'applicazione dal gateway per assemblare un messaggio. In questo esempio, il messaggio di payload desiderato è un oggetto con codifica JSON inviato a ThingSpeak.

1) Torna alla visualizzazione dell'applicazione utilizzando il menu di navigazione in alto. Quindi fare clic sulla scheda Formati payload.

2) Nell'interfaccia decoder, crea il codice per convertire i byte inviati dal tuo dispositivo in un oggetto JSON da scrivere su ThingSpeak. Il codice condizionale per lat e lon gestisce la possibilità di valori positivi o negativi.

function Decoder(b, port) {
  
 var counter = b[0] << 8) | b[1];
 var moisture = b[2] | b[3] << 8;
 var temp= ( b[4] | b[5] << 8 )/100;
 var lat = ( b[6] | b[7] << 8 | b[8] << 16 | (b[8] & 0x80 ? 0xFF << 24 : 0)) / 10000;
 var lon = ( b[9] | b[10] << 8 | b[11] << 16 | (b[11] & 0x80 ? 0xFF << 24 : 0)) / 10000;

  return {
    field1: counter,
    field2: moisture,
    field3: temp,
    latitude: lat,
    longitude: lon
  }
}

Aggiungi integrazione

Per inoltrare dati a ThingSpeak, è necessario disporre di un'applicazione The Things Network con un dispositivo registrato e un formattatore di payload. Crea un'integrazione ThingSpeak per inoltrare i dati.

1) Accedi al tuo The Things Network Console.

2) Seleziona Applicazioni e seleziona l'applicazione da cui desideri inoltrare i dati a ThingSpeak .

3) Fare clic sulla scheda Integrazioni.

4) Selezionare ThingSpeak.

5) Nel campo ID processo, assegna un nome alla tua integrazione.

6) Nel campo Autorizzazione, inserisci la chiave API di scrittura per il canale in cui desideri archiviare i tuoi dati. La chiave API è disponibile nella scheda Chiavi API del tuo canale ThingSpeak .

7) Nel campo ID canale, inserire l'ID canale per il canale ThingSpeak a cui si desidera inoltrare i dati. L'ID del canale è disponibile sulla pagina del tuo canale ThingSpeak .

Crea dispositivo

Hardware utilizzato per creare il nodo sensore

Puoi utilizzare vari dispositivi LoRa che supportano i protocolli LoRaWan per la connessione a The Things Network. Questo esempio dimostra la procedura utilizzando la seguente configurazione hardware.

Schema e collegamenti

Collegare i sensori come mostrato nello schema. La fotografia mostra una possibile configurazione dei sensori in una scatola di progetto. In questa configurazione il sensore di temperatura all'interno del box potrebbe non riflettere esattamente la temperatura esterna. Devi add an antenna alla radio LoRa.

1) Collegare le connessioni di alimentazione e di terra per il GPS e i sensori di temperatura. Non collegare l'alimentazione al sensore di umidità.

2) Collegare l'uscita del sensore di umidità del suolo all'ingresso analogico su A0.

3) Configurare il sistema in modo che l'alimentazione del sensore di umidità si spenga quando non viene utilizzata. Il pin di alimentazione del sensore di umidità è collegato al pin GPIO 11 sul feather M0. Spegnendo il sensore quando non in uso si prolunga la durata del sensore.

4) Collegare il pin dati del sensore DH-22 al PA-15 sul Feather M0, che è il pin 5 nello schizzo di Arduino.

5) Per la scheda GPS, collegare TX a RX sul Feather M0 e RX a TX.

6) Abilita la radio LoRa collegando PA20 (pin 29, GPIO 6) sul Feather M0 a terra.

7) Creare un interruttore di alimentazione collegando un interruttore dal pin En a terra.

Dispositivo di programma

Impostazione della programmazione

1) Scarica l'ultimo IDE Arduino.

2) Scarica la Adafruit GPS library o aggiungi la libreria Adafruit_GPS nel gestore della libreria. Selezionare Sketch > Include Library > Manage Libraries. Cerca Adafruit_GPS per aggiungerlo alle librerie installate.

3) Scaricare LoraWan-in-C library per l'ambiente Arduino o aggiungere le lmic e hal/hal nel gestore delle librerie. Selezionare Sketch > Include Library > Manage Libraries. Cerca lmic e seleziona MCCI LoRaWAN LMIC library per aggiungerlo alle librerie installate. Aggiungi anche il MCCI Arduino LoRaWan Library to the library manager.

4) Creare l'applicazione. Apri una nuova finestra nell'IDE di Arduino e salva il file. Aggiungi il codice fornito nella sezione Codice.

Codice

1) Inizia includendo le librerie appropriate e inizializzando le variabili.

#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include "DHT.h"
#include <Adafruit_GPS.h>

#define DHTPIN 5
#define GPSSerial Serial1
#define SOIL_PIN 14
#define SOIL_POWER_PIN 11
#define GPSECHO false   // Set to 'true' if you want to debug and listen to the raw GPS sentences
#define PAYLOAD_SIZE 13 // Number of bytes sent plus 2


// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = {0x98, 0xEB, 0x1A, 0xC5, 0xF9, 0x20, 0x15, 0xCD, 0x12, 0xE5, 0x72, 0xFF, 0xCD, 0xE2, 0x94, 0x46};
// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = {0x50, 0x28, 0x4D, 0xAE, 0xEA, 0x41, 0x53, 0x7E, 0xCA, 0x70, 0xD2, 0x26, 0xCC, 0x14, 0x66, 0x19};
// LoRaWAN end-device address (DevAddr)
static const u4_t DEVADDR = 0x26021115;

// Callbacks are only used in over-the-air activation. Leave these variables empty unless you use over the air activation.
void os_getArtEui(u1_t *buf) {}
void os_getDevEui(u1_t *buf) {}
void os_getDevKey(u1_t *buf) {}

// Payload to send to TTN gateway
static uint8_t payload[PAYLOAD_SIZE];
static osjob_t sendjob;

// Schedule TX at least this many seconds
const unsigned TX_INTERVAL = 60; //was 30

// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
    .nss = 8,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4,
    .dio = {3, 6, LMIC_UNUSED_PIN},
    .rxtx_rx_active = 0,
    .rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB.
    .spi_freq = 8000000,
};

Adafruit_GPS GPS(&GPSSerial); // Connect to the GPS on the hardware port.

DHT dht(DHTPIN, DHT22);  // Connect to the temperature sensor.
uint16_t counter = 0;
int32_t myLatitude = -12345; // Initialize for testing before GPS finds a lock.
int32_t myLongitude = 54321; // Initialize for testing.
int myMoisture = 0; // 10 bit ADC value.
float temperatureF = 1111; 

2) Utilizzare la funzione setup per avviare il sensore di temperatura, il GPS e la radio LoRa.

void setup()
{
    Serial.begin(115200);
    dht.begin();
    Serial.println("Start");
    // Set the power pin for the moisture sensor
    pinMode(SOIL_POWER_PIN,OUTPUT);
    digitalWrite(SOIL_POWER_PIN, LOW);

    GPS.begin(9600); // 9600 NMEA is the default baud rate.
    GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
    GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // Set a 1 Hz update rate.

    delay(1000); // Wait for GPS to initialize.

    // Ask for firmware version
    GPSSerial.println(PMTK_Q_RELEASE);
    // Initialize the LMIC.
    os_init();
    // Reset the MAC state. Resetting discards the session and pending data transfers. 
    LMIC_reset();

    // Set static session parameters. 
    uint8_t appskey[sizeof(APPSKEY)];
    uint8_t nwkskey[sizeof(NWKSKEY)];
    memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
    memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
    LMIC_setSession(0x13, DEVADDR, nwkskey, appskey);

    LMIC_selectSubBand(1);
    // Only use the correct The Things Network channels, disable the others.
    for (int c = 0; c < 72; c++)
    {
        if ((c < 8) || (c > 15))
        {
            LMIC_disableChannel(c);
        }
    }
    
    LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);

    // Disable link check validation
    LMIC_setLinkCheckMode(0);

    // TTN uses SF9 for its RX2 window.
    LMIC.dn2Dr = DR_SF9;

    // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
    LMIC_setDrTxpow(DR_SF7, 14);

    // Start job.
    processJob(&sendjob);
}

3) Utilizzare la funzione loop per avviare il processo LoRa e analizzare i dati GPS.

void loop() // Run over and over again
{
    os_runloop_once();

    char c = GPS.read();
    if (GPSECHO)
     {
        if (c){
            Serial.print(c);
              }
     }
    // If a sentence is received, parse it
    if (GPS.newNMEAreceived())
    {
        if (!GPS.parse(GPS.lastNMEA())) // Also sets the newNMEAreceived() flag to false
            return;                   
    }
}

4) La funzione GetSensorData accende il sensore di umidità e ne legge i dati, quindi lo spegne. Legge anche il sensore di temperatura e controlla le informazioni dal dispositivo GPS. Se è presente un fix GPS, questa funzione aggiorna le informazioni sulla posizione.

void GetSensorData()
{
    digitalWrite(SOIL_POWER_PIN, HIGH);
    delay(1000);
    myMoisture = analogRead(SOIL_PIN);
    digitalWrite(SOIL_POWER_PIN, LOW);
    temperatureF = dht.readTemperature( true );
    Serial.println("moisture " + String( myMoisture ) + " temp " + String( temperatureF ));
     
    if (GPS.fix)
    {
        Serial.print( "Location: " );
        Serial.print( GPS.latitudeDegrees * 100, 4 );
        Serial.print( " break " );
        Serial.print( GPS.lat );
        Serial.print( ", " );
        Serial.print( GPS.longitudeDegrees * 100 , 4 );
        Serial.println( GPS.lon );
        myLatitude = GPS.latitudeDegrees * 10000;
        myLongitude = GPS.longitudeDegrees * 10000;
    }
}

5) Utilizzare la funzione onEvent per elaborare gli eventi dalla radio LoRa. La funzione aggiorna il monitor seriale, pianifica la trasmissione successiva e riceve i messaggi.

void onEvent(ev_t ev)
{
    Serial.print(os_getTime());
    Serial.print(": ");

    switch (ev)
    {
    case EV_SCAN_TIMEOUT:
        Serial.println(F("EV_SCAN_TIMEOUT"));
        break;
    case EV_BEACON_FOUND:
        Serial.println(F("EV_BEACON_FOUND"));
        break;
    case EV_BEACON_MISSED:
        Serial.println(F("EV_BEACON_MISSED"));
        break;
    case EV_BEACON_TRACKED:
        Serial.println(F("EV_BEACON_TRACKED"));
        break;
    case EV_JOINING:
        Serial.println(F("EV_JOINING"));
        break;
    case EV_JOINED:
        Serial.println(F("EV_JOINED"));
        break;
    case EV_JOIN_FAILED:
        Serial.println(F("EV_JOIN_FAILED"));
        break;
    case EV_REJOIN_FAILED:
        Serial.println(F("EV_REJOIN_FAILED"));
        break;
    case EV_TXCOMPLETE:
        Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
        if (LMIC.txrxFlags & TXRX_ACK)
            Serial.println(F("Received ack"));
        if (LMIC.dataLen)
        {
            Serial.println(F("Received "));
            Serial.println(LMIC.dataLen);
            Serial.println(F(" bytes of payload"));
        }
        // Schedule next transmission
        os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
        break;
    case EV_LOST_TSYNC:
        Serial.println(F("EV_LOST_TSYNC"));
        break;
    case EV_RESET:
        Serial.println(F("EV_RESET"));
        break;
    case EV_RXCOMPLETE:
        // data received in ping slot
        Serial.println(F("EV_RXCOMPLETE"));
        break;
    case EV_LINK_DEAD:
        Serial.println(F("EV_LINK_DEAD"));
        break;
    case EV_LINK_ALIVE:
        Serial.println(F("EV_LINK_ALIVE"));
        break;

    case EV_TXSTART:
        Serial.println(F("EV_TXSTART"));
        break;
    default:
        Serial.print(F("Unknown event: "));
        Serial.println((unsigned)ev);
        break;
    }
}

6) La funzione processJob converte i dati del sensore in bit da inviare alla radio LoRa.

void processJob(osjob_t *j)
{
    getSensorData();
    
    if (LMIC.opmode & OP_TXRXPEND) // Check if there is a current TX/RX job running.
    {
        Serial.println(F("OP_TXRXPEND, not sending"));
    }
    else
    {
        payload[0] = byte(counter);
        payload[1] = counter >>8;

        payload[2] = byte(myMoisture);
        payload[3] = myMoisture >> 8;

        int shiftTemp = int(temperatureF * 100); // Convet temperature float to integer for sending and save two places.
        payload[4] = byte(shiftTemp);
        payload[5] = shiftTemp >> 8;

        payload[6] = byte(myLatitude);
        payload[7] = myLatitude >> 8;
        payload[8] = myLatitude >> 16;

        payload[9] = byte(myLongitude);
        payload[10] = myLongitude >> 8;
        payload[11] = myLongitude >> 16;

        LMIC_setTxData2(1, payload, sizeof(payload) - 1, 0); // Prepare upstream data transmission at the next possible time.

        counter++;
        Serial.println(String(counter));
    }
    // Next TX is scheduled after TX_COMPLETE event.

Per sapere come creare una dashboard di visualizzazione dettagliata nel tuo canale ThingSpeak , consulta Create Customized ThingSpeak Channel View.