1. LoRaWAN - mensajes MQTT
Los datos son enviados como un tren de bits escritos en hexadecimal desde el dispositivo.
Por ejemplo, un mensaje a transmitir conformado por 4 datos numéricos en hexadecimal desde el dispositivo son:
static void prepareTxFrame( uint8_t port ){
appDataSize = 4;//AppDataSize max value is 64
appData[0] = 0x00;
appData[1] = 0x01;
appData[2] = 0x02;
appData[3] = 0x03;
}
Se leen en un mensaje mqtt como:
application/1/device/3532363324003700/event/up {
"applicationID":"1",
"applicationName":"GirniAppPrueba01",
"deviceName":"GirniDispositivo01",
"devEUI":"3532363324003700",
"txInfo":{"frequency":902700000,"dr":0},
"adr":true,
"fCnt":0,
"fPort":2,
"data":"AAECAw=="
}
por lo que el mensaje recibido por el gateway es:
"data":"AAECAw=="
que para leerlo nuevamente en hexadecimal requiere ser traducido desde "base64" por ejemplo en la consola de Rasberry OS como:
pi@GWHTM01:~ $ echo -n AAECAw== | base64 --decode | hexdump -C
00000000 00 01 02 03 |....|
00000004
que es el mensaje original enviado desde el dispositivo
2. Mensajes MQTT con Python
De disponer de acceso al servidor MQTT se pueden capturar los mensajes y procesarlos por ejemplo para realizar estadísticas de RSSI y SNR de cada dispositivo respecto al Gateway.
Se requiere una conexión autenticada al servidor MQTT, para caso experimental se recurre a Python con la librería PAHO para acceder como cliente.
# grabando mensajes MQTT
# configurar los parámetros para la creacion de archivo de texto
import paho.mqtt.client as mqtt
# INGRESO
# Parametros para la conexión
servidormqtt = "192.168.xx.xx"
topicolee = "#"
# Para el archivo.txt
cuentamensaje = 0
nombrearchivo = 'unreporte.txt'
archivo = open(nombrearchivo,'w')
archivo.close() # Cierra el archivo
tramabuscada = ['application/1/device/c9c2a03913ac2ec5/event/up',
'application/1/device/b35915f22af620d1/event/up',
'application/1/device/b5a2349b828d97ea/event/up',
'application/1/device/f2f724028c0e996c/event/up']
cuentaDisp = [0,0,0,0]
cuentagtw = 0
# BLOQUE BÁSICO DE PROGRAMA
# Al recibir CONNACK desde el servidor.
def on_connect(client, userdata, flags, rc):
print("Conexión/código de resultado: "+str(rc))
# Inicio o renovación de subscripción
client.subscribe(topicolee)
return()
# el tópico tiene una publicación
def on_message(client, userdata, msg):
global cuentamensaje
print(msg.topic) #+" "+str(msg.payload))
unmensaje = msg.topic+" "+str(msg.payload)
# Archivo en modo añadir 'append'
archivo = open(nombrearchivo,'a')
unalinea = unmensaje + '\n'
archivo.write(unalinea)
if (msg.topic in tramabuscada):
cual = tramabuscada.index(msg.topic)
cuentaDisp[cual] = cuentaDisp[cual] + 1
cuentamensaje = cuentamensaje + 1
print('\n mensajes recibidos: ', cuentamensaje)
print(' cuenta por dispositivos: ', cuentaDisp)
print()
return()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(servidormqtt, 1883, 60)
client.loop_forever()
3. Mensajes MQTT y reporte txt con Python
Para procesar el archivo del reporte.txt se puede leer mensaje por mensaje y extraer el registro de RSSI y SNR de cada dispositivo usando Python.
# procesar un archivo de mensajes mqtt
import numpy as np
import json as json
# INGRESO
# Parametros para la conexión
servidormqtt = "192.168.xx.xx"
topicolee = "#"
# Para el archivo.txt
nombrearchivo = 'unreporte.txt'
conteo = {"lineas":{'cuenta':0},
"gateway":{'cuenta':0},
"application":{'cuenta':0}
}
tipotrama = []
# para tabular
tabla = []
registros = {}
frecuencias = []
tramabuscada = ['application/1/device/c9c2a03913ac2ec5/event/up',
'application/1/device/b35915f22af620d1/event/up',
'application/1/device/b5a2349b828d97ea/event/up',
'application/1/device/f2f724028c0e996c/event/up']
# PROCEDIMIENTO
archivo = open(nombrearchivo,'r')
unalinea = archivo.readline()
while not(unalinea==''):
conteo["lineas"]['cuenta'] = conteo["lineas"]['cuenta'] + 1
unalinea = archivo.readline()
unalinea = unalinea.strip('\n')
desde = unalinea.find(" b'{")
untipotrama = unalinea[0:desde]
if not(untipotrama in tipotrama) and (untipotrama != ''):
tipotrama.append(untipotrama)
conteo[untipotrama] = {'cuenta':0}
for entrada in conteo:
if unalinea.startswith(entrada):
conteo[entrada]['cuenta'] = conteo[entrada]['cuenta']+1
for unapptrama in tramabuscada:
tamanot = len(unapptrama)
if unalinea.startswith(unapptrama):
datostxt = unalinea[tamanot+3:].strip("'")
datosjson = json.loads(datostxt)
undeviceName = datosjson["deviceName"]
unrssi = datosjson["rxInfo"][0]["rssi"]
unloRaSNR = datosjson["rxInfo"][0]["loRaSNR"]
unfrequency = datosjson["txInfo"]["frequency"]
undr = datosjson["txInfo"]["dr"]
if not(unfrequency in frecuencias):
frecuencias.append(unfrequency)
if undeviceName in registros:
registros[undeviceName]['conteo'] = registros[undeviceName]['conteo']+1
registros[undeviceName]['rssi'].append([unfrequency,unrssi,
unloRaSNR,undr])
else:
registros[undeviceName]={'rssi':[],
'conteo':0,
'resumen':[0,0,0,0],
}
archivo.close() # Cierra el archivo
# Calcula resumen por dispositivo
frecuencias.sort()
frecuencia = [902300000, 902500000, 902700000, 902900000,
903100000, 903300000, 903500000, 903700000]
canalobserva = len(frecuencia)
for dispositivo in registros:
vector = np.array(registros[dispositivo]['rssi'])
cuenta = np.zeros(canalobserva, dtype=int)
suma = np.zeros(canalobserva,dtype=int)
channelid = np.arange(1, canalobserva+1)
cadaRSSI = [[],[],[],[],[],[],[],[],[]]
cadaSNR = [[],[],[],[],[],[],[],[],[]]
cadadr = [[],[],[],[],[],[],[],[],[]]
resumen = []
# Clasificando
k = len(vector)
for j in range (0,k,1):
cual = frecuencia.index(vector[j][0])
valorRssi = vector[j][1]
valorSNR = vector[j][2]
valordr = vector[j][3]
cadaRSSI[cual].append(valorRssi)
cadaSNR[cual].append(valorSNR)
cadadr[cual].append(valordr)
for j in range(0,canalobserva,1):
vectorRSSI = np.array(cadaRSSI[j])
vectorSNR = np.array(cadaSNR[j])
vectordr = np.array(cadadr[j])
if len(vectorRSSI)>0:
promedioRSSI = np.average(vectorRSSI)
maximoRSSI = np.max(vectorRSSI)
cantidadRSSI = len(vectorRSSI)
minimoRSSI = np.min(vectorRSSI)
promedioSNR = np.average(vectorSNR)
maximoSNR = np.max(vectorSNR)
cantidadSNR = len(vectorSNR)
minimoSNR = np.min(vectorSNR)
promediodr = np.average(vectordr)
maximodr = np.max(vectordr)
cantidaddr = len(vectordr)
minimodr = np.min(vectordr)
resumen.append(np.array([ j+1,
cantidadRSSI,
promedioRSSI,
minimoRSSI,
maximoRSSI,
promedioSNR,
minimoSNR,
maximoSNR,
promediodr,
]))
resumen = np.array(resumen)
registros[dispositivo]['resumen'] = resumen
# SALIDA
np.set_printoptions(precision = 2)
print('conteo de tramas')
for entrada in conteo:
print(entrada,": ", conteo[entrada]['cuenta'])
print('frecuencias: ',frecuencia)
print('\nTabulando ---------')
for dispositivo in registros:
print()
print('dispositivo_id: '+str(dispositivo))
print('total muestras: '+str(registros[dispositivo]['conteo']))
print('Promedios RSSI y SNR: ')
print('[canal muestras\t RSSI \t min \t max \t SNR min max DR ]')
print(registros[dispositivo]['resumen'])
registros[dispositivo]['conteo']