Main Content

Esta página se ha traducido mediante traducción automática. Haga clic aquí para ver la última versión en inglés.

Recopile datos agrícolas a través de The Things Network

Este ejemplo muestra cómo configurar la recopilación de datos de tres sensores conectados a una placa de microprocesador con una radio LoRa®.

Esta configuración permite la creación de una red de sensores distribuidos en un área grande. Los sensores envían datos a The Things Network, que luego se reenvían a ThingSpeak™ para su análisis y visualización. En el ejemplo, usted construye un prototipo de dispositivo, se conecta a The Things Network e integra la recopilación de datos con ThingSpeak. El dispositivo que se muestra aquí recopila datos de temperatura, humedad del suelo y GPS.

Descripción general

El ejemplo consta de tres pasos principales. La integración de Things Network se divide a su vez en varios subpasos. El paso más complicado es la construcción del dispositivo. Para completar el ejemplo, necesita una cuenta de ThingSpeak y una cuenta en The Things Network. En ThingSpeak, creas un nuevo canal. En Things Network, creas una aplicación y registras un dispositivo. Luego crea un decodificador de carga útil y agrega la integración que reenvía los datos a ThingSpeak.

1) Configure un canal ThingSpeak para recopilar datos

2) Configurar la red de cosas

  • Crear aplicación

  • Registrar dispositivo

  • Crear formato de carga útil

  • Agregar integración

3) Crear dispositivo

  • Hardware utilizado para crear el nodo sensor

  • Esquema y conexiones

4) Dispositivo de programa

  • Configuración de programación

  • Código

Configurar un canal ThingSpeak para recopilar datos

1) Cree un canal ThingSpeak, como se muestra en Collect Data in a New Channel. Registre la clave API de escritura y el ID del canal para su nuevo canal.

2) Navegue a la página Configuración del canal. Configure las etiquetas de campo de la siguiente manera.

  • Campo 1 : Counter

  • Campo 2: Soil Moisture

  • Campo 3: Temperature F

3) Haga clic en Guardar canal en la parte inferior para guardar su configuración.

Configurar la aplicación de red Things

Crea una cuenta en The Things Network, y luego inicia sesión en The Things Network Console.

Crear aplicación

1) Seleccione Aplicaciones.

2) Seleccione Agregar aplicación.

3) Cree un ID de aplicación, luego agregue una Descripción. Seleccione el Registro de manejador según su ubicación.

Registrar un dispositivo

1) Haga clic en la pestaña Dispositivos y registre un dispositivo. Para obtener más información, consulte Device Registration.

2) Cree una identificación de dispositivo. Ingrese el EUI del dispositivo si su dispositivo tiene uno. De lo contrario, seleccione el botón a la izquierda del campo Device EUI para generar el EUI automáticamente.

3) Haga clic en Registrarse. El navegador le devuelve a la pestaña Descripción general.

4) Seleccione la pestaña Configuración.

5) En la configuración, seleccione ABP para el método de activación. Para ayudar a la depuración, opcionalmente puede desactivar las Comprobaciones del contador de fotogramas en la parte inferior de la página.

6) Registre la Dirección del dispositivo, la Clave de sesión de red y la Clave de sesión de la aplicación. Esta información es necesaria en el código de su dispositivo.

Crear formateador de carga útil

El formateador de carga útil utiliza los bytes enviados a la aplicación desde la puerta de enlace para ensamblar un mensaje. En este ejemplo, el mensaje de carga útil deseado es un objeto codificado en JSON que se envía a ThingSpeak.

1) Regrese a la vista de la aplicación usando el menú de navegación en la parte superior. Luego haga clic en la pestaña Formatos de carga útil.

2) En la interfaz decoder , cree el código para convertir los bytes enviados desde su dispositivo en un objeto JSON para escribir en ThingSpeak. El código condicional para lat y lon maneja la posibilidad de valores positivos o negativos.

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

Agregar integración

Para reenviar datos a ThingSpeak, debe tener una aplicación en Things Network con un dispositivo registrado y un formateador de carga útil. Cree una integración de ThingSpeak para reenviar los datos.

1) Inicie sesión en su The Things Network Console.

2) Seleccione Aplicaciones y seleccione la aplicación desde la que desea reenviar datos a ThingSpeak.

3) Haga clic en la pestaña Integraciones.

4) Seleccione Cosa Habla.

5) En el campo ID de proceso, asigne un nombre a su integración.

6) En el campo Autorización, ingrese la clave API de escritura para el canal en el que desea almacenar sus datos. La clave API está disponible en la pestaña Claves API de tu canal ThingSpeak.

7) En el campo ID de canal, ingrese el ID del canal de ThingSpeak al que desea reenviar datos. El ID del canal está disponible en la página de su canal ThingSpeak.

Crear dispositivo

Hardware utilizado para crear el nodo sensor

Puede utilizar varios dispositivos LoRa que admitan protocolos LoRaWan para conectarse a The Things Network. Este ejemplo demuestra el procedimiento utilizando la siguiente configuración de hardware.

Esquema y conexiones

Conecte los sensores como se muestra en el esquema. La fotografía muestra una posible configuración de los sensores en una caja de proyecto. En esta configuración, es posible que el sensor de temperatura dentro de la caja no refleje exactamente la temperatura exterior. Necesita add an antenna a la radio LoRa.

1) Conecte las conexiones de alimentación y tierra para el GPS y los sensores de temperatura. No conecte la alimentación al sensor de humedad.

2) Conecte la salida del sensor de humedad del suelo a la entrada analógica en A0.

3) Configure el sistema para que el sensor de humedad se apague cuando no esté en uso. El pin de alimentación del sensor de humedad está conectado al pin GPIO 11 en la pluma M0. Apagar la alimentación cuando no se utiliza prolonga la vida útil del sensor.

4) Conecte el pin de datos del sensor DH-22 al PA-15 en el Feather M0, que es el pin 5 en el boceto de Arduino.

5) Para la placa GPS, conecte TX a RX en el Feather M0 y RX a TX.

6) Habilite la radio LoRa conectando PA20 (pin 29, GPIO 6) en el Feather M0 a tierra.

7) Cree un interruptor de alimentación conectando un interruptor del pin En a tierra.

Dispositivo de programa

Configuración de programación

1) Descargue el último IDE de Arduino.

2) Descargue la Adafruit GPS library o agregue la biblioteca Adafruit_GPS en el administrador de bibliotecas. Seleccione Sketch > Include Library > Manage Libraries. Busque Adafruit_GPS para agregarlo a sus bibliotecas instaladas.

3) Descargue el LoraWan-in-C library para el entorno Arduino o agregue las bibliotecas lmic y hal/hal en el administrador de bibliotecas. Seleccione Sketch > Include Library > Manage Libraries. Busque lmic y seleccione MCCI LoRaWAN LMIC library para agregarlo a sus bibliotecas instaladas. Añade también el MCCI Arduino LoRaWan Library to the library manager.

4) Crea la aplicación. Abra una nueva ventana en el IDE de Arduino y guarde el archivo. Agregue el código proporcionado en la sección Código.

Código

1) Comience incluyendo las bibliotecas apropiadas e inicializando las 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) Utilice la función setup para iniciar el sensor de temperatura, el GPS y 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) Utilice la función loop para iniciar el proceso LoRa y analizar los datos del 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 función GetSensorData enciende el sensor de humedad y lee sus datos, luego lo apaga. También lee el sensor de temperatura y busca información del dispositivo GPS. Si hay una posición de GPS, esta función actualiza la información de posición.

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) Utilice la función onEvent para procesar eventos de la radio LoRa. La función actualiza el monitor serie, programa la siguiente transmisión y recibe mensajes.

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 función processJob convierte los datos del sensor en bits para enviarlos a través de 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.

Para aprender cómo crear un panel de visualización detallado en su canal ThingSpeak, consulte Create Customized ThingSpeak Channel View.