Getting Framelogs through API

Is there a way to access the raw, unencrypted frame log that is typically visible in the LoRaWAN frame tab within the Chirpstack.API? I’m working on testing MAC commands and need access to frames with all the Phypayload information exactly as it appears in Chirpstack under LoRaWAN frames.

Up to this point, I’ve tried a couple of approaches:

  1. Setting up a stream to Redis: This method didn’t work for my needs because the payload is encrypted, and I’d like to avoid the need for decrypting each frame.

  2. Listening on events from PostgreSQL: This approach also didn’t meet my requirements since events don’t provide detailed information like fhdr and f_opts.

  3. Using InternalServiceClient.StreamGatewayFrames() from the Chirpstack api. This returns the raw frame unencrypted, but is very very slow. Retrieving 3 frames with the MoveNext() operator, takes about 1.3 min. On top of that it starts with the oldest frame, where I would prefer the newest frame.

Is there a way to access this information directly through Chirpstack.API without the need to handle decryption or unnecessary parsing? Or maybe a fix to the MoveNext() time? Any advice is appreciated

your first option is the way to do it, but you need to use the chirpstack rpc to decode the packet

Yeah this is what i feared. This solution is annoying though, since I have to get the NwkSKey to decrypt the payload. And as I see it, the only way to get this through chirpstack, is to look in the joinAccept frame and get the JoinNonce, and then calculate the NwkSKey.
This is a problem since during tests a device might already be joined. The only way to combat this is to join the relay every time I start the testing.
Unless theres a cleaner way to get the NwkSKey?

yeh, you can use the rpc or http api to collect that information if you know the device eui.
you will need to generate a api-token for the request though easiest way it by using the webui - it might need to be an admin token to access that (I haven’t tried with a regular tenant to call that).

The only thing i can succeed in getting is the nwkKey, appKey using GetDeviceKeysResponse(GetDeviceKeysRequest) and not the nwkSKey

import os
import grpc
from google.protobuf.json_format import MessageToJson
from chirpstack_api import api

api_token = [('authorization', f'Bearer {os.getenv("CHIRPSTACK_APIKEY")}')]
chirpstack_server = os.getenv('CHIRPSTACK_SERVER')


def get_device_activation(dev_eui: str):
    with grpc.insecure_channel(chirpstack_server) as channel:
        client = api.DeviceServiceStub(channel)
        req = api.GetDeviceActivationRequest()
        req.dev_eui = dev_eui
        resp = client.GetActivation(req, metadata=api_token)
    return MessageToJson(resp)


if __name__ == '__main__':
    dev_eui = input('Device Eui: ')
    print(get_device_activation(dev_eui))

this should return a json like so…

{
  "deviceActivation": {
    "devEui": "0102030405060708",
    "devAddr": "78000024",
    "appSKey": "<truncated>...",
    "nwkSEncKey": "<truncated>...", <-- here
    "fCntUp": 1841,
    "nFCntDown": 54,
    "sNwkSIntKey": "<truncated>...",
    "fNwkSIntKey": "<truncated>..."
  }
}
1 Like

or via http api… curl example.

curl -X 'GET' \
  'https://example.com/api/devices/<DEVICE EUI>/activation' \
  -H 'accept: application/json' \
  -H 'Grpc-Metadata-Authorization: Bearer <YOUR TOKEN>'

returns json like so…

{
  "deviceActivation": {
    "devEui": "0102030405060708",
    "devAddr": "78000024",
    "appSKey": "<truncated>...",
    "nwkSEncKey": "<truncated>...", <-- here
    "sNwkSIntKey": "<truncated>...",
    "fNwkSIntKey": "<truncated>...",
    "fCntUp": 1842,
    "nFCntDown": 54,
    "aFCntDown": 0
  }
}

Thank you very much, this clears it up. I wasn’t aware that DeviceActivationRequest returned this.

np, mark it as solution if you think it may help someone else.

Will do. Will update if I run into other problems :slight_smile:

This topic was automatically closed after 90 days. New replies are no longer allowed.