RAK2287: Scheduling a downlink using MQTT

Issue: Can’t schedule a downlink using MQTT on RAK2287

Setup: RAK2287 with software 4.2.3R

Server: Chirpstack

Details: I have a RAK2287 gateway/application server/network server. I have successfully written a python script to access the uplink messages from my node, using paho-mqtt.

I would now like to schedule downlinks using MQTT. I have found this page (https://www.chirpstack.io/application-server/integrations/mqtt/) and I’ve attempted to follow it, using paho-mqtt’s connect(), subscribe() and publish() commands. Unfortunately, despite my best efforts, I can’t schedule a downlink.

I don’t know what’s wrong because I don’t know of anywhere in chirpstack I can go to see why my MQTT messages are being rejected. Can anyone help with debugging?

This is the basics of my code:

import paho.mqtt.client as mqtt
import json
import base64

def on_connect(client,userdata,flags,rc):
    print("Connected with result code:"+str(rc))
    client.subscribe("application/4/device/MYEUI/command/down")

mqttc= mqtt.Client()
mqttc.on_connect=on_connect

mqttc.connect("192.168.xxx.xxx",1883,10)

datatosend = b'\x01\x02\x04\x00\x00\x00\x00'
datatosendb64 = base64.b64encode(datatosend)

packettosend = {
    "confirmed": 'true',
    "fPort": 3,
    "data": str(datatosendb64)
}

json_packettosend = json.dumps(packettosend)

mqttc.publish("application/4/device/MYEUI/command/down", json_packettosend, 0, False)

Many thanks for any help you can offer.

Given the architectural divisions in LoRaWAN, this question has essentially nothing to do with the RAK2287, and everything to do with chirpstack, so it’s posted in the wrong sub-forum, so it really should be in the network server stack area. You are also more likely to find existing topics that might help with your issue there.

You may also want to review documentation on chirpstack’s own site and check their forum for existing threads. Though asking the same question on multiple sites is perhaps slightly discouraged.

In terms of asking a question about why something does not work, you should include any error output.

There’s a fair chance that either the ip address, or the MQTT topic referring to a particular node are not correct for your setup - if those came from an example, yours will certainly be different.

Thank you for your comments. I haven’t included any error output because I don’t know where to find it. I’m basically firing a message into a black hole without any way of knowing why it doesn’t work. That’s why I can’t start to debug the issues myself and the main reason why I resorted to posting on a forum.Do you know where I can find the error output?

The IP address is definitely correct. The name of the topic came from the example code on the chirpstack webpage page I referenced.

Thanks again.

Maybe find out where ChirpStack puts its error logs?

And some of the GUI clients should give you some feedback when you put in a request.

What is in your code is of course literally wrong; probably you’ve tried to pointelessly obfuscate it, but since your level of experience is unclear, it’s hard to know what is obfuscation and what could be mistake.

Both the application number and the EUI in the topic will be unique to your particular case, and need to be correct for your case. Those from an example will not work.

Before you worry about downlink, make sure you can subscribe to the uplink topic and actually get data. Try using mosquitto-sub instead of python. Add debug output to your python code so that you know it has connected to the broker and actually subscribed. Print out the uplink message JSON objects received…

Thank you for your message.

As I said in my original post, I have already been able to subscribe to the uplink topic successfully and see the uplink messages from my node.

Yes, I’ve obfuscated the IP address, and my eui. I have completed them correctly for my system.

As far as my python code is concerned, the message is being sent to the broker OK (I’ve checked the result of the subscribe() and publish() commands, both returning 0).

I’ve printed out the json data I’m passing to the publish() command and it looks ok to me:
{"confirmed": "true", "fPort": 3, "data": "AQIEAAAAAA=="}

My assumption, though, is that something about the json data I’m sending must be wrong, but unless I can find the place in chirpstack where this is reported I don’t know how I can debug it.

Thanks again.

How exactly do you know it’s not working? Not disputing the fact, but where you are looking changes the number of things which need to work for progress to reach that point of observation.

In terms of getting debug output from chirpstack, probably some usage of docker logs assuming you are running it that way.

I’m looking on the Device page in Chirpstack.

If I use the ENQUEUE PAYLOAD function on that page, the enqueued payload appears in the “Downlink queue” until it is sent to the node. I was expecting (an assumption, admittedly) that if I enqueued a payload using mqtt instead of the ENQUEUE PAYLOAD function, it would also appear in the Downlink queue, but it doesn’t. That’s the basis on which I’ve declared failure.

I’ve gone further now, in that I’ve asked my node to check for downlink messages. It reports zero downlink messages available.

Does it work if you queue a downlink on the ChirpStack web console?

I’ve got it working, finally!

Noting the comment at https://www.chirpstack.io/application-server/integrations/mqtt/ that I might need to use the /tx topic instead of the /command/down topic, I tried /tx.

This time, I finally saw messages relevant to the downlink in the application server log (accessed with journalctl -f -n 100 -u chirpstack-application-server) as follows:

Oct 09 10:20:47 rak-gateway chirpstack-application-server[27928]: time="2020-10-09T10:20:47+01:00" level=info msg="integration/mqtt: data-down payload received" topic=application/3/device/MYEUI/tx

Oct 09 10:20:47 rak-gateway chirpstack-application-server[27928]: time="2020-10-09T10:20:47+01:00" level=error msg="integration/mqtt: tx payload unmarshal error: json: cannot unmarshal string into Go struct field DataDownPayload.confirmed of type bool" data_base64="eyJjb25maXJtZWQiOiAidHJ1ZSIsICJmUG9ydCI6IDAsICJkYXRhIjogImInTVRJME9BPT0nIn0="

The first message gave me encouragement that /tx is the correct topic to use. The second one made me think the issue was the confirmed field in my json. It was complaining that I had not supplied a bool.

The relevant line in my code was:
"confirmed": 'true'

Indeed, I hadn’t supplied a bool. The problem was that if I changed this code to
"confirmed": true

then I got this error message when I ran the code:
Traceback (most recent call last):
File “mqtt_chirpstack_pHat_send.py”, line 82, in
“confirmed”: true,
NameError: name ‘true’ is not defined

Turns out that assigning a variable to be true in python requires True to have a capital T!

Final issue:
Oct 09 10:34:45 rak-gateway chirpstack-application-server[27928]: time="2020-10-09T10:34:45+01:00" level=error msg="integration/mqtt: tx payload unmarshal error: illegal base64 data at input byte 1" data_base64=eyJjb25maXJtZWQiOiB0cnVlLCAiZlBvcnQiOiAwLCAiZGF0YSI6ICJiJ01USTBPQT09JyJ9

Turns out I need to strip the b' from the beginning and the ' from the end of my base64 data so:
"data": (str(datatosendb64))[2:len(str(datatosendb64))-1]

Hey presto it now works!

The scheduled message is shown in the Download queue in the chirpstack GUI.

The application server log shows:
Oct 09 10:45:48 rak-gateway chirpstack-application-server[27928]: time="2020-10-09T10:45:48+01:00" level=info msg="downlink device-queue item handled" confirmed=true dev_eui=MYEUI f_cnt=1

And my node reports and downloads the downlink when asked to.

So my code now looks like this:

import paho.mqtt.client as mqtt
import json
import base64

def on_connect(client,userdata,flags,rc):
    print("Connected with result code:"+str(rc))
    client.subscribe("application/4/device/MYEUI/tx")

mqttc= mqtt.Client()
mqttc.on_connect=on_connect

mqttc.connect("192.168.xxx.xxx",1883,10)

datatosend = b'\x01\x02\x04\x00\x00\x00\x00'
datatosendb64 = base64.b64encode(datatosend)

packettosend = {
    "confirmed": True,
    "fPort": 3,
    "data": str(datatosendb64)[2:len(str(datatosendb64))-1]
}

json_packettosend = json.dumps(packettosend)

mqttc.publish("application/4/device/MYEUI/tx", json_packettosend, 0, False)

Please note that MYEUI should be replace with your own DevEUI, 192.168.xxx.xxx should be replaced with the IP address of your own Chirpstack Server and datatosend should be replaced with the bytes you want to send.

Sorry about the long post but I hope it might help others who are looking to schedule a downlink in Chirpstack using MQTT.

Glad you got things working!

Worth noting however that this:

Turns out I need to strip the b' from the beginning and the ' from the end of my base64 data so:
"data": (str(datatosendb64))[2:len(str(datatosendb64))-1]

is fragile because you’re sort of abusing python’s object dump format as a basis of conversion. You should probably do something like this:

"data": datatosendb64.decode('iso-8859-1')

to turn it into a plain “string”. In python 2.7 it just worked and you didn’t need to do anything, but python 3.x tries to be more precise…

Thank you for this. I’ll make that change…

Can you please help to fix my problem.

I have previously used this to publish a downlink

def publish(client: mqtt_client, device_eui):
“”“Downlink new settings to sensor via ChirpStack”“”
payload = “00 00 00 00 fe 02 02 b4”
topic_down = f"application/1/device/{device_eui}/command/down"

frame = {
    "confirmed": True,
    "fPort": 2,
    "data": base64.b64encode(bytes.fromhex(payload)).decode()
}

data = json.dumps(frame)
client.publish(topic_down, data)