Framecounter

In order to be able to identify packet losses, for example, LoRaWAN has a frame counter. The frame counter is a counter that increases by 1 with each transmission and whose current value is stored both in the end device and on the LoRaWAN server. All packets that are transmitted to the LoRaWAN network are recorded. This value is also transmitted with the payload and can thus be read out by niotix. How this works is explained in the following instructions.

In each Virtual Device there is automatically the _raw data point, which contains in JSON format all values sent by the device.

What the value of a _raw data point looks like can be seen here:

Example _raw State
{
  "ack": null,
  "uid": "069218fa-fd24-4a16-b028-9560e642e7f7",
  "port": 5,
  "topic": "organizations/8046/devices/A81758FFFE03AD50",
  "device": {
    "id": 31767,
    "eui": "A81758FFFE03AD50",
    "name": "Luftqualitätssensor",
    "address": "286A97AE",
    "device_class_id": null,
    "organization_id": 8046
  },
  "parsed": null,
  "payload": "0100C802360400870500070DB7",
  "location": null,
  "mic_pass": true,
  "variable": "_raw",
  "bandwidth": 125,
  "device_id": "A81758FFFE03AD50",
  "_device_id": 31767,
  "updated_at": "2023-04-19T16:27:10.345594",
  "inserted_at": "2023-04-19T16:27:10.345617",
  "raw_payload": "40AE976A288090CD05AFF90C098A44270229FFE8444CC71A411D",
  "server_data": {
    "raw": "QK6XaiiAkM0Fr/kMCYpEJwIp/+hETMcaQR0=",
    "chan": 2,
    "codr": "4/5",
    "datr": "SF11BW125",
    "freq": 868.5,
    "gwrx": [
      {
        "lsnr": -15.2,
        "rssi": -118,
        "time": "2023-04-19T16:27:08.445963Z",
        "tmst": 74950700,
        "gweui": "0000024B0806061A",
        "srv_rcv_time": 1681921628895179
      }
    ],
    "modu": "LORA",
    "size": 26,
    "fopts": "",
    "mtype": "unconfirmed_data_up",
    "mac_cmds": [],
    "mic_pass": true,
    "dev_addr_hex": "286a97ae"
  },
  "device_class": null,
  "organization": {},
  "frame_counter": 52624,
  "parsed_packet": {
    "ack": false,
    "adr": true,
    "dir": "up",
    "fcnt": 52624,
    "port": 5,
    "major": 0,
    "mtype": "unconfirmed_data_up",
    "pending": false,
    "mac_cmds": [],
    "mic_pass": true,
    "adrackreq": false,
    "fopts_len": 0,
    "dev_addr_hex": "286a97ae"
  },
  "organization_id": 8046,
  "spreading_factor": 11,
  "payload_encrypted": false
}

Design and implementation

1. Create frame counter

For this frame counter, we create a new data point in the virtual device whose frame counter we want to capture. To do this, we go to the “Data Points” tab in the Virtual Device and click the add-button ().

Metadata

In the meta data.

  • Title: Framecounter
  • Key: framecounter
  • Unit: -
  • Icon: For example, “tally” is a suitable icon.
Source

Since we want to access an existing data point of the current virtual device, we select “Virtual Devices” as source and search for the current device.

The easiest way to do this is to use the Device ID. This is displayed in the URL.

Once the Virtual Device has been selected, the list of existing data points is selected. Here we select the first datapoint with key _raw. We change the type to “number”, because that is what the frame counter is.

Visualization

We can leave the visualization at default, which corresponds to the count clock.

Javascript-Transformer

As source we have selected the _raw data point above. Therefore, the current value of the datapoint we are currently trying to apply corresponds to the JSON object of this _raw datapoint. Therefore, as a next step, we need to extract the frame_counter object as a value from the entire JSON object. To do this, we enter the following javascript code as a transformer.

module.exports = (data) => {
  return data.frame_counter;
}

data corresponds to the _raw data state, since this was selected at the top. Since the frame_counter object is at the top level of the hierarchy, we can access the frame_counter object with data.frame_counter.
For example, if we wanted to access the address object, we would have to enter data.server_data.address.

This data point can now be saved.

2. Create difference value

Now to easily see if a data packet was lost or if a data packet was sent twice, we now create another data state. This data point looks at the difference of the last two received frame counter values, which should always result in the value 1 as described above.

Metadata

In the meta data

  • title: framecounter difference
  • Key: framecounter-difference
Source

As source we now select “aggregated timeseries” and look for the previously created data state with the title framecounter in the dropdown. As operation for the temporal aggregation we select “Difference to last value”, We change the type to “boolean” this time.

Javascript-Transformer

Before we customize the visualization now, we skip this point and go to the javaspript transformer and enter the following javascript code:

module.exports = (data) => {
  if (data != 1) {
    return false;
  }
  return true;
}

The script looks at the value of the data state and returns falseif the value does NOT correspond to a 1, and returns true if the value corresponds to a 1.

Visualization

In the visualization we now select the icon “check” for true and choose light green as color. For the value false we select the icon “times” and choose red as color.

So now a green check mark is displayed if there is no packet loss and an x if there is a packet loss.

This data state can now be saved.

Further thoughts & ideas

Building on these data state, the following ideas arise:

  • Another data state of type “ggregated timeseries” that outputs the number of packet losses within a day.
  • A rule that notifies me by email when a package is lost.
  • A customized health status that issues a warning as soon as there are too many package losses.