Main Content

Diese Seite wurde mithilfe maschineller Übersetzung übersetzt. Klicken Sie hier, um die neueste Version auf Englisch zu sehen.

Sammeln Sie landwirtschaftliche Daten über das Things Network

Dieses Beispiel zeigt, wie die Datenerfassung von drei Sensoren eingerichtet wird, die mit einem LoRa®-Funkgerät an eine Mikroprozessorplatine angeschlossen sind.

Diese Konfiguration ermöglicht den Aufbau eines Netzwerks verteilter Sensoren über eine große Fläche. Die Sensoren senden Daten an The Things Network, die dann zur Analyse und Visualisierung an ThingSpeak™ weitergeleitet werden. Im Beispiel bauen Sie einen Geräteprototyp, stellen eine Verbindung zu The Things Network her und integrieren die Datenerfassung mit ThingSpeak. Das hier gezeigte Gerät sammelt Temperatur-, Bodenfeuchtigkeits- und GPS-Daten.

Überblick

Das Beispiel besteht aus drei Hauptschritten. Die Things Network-Integration ist weiter in mehrere Teilschritte unterteilt. Der aufwändigste Schritt ist der Bau des Geräts. Um das Beispiel zu vervollständigen, benötigen Sie ein ThingSpeak Konto und ein Konto bei The Things Network. Auf ThingSpeak erstellen Sie einen neuen Kanal. Im Things Network erstellen Sie eine Anwendung und registrieren ein Gerät. Anschließend erstellen Sie einen Payload-Decoder und fügen die Integration hinzu, die die Daten an ThingSpeak weiterleitet.

1) Richten Sie einen ThingSpeak Kanal zum Sammeln von Daten ein

2) Richten Sie das Things-Netzwerk ein

  • Anwendung erstellen

  • Gerät registrieren

  • Nutzlastformat erstellen

  • Integration hinzufügen

3) Gerät erstellen

  • Hardware, die zum Erstellen eines Sensorknotens verwendet wird

  • Schaltplan und Anschlüsse

4) Gerät programmieren

  • Programmier-Setup

  • Code

Richten Sie einen ThingSpeak Kanal ein, um Daten zu sammeln

1) Erstellen Sie einen ThingSpeak Kanal, wie in Collect Data in a New Channel gezeigt. Notieren Sie den Schreib-API-Schlüssel und die Kanal-ID für Ihren neuen Kanal.

2) Navigieren Sie zur Seite „Kanaleinstellungen“. Legen Sie die Feldbeschriftungen wie folgt fest.

  • Feld 1 – Counter

  • Feld 2 – Soil Moisture

  • Feld 3 – Temperature F

3) Klicken Sie unten auf „Kanal speichern“, um Ihre Einstellungen zu speichern.

Konfigurieren Sie die Things Network-Anwendung

Erstellen Sie ein Konto bei The Things Network und melden Sie sich dann bei The Things Network Console an.

Anwendung erstellen

1) Wählen Sie „Anwendungen“.

2) Wählen Sie „Anwendung hinzufügen“.

3) Erstellen Sie eine „Anwendungs-ID“ und fügen Sie dann eine „Beschreibung“ hinzu. Wählen Sie die „Handlerregistrierung“ basierend auf Ihrem Standort aus.

Registrieren Sie ein Gerät

1) Klicken Sie auf die Registerkarte „Geräte“ und registrieren Sie ein Gerät. Weitere Informationen finden Sie Device Registration.

2) Erstellen Sie eine Geräte-ID. Geben Sie die Geräte-EUI ein, falls Ihr Gerät über eine verfügt. Wenn nicht, wählen Sie die Schaltfläche links neben dem Feld „Geräte-EUI“, um die EUI automatisch zu generieren.

3) Klicken Sie auf „Registrieren“. Der Browser führt Sie zurück zum Reiter „Übersicht“.

4) Wählen Sie die Registerkarte „Einstellungen“.

5) Wählen Sie in den Einstellungen ABP als Aktivierungsmethode aus. Um das Debuggen zu erleichtern, können Sie optional die „Frame Counter Checks“ unten auf der Seite deaktivieren.

6) Notieren Sie die „Geräteadresse“, den „Netzwerksitzungsschlüssel“ und den „App-Sitzungsschlüssel“. Diese Informationen sind in Ihrem Gerätecode erforderlich.

Erstellen Sie einen Payload-Formatierer

Der Nutzlastformatierer verwendet die vom Gateway an die Anwendung gesendeten Bytes, um eine Nachricht zusammenzustellen. In diesem Beispiel ist die gewünschte Nutzlastnachricht ein JSON-codiertes Objekt, das an ThingSpeak gesendet wird.

1) Kehren Sie über das Navigationsmenü oben zur Anwendungsansicht zurück. Klicken Sie dann auf die Registerkarte „Payload-Formate“.

2) Erstellen Sie in der decoder- Schnittstelle den Code, um die von Ihrem Gerät gesendeten Bytes in ein JSON-Objekt zum Schreiben in ThingSpeak umzuwandeln. Der Bedingungscode für lat und lon behandelt die Möglichkeit positiver oder negativer Werte.

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

Integration hinzufügen

Um Daten an ThingSpeak weiterzuleiten, benötigen Sie eine Anwendung im Things Network mit einem registrierten Gerät und einem Payload-Formatierer. Erstellen Sie eine ThingSpeak Integration, um die Daten weiterzuleiten.

1) Melden Sie sich bei Ihrem The Things Network Console an.

2) Wählen Sie „Anwendungen“ und wählen Sie die Anwendung aus, von der Sie Daten an ThingSpeak weiterleiten möchten.

3) Klicken Sie auf die Registerkarte „Integrationen“.

4) Wählen Sie ThingSpeak aus.

5) Geben Sie im Feld „Prozess-ID“ einen Namen für Ihre Integration ein.

6) Geben Sie im Feld Autorisierung den Schreib-API-Schlüssel für den Kanal ein, in dem Sie Ihre Daten speichern möchten. Der API-Schlüssel ist auf der Registerkarte „API-Schlüssel“ Ihres ThingSpeak Kanals verfügbar.

7) Geben Sie im Feld Kanal-ID die Kanal-ID für den ThingSpeak Kanal ein, an den Sie Daten weiterleiten möchten. Die Kanal-ID ist auf der Seite Ihres ThingSpeak Kanals verfügbar.

Gerät erstellen

Hardware, die zum Erstellen eines Sensorknotens verwendet wird

Sie können verschiedene LoRa-Geräte verwenden, die LoRaWan-Protokolle für die Verbindung mit The Things Network unterstützen. Dieses Beispiel demonstriert die Vorgehensweise anhand des folgenden Hardware-Setups.

Schaltplan und Anschlüsse

Schließen Sie die Sensoren wie im Schaltplan gezeigt an. Das Foto zeigt eine mögliche Konfiguration der Sensoren in einer Projektbox. In dieser Konfiguration spiegelt der Temperatursensor im Inneren der Box möglicherweise nicht genau die Außentemperatur wider. Sie müssen add an antenna mit dem LoRa-Radio verbinden.

1) Schließen Sie die Strom- und Erdungsanschlüsse für GPS und Temperatursensoren an. Schließen Sie den Feuchtigkeitssensor nicht an die Stromversorgung an.

2) Verbinden Sie den Ausgang des Bodenfeuchtesensors mit dem Analogeingang bei A0.

3) Richten Sie das System so ein, dass sich der Feuchtigkeitssensor ausschaltet, wenn er nicht verwendet wird. Der Stromversorgungspin des Feuchtigkeitssensors ist mit dem GPIO-Pin 11 am Feather M0 verbunden. Das Ausschalten des Geräts bei Nichtgebrauch verlängert die Lebensdauer des Sensors.

4) Verbinden Sie den DH-22-Sensordaten-Pin mit PA-15 am Feather M0, was in der Arduino-Skizze Pin 5 ist.

5) Verbinden Sie für die GPS-Karte TX mit RX am Feather M0 und RX mit TX.

6) Aktivieren Sie die LoRa-Funkverbindung, indem Sie PA20 (Pin 29, GPIO 6) am Feather M0 mit Masse verbinden.

7) Erstellen Sie einen Netzschalter, indem Sie einen Schalter vom En-Pin an Masse anschließen.

Programmgerät

Programmier-Setup

1) Laden Sie die neueste Arduino-IDE herunter.

2) Laden Sie die Adafruit GPS library herunter oder fügen Sie die Adafruit_GPS- Bibliothek im Bibliotheksmanager hinzu. Wählen Sie Sketch > Include Library > Manage Libraries. Suchen Sie nach Adafruit_GPS , um es zu Ihren installierten Bibliotheken hinzuzufügen.

3) Laden Sie LoraWan-in-C library für die Arduino-Umgebung herunter oder fügen Sie die Bibliotheken lmic und hal/hal im Bibliotheksmanager hinzu. Wählen Sie Sketch > Include Library > Manage Libraries. Suchen Sie nach lmic und wählen Sie MCCI LoRaWAN LMIC library aus, um es zu Ihren installierten Bibliotheken hinzuzufügen. Fügen Sie außerdem MCCI Arduino LoRaWan Library to the library manager. hinzu

4) Erstellen Sie die Anwendung. Öffnen Sie ein neues Fenster in der Arduino IDE und speichern Sie die Datei. Fügen Sie den im Abschnitt „Code“ bereitgestellten Code hinzu.

Code

1) Beginnen Sie mit der Einbindung der entsprechenden Bibliotheken und der Initialisierung der Variablen.

#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) Verwenden Sie die Funktion setup , um den Temperatursensor, das GPS und das LoRa-Radio zu starten.

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) Verwenden Sie die Funktion loop , um den LoRa-Prozess zu starten und die GPS-Daten zu analysieren.

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) Die Funktion GetSensorData schaltet die Stromversorgung des Feuchtigkeitssensors ein, liest seine Daten und schaltet dann die Stromversorgung aus. Es liest auch den Temperatursensor und prüft, ob Informationen vom GPS-Gerät vorliegen. Wenn ein GPS-Fix vorliegt, aktualisiert diese Funktion die Positionsinformationen.

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) Verwenden Sie die Funktion onEvent , um Ereignisse vom LoRa-Radio zu verarbeiten. Die Funktion aktualisiert den seriellen Monitor, plant die nächste Übertragung und empfängt Nachrichten.

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) Die Funktion processJob wandelt Sensordaten in Bits um, die über den LoRa-Funk gesendet werden.

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.

Informationen zum Erstellen eines detaillierten Visualisierungs-Dashboards in Ihrem ThingSpeak Kanal finden Sie unter Create Customized ThingSpeak Channel View.