Skip to main content

Conectar a The Things Network

The Things Network (TTN) es una plataforma IoT global de código abierto construida sobre LoRaWAN®, que ofrece conectividad inalámbrica de bajo consumo y largo alcance. Es compatible con The Things Stack (TTS), un servidor de red LoRaWAN® que proporciona gestión segura de dispositivos y enrutamiento de datos. En este capítulo, guiaremos a los usuarios para conectar el SenseCAP T2000 Tracker a The Things Network.

Configuración del Dispositivo

Antes de conectar a TTS, necesitas configurar los parámetros básicos de tu dispositivo en la APP SenseCraft, consulta Inicio Rápido para más detalles.

Establece la plataforma en The Things Network, y luego copia el Device EUI / AppEUI / AppKey. Después añade dispositivos manualmente en The Things Stack.

pir

The Things Network

The Things Stack(TTS) es un servidor de red LoRaWAN de grado empresarial, construido sobre un núcleo de código abierto. The Things Stack te permite construir y gestionar redes LoRaWAN en tu propio hardware o en la nube.

Para comenzar, registra una cuenta en The Things Network.

pir

Paso 1: Crear una Aplicación

Navega a la página Applications, haz clic en Add application.

pir

Introduce un Application ID, Application name, haz clic en Create application para guardar los cambios.

pir

Paso 2: Registrar el Dispositivo

Después de crear la aplicación, haz clic en Register end device.

pir

Hay dos formas para que los usuarios registren un dispositivo final:

  • Seleccionar el dispositivo final en el Repositorio de Dispositivos LoRaWAN
  • Introducir las especificaciones del dispositivo final manualmente

1. Seleccionar el dispositivo final en el Repositorio de Dispositivos LoRaWAN

Elige Select the end device in the LoRaWAN Device Repository.
Selecciona SenseCAP y selecciona el Modelo T2000 Tracker A/B/C.
Mantén la versión de Software y Hardware como predeterminada, y selecciona el Profile(Region) correspondiente según la configuración de banda del dispositivo.

pir

Elige un Plan de Frecuencia apropiado. Tu dispositivo y gateway deben usar el mismo plan de frecuencia para comunicarse.
Pega el Device EUI / AppEUI / AppKey de la App SenseCraft, y luego haz clic en Register end device.

note

El "JoinEUI" anterior es similar a "AppEUI".

pir

pir

2. Introducir las especificaciones del dispositivo final manualmente

Alternativamente, puedes elegir Enter end device specifics manually. Y por favor consulta la información a continuación para asegurar que introduces la siguiente información correctamente.

pir

Elige un Plan de Frecuencia apropiado. Tu dispositivo y gateway deben usar el mismo plan de frecuencia para comunicarse.

info

Selecciona los campos de Versión LoRaWAN y versión de Parámetros Regionales para tu dispositivo específico.
Versión LoRaWAN: LoRaWAN Specification 1.0.4
Versión de Parámetros Regionales: RP002 Regional Parameters 1.0.3

Pega el Device EUI / AppEUI / AppKey de la App SenseCraft, y luego haz clic en Register end device.

pir

Luego sube el Formateador de Carga Útil.

Navega a la página Payload Formatters, elige Custom Javascript Formatter. Completa el código del Formateador con el decodificador a continuación y guarda los cambios:

Para TTN(ChirpStack V4)
function decodeUplink (input) {
const bytes = input['bytes']
const bytesString = bytes2HexString(bytes)
const originMessage = bytesString.toLocaleUpperCase()
const decoded = {
valid: true,
err: 0,
payload: bytesString,
messages: []
}
let measurement = messageAnalyzed(originMessage)
if (measurement.length === 0) {
decoded.valid = false
return { data: decoded }
}

for (let message of measurement) {
if (message.length === 0) {
continue
}
let elements = []
for (let element of message) {
if (element.errorCode) {
decoded.err = element.errorCode
decoded.errMessage = element.error
} else {
elements.push(element)
}
}
if (elements.length > 0) {
decoded.messages.push(elements)
}
}
return { data: decoded }
}

function messageAnalyzed (messageValue) {
try {
let frames = unpack(messageValue)
let measurementResultArray = []
for (let i = 0; i < frames.length; i++) {
let item = frames[i]
let dataId = item.dataId
let dataValue = item.dataValue
let measurementArray = deserialize(dataId, dataValue)
measurementResultArray.push(measurementArray)
}
return measurementResultArray
} catch (e) {
return e.toString()
}
}

function unpack (messageValue) {
let frameArray = []
const FIXED_LENGTH_PACKAGES = {
'27': 92, '28': 60, '29': 24, '2A': 12, '2B': 46, '2E': 34, '31': 30, '32': 18
}
const DYNAMIC_LENGTH_PACKAGES = {
'2C': {minLen: 32, scanCountPos: [30, 32], baseLen: 23, itemLen: 7},
'2D': {minLen: 32, scanCountPos: [30, 32], baseLen: 23, itemLen: 7},
'2F': {minLen: 20, scanCountPos: [18, 20], baseLen: 17, itemLen: 7},
'30': {minLen: 20, scanCountPos: [18, 20], baseLen: 17, itemLen: 7}
}

for (let i = 0; i < messageValue.length; i++) {
let remainMessage = messageValue
let dataId = remainMessage.substring(0, 2).toUpperCase()
let dataValue
let dataObj = {}

if (dataId === '0C') {
dataValue = ''
messageValue = remainMessage.substring(2)
dataObj = {'dataId': dataId, 'dataValue': ''}
} else if (dataId === '0D') {
dataValue = remainMessage.substring(2, 10)
messageValue = remainMessage.substring(10)
dataObj = {'dataId': dataId, 'dataValue': dataValue}
} else if (FIXED_LENGTH_PACKAGES[dataId]) {
let packageLen = FIXED_LENGTH_PACKAGES[dataId]
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {'dataId': dataId, 'dataValue': dataValue}
} else if (DYNAMIC_LENGTH_PACKAGES[dataId]) {
let config = DYNAMIC_LENGTH_PACKAGES[dataId]
if (remainMessage.length < config.minLen) {
return frameArray
}
let scanCount = parseInt(remainMessage.substring(config.scanCountPos[0], config.scanCountPos[1]), 16)
let packageLen = (config.baseLen + (scanCount - 1) * config.itemLen) * 2
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {'dataId': dataId, 'dataValue': dataValue}
} else {
return frameArray
}

if (dataValue.length < 2 && dataObj.dataId !== '0C') {
break
}
frameArray.push(dataObj)
}
return frameArray
}

function deserialize (dataId, dataValue) {
let measurementArray = []
let eventList = []
let timestamp = 0
let value = null
let motionId = 0
let scanMax = 0
let interval = 0
let workMode = 0
let heartbeatInterval = 0
let periodicInterval = 0
let eventInterval = 0
switch (dataId) {
case '0C':
measurementArray.push({type: "timeSync"})
break
case '0D':
let errorCode = getInt(dataValue)
let error = ''
switch (errorCode) {
case 1:
error = 'FAILED TO OBTAIN THE UTC TIMESTAMP'
break
case 2:
error = 'ALMANAC TOO OLD'
break
case 3:
error = 'DOPPLER ERROR'
break
}
measurementArray.push({errorCode, error})
break
case '27':
measurementArray.push(...getUpT2000(dataValue))
break
case '28':
interval = 0
workMode = getInt(dataValue.substring(0, 2))
heartbeatInterval = getMinsByMin(dataValue.substring(4, 8))
periodicInterval = getMinsByMin(dataValue.substring(8, 12))
eventInterval = getMinsByMin(dataValue.substring(12, 16))
switch (workMode) {
case 0:
interval = heartbeatInterval
break
case 1:
interval = periodicInterval
break
case 2:
interval = eventInterval
break
}
measurementArray = [
{
measurementId: '3940', measurementValue: workMode
}, {
measurementId: '3965', measurementValue: getPositioningStrategy(dataValue.substring(2, 4))
}, {
measurementId: '3942', measurementValue: heartbeatInterval
}, {
measurementId: '3943', measurementValue: periodicInterval
}, {
measurementId: '3944', measurementValue: eventInterval
}, {
measurementId: '3974', measurementValue: getInt(dataValue.substring(16, 18))
}, {
measurementId: '3976', measurementValue: getInt(dataValue.substring(18, 20))
}, {
measurementId: '3977', measurementValue: getInt(dataValue.substring(20, 22))
}, {
measurementId: '3900', measurementValue: interval
}, {
measurementId: '3978', measurementValue: getInt(dataValue.substring(22, 24))
}, {
measurementId: '3979', measurementValue: dataValue.substring(26, 26 + getInt(dataValue.substring(24, 26)) * 2)
}
]
// measurementArray.push(measurement)
break
case '29':
measurementArray.push({
measurementId: '3946', measurementValue: getInt(dataValue.substring(0, 2))
})
measurementArray.push({
measurementId: '3947', measurementValue: getSensorValue(dataValue.substring(2, 6), 1)
})
measurementArray.push({
measurementId: '3948', measurementValue: getMinsByMin(dataValue.substring(6, 10))
})
measurementArray.push({
measurementId: '3949', measurementValue: getInt(dataValue.substring(10, 12))
})
measurementArray.push({
measurementId: '3950', measurementValue: getMinsByMin(dataValue.substring(12, 16))
})
measurementArray.push({
measurementId: '3951', measurementValue: getInt(dataValue.substring(16, 18))
})
measurementArray.push({
measurementId: '3952', measurementValue: getInt(dataValue.substring(18, 22))
})
break
case '2A':
measurementArray.push({
measurementId: '3000', measurementValue: getBattery(dataValue.substring(0, 2))
})
measurementArray.push({
measurementId: '3940', measurementValue: getWorkingMode(dataValue.substring(2, 4))
})
measurementArray.push({
measurementId: '3965', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))
})
measurementArray.push({
measurementId: '3974', measurementValue: getInt(dataValue.substring(6, 8))
})
measurementArray.push({
measurementId: '3976', measurementValue: getInt(dataValue.substring(8, 10))
})
break
case '2B':
eventList = getEventStatus(dataValue.substring(0, 4))
motionId = getMotionId(dataValue.substring(4, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
parseAccelerometerData(dataValue, 14, timestamp, motionId, measurementArray)
parseLocationData(dataValue, 26, timestamp, motionId, measurementArray)
parseBatteryData(dataValue, 42, timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
case '2C':
case '2D':
eventList = getEventStatus(dataValue.substring(0, 4))
motionId = getMotionId(dataValue.substring(4, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
parseAccelerometerData(dataValue, 14, timestamp, motionId, measurementArray)
parseBatteryData(dataValue, 26, timestamp, motionId, measurementArray)
scanMax = getInt(dataValue.substring(28, 30))
parseScanData(scanMax, dataValue, 30, dataId === '2C' ? '5001' : '5002', timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
case '2E':
eventList = getEventStatus(dataValue.substring(0, 4))
motionId = getMotionId(dataValue.substring(4, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
parseLocationData(dataValue, 14, timestamp, motionId, measurementArray)
parseBatteryData(dataValue, 30, timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
case '2F':
case '30':
eventList = getEventStatus(dataValue.substring(0, 4))
motionId = getMotionId(dataValue.substring(4, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
parseBatteryData(dataValue, 14, timestamp, motionId, measurementArray)
scanMax = getInt(dataValue.substring(16, 18))
parseScanData(scanMax, dataValue, 18, dataId === '2F' ? '5001' : '5002', timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
case '31':
eventList = getEventStatus(dataValue.substring(2, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
measurementArray.push({
measurementId: '3576',
timestamp,
motionId,
measurementValue: getPositingStatus(dataValue.substring(0, 2))
})
parseAccelerometerData(dataValue, 14, timestamp, motionId, measurementArray)
parseBatteryData(dataValue, 26, timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
case '32':
eventList = getEventStatus(dataValue.substring(2, 6))
timestamp = getUTCTimestamp(dataValue.substring(6, 14))
measurementArray.push({
measurementId: '3576',
timestamp,
motionId,
measurementValue: getPositingStatus(dataValue.substring(0, 2))
})
parseBatteryData(dataValue, 14, timestamp, motionId, measurementArray)
parseEventData(eventList, timestamp, motionId, measurementArray)
break
}
if (measurementArray.length > 0) {
for (let frag of measurementArray) {
if (frag.measurementId) {
frag.type = getTypeByMeasurementId(frag.measurementId)
}
}
}
return measurementArray
}

function parseAccelerometerData (dataValue, startPos, timestamp, motionId, measurementArray) {
const accelerometerIds = ['4210', '4211', '4212']
for (let i = 0; i < 3; i++) {
let value = getSignSensorValue(dataValue.substring(startPos + i * 4, startPos + (i + 1) * 4), 1)
if (value !== null) {
measurementArray.push({
measurementId: accelerometerIds[i],
timestamp,
motionId,
measurementValue: value
})
}
}
}

function parseBatteryData (dataValue, pos, timestamp, motionId, measurementArray) {
measurementArray.push({
measurementId: '3000',
timestamp,
motionId,
measurementValue: '' + getBattery(dataValue.substring(pos, pos + 2))
})
}

function parseEventData (eventList, timestamp, motionId, measurementArray) {
if (eventList && eventList.length > 0) {
measurementArray.push({
measurementId: '4200',
timestamp,
motionId,
measurementValue: eventList
})
}
}

function parseLocationData (dataValue, startPos, timestamp, motionId, measurementArray) {
measurementArray.push({
measurementId: '4197',
timestamp,
motionId,
measurementValue: '' + getSensorValue(dataValue.substring(startPos, startPos + 8), 1000000)
})
measurementArray.push({
measurementId: '4198',
timestamp,
motionId,
measurementValue: '' + getSensorValue(dataValue.substring(startPos + 8, startPos + 16), 1000000)
})
}

function parseScanData (scanMax, dataValue, startPos, measurementId, timestamp, motionId, measurementArray) {
if (scanMax && scanMax > 0) {
measurementArray.push({
measurementId,
timestamp,
motionId,
measurementValue: getMacAndRssiObj(dataValue.substring(startPos))
})
}
}

function getTypeByMeasurementId (measurementId) {
const TYPE_MAP = {
'3000': 'Battery',
'3502': 'Firmware Version',
'3001': 'Hardware Version',
'3940': 'Work Mode',
'3965': 'Positioning Strategy',
'3942': 'Heartbeat Interval',
'3943': 'Periodic Interval',
'3944': 'Event Interval',
'3974': '3X Sensor Enable',
'3976': 'Anti-Theft',
'3977': 'GNSS Scan Timeout',
'3900': 'Uplink Interval',
'3978': 'BLE Scan Timeout',
'3979': 'UUID Filter',
'3946': 'Motion Enable',
'3947': 'Any Motion Threshold',
'3948': 'Motion Start Interval',
'3949': 'Static Enable',
'3950': 'Device Static Timeout',
'3951': 'Shock Enable',
'3952': 'Shock Threshold',
'4210': 'AccelerometerX',
'4211': 'AccelerometerY',
'4212': 'AccelerometerZ',
'4197': 'Longitude',
'4198': 'Latitude',
'4200': 'Event Status',
'5001': 'Wi-Fi Scan',
'5002': 'BLE Scan',
'3576': 'Positioning Status'
}
return TYPE_MAP[measurementId] || ''
}

function getMotionId (str) {
return getInt(str)
}

function getPositingStatus (str) {
let status = getInt(str)
const STATUS_MAP = {
0: "locate successful.",
1: "The GNSS scan timed out.",
2: "The Wi-Fi scan timed out.",
3: "The Wi-Fi + GNSS scan timed out.",
4: "The GNSS + Wi-Fi scan timed out.",
5: "The Bluetooth scan timed out.",
6: "The Bluetooth + Wi-Fi scan timed out.",
7: "The Bluetooth + GNSS scan timed out.",
8: "The Bluetooth + Wi-Fi + GNSS scan timed out.",
9: "Location Server failed to parse the GNSS location.",
10: "Location Server failed to parse the Wi-Fi location.",
11: "Location Server failed to parse the Bluetooth location.",
12: "Failed to parse location due to the poor accuracy.",
13: "Time synchronization failed.",
14: "Failed due to the old Almanac.",
15: "The GNSS +Bluetooth scan timed out."
}
if (STATUS_MAP[status] !== undefined) {
return {id: status, statusName: STATUS_MAP[status]}
}
return getInt(str)
}

function getUpT2000 (messageValue) {
let interval = 0
let workMode = getInt(messageValue.substring(10, 12))
let heartbeatInterval = getMinsByMin(messageValue.substring(14, 18))
let periodicInterval = getMinsByMin(messageValue.substring(18, 22))
let eventInterval = getMinsByMin(messageValue.substring(22, 26))
switch (workMode) {
case 0:
interval = heartbeatInterval
break
case 1:
interval = periodicInterval
break
case 2:
interval = eventInterval
break
}
let data = [
{
measurementId: '3000', measurementValue: getBattery(messageValue.substring(0, 2))
}, {
measurementId: '3502', measurementValue: getSoftVersion(messageValue.substring(2, 6))
}, {
measurementId: '3001', measurementValue: getHardVersion(messageValue.substring(6, 10))
}, {
measurementId: '3940', measurementValue: workMode
}, {
measurementId: '3965', measurementValue: getPositioningStrategy(messageValue.substring(12, 14))
}, {
measurementId: '3942', measurementValue: heartbeatInterval
}, {
measurementId: '3943', measurementValue: periodicInterval
}, {
measurementId: '3944', measurementValue: eventInterval
}, {
measurementId: '3974', measurementValue: getInt(messageValue.substring(26, 28))
}, {
measurementId: '3976', measurementValue: getInt(messageValue.substring(28, 30))
}, {
measurementId: '3977', measurementValue: getInt(messageValue.substring(30, 32))
}, {
measurementId: '3900', measurementValue: interval
}, {
measurementId: '3978', measurementValue: getInt(messageValue.substring(54, 56))
}, {
measurementId: '3979', measurementValue: messageValue.substring(58, 58 + getInt(messageValue.substring(56, 58)) * 2)
}
]
let motionSetting = getMotionSetting(messageValue.substring(32, 42))
let staticsSetting = getStaticSetting(messageValue.substring(42, 48))
let shockSetting = getShockSetting(messageValue.substring(48, 54))
data = [...data, ...motionSetting, ...staticsSetting, ...shockSetting]
return data
}

function getMotionSetting (str) {
return [
{measurementId: '3946', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3947', measurementValue: getSensorValue(str.substring(2, 6), 1)},
{measurementId: '3948', measurementValue: getMinsByMin(str.substring(6, 10))},
]
}

function getStaticSetting (str) {
return [
{measurementId: '3949', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3950', measurementValue: getMinsByMin(str.substring(2, 6))}
]
}

function getShockSetting (str) {
return [
{measurementId: '3951', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3952', measurementValue: getInt(str.substring(2, 6))}
]
}

function getBattery (batteryStr) {
return loraWANV2DataFormat(batteryStr)
}
function getSoftVersion (softVersion) {
return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}`
}
function getHardVersion (hardVersion) {
return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}`
}

function getMinsByMin (str) {
return getInt(str)
}

function getSensorValue (str, dig) {
if (str === '8000') {
return null
} else {
return loraWANV2DataFormat(str, dig)
}
}

function isNull (str) {
if (str.substring(0, 1) !== '8') {
return false
}
for (let i = 1; i < str.length; i++) {
if (str.substring(i, i + 1) !== '0') {
return false
}
}
return true
}

function getSignSensorValue (str, dig = 1) {
if (isNull(str)) {
return null
}
return loraWANV2DataFormat(str, dig)
}

function 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
}
function loraWANV2DataFormat (str, divisor = 1) {
let strReverse = bigEndianTransform(str)
let str2 = toBinary(strReverse)
if (str2.substring(0, 1) === '1') {
let arr = str2.split('')
let reverseArr = arr.map((item) => {
if (parseInt(item) === 1) {
return 0
} else {
return 1
}
})
str2 = parseInt(reverseArr.join(''), 2) + 1
return parseFloat('-' + str2 / divisor)
}
return parseInt(str2, 2) / divisor
}

function bigEndianTransform (data) {
let dataArray = []
for (let i = 0; i < data.length; i += 2) {
dataArray.push(data.substring(i, i + 2))
}
return dataArray
}

function toBinary (arr) {
let binaryData = arr.map((item) => {
let data = parseInt(item, 16)
.toString(2)
let dataLength = data.length
if (data.length !== 8) {
for (let i = 0; i < 8 - dataLength; i++) {
data = `0` + data
}
}
return data
})
return binaryData.toString().replace(/,/g, '')
}

function getMacAndRssiObj (pair) {
let pairs = []
if (pair.length % 14 === 0) {
for (let i = 0; i < pair.length; i += 14) {
let mac = getMacAddress(pair.substring(i, i + 12))
if (mac) {
let rssi = getInt8RSSI(pair.substring(i + 12, i + 14))
pairs.push({mac: mac, rssi: rssi})
} else {
continue
}
}
}
return pairs
}

function getMacAddress (str) {
if (str.toLowerCase() === 'ffffffffffff') {
return null
}
let macArr = []
for (let i = 1; i < str.length; i++) {
if (i % 2 === 1) {
macArr.push(str.substring(i - 1, i + 1))
}
}
let mac = ''
for (let i = 0; i < macArr.length; i++) {
mac = mac + macArr[i]
if (i < macArr.length - 1) {
mac = mac + ':'
}
}
return mac
}

function getInt8RSSI (str) {
return loraWANV2DataFormat(str)
}

function getInt (str) {
return parseInt(str, 16)
}

function getEventStatus (str) {
let bitStr = getByteArray(str)
let bitArr = []
for (let i = 0; i < bitStr.length; i++) {
bitArr[i] = bitStr.substring(i, i + 1)
}
bitArr = bitArr.reverse()
const EVENT_MAP = {
0: {id: 1, eventName: "Start moving event."},
1: {id: 2, eventName: "End movement event."},
2: {id: 3, eventName: "Motionless event."},
3: {id: 4, eventName: "Shock event."},
4: {id: 5, eventName: "Temperature event."},
5: {id: 6, eventName: "Light event."},
6: {id: 7, eventName: "SOS event."},
7: {id: 8, eventName: "Press once event."},
8: {id: 9, eventName: "disassembled event"}
}
let event = []
for (let i = 0; i < bitArr.length; i++) {
if (bitArr[i] === '1' && EVENT_MAP[i]) {
event.push(EVENT_MAP[i])
}
}
return event
}

function getByteArray (str) {
let bytes = []
for (let i = 0; i < str.length; i += 2) {
bytes.push(str.substring(i, i + 2))
}
return toBinary(bytes)
}

function getWorkingMode (workingMode) {
return getInt(workingMode)
}

function getPositioningStrategy (strategy) {
return getInt(strategy)
}

function getUTCTimestamp(str){
return parseInt(loraWANV2PositiveDataFormat(str)) * 1000
}

function loraWANV2PositiveDataFormat (str, divisor = 1) {
let strReverse = bigEndianTransform(str)
let str2 = toBinary(strReverse)
return parseInt(str2, 2) / divisor
}

pir

Paso 3: Verificar los Datos

Cuando el dispositivo intenta conectarse a la red, la luz verde parpadeará de forma intermitente. Si el dispositivo se une a la red exitosamente, la luz verde parpadeará 5 veces rápidamente.

Puedes verificar la actividad del dispositivo en la página de resumen de la aplicación.

pir

Haz clic en el dispositivo final, luego verifica los Live data. Cuando veas el mensaje a continuación, tu dispositivo se ha unido exitosamente a la red.

pir

pir

Luego puedes verificar los datos en la consola TTS.

pir

Recursos

Decodificador SenseCAP T2000 Tracker para TTN

Soporte Técnico y Discusión de Productos

¡Gracias por elegir nuestros productos! Estamos aquí para brindarte diferentes tipos de soporte para asegurar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para satisfacer diferentes preferencias y necesidades.

Loading Comments...