Ir al contenido principal

Conectar la serie SenseCap S210X de Seeed Studio a Ubidots [Helium LNS]

Este artículo explora cómo conectar cualquiera de los sensores LoRaWAN de la serie SenseCap S210X de Seeed Studio a Ubidots utilizando Helium LNS.

Escrito por Sergio M

⚠️ INTEGRACIÓN DESCONTINUADA

La consola de Helium (console.helium.com) fue retirada por Nova Labs / Helium Foundation. Las instrucciones a continuación se mantienen como referencia pero ya no reciben mantenimiento.

Para conectar tu SenseCap serie S210X hoy, sigue la guía actualizada de The Things Stack (TTS). También puedes usar el Servidor de Red LoRaWAN de Ubidots propio.


SenseCap S210X es una línea poderosa de sensores con interfaz Bluetooth y LoRaWAN integradas, especialmente diseñada para aplicaciones al aire libre como la agricultura, ciudades inteligentes, entre muchas otras. Esta serie está compuesta por los siguientes dispositivos:

El procedimiento especificado aquí funciona de la misma manera para los 5 dispositivos que componen la serie S210X.

image.png

Requisitos:

  • Cualquiera de los SenseCap S210X de Seeed Studio Serie

  • Una cuenta activa en Helium Console

  • Una cuenta activa en Ubidots

  • Un teléfono celular que ejecute Android o iOS con Bluetooth

1. Configurar el SenseCap S210X

  • Instala la aplicación móvil SenseCAP buscando “SenseCAP Mate” en la tienda de aplicaciones de tu dispositivo o escaneando el siguiente código QR:

image.png
  • Activa el Bluetooth de tu teléfono celular y luego enciende el SenseCap presionando y manteniendo el botón de configuración durante 3 segundos:

image.png
  • Abre la aplicación SenseCAP en tu dispositivo móvil y, allí, selecciona S210X Sensor, luego toca en Configuración

1.png
  • Selecciona tu dispositivo tocando sobre él:

2.png

Las siguientes configuraciones dependen de tu región, por ejemplo, si te encuentras en Europa deberías seleccionar EU_863, si te encuentras en India, deberías elegir IN_865. En el siguiente enlace puedes encontrar más información sobre cada banda permitida en cada país y sus regulaciones. Esta guía fue desarrollada utilizando la banda AUS_915, sin embargo, recuerda cambiar estas configuraciones de acuerdo a tu región.

  • Toca en la pestaña “Configuraciones” y edita las siguientes configuraciones:

    • Plataforma: Helium

    • Plan de Frecuencia: AUS915

    • Intervalo de Uplink (opcional): 5

  • Copia los siguientes valores (no modifiques ninguno). Los utilizaremos más tarde:

    • Device EUI

    • APP EUI

    • APP Key

  • Haz clic en “Enviar”

3.png

2. Registrar el SenseCap S210X en Helium LNS

  • Inicia sesión en tu consola de Helium.

  • Ve a la sección “Dispositivos”

  • Haz clic en el botón “Agregar dispositivo”

  • Dale a tu dispositivo un nombre significativo

  • Configura los datos del dispositivo como "DevEui", "AppEui", etc.

  • Dale a tu dispositivo una etiqueta en caso de que estés configurando varios dispositivos del mismo tipo

  • Haz clic en el botón "Guardar Dispositivo"

3. Crear la Integración a Ubidots

  • Ve a la sección "Integraciones"

  • Haz clic en "Agregar integración"

  • Busca la integración de Ubidots entre la lista de socios y haz clic en ella

  • Haz clic en "+ Agregar integración"

  • Ingresa tu Token de Ubidots y haz clic en el botón "Obtener URL de Webhook"

  • Espera el mensaje "¡URL de Webhook de Ubidots obtenida!" y haz clic en el botón "Continuar"

  • Establece un nombre para tu integración

  • Haz clic en "Agregar Integración"

4. Configurar la función de decodificación

  • Ve a la sección "Funciones"

  • Haz clic en el botón "Crear nueva función"

  • Haz clic en "Personalizado"

  • Establece un nombre para tu función de decodificación

  • Elimina todo el código en el cuadro de texto

  • Pega el siguiente código

  • Haz clic en el botón "Guardar Función"

Código de la función de decodificación:

Este decodificador es proporcionado y soportado oficialmente por Seeed Studio, únicamente para Helium LNS en el siguiente enlace. Por favor, consulta el enlace proporcionado para obtener el decodificador más actualizado para tu aplicación.

/** * Entry, decoder.js */function Decoder (bytes, port) {    // init    var bytesString = bytes2HexString(bytes)        .toLocaleUpperCase();    var decoded = {        // valid        valid: true,        err: 0,        // bytes        payload: bytesString,        // messages array        messages: []    };    // CRC check    if (!crc16Check(bytesString)) {        decoded["valid"] = false;        decoded["err"] = -1; // "crc check fail."        return decoded;    }    // Length Check    if ((((bytesString.length / 2) - 2) % 7) !== 0) {        decoded["valid"] = false;        decoded["err"] = -2; // "length check fail."        return decoded;    }    // Cache sensor id    var sensorEuiLowBytes;    var sensorEuiHighBytes;    // Handle each frame    var frameArray = divideBy7Bytes(bytesString);    for (var forFrame = 0; forFrame < frameArray.length; forFrame++) {        var frame = frameArray[forFrame];        // Extract key parameters        var channel = strTo10SysNub(frame.substring(0, 2));        var dataID = strTo10SysNub(frame.substring(2, 6));        var dataValue = frame.substring(6, 14);        var realDataValue = isSpecialDataId(dataID) ? ttnDataSpecialFormat(dataID, dataValue) : ttnDataFormat(dataValue);        if (checkDataIdIsMeasureUpload(dataID)) {            // if telemetry.            decoded.messages.push({                type: "report_telemetry",                measurementId: dataID,                measurementValue: realDataValue            });        } else if (isSpecialDataId(dataID) || (dataID === 5) || (dataID === 6)) {            // if special order, except "report_sensor_id".            switch (dataID) {                case 0x00:                    // node version                    var versionData = sensorAttrForVersion(realDataValue);                    decoded.messages.push({                        type: "upload_version",                        hardwareVersion: versionData.ver_hardware,                        softwareVersion: versionData.ver_software                    });                    break;                case 1:                    // sensor version                    break;                case 2:                    // sensor eui, low bytes                    sensorEuiLowBytes = realDataValue;                    break;                case 3:                    // sensor eui, high bytes                    sensorEuiHighBytes = realDataValue;                    break;                case 7:                    // battery power && interval                    decoded.messages.push({                        type: "upload_battery",                        battery: realDataValue.power                    }, {                        type: "upload_interval",                        interval: parseInt(realDataValue.interval) * 60                    });                    break;                case 0x120:                    // remove sensor                    decoded.messages.push({                        type: "report_remove_sensor",                        channel: 1                    });                    break;                default:                    break;            }        } else {            decoded.messages.push({                type: "unknown_message",                dataID: dataID,                dataValue: dataValue            });        }    }    // if the complete id received, as "upload_sensor_id"    if (sensorEuiHighBytes && sensorEuiLowBytes) {        decoded.messages.unshift({            type: "upload_sensor_id",            channel: 1,            sensorId: (sensorEuiHighBytes + sensorEuiLowBytes).toUpperCase()        });    }    // return    //return decoded;    var ubidotsFields = [];    var messages = decoded.messages;    for (var i = 0; i < messages.length; i++) {        var message = messages[i];        var id = message.measurementId;        var value = message.measurementValue;        switch (id) {            case 4097:                ubidotsFields.push({                    "field":"TEMPERATURE",                    "value": value                });                break;            case 4098:                ubidotsFields.push({                    "field":"HUMIDITY",                    "value": value                });                break;            case 4099:                ubidotsFields.push({                    "field":"LIGHT_INTENSITY",                    "value": value                });                break;            case 4100:                ubidotsFields.push({                    "field":"CO2",                    "value": value                });                break;            case 4101:                ubidotsFields.push({                    "field":"BAROMETRIC_PRESSURE",                    "value": value                });                break;            case 4102:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE",                    "value": value                });                break;            case 4103:                ubidotsFields.push({                    "field":"SOIL_MOISTURE",                    "value": value                });                break;            case 4104:                ubidotsFields.push({                    "field":"WIND_DIRECTION",                    "value": value                });                break;            case 4105:                ubidotsFields.push({                    "field":"WIND_SPEED",                    "value": value                });                break;            case 4106:                ubidotsFields.push({                    "field":"PH",                    "value": value                });                break;            case 4107:                ubidotsFields.push({                    "field":"LIGHT_QUANTUM",                    "value": value                });                break;            case 4108:                ubidotsFields.push({                    "field":"ELECTRICAL_CONDUCTIVITY",                    "value": value                });                break;            case 4109:                ubidotsFields.push({                    "field":"DISSOLVED_OXYGEN",                    "value": value                });                break;            case 4110:                ubidotsFields.push({                    "field":"SOIL_VOLUMETRIC_WATER_CONTENT",                    "value": value                });                break;            case 4111:                ubidotsFields.push({                    "field":"SOIL_ELECTRICAL_CONDUCTIVITY",                    "value": value                });                break;            case 4112:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE(SOIL_TEMPERATURE, VWC & EC Sensor)",                    "value": value                });                break;            case 4113:                ubidotsFields.push({                    "field":"RAINFALL_HOURLY",                    "value": value                });                break;            case 4115:                ubidotsFields.push({                    "field":"DISTANCE",                    "value": value                });                break;            case 4116:                ubidotsFields.push({                    "field":"WATER_LEAK",                    "value": value                });                break;            case 4117:                ubidotsFields.push({                    "field":"LIGUID_LEVEL",                    "value": value                });                break;            case 4118:                ubidotsFields.push({                    "field":"NH3",                    "value": value                });                break;            case 4119:                ubidotsFields.push({                    "field":"H2S",                    "value": value                });                break;            case 4120:                ubidotsFields.push({                    "field":"FLOW_RATE",                    "value": value                });                break;            case 4121:                ubidotsFields.push({                    "field":"TOTAL_FLOW",                    "value": value                });                break;            case 4122:                ubidotsFields.push({                    "field":"OXYGEN_CONCENTRATION",                    "value": value                });                break;            case 4123:                ubidotsFields.push({                    "field":"WATER_ELETRICAL_CONDUCTIVITY",                    "value": value                });                break;            case 4124:                ubidotsFields.push({                    "field":"WATER_TEMPERATURE",                    "value": value                });                break;            case 4125:                ubidotsFields.push({                    "field":"SOIL_HEAT_FLUX",                    "value": value                });                break;            case 4126:                ubidotsFields.push({                    "field":"SUNSHINE_DURATION",                    "value": value                });                break;            case 4127:                ubidotsFields.push({                    "field":"TOTAL_SOLAR_RADIATION",                    "value": value                });                break;            case 4128:                ubidotsFields.push({                    "field":"WATER_SURFACE_EVAPORATION",                    "value": value                });                break;            case 4129:                ubidotsFields.push({                    "field":"PHOTOSYNTHETICALLY_ACTIVE_RADIATION_PAR",                    "value": value                });                break;            case 4130:                ubidotsFields.push({                    "field":"ACCELEROMETER",                    "value": value                });                break;            case 4131:                ubidotsFields.push({                    "field":"VOLUME",                    "value": value                });                break;            case 4133:                ubidotsFields.push({                    "field":"SOIL_TENSION",                    "value": value                });                break;            case 4134:                ubidotsFields.push({                    "field":"SALINITY",                    "value": value                });                break;            case 4135:                ubidotsFields.push({                    "field":"TDS",                    "value": value                });                break;            case 4136:                ubidotsFields.push({                    "field":"LEAF_TEMPERATURE",                    "value": value                });                break;            case 4137:                ubidotsFields.push({                    "field":"LEAF_WETNESS",                    "value": value                });                break;            case 4138:                ubidotsFields.push({                    "field":"SOIL_MOISTURE_10CM",                    "value": value                });                break;            case 4139:                ubidotsFields.push({                    "field":"SOIL_MOISTURE_20CM",                    "value": value                });                break;            case 4140:                ubidotsFields.push({                    "field":"SOIL_MOISTURE_30CM",                    "value": value                });                break;            case 4141:                ubidotsFields.push({                    "field":"SOIL_MOISTURE_40CM",                    "value": value                });                break;            case 4142:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE_10CM",                    "value": value                });                break;            case 4143:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE_20CM",                    "value": value                });                break;            case 4144:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE_30CM",                    "value": value                });                break;            case 4145:                ubidotsFields.push({                    "field":"SOIL_TEMPERATURE_40CM",                    "value": value                });                break;            case 4146:                ubidotsFields.push({                    "field":"PM2_5",                    "value": value                });                break;            case 4147:                ubidotsFields.push({                    "field":"PM10",                    "value": value                });                break;            case 4148:                ubidotsFields.push({                    "field":"NOISE",                    "value": value                });                break;            case 4150:                ubidotsFields.push({                    "field":"ACCELEROMETERX",                    "value": value                });                break;            case 4151:                ubidotsFields.push({                    "field":"ACCELEROMETERY",                    "value": value                });                break;            case 4152:                ubidotsFields.push({                    "field":"ACCELEROMETERZ",                    "value": value                });                break;            case 5100:                ubidotsFields.push({                    "field":"SWITCH",                    "value": value                });                break;            case 9990100:                ubidotsFields.push({                    "field":"BATTERY",                    "value": message.battery                });                break;            case 9990200:                ubidotsFields.push({                    "field":"INTERVAL",                    "value": message.interval                });                break;            case 9990300:                ubidotsFields.push({                    "field":"REMOVED",                    "value": message.interval                });                break;        }    }    return ubidotsFields}function crc16Check (data) {    var crc16tab = [        0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,        0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,        0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,        0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,        0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,        0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,        0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,        0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,        0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,        0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,        0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,        0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,        0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,        0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,        0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,        0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,        0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,        0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,        0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,        0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,        0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,        0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,        0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,        0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,        0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,        0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,        0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,        0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,        0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,        0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,        0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,        0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78    ];    var result = false;    var crc = 0;    var dataArray = [];    for (var i = 0; i < data.length; i += 2) {        dataArray.push(data.substring(i, i + 2));    }    for (var j = 0; j < dataArray.length; j++) {        var item = dataArray[j];        crc = (crc >> 8) ^ crc16tab[(crc ^ parseInt(item, 16)) & 0xFF];    }    if (crc === 0) {        result = true;    }    return result;}// utilfunction bytes2HexString (arrBytes) {    var str = "";    for (var i = 0; i < arrBytes.length; i++) {        var tmp;        var num = arrBytes[i];        if (num < 0) {            tmp = (255 + num + 1).toString(16);        } else {            tmp = num.toString(16);        }        if (tmp.length === 1) {            tmp = "0" + tmp;        }        str += tmp;    }    return str;}// utilfunction divideBy7Bytes (str) {    var frameArray = [];    for (var i = 0; i < str.length - 4; i += 14) {        var data = str.substring(i, i + 14);        frameArray.push(data);    }    return frameArray;}// utilfunction littleEndianTransform (data) {    var dataArray = [];    for (var i = 0; i < data.length; i += 2) {        dataArray.push(data.substring(i, i + 2));    }    dataArray.reverse();    return dataArray;}// utilfunction strTo10SysNub (str) {    var arr = littleEndianTransform(str);    return parseInt(arr.toString()        .replace(/,/g, ""), 16);}// utilfunction checkDataIdIsMeasureUpload (dataId) {    return parseInt(dataId) > 4096;}// configurable.function isSpecialDataId (dataID) {    switch (dataID) {        case 0:        case 1:        case 2:        case 3:        case 4:        case 7:        case 0x120:            return true;        default:            return false;    }}// configurablefunction ttnDataSpecialFormat (dataId, str) {    var strReverse = littleEndianTransform(str);    if (dataId === 2 || dataId === 3) {        return strReverse.join("");    }    // handle unsigned number    var str2 = toBinary(strReverse);    var dataArray = [];    switch (dataId) {        case 0: // DATA_BOARD_VERSION        case 1: // DATA_SENSOR_VERSION            // Using point segmentation            for (var k = 0; k < str2.length; k += 16) {                var tmp146 = str2.substring(k, k + 16);                tmp146 = (parseInt(tmp146.substring(0, 8), 2) || 0) + "." + (parseInt(tmp146.substring(8, 16), 2) || 0);                dataArray.push(tmp146);            }            return dataArray.join(",");        case 4:            for (var i = 0; i < str2.length; i += 8) {                var item = parseInt(str2.substring(i, i + 8), 2);                if (item < 10) {                    item = "0" + item.toString();                } else {                    item = item.toString();                }                dataArray.push(item);            }            return dataArray.join("");        case 7:            // battery && interval            return {                interval: parseInt(str2.substr(0, 16), 2),                power: parseInt(str2.substr(-16, 16), 2)            };    }}// utilfunction ttnDataFormat (str) {    var strReverse = littleEndianTransform(str);    var str2 = toBinary(strReverse);    if (str2.substring(0, 1) === "1") {        var arr = str2.split("");        var reverseArr = [];        for (var forArr = 0; forArr < arr.length; forArr++) {            var item = arr[forArr];            if (parseInt(item) === 1) {                reverseArr.push(0);            } else {                reverseArr.push(1);            }        }        str2 = parseInt(reverseArr.join(""), 2) + 1;        return parseFloat("-" + str2 / 1000);    }    return parseInt(str2, 2) / 1000;}// utilfunction sensorAttrForVersion (dataValue) {    var dataValueSplitArray = dataValue.split(",");    return {        ver_hardware: dataValueSplitArray[0],        ver_software: dataValueSplitArray[1]    };}// utilfunction toBinary (arr) {    var binaryData = [];    for (var forArr = 0; forArr < arr.length; forArr++) {        var item = arr[forArr];        var data = parseInt(item, 16)            .toString(2);        var dataLength = data.length;        if (data.length !== 8) {            for (var i = 0; i < 8 - dataLength; i++) {                data = "0" + data;            }        }        binaryData.push(data);    }    return binaryData.toString()        .replace(/,/g, "");}

5. Conectar la Integración a Ubidots

  • Ve a la sección "Flujos"

  • Busca tu dispositivo en la sección "Dispositivos" en el menú desplegable y arrástralo al área en blanco

  • En el mismo menú desplegable, cambia la pestaña a "Función" y busca la función creada en el paso anterior, mantén presionado y arrástrala al área en blanco

  • Haz lo mismo que arriba, en su lugar, esta vez busca la integración creada en el paso 3. Mantén presionado y arrástrala al área en blanco.

  • Conecta los puntos como muestra el siguiente GIF

6. Configurar el decodificador de Ubidots

  • Ve a tu cuenta de Ubidots

  • Ve a "Dispositivos" --> "Plugins"

  • Busca un plugin recién creado. Su nombre probablemente sea "Integración de Helium"

  • Haz clic en el ícono de lápiz

  • Dirígete a la sección "Decodificador" en el lado izquierdo de la pantalla

  • Desplázate hacia abajo hasta la sección "Función de Decodificación" y elimina todo el código presente en el cuadro de texto

  • Pega el siguiente código

  • Haz clic en el botón "GUARDAR & HACER VISIBLE" para guardar los cambios

Código de la función de decodificación:

 def format_payload(args):    payload = args["decoded"]["payload"]    ubidots_payload = {data["field"]:data["value"] for data in args["decoded"]["payload"]}    print(args)    return(ubidots_payload)

7. Visualizar los Datos en Ubidots

  • Dirígete a la sección “Dispositivos” en tu cuenta de Ubidots y podrás ver un dispositivo recién creado con el mismo nombre que usaste para “Nombre del dispositivo” en el paso 2. Aquí puedes ver un ejemplo.

8. Comentarios, Sugerencias y Artículos Relacionados

No dudes en publicar preguntas o sugerencias en nuestro portal de la comunidad, o contáctanos a través de support@ubidots.com.


Otros usuarios también encontraron útil...

¿Ha quedado contestada tu pregunta?