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.
Adafruit Plume M0
Adafruit Ultimate GPS FeatherWing
Moniteur de sol (par exemple, le Sparkfun Moisture Sensor SEN 13322)
DHT22
En-têtes et fil
Antenne GPS W14Q5A-y
Interrupteur à bascule
Batterie LiPo 500 mAh
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.