Conectando o SenseCAP T1000 ao Helium
Configuração do dispositivo
Antes de se conectar ao Helium, você precisa configurar os parâmetros básicos do seu dispositivo no aplicativo SenseCAP Mate. Consulte Get Started para mais detalhes.
- Defina a plataforma como
Heliume, em seguida, copie oDevice EUI/APP EUI/APP Key.
![]()
Configuração do console Helium
O console Helium não está mais aberto para novas contas. A descrição de como conectar um T1000 ao Helium Console permanece aqui para usuários que já possuem uma conta. Para novos usuários, consulte as etapas do ChirpStack LNA acima ou determine as etapas necessárias para o seu LNA específico com base nos dois exemplos existentes aqui.
Adicionar novo dispositivo
Faça login no seu console Helium, depois vá para a seção Devices e clique no botão Add device.
![]()
Preencha os campos obrigatórios, como o nome do dispositivo**,** as credenciais LoRaWAN, etc.
Em seguida, clique no botão Save Device.
![]()
Criar a função de decodificação
A próxima etapa é configurar a função que irá decodificar os bytes brutos em um formato legível para humanos.
Vá até a aba Function no painel do lado esquerdo. Em seguida, clique no botão Add New Function e dê um nome a ela:

Copie o código a seguir e depois salve as alterações.
Decoder for Helium
function Decoder (bytes, port) {
const bytesString = bytes2HexString(bytes)
const originMessage = bytesString.toLocaleUpperCase()
const fport = parseInt(port)
const decoded = {
valid: true,
err: 0,
payload: bytesString,
messages: []
}
if (fport === 199 || fport === 192) {
decoded.messages.push({fport: fport, payload: bytesString})
return { data: decoded }
}
if (fport !== 5) {
decoded.valid = false
return { data: decoded }
}
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)
}
}
// decoded.messages = measurement
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 = []
for (let i = 0; i < messageValue.length; i++) {
let remainMessage = messageValue
let dataId = remainMessage.substring(0, 2).toUpperCase()
let dataValue
let dataObj = {}
let packageLen
switch (dataId) {
case '01':
packageLen = 94
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '02':
packageLen = 32
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '03':
packageLen = 64
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '04':
packageLen = 20
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '05':
packageLen = 10
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '06':
packageLen = 44
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '07':
packageLen = 84
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '08':
packageLen = 70
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '09':
packageLen = 36
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '0A':
packageLen = 76
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '0B':
packageLen = 62
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '0C':
packageLen = 2
if (remainMessage.length < packageLen) {
return frameArray
}
break
case '0D':
packageLen = 10
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '0E':
packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '0F':
packageLen = 34
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '10':
packageLen = 26
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
case '11':
packageLen = 28
if (remainMessage.length < packageLen) {
return frameArray
}
dataValue = remainMessage.substring(2, packageLen)
messageValue = remainMessage.substring(packageLen)
dataObj = {
'dataId': dataId, 'dataValue': dataValue
}
break
default:
return frameArray
}
if (dataValue.length < 2) {
break
}
frameArray.push(dataObj)
}
return frameArray
}
function deserialize (dataId, dataValue) {
let measurementArray = []
let eventList = []
let measurement = {}
let collectTime = 0
let groupId = 0
let shardFlag = {}
let payload = ''
let result = []
let dataArr = []
switch (dataId) {
case '01':
measurementArray = getUpShortInfo(dataValue)
measurementArray.push(...getMotionSetting(dataValue.substring(30, 40)))
measurementArray.push(...getStaticSetting(dataValue.substring(40, 46)))
measurementArray.push(...getShockSetting(dataValue.substring(46, 52)))
measurementArray.push(...getTempSetting(dataValue.substring(52, 72)))
measurementArray.push(...getLightSetting(dataValue.substring(72, 92)))
break
case '02':
measurementArray = getUpShortInfo(dataValue)
break
case '03':
measurementArray.push(...getMotionSetting(dataValue.substring(0, 10)))
measurementArray.push(...getStaticSetting(dataValue.substring(10, 16)))
measurementArray.push(...getShockSetting(dataValue.substring(16, 22)))
measurementArray.push(...getTempSetting(dataValue.substring(22, 42)))
measurementArray.push(...getLightSetting(dataValue.substring(42, 62)))
break
case '04':
let interval = 0
let workMode = getInt(dataValue.substring(0, 2))
let heartbeatInterval = getMinsByMin(dataValue.substring(4, 8))
let periodicInterval = getMinsByMin(dataValue.substring(8, 12))
let 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', type: 'Work Mode', measurementValue: workMode},
{measurementId: '3942', type: 'Heartbeat Interval', measurementValue: heartbeatInterval},
{measurementId: '3943', type: 'Periodic Interval', measurementValue: periodicInterval},
{measurementId: '3944', type: 'Event Interval', measurementValue: eventInterval},
{measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))},
{measurementId: '3900', type: 'Uplink Interval', measurementValue: interval}
]
break;
case '05':
measurementArray = [
{measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))},
{measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))},
{measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))},
{measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))}
]
break
case '06':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))},
{measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))},
{measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)},
{measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))}
]
break
case '07':
eventList = getEventStatus(dataValue.substring(0, 6))
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))},
{measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)},
{measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))}
]
break
case '08':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))},
{measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)},
{measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))}
]
break
case '09':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))},
{measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))}
]
break
case '0A':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))}
]
break
case '0B':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray = [
{measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))},
{measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))},
{measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))},
]
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 '0E':
shardFlag = getShardFlag(dataValue.substring(0, 2))
groupId = getInt(dataValue.substring(2, 6))
payload = dataValue.substring(6)
measurement = {
measurementId: '6152',
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'gnss-ng payload',
measurementValue: payload
}
measurementArray.push(measurement)
break
case '0F':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
shardFlag = getShardFlag(dataValue.substring(26, 28))
groupId = getInt(dataValue.substring(28, 32))
measurementArray.push({
measurementId: '4200',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Event Status',
measurementValue: getEventStatus(dataValue.substring(0, 6))
})
measurementArray.push({
measurementId: '4097',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Air Temperature',
measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10)
})
measurementArray.push({
measurementId: '4199',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Light',
measurementValue: '' + getSensorValue(dataValue.substring(20, 24))
})
measurementArray.push({
measurementId: '3000',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Battery',
measurementValue: '' + getBattery(dataValue.substring(24, 26))
})
break
case '10':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
shardFlag = getShardFlag(dataValue.substring(18, 20))
groupId = getInt(dataValue.substring(20, 24))
measurementArray.push({
measurementId: '4200',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Event Status',
measurementValue: getEventStatus(dataValue.substring(0, 6))
})
measurementArray.push({
measurementId: '3000',
timestamp: collectTime,
motionId: getMotionId(dataValue.substring(6, 8)),
groupId: groupId,
index: shardFlag.index,
count: shardFlag.count,
type: 'Battery',
measurementValue: '' + getBattery(dataValue.substring(16, 18))
})
break
case '11':
collectTime = getUTCTimestamp(dataValue.substring(8, 16))
measurementArray.push({
measurementId: '3576',
timestamp: collectTime,
type: 'Positioning Status',
measurementValue: getPositingStatus(dataValue.substring(0, 2))
})
measurementArray.push({
timestamp: collectTime,
measurementId: '4200',
type: 'Event Status',
measurementValue: getEventStatus(dataValue.substring(2, 8))
})
if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) {
measurementArray.push({
timestamp: collectTime,
measurementId: '4097',
type: 'Air Temperature',
measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10)
})
}
if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) {
measurementArray.push({
timestamp: collectTime,
measurementId: '4199',
type: 'Light',
measurementValue: '' + getSensorValue(dataValue.substring(20, 24))
})
}
measurementArray.push({
timestamp: collectTime,
measurementId: '3000',
type: 'Battery',
measurementValue: '' + getBattery(dataValue.substring(24, 26))
})
break
}
return measurementArray
}
function getMotionId (str) {
return getInt(str)
}
function getPositingStatus (str) {
let status = getInt(str)
switch (status) {
case 0:
return {id:status, statusName:"Positioning successful."}
case 1:
return {id:status, statusName:"The GNSS scan timed out and failed to obtain the location."}
case 2:
return {id:status, statusName:"The Wi-Fi scan timed out and failed to obtain the location."}
case 3:
return {id:status, statusName:"The Wi-Fi + GNSS scan timed out and failed to obtain the location."}
case 4:
return {id:status, statusName:"The GNSS + Wi-Fi scan timed out and failed to obtain the location."}
case 5:
return {id:status, statusName:"The Bluetooth scan timed out and failed to obtain the location."}
case 6:
return {id:status, statusName:"The Bluetooth + Wi-Fi scan timed out and failed to obtain the location."}
case 7:
return {id:status, statusName:"The Bluetooth + GNSS scan timed out and failed to obtain the location."}
case 8:
return {id:status, statusName:"The Bluetooth + Wi-Fi + GNSS scan timed out and failed to obtain the location."}
case 9:
return {id:status, statusName:"Location Server failed to parse the GNSS location."}
case 10:
return {id:status, statusName:"Location Server failed to parse the Wi-Fi location."}
case 11:
return {id:status, statusName:"Location Server failed to parse the Bluetooth location."}
case 12:
return {id:status, statusName:"Failed to parse the GNSS location due to the poor accuracy."}
case 13:
return {id:status, statusName:"Time synchronization failed."}
case 14:
return {id:status, statusName:"Failed to obtain location due to the old Almanac."}
}
return getInt(str)
}
function getUpShortInfo (messageValue) {
return [
{
measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2))
}, {
measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6))
}, {
measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10))
}, {
measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12))
}, {
measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(messageValue.substring(12, 14))
}, {
measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getMinsByMin(messageValue.substring(14, 18))
}, {
measurementId: '3943', type: 'Periodic Interval', measurementValue: getMinsByMin(messageValue.substring(18, 22))
}, {
measurementId: '3944', type: 'Event Interval', measurementValue: getMinsByMin(messageValue.substring(22, 26))
}, {
measurementId: '3945', type: 'Sensor Enable', measurementValue: getInt(messageValue.substring(26, 28))
}, {
measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30))
}
]
}
function getMotionSetting (str) {
return [
{measurementId: '3946', type: 'Motion Enable', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3947', type: 'Any Motion Threshold', measurementValue: getSensorValue(str.substring(2, 6), 1)},
{measurementId: '3948', type: 'Motion Start Interval', measurementValue: getMinsByMin(str.substring(6, 10))},
]
}
function getStaticSetting (str) {
return [
{measurementId: '3949', type: 'Static Enable', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3950', type: 'Device Static Timeout', measurementValue: getMinsByMin(str.substring(2, 6))}
]
}
function getShockSetting (str) {
return [
{measurementId: '3951', type: 'Shock Enable', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3952', type: 'Shock Threshold', measurementValue: getInt(str.substring(2, 6))}
]
}
function getTempSetting (str) {
return [
{measurementId: '3953', type: 'Temp Enable', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3954', type: 'Event Temp Interval', measurementValue: getMinsByMin(str.substring(2, 6))},
{measurementId: '3955', type: 'Event Temp Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))},
{measurementId: '3956', type: 'Temp ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)},
{measurementId: '3957', type: 'Temp ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)},
{measurementId: '3958', type: 'Temp Warning Type', measurementValue: getInt(str.substring(18, 20))}
]
}
function getLightSetting (str) {
return [
{measurementId: '3959', type: 'Light Enable', measurementValue: getInt(str.substring(0, 2))},
{measurementId: '3960', type: 'Event Light Interval', measurementValue: getMinsByMin(str.substring(2, 6))},
{measurementId: '3961', type: 'Event Light Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))},
{measurementId: '3962', type: 'Light ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)},
{measurementId: '3963', type: 'Light ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)},
{measurementId: '3964', type: 'Light Warning Type', measurementValue: getInt(str.substring(18, 20))}
]
}
function getShardFlag (str) {
let bitStr = getByteArray(str)
return {
count: parseInt(bitStr.substring(0, 4), 2),
index: parseInt(bitStr.substring(4), 2)
}
}
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 getSecondsByInt (str) {
return getInt(str)
}
function getMinsByMin (str) {
return getInt(str)
}
function getSensorValue (str, dig) {
if (str === '8000') {
return null
} else {
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 '-' + 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 getSOSMode (str) {
return loraWANV2DataFormat(str)
}
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) {
// return getInt(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()
let event = []
for (let i = 0; i < bitArr.length; i++) {
if (bitArr[i] !== '1') {
continue
}
switch (i){
case 0:
event.push({id:1, eventName:"Start moving event."})
break
case 1:
event.push({id:2, eventName:"End movement event."})
break
case 2:
event.push({id:3, eventName:"Motionless event."})
break
case 3:
event.push({id:4, eventName:"Shock event."})
break
case 4:
event.push({id:5, eventName:"Temperature event."})
break
case 5:
event.push({id:6, eventName:"Light event."})
break
case 6:
event.push({id:7, eventName:"SOS event."})
break
case 7:
event.push({id:8, eventName:"Press once event."})
break
}
}
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
}
Verificar os dados
Quando o dispositivo tenta se conectar à rede, a luz de respiração piscará. Se o dispositivo entrar na rede com sucesso, a luz de respiração piscará rapidamente e haverá uma melodia leve e alegre.
Em seguida, você pode verificar os dados no console Helium.
Observação
Para usuários operando na região EU868/RU864:
Não é recomendado definir o intervalo de upload para menos de 4 minutos.
Se você definir um intervalo de upload menor que 4 minutos, poderá notar um desalinhamento de carimbo de data/hora entre o uplink do dispositivo e a hora atual.
Aqui está a justificativa:
Dada a restrição de ciclo de trabalho de 1% em EU868, o dispositivo deve aguardar pacientemente aproximadamente 4 minutos para cada transmissão de uplink. Além disso, a rede Helium inicia correções de taxa de dados e potência somente após acumular 20 pacotes de uplink consecutivos marcados com o bit ADR definido como 1.
Portanto, se o intervalo de upload que você definiu for menor que 4 minutos, os dados em tempo real serão temporariamente armazenados na RAM e mantidos até que a rede Helium acione correções de taxa de dados e potência antes do upload.
ChirpStack LNS
Para novos usuários, para receber os dados de um dispositivo na rede Helium ele deve ser associado a um LNS (LoraWAN Network Server), normalmente usando um dos LNSs públicos, muitos dos quais usam ChirpStack, mas também é possível conectar o próprio LNS à Helium.
Para aqueles familiarizados com o processo geral, o resumo é:
- crie um perfil de dispositivo com a região apropriada e o codec (veja o código-fonte abaixo)
- crie o dispositivo com
devEUI,appKeye uma variávelapp_euicom o AppEUI, todos os três valores vindos do AppSenseCraft
Adicionar perfil de dispositivo
O primeiro passo é adicionar um perfil de dispositivo para o T1000 Tracker ao seu ChirpStack LNS. Isso informa ao LNS como decodificar os pacotes que ele recebe de um T1000, bem como uma série de outras configurações.
No painel do ChirpStack selecione Device Profiles e clique em Add device profile.
Na guia geral, insira um nome de perfil de dispositivo que você reconhecerá e selecione os parâmetros de região apropriados.
Versão MAC LoRaWAN: 1.0.4
O intervalo de uplink esperado também pode ser definido, a principal coisa que ele controla é quando a interface do usuário do LNS mostra o dispositivo como ativo vs. inativo. Ele não tem efeito sobre a entrega dos pacotes através do LNS.
Na guia Codec selecione JavaScript functions e insira o codec:
Existem 2 versões do ChirpStack, selecione a apropriada:
Adicionar Aplicação e seu Dispositivo
O próximo passo é criar uma aplicação e adicionar dispositivos reais a ela.
Vá para a seção Applications e adicione uma nova aplicação.
Em seguida, adicione um dispositivo à aplicação e insira o devEUI conforme capturado anteriormente no App SenseCraft.
Na guia de variáveis adicione uma variável chamada app_eui com o AppEUI do app SenseCraft como valor:
Ao clicar em submit aparecerá uma página solicitando o AppKey, novamente conforme capturado anteriormente usando o app SenseCraft:
Ver a conexão do dispositivo
Na guia LoRaWAN frames você verá um indicador de carregamento e, em seguida, os pacotes aparecerão conforme forem recebidos/enviados.
Pressione o botão do seu T1000 Tracker para fazer com que ele faça uma medição e envie um join request para se conectar ao LNS.
Uma vez que isso aconteça, você deverá ver algo assim:
Depois que o processo de join tiver sido realizado, o T1000 envia dados. O LNS responde com algumas informações sobre as frequências da rede e coisas do tipo, mas depois disso só deverá haver uplinks com dados.