Main Content

Cette page a été traduite par traduction automatique. Cliquez ici pour voir la dernière version en anglais.

Recueillir des données agricoles sur The Things Network

Cet exemple montre comment configurer la collecte de données à partir de trois capteurs connectés à une carte à microprocesseur avec une radio LoRa®.

Cette configuration permet la création d'un réseau de capteurs répartis sur une grande surface. Les capteurs envoient des données à The Things Network, qui sont ensuite transmises à ThingSpeak™ pour analyse et visualisation. Dans l'exemple, vous créez un prototype appareil, vous vous connectez à The Things Network et intégrez la collecte de données à ThingSpeak. L' appareil présenté ici collecte la température, l'humidité du sol et les données GPS.

Aperçu

L'exemple se compose de trois étapes principales. L'intégration de Things Network est divisée en plusieurs sous-étapes. L'étape la plus complexe est la construction de l' appareil. Pour compléter l'exemple, vous avez besoin d'un compte ThingSpeak et d'un compte sur The Things Network. Sur ThingSpeak, vous créez une nouvelle canal. Sur le réseau Things, vous créez une application et enregistrez un appareil. Ensuite, vous créez un décodeur de charge utile et ajoutez l'intégration qui transfère les données à ThingSpeak.

1) Configurer un canal ThingSpeak pour collecter des données

2) Configurer The Things Network

  • Créer une demande

  • Enregistrer l'appareil

  • Créer un format de charge utile

  • Ajouter une intégration

3) Créer un appareil

  • Matériel utilisé pour créer un nœud de capteur

  • Schéma et connexions

4) Dispositif de programme

  • Configuration de la programmation

  • Code

Configurer un canal ThingSpeak pour collecter des données

1) Créez un canal ThingSpeak , comme indiqué dans Collect Data in a New Channel. Enregistrez la clé d'API en écriture et l'ID du canal pour votre nouveau canal.

2) Accédez à la page  Paramètres des canaux . Définissez les étiquettes de champ comme suit.

  • Champ 1— Counter

  • Champ 2— Soil Moisture

  • Champ 3— Temperature F

3) Cliquez sur Enregistrer le canal en bas pour enregistrer vos paramètres.

Configurer l'application Things Network

Créez un compte sur The Things Network, puis connectez-vous à The Things Network Console.

Créer une demande

1) Sélectionnez Applications.

2) Sélectionnez  Ajouter une application .

3) Créez un ID d'application , puis ajoutez une Description . Sélectionnez  Inscription du gestionnaire  en fonction de votre emplacement.

Enregistrer un appareil

1) Cliquez sur l'onglet  Appareils  et enregistrez un appareil. Pour plus d'informations, voir Device Registration.

2) Créez un identifiant appareil . Entrez l'EUI de l'appareil si votre appareil en possède un. Sinon, sélectionnez le bouton à gauche du champ  Device EUI  pour générer automatiquement l'EUI.

3) Cliquez sur S'inscrire . Le navigateur vous ramène à l'onglet Aperçu  .

4) Sélectionnez l'ongletParamètres.

5) Dans les paramètres, sélectionnez ABP pour la méthode d'activation. Pour faciliter le débogage, vous pouvez éventuellement désactiver les vérifications du compteur de trames en bas de la page.

6) Enregistrez l'adresse de l'appareil, la clé de session réseau et la clé de session d'application. Cette information est nécessaire dans le code de votre appareil .

Créer un formateur de charge utile

Le formateur de charge utile utilise les octets envoyés à l'application depuis la passerelle pour assembler un message. Dans cet exemple, le message de charge utile souhaité est un objet codé JSON qui est envoyé à ThingSpeak.

1) Revenez à la vue de l'application en utilisant le menu de navigation en haut. Cliquez ensuite sur l'onglet Formats de charge utile .

2) Dans l'interface decoder, créez le code pour convertir les octets envoyés depuis votre appareil en un objet JSON à écrire dans ThingSpeak. Le code conditionnel pour lat et lon gère la possibilité de valeurs positives ou négatives.

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
  }
}

Ajouter une intégration

Pour transmettre des données à ThingSpeak, vous devez disposer d'une application sur le réseau Things avec un appareil enregistré et un formateur de charge utile. Créez une intégration ThingSpeak pour transférer les données.

1) Connectez-vous à votre The Things Network Console.

2) Sélectionnez Applications et sélectionnez l'application à partir de laquelle vous souhaitez transférer des données vers ThingSpeak .

3) Cliquez sur l'ongletIntégrations.

4) Sélectionnez ThingSpeak.

5) Dans le champ Process ID, nommez votre intégration.

6) Dans le champ Autorisation, entrez la clé d'API en écriture pour le canal dans lequel vous souhaitez stocker vos données. La clé d'API est disponible depuis l'onglet Clés API de votre canal ThingSpeak .

7) Dans le champ Channel ID, entrez l'ID du canal ThingSpeak vers lequel vous souhaitez transférer des données. L'ID du canal est disponible sur la page de votre canal ThingSpeak .

Créer un appareil

Matériel utilisé pour créer un nœud de capteur

Vous pouvez utiliser divers appareils LoRa prenant en charge les protocoles LoRaWan pour vous connecter à The Things Network. Cet exemple illustre la procédure utilisant la configuration hardware suivante.

Schéma et connexions

Connectez les capteurs comme indiqué sur le schéma. La photographie montre une configuration possible des capteurs dans une boîte de projet. Dans cette configuration, le capteur de température à l'intérieur du boîtier peut ne pas refléter exactement la température extérieure. Vous devez add an antenna à la radio LoRa.

1) Connectez les connexions d'alimentation et de masse pour le GPS et les capteurs de température. Ne connectez pas l'alimentation au capteur d'humidité.

2) Connectez la sortie du capteur d'humidité du sol à l'entrée analogique en A0.

3) Configurez le système de manière à ce que le capteur d'humidité s'éteigne lorsqu'il n'est pas utilisé. La broche d'alimentation du capteur d'humidité est connectée à la broche GPIO 11 sur la plume M0. La mise hors tension lorsqu'elle n'est pas utilisée prolonge la durée de vie du capteur.

4) Connectez la broche de données du capteur DH-22 à PA-15 sur le Feather M0, qui est la broche 5 dans la figure Arduino.

5) Pour la carte GPS, connectez TX à RX sur le Feather M0 et RX à TX.

6) Activez la radio LoRa en connectant PA20 (broche 29, GPIO 6) sur le Feather M0 à la terre.

7) Créez un interrupteur d'alimentation en connectant un interrupteur de la broche En à la terre.

Dispositif de programme

Configuration de la programmation

1) Téléchargez le dernier IDE Arduino.

2) Téléchargez la bibliothèque Adafruit GPS library ou ajoutez la bibliothèque Adafruit_GPS dans le gestionnaire de bibliothèque. Sélectionnez Sketch > Include Library > Manage Libraries. Recherchez Adafruit_GPS pour l’ajouter à vos bibliothèques installées.

3) Téléchargez les bibliothèques LoraWan-in-C library pour l'environnement Arduino ou ajoutez les bibliothèques lmic et hal/hal dans le gestionnaire de bibliothèques. Sélectionnez Sketch > Include Library > Manage Libraries. Recherchez lmic et sélectionnez MCCI LoRaWAN LMIC library pour l'ajouter à vos bibliothèques installées. Ajoutez également le MCCI Arduino LoRaWan Library to the library manager.

4) Créez l'application. Ouvrez une nouvelle fenêtre dans l'IDE Arduino et enregistrez le fichier. Ajoutez le code fourni dans la section Code.

Code

1) Commencez par inclure les bibliothèques appropriées et initialisez les variables.

#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) Utilisez la fonction setup pour démarrer le capteur de température, le GPS et 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) Utilisez la fonction loop pour lancer le processus LoRa et analyser les données 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 fonction GetSensorData met le capteur d'humidité sous tension et lit ses données, puis coupe l'alimentation. Il lit également le capteur de température et vérifie les informations de l' appareil GPS. S'il existe une position GPS, cette fonction met à jour les informations de position.

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) Utilisez la fonction onEvent pour traiter les événements de la radio LoRa. La fonction met à jour le moniteur série, planifie la prochaine transmission et reçoit des messages.

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 fonction processJob convertit les données du capteur en bits à envoyer via la 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.

Pour savoir comment créer un tableau de bord de visualisation détaillé dans votre canal ThingSpeak , voir Create Customized ThingSpeak Channel View.