Send Downlink command as JSON via gRPC and Python with use of payload formatter

Hey,
I’m trying to send a downlink command via gRPC and Python to an existing device.
It works to a point, but I tried to send a JSON, which then should get processed via the payload formatter.
The problem is that if I send the JSON as an utf-8 encoded string, it does not get passed through the payload format but gets enqueued directly to the device.
I tried to assign the req.queue_item.object, but it gives me an error (“AttributeError: Assignment not allowed to message, map, or repeated field “object” in the protocol message object.”).
Is there a way to send a downlink to chirpstack with a JSON so that the payload formatter can encode it for the device?

    def send_downlink(self, message, fport: int):
        req = api.EnqueueDeviceQueueItemRequest()
        req.queue_item.dev_eui = str(self.device.internal_id)
        req.queue_item.confirmed = False
        req.queue_item.f_port = fport
        req.queue_item.data = message
        try:
            self.client.Enqueue(req, metadata=self.auth_token())
            return True
        except grpc.RpcError as e:
            logger.error(e)
        return False

Are you testing this against ChirpStack v3 or v4?

Hey,
We use ChirpStack v4 and the corresponding PyPI library.

@brocaar, is this a bug, or is this functionality not yet implemented?

Where in v3 you had to pass the JSON object as string, you must pass it as JSON object in v4 (https://github.com/chirpstack/chirpstack/blob/master/api/proto/api/device.proto#L483).

@brocaar I know, but if I set it to either a python JSON object or a google.protobuf.Struct it returns:

And what do I do with the data field, I can’t let it be empty.

I’m not familiar with the Python API for Protobuf struct types, but maybe this could help you? dictionary - How do you create a Protobuf Struct from a Python Dict? - Stack Overflow

@brocaar I tried that before but same message:

AttributeError: Assignment not allowed to message, map, or repeated field "object" in protocol message object.

I think there is something else wrong. Maybe the word object is conflicting with something in python? Or something went wrong with the code generation for python. But I honestly don’t know how to debug this.

Found the solution. If you use:

s = Struct()
s.update({"state": "ON"})
req.queue_item.object.CopyFrom(s)

Instead of:

req.queue_item.object = s

Then everything works.