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!!!
Actualización (2019-11-20): conexión pines TTGO LORA32 V2.0
Hemos recibido un comentario por correo (fallaron los comentarios web en ese momento) de Jordi indicándonos que no quedaba claro el punto de la conexión física comentada de los pines de la tarjeta.
Culpa mía, con las prisas expliqué ese punto de manera superficial sin pensar que pudiera ser problemático.
Lo primero indicar que estás conexiones serán distintas o innecesarias dependiendo de cada modelo de tarjeta. Así que será preciso consultar la documentación de cada una para saber si hay que realizarlas.
Para la tarjeta que nos ocupa veremos primero el pinout:
Viendo los pines, hay 2 marcados como LoRa_DIO1 y LoRa_DIO2, estos corresponden con señales del módulo LoRa, pero no están conectadas al uC internamente en la tarjeta (supongo que para tener más pines disponibles si no se usa el módulo LoRa) por lo que tenemos que conectarlas externamente.
Los pines empleados para la conexión son GPIO33 y GPIO32, respectivamente. Se hallan directamente enfrentados en la fila opuesta por lo que la conexión será sencilla.
- LoRa_DIO1 conectado con GPIO33
- LoRa_DIO2 conectado con GPIO32
Estos números (33 y 32) corresponderán con los puestos en el código en la estructura lmic_pins.
Así que haremos la unión, siguiendo uno de estos 3 métodos (a elegir según nuestro diseño/necesidades):
- Soldar cables directamente a los pines en nuestra tarjeta. Esta opción solo la emplearía para un módulo final que no se vaya a modificar posteriormente y que no vaya sobre otro PCB.
- Si tenemos los pines montados, usar cables del tipo Jumper para hacer la unión. En este caso la unión es la más sencilla de hacer y como es “temporal” (se puede desconectar) es ideal para realizar pruebas.
- Sí vamos a “pinchar” la tarjeta sobre otra tarjeta, realizar la unión sobre el “routeado” de esta otra (físicamente con cables, puentes y/o estaño sí es artesanal o en el diseño electrónico, p.e. usando KiCad, antes de mandarla a fabricar).
Veamos imágenes con los 2 últimos casos:
Se marca en rojo las uniones relativas a estas señales, ya que en la imagen pueden verse otras conexiones de la tarjeta (para los sensores).
No hay foto del primer método (soldar directamente sobre el TTGO) pues no lo he realizado. Pero, visualmente, vendría a ser una “mezcla” de los otros dos métodos.
Bueno, como despedida, aprovecho para animaros a hacer como Jordi y dejar en los comentarios (o por correo si falla la web) vuestras dudas y preguntas. Tanto para este, como para cualquier otro post. Pues, como se acaba de demostrar ?, podemos pasar por alto o no explicar correctamente distintos puntos que nos parezcan claros y no hayamos conseguido desarrollarlos para que sean adecuadamente entendidos.
Muy buen post!! Gracias!!
Hola,
estoy siguiendo este tutorial pero la tarjeta que utilizo es la TTGO LORA32 v1 y no se como conectar los pins DIO1 y 2, básicamente porque no encuentro un esquema pinout como el que tienes en tu articulo, para saber donde estan y conectarlos al GPIO32 y GPIO33 …puedes ayudarme ?
GRACIAS
Hola Germán, lo primero disculpa la tardanza en contestar.
No he podido probar la versión v1, pero creo recordar que DIO1 y DIO2 ya están unidos internamente en ese modelo. Por lo que no haría falta hacer ninguna conexión exteriormente.
Has podido probarlo?