Ir al contenido principal
Todas las coleccionesConecta tus dispositivos
Conecta tu Thinxtra Xkit usando Sigfox
Conecta tu Thinxtra Xkit usando Sigfox

Aprende a construir una aplicación IoT sobre Sigfox integrada con Ubidots.

Sergio M avatar
Escrito por Sergio M
Actualizado hace más de 2 meses

El kit de desarrollo Thinxtra Xkit cuenta con un conjunto completo de características y accesorios para empoderar a cualquiera a desarrollar una solución IoT. Perfecto para startups, proyectos de IoT para el hogar DIY y investigación académica, este kit tiene todo lo que necesitas para comenzar a trabajar utilizando la red de conexión global de Sigfox.

El Thinxtra Shield tiene integrados los siguientes sensores: temperatura, presión, luz, choque y acelerómetro 3D.

En este artículo, aprenderás cómo programar un Thinxtra Xkit para una aplicación IoT, enviando datos de los sensores cada 10 minutos.

Requisitos

1. Configuración del Dispositivo

1.- Registra tu kit de desarrollo en el portal de backend de Sigfox; consulta el video a continuación para aprender más y registrar tu dispositivo Thinxtra Xkit en el backend de Sigfox.

Descarga el repositorio de Thinxtra para recibir las bibliotecas requeridas. Las bibliotecas deben ser copiadas a la ubicación de las bibliotecas de Arduino.

Una vez que las bibliotecas estén guardadas en el IDE de Arduino, copia y pega el siguiente código en el IDE:

#include <WISOL.h>#include <Tsensors.h>#include <Wire.h>#include <math.h>#include <avr/wdt.h>/********************************************************** * Constantes y definiciones *********************************************************/typedef union{    float number;    uint8_t bytes[4];} FLOATUNION_t;typedef union{    uint16_t number;    uint8_t bytes[2];} UINT16_t;typedef union{    int16_t number;    uint8_t bytes[2];} INT16_t;Isigfox *Isigfox = new WISOL();Tsensors *tSensors = new Tsensors();uint8_t buttonCounter;const uint8_t buttonPin = A1;unsigned long my_time;const unsigned long sendTime = 600000; // Para enviar datos cada 10 minutos./********************************************************** * Funciones auxiliares *********************************************************/// SendPayload Function => Enviar mensajes a la red Sigfoxvoid Send_Pload(uint8_t *sendData, int len) {  recvMsg *RecvMsg;  RecvMsg = (recvMsg *)malloc(sizeof(recvMsg));  Isigfox->sendPayload(sendData, len, 0, RecvMsg);  for (int i = 0; i < RecvMsg->len; i++) {    Serial.print(RecvMsg->inData[i]);  }  Serial.println("");  free(RecvMsg);}void Send_Sensors(){  UINT16_t tempt, photo, pressure;  INT16_t x_g, y_g, z_g;  acceleration_xyz *xyz_g;  FLOATUNION_t a_g;  // Enviar un float requiere al menos 4 bytes  // En esta demostración, los valores medidos (temperatura, presión, sensor) están escalados para variar de 0-65535.  // Por lo tanto, pueden ser almacenados en 2 bytes  tempt.number = (uint16_t) (tSensors->getTemp() * 100);  Serial.print("Temp: "); Serial.println((float)tempt.number/100);  pressure.number =(uint16_t) (tSensors->getPressure()/3);  Serial.print("Pressure: "); Serial.println((float)pressure.number*3);  photo.number = (uint16_t) (tSensors->getPhoto() * 1000);  Serial.print("Photo: "); Serial.println((float)photo.number/1000);  xyz_g = (acceleration_xyz *)malloc(sizeof(acceleration_xyz));  tSensors->getAccXYZ(xyz_g);  x_g.number = (int16_t) (xyz_g->x_g * 250);  y_g.number = (int16_t) (xyz_g->y_g * 250);  z_g.number = (int16_t) (xyz_g->z_g * 250);  Serial.print("Acc X: "); Serial.println((float)x_g.number/250);  Serial.print("Acc Y: "); Serial.println((float)y_g.number/250);  Serial.print("Acc Z: "); Serial.println((float)z_g.number/250);  Serial.print("\0");  free(xyz_g);  const uint8_t payloadSize = 12; //en bytes//  byte* buf_str = (byte*) malloc (payloadSize);  uint8_t buf_str[payloadSize];  buf_str[0] = tempt.bytes[0];  buf_str[1] = tempt.bytes[1];  buf_str[2] = pressure.bytes[0];  buf_str[3] = pressure.bytes[1];  buf_str[4] = photo.bytes[0];  buf_str[5] = photo.bytes[1];  buf_str[6] = x_g.bytes[0];  buf_str[7] = x_g.bytes[1];  buf_str[8] = y_g.bytes[0];  buf_str[9] = y_g.bytes[1];  buf_str[10] = z_g.bytes[0];  buf_str[11] = z_g.bytes[1];  Serial.println("enviando carga útil");  Send_Pload(buf_str, payloadSize);//  free(buf_str);}void checkPress() {  while (digitalRead(buttonPin) != 1) {    buttonCounter++;    delay(50);    if (buttonCounter > 4) break;  }  if (buttonCounter > 4) {    Send_Sensors();    delay(1000);  }  buttonCounter = 0;}/********************************************************** * Funciones principales *********************************************************/void setup() {  int flagInit;  my_time = millis();    Wire.begin();  Wire.setClock(100000);  Serial.begin(9600);  // Prueba WISOL  flagInit = -1;  while (flagInit == -1) {    Serial.println(""); // Hacer un reinicio limpio    delay(1000);    flagInit = Isigfox->initSigfox();    Isigfox->testComms();  }    // Inicializar sensores en el módulo Thinxtra  tSensors->initSensors();  buttonCounter = 0;  Serial.println(""); // Hacer un inicio limpio  delay(1000);}void loop() {  // pon tu código principal aquí, para que se ejecute repetidamente:  //checkPress();    if (millis() - my_time > sendTime) {    my_time = millis();    Send_Sensors();  }}

NOTA: Antes de cargar el código en la placa Arduino (con el escudo Xkit conectado), debes quitar los puentes P9 en el escudo Xkit como se describe en la imagen a continuación o simplemente desconectar el escudo Xkit de la placa Arduino.

  • Conecta la placa a la computadora, luego selecciona el Arduino UNO como placa desde Herramientas > Placas, también selecciona el puerto COM de la placa desde Herramientas > Puerto.

  • Verifica tu código en el IDE de Arduino eligiendo el icono "Marca de verificación" en la parte superior izquierda del IDE. Una vez que el código esté verificado, recibirás un mensaje "Compilación completada" en el IDE de Arduino.

  • Carga el código en el Arduino UNO eligiendo el icono "flecha derecha" al lado del icono de marca de verificación. Una vez cargado, recibirás un mensaje "Carga completada" en el IDE de Arduino.

  • Conecta los puentes P9 del escudo Thinxtra con el Arduino UNO y reinicia la placa presionando el botón rojo

El código anterior envía el valor de temperatura, el voltaje de salida del sensor fotovoltaico, el valor de presión y la aceleración a Sigfox cada 10 segundos.

Para visualizar los datos enviados, abre el monitor serial del IDE de Arduino presionando el icono de lupa en la esquina superior derecha.

También puedes verificar los mensajes a través del backend de Sigfox seleccionando el ID del dispositivo Thinxtra de la lista de dispositivos.

A continuación, selecciona la opción "mensaje" del menú de la izquierda:

Con los mensajes comenzando a ser recibidos por el backend de Sigfox, notamos que todo el paquete de datos se envía en formato hexadecimal, por lo que para ser leído correctamente desde Ubidots es necesario transformarlo en un formato json. Esta función se puede realizar utilizando el complemento UbiFunctions.

2. Configuración de UbiFunction y callback de Sigfox Backend.

Antes de comenzar a codificar, es necesario crear una UbiFunction para analizar la estructura de carga útil que proviene del Thinxtra Xkit, pasando primero por el backend de Sigfox.

NOTA: Todas las imágenes utilizadas en este paso fueron tomadas de la documentación oficial de Thinxtra Xkit.

Como se ve en la imagen anterior, la estructura de carga útil está compuesta por 12 bytes donde cada par de bytes codifica el valor de una variable. Teniendo esto en cuenta, para codificar los datos, es necesario extraer el Little Endian de cada 2 bytes, lo que significa que el LSB (Less Significant Bit) está en el lado más a la izquierda del marco cuando se lee de izquierda a derecha.

Para obtener el valor real de la medición, se deben realizar las siguientes operaciones para cada variable:

  • Temperatura Real = temperatura (2 bytes) / 100 [°C]

  • Presión Real = presión (2 bytes) * 3 [Pa]

  • Voltaje de salida del sensor fotovoltaico = foto (2 bytes) / 1000 [V]

  • Aceleración x = x_Acc (2 bytes) / 250 [g]

  • Aceleración y = y_Acc (2 bytes) / 250 [g]

  • Aceleración z = z_Acc (2 bytes) / 250 [g]

Además, es necesario configurar un callback en el backend de Sigfox para reenviar los datos del dispositivo a un sistema externo como Ubidots. Para completar con éxito este paso, debes consultar los pasos 1, 2 y 3 de la guía "UbiFunctions: Gestionar mensajes de uplink desde el backend de Sigfox a Ubidots," asegurándote de aplicar los cambios necesarios que se muestran a continuación:

  1. Borra el código predeterminado ubicado en el editor de UbiFunction, luego copia y pega el siguiente código de muestra (Python 3) reemplazando el código predeterminado. Después de pegar, asegúrate de asignar tu TOKEN de Ubidots donde se indica.

import requestsimport structimport json#ConstantesTOKEN = "{PUT_YOUR_TOKEN_HERE}" #Asigna tu TOKEN de UbidotsBASE_URL = "https://industrial.api.ubidots.com"#convertir los datos a cadena def decodeHexToJson(data:str):    #convertir la cadena a hex y tomar el little endian    #H:ushort, h:short    rawTemperature=struct.unpack("<H",bytearray.fromhex(data[0:4]))    temperature=rawTemperature[0]/100    rawPreassure=struct.unpack("<H",bytearray.fromhex(data[4:8]))    preassure=rawPreassure[0]*3    rawPhoto=struct.unpack("<H",bytearray.fromhex(data[8:12]))    photo=rawPhoto[0]/1000    rawAcelaration_x=struct.unpack("<h",bytearray.fromhex(data[12:16]))    acelaration_x=rawAcelaration_x[0]/250    rawAcelaration_y=struct.unpack("<h",bytearray.fromhex(data[16:20]))    acelaration_y=rawAcelaration_y[0]/250    rawAcelaration_z=struct.unpack("<h",bytearray.fromhex(data[20:24]))    acelaration_z=rawAcelaration_z[0]/250    payload = {    "acelaration_x": acelaration_x,    "acelaration_y": acelaration_y,    "acelaration_z": acelaration_z,    "photo": photo,    "preassure": preassure,    "temperature": temperature    }    return payloaddef sendToUbidots(payload:str,device:str):    url = "{}/api/v1.6/devices/{}".format(BASE_URL, device)    headers = {"X-Auth-Token": TOKEN, "Content-Type": "application/json"}    req=requests.post(url,json=payload,headers=headers)    return reqdef main(args):    print(args)    #jsonData=json.loads(args)    print(args['data'])    payload = decodeHexToJson(args['data'])    req=sendToUbidots(payload,args['device'])    # Imprime el resultado de la solicitud    print("[INFO] Resultado de la solicitud:")    print(req.text)    return {"status": "Ok", "result": req.json()}


2. Establece los parámetros a continuación en la configuración del callback para poder manejar estos datos de Sigfox con el callback correctamente:

  • Tipo: DATA - UPLINK

  • Canal: URL

  • Configuración de carga útil personalizada: Déjalo en blanco

  • Patrón de URL: Esta es la URL generada por la UbiFunction en el campo "URL de punto final HTTPS." Debes agregar el parámetro "dispositivo" a ella. La URL resultante debería verse así:

https://parse.ubidots.com/prv/YOUR-USERNAME/YOUR_UBIFUNCTION_NAME
  • Usar método HTTP: POST

  • Tipo de contenido: application/json

  • Cuerpo:

{  "data" : "data",  "device" : "device"} 

Una vez que hayas ingresado todos los parámetros requeridos, verifica que tu callback se parezca al de abajo:

3. Configuración de callback de Sigfox Backend con carga útil personalizada

Otra forma de enviar los datos con éxito a Ubidots es utilizando la opción de callback configuración de carga útil personalizada, que analiza los datos entrantes y los devuelve como datos estructurados, el nuevo parámetro será:

  • Tipo: DATA - UPLINK

  • Canal: URL

  • Configuración de carga útil personalizada: temperature::float:32:little-endian

  • Patrón de URL:

  • Usar método HTTP: POST

  • Tipo de contenido: application/json

  • Cuerpo:

{  "device" : "{device}",  "temperature" : "{temperature}",} 

NOTA: La configuración de carga útil personalizada es solo para decodificar el valor de temperatura.

Una vez que hayas ingresado todos los parámetros requeridos, verifica que tu callback se parezca al de abajo:

NOTA IMPORTANTE DE DESPLIEGUE: Ubidots y Sigfox se comunican a través de URL o Batch URL (utilizado para grandes despliegues). Este tutorial explica el canal estándar de URL. Si tienes una red de sensores a gran escala, comunícate con sales@ubidots.com para recibir información adicional sobre integraciones de Batch URL.

4. Visualiza tus datos en Ubidots.

Con los pasos anteriores, tu dispositivo ahora está integrado con Ubidots y enviando datos desde el Thinxtra Xkit. Para visualizar tus datos, inicia sesión en tu cuenta de Ubidots y verifica el dispositivo recién creado con el ID del dispositivo y ve y manipula los datos recopilados según sea necesario.


NOTA IMPORTANTE: Si deseas devolver mensajes del dispositivo donde al menos un callback ha fallado, consulta la API de Sigfox para saber cómo implementarlo.

Resultado

Ahora es el momento de crear un panel de control para controlar y gestionar las variables de tu dispositivo Sigfox. Para aprender más sobre los widgets y eventos de Ubidots, consulta estos tutoriales en video.

Consejo Profesional: Ubidots te permite modificar el nombre del dispositivo por uno más amigable cuando sea necesario, si no sabes cómo modificarlo consulta el artículo a continuación:

¿Ha quedado contestada tu pregunta?