The Things Network, creación de un nodo físico

En las dos entradas anteriores vimos como configurar la parte de servidor de TTN. Así que en este punto nos vamos a centrar en la realización de los nodos.

 

Elección del hardware

En primer lugar deberemos de elegir que componentes vamos a utilizar para nuestro proyecto. Nos centraremos en 4 puntos.

  • Tarjeta de control: Como somos fanes de software y hardware libre, elegiremos una compatible con Arduino.
  • Módulo de radio LoRa: Aquí quien lleva ventaja son los módulos de la serie RMF95.
  • Sensor: En este ejemplo y por no complicarnos mucho, vamos a poner un sensor de temperatura DS18B20.
  • Otros: Cualquier otro elemento que queramos incorporar. Por ejemplo, muchas tarjetas llevan un pequeño display OLED, que nos puede servir para mostrar los datos a la vez que los enviamos.

 

Hemos elegido una tarjeta que está tomando mucha fama que es la TTGO LORA32 (existen varias versiones). Una de las ventajas de esta tarjeta es que lleva el módulo de LoRa ya integrado, por lo que nos ahorramos el tener que soldarlo. Además, al estar basada en un ESP32, dispone de WiFi y Bluetooth, algunas versiones incluyen también display. La vemos aquí montada sobre un PCB incluyendo el sensor.

En esta tarjeta, y algunas otras, hay un par de conexiones del módulo LoRa que no están realizadas internamente en la tarjeta, por lo que tendremos que realizar esas conexiones externamente para que nuestro módulo funcione. Los veremos más adelante. Otra conexión que también deberemos hacer será la del sensor que queramos utilizar.

Por supuesto, cada uno podrá elegir su hardware según sus gustos y necesidades.

Realización del software

Instalación de la librería

El primer paso será instalar la librería en nuestro sistema. Para ello, dentro del Arduino IDE iremos a Programa->Incluir librería->Administrar bibliotecas. Allí buscaremos LMIC.

Veréis que aparecen 3 librerías distintas. Salvo error, las dos primeras han quedado algo obsoletas ya que se han unificado en la tercera «MCCI LoRaWAN LMIC library«, así que instalaremos esta última.

WARNING!!! Un detalle importante es que tendremos que configurar la librería para funcionar en nuestra frecuencia, a menos que nos encontremos en USA pues viene por defecto configurada para esa zona (915MHz), en Europa se usa la frecuencia 868MHz.

Para ello, localizaremos el fichero lmic_project_config.h que se encuentra dentro de la ruta de la librería. Generalmente, las librerías de Arduino se instalan a partir del directorio de usuario, por lo que nos situaremos en el nuestro y accederemos a los distintos subdirectorios ./Arduino/libraries/MCCI_LoRaWAN_LMIC_library/project_config:

Una vez localizado, editaremos el fichero comentando CFG_us915 y quitando el comentario de CFG_eu868:

// project-specific definitions
#define CFG_eu868 1
//#define CFG_us915 1
//#define CFG_au921 1
//#define CFG_as923 1
// #define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP /* for as923-JP */
//#define CFG_in866 1
#define CFG_sx1276_radio 1
//#define LMIC_USE_INTERRUPTS

Nodo de ejemplo

Lo más sencillo para empezar es partir de algún ejemplo de la propia librería. Por lo que iremos a Archivo->Ejemplos->MCCI LoRaWAN LMIC library->ttn-abp.

Este ejemplo envía el texto «Hello, world!» (Hola mundo) una vez por minuto, aproximadamente. Pero tendremos que realizar algunos cambios para que funcione, además de que queremos que la funcionalidad de nuestro nodo sea distinta.

Configuración para utilizar nuestro hardware

El punto principal que tenemos que configurar respecto al hardware es a qué pines de nuestra tarjeta (o del uC más concretamente) está conectado el módulo de radio LoRa.

Para ello existe en el código una estructura que contiene estos valores, así que la localizaremos:

// Pin mapping
// Adapted for Feather M0 per p.10 of [feather]
const lmic_pinmap lmic_pins = {
    .nss = 8, // chip select on feather (rf95module) CS
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 4, // reset pin
    .dio = {6, 5, LMIC_UNUSED_PIN}, // assumes external jumpers [feather_lora_jumper]
                                    // DIO1 is on JP1-1: is io1 - we connect to GPO6
                                    // DIO1 is on JP5-3: is D2 - we connect to GPO5
};

Como se puede ver por los comentarios, los valores que vienen por defecto son para la tarjeta Feather M0 con lora, por lo que si esta es nuestra tarjeta, no tendremos que tocar nada.

 

En nuestro caso es una TTGO LORA32 v2.0 por lo que cambiaremos los valores:

// Pin mapping
// Adapted for TTGO LORA32 v2.0
const lmic_pinmap lmic_pins = {
    .nss = 18, // chip select (rf95module) CS
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14, // reset pin
    .dio = {26, 33, 32}, // assumes external jumpers
                         // DIO1 is on GPIO33
                         // DIO2 is on GPIO32
};

Como hemos comentado antes, hay que hacer un par de uniones físicas en la tarjeta para que funcione y estas son las relativas a DIO1 y DIO2 del módulo LoRa que conectaremos a los pines GPIOs que queramos (los mostrados son los más sencillos y recomendados).

Con estos cambios, nuestro uC ya será capaz de comunicar con el módulo LoRa y así poder transmitir los mensajes, pero aún tenemos que identificarnos dentro de la red TTN para que lleguen a buen puerto.

Configuración para TTN

Para que el nodo se conecte a nuestra aplicación TTN tendremos que configurar 3 variables en el código. El propio código de ejemplo nos indica cuales son, utilizando la palabra FILLMEIN (rellename) en los sitios donde tendremos que poner los datos correctos.

Estas variables son:

  • NWKSKEY: la contraseña de la sesión de red.
  • APPSKEY: la contraseña de la sesión de aplicación.
  • DEVADDR: la dirección de nuestro nodo.

Estos datos son los que identificarán al nodo dentro de la red y podremos obtenerlos de la consola TTN en la visualización de los detalles del nodo:

Como podéis ver, los datos relativos a contraseñas aparecen «tapados» por motivos de seguridad y que nadie a nuestro alrededor pueda ver los datos. Pero si pulsamos sobre el icono del ojo, al lado del dato, este se hará visible. Más interesantes son los otros iconos que le acompañan, ya que al pulsarlos nos permitirá mostrar la información en el formato de un array de C, esto se logra pulsando sobre <>, mientras que al pulsar sobre el de las flechas cambia entre msb y lsb, lo dejaremos en msb.

Y ahora viene lo mejor, si pulsamos sobre el icono de la derecha… los datos se copian al portapapeles!!! Sin duda una de las cosas más útiles, ya que nos ahorramos tener que escribir los datos y evitamos equivocarnos en algún valor.

Así que con los datos copiados en el portapapeles, volveremos al IDE Arduino y de daremos a pegar sobre el correspondiente FILLMEIN. Lo repetiremos para los 3 datos y ya podremos darle a compilar.

Mientras que NWKSKEY y APPSKEY habrá que incluir los datos en el formato de array, para DEVADDR el valor habrá que ponerlo como un único dato, al ser la variable de tipo u4_t.

static const u4_t DEVADDR = 0x00000000;

 

Bueno, con esto configurado, nuestro nodo ya funcionaría. Pero claro, a menos que queramos enviar simplemente «Hello, world!» para siempre, tendremos que realizar unos últimos cambios en el código.

Uso del sensor

Para usar nuestro sensor tendremos que añadir/modificar varias cosas:

Definición del sensor

En primer lugar tendremos que añadir las definiciones y el objeto que tratará el sensor. Así que por el principio del código pondremos:

#include <OneWire.h> 
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 0
OneWire oneWire(ONE_WIRE_BUS); 
DallasTemperature sensor(&oneWire);

En caso de no tener instalada la librería de nuestro sensor tendremos que instalarla antes o fallará la compilación. El valor de ONE_WIRE_BUS lo haremos corresponder con el pin al que hayamos conectado el sensor.

Configuración

Ahora, dentro de la función setup() inicializaremos el sensor incluyendo:

sensor.begin();
sensor.setResolution(11);

El valor de la resolución lo podremos variar según la deseada. Y ya tendremos listo el sensor para poder usarlo.

Lectura de valores y envío de los datos

El último punto será realizar la lectura del sensor y enviar los datos. esto se realizará sobre la función do_send() así que la localizaremos y modificaremos:

void do_send(osjob_t* j){
    // Check if there is not a current TX/RX job running
    if (LMIC.opmode & OP_TXRXPEND) {
        Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
        // Prepare upstream data transmission at the next possible time.

        sensor.requestTemperatures();
        mydata[0] = sensor.getTempCByIndex(0);
        LMIC_setTxData2(1, mydata, sizeof(mydata), 0);

        Serial.println(F("Packet queued"));
    }
    // Next TX is scheduled after TX_COMPLETE event.
}

Unos comentarios a tener en cuenta:

  • La parte modificada es la que está en negrita.
  • Lo que hace el programa es enviar los datos que haya en el array mydata.
  • Este array originalmente tiene el tamaño del texto «Hello, world!«, por lo que tendremos que modificar este array para que corresponda con el tamaño de nuestros datos.
  • El código esta muy simplificado y se mejorar. Por ejemplo, tal y como está no se envía la parte decimal de la temperatura, por lo que podría modificarse para enviar también los decimales.

 

Bueno, pues ahora sí. Ya tenemos un nodo funcional que hace lo que queremos. Si hemos configurado nuestra aplicación TTN para obtener sus datos, podremos ver cada minuto llega un nuevo valor de temperatura.

 

Otro día hablaremos un poco más de la librería LMIC para entender mejor como funciona, pero por hoy creo que podemos estar contentos de tener, al fin, un nodo funcionando!!!

 

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

dieciocho − ocho =

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.