Solution for resolving the geolocation of a LoRa sensor - SX1303 - Fine timestamp - TDoA

Hi All,

LoRa sensor tracker

I have developed geolocation service prototype for the ChirpStack. A testbed solution basis on:

  • Radio part: Concentrator with Semtech SX1303 chipset (with the fine timestamping property + GPS PPS signal)
  • ChirpStack-concentratord module
  • ChirpStack-mqtt-forwarder module
  • ChirpStack - open-source LoRaWAN Network Server
  • GLSmqttcs - sensor location estimator, geolocation resolver module
  • GLSensor tracker server - demo application for visualizing the sensor map in the browser

Pic 1. Testbed - Concentratord, mqtt-forwarder and ChirpStack LNS.

How the sensor tracker works?

LoRa sensor location can be resolved by using Time Difference of radio signal Arrival measurement techniques (TDoA) or by using received signal strength data (RSSI). The system has a predictive location estimator module to do complicated calculation tasks on real time.

A simplified picture below describes on general level how to sensor tracker resolves a LoRa sensor location on real time.

Pic 2. Testbed - Sensor location estimator module, GLSensor tracker server and the ChirpStack - open-source LoRaWAN Network Server framework.

At the first, three LoRa base stations receives sensor radio signal. Each base station attaches high accuracy timestamp of radio signal arrival time to received data.

Received sensor data of each base station are propagated to the LoRaWAN network server which combines the sensor data into one message structure. Now sensor message holds sensor’s measurement data and received radio signal information from all base stations.

On the ChirpStack Application screen of the ChirpStack server you can see the following event message with three different rxinfo item (3 gateways/receivers, measurement triangle). Each item has fineTimeSinceGpsEpoch attribute which tells when a gateway was received radio signal. This fine timestamp information is used for precise location calculation.

        "deduplicationId": "ba7f0cff-2111-4601-9c64-fea2dc28cec8",
        "time": "2024-06-05T19:14:22.122547750+00:00",
        "deviceInfo": {
            "tenantId": "52f14cd4-c6f1-4fbd-8f87-4025e1d49242",
            "tenantName": "ChirpStack",
            "applicationId": "e89a9f76-2455-44dd-b44b-c93fa8f0c54a",
            "applicationName": "GL Sensors",
            "deviceProfileId": "ee6ac99d-1217-4e74-aa57-f9c4db62373e",
            "deviceProfileName": "xxxxxxx",
            "deviceName": "GLSensor 3D",
            "devEui": "ab1a1xxxxxxxxxxx",
            "deviceClassEnabled": "CLASS_A",
            "tags": {}
        "devAddr": "xxxxxxxx",
        "adr": true,
        "dr": 5,
        "fCnt": 275,
        "fPort": 2,
        "confirmed": false,
        "data": "FwUXCRhcbA4AAAgAAADm",
        "object": {
            "T": 24.92,
            "T0": 23.5,
            "Z": 0.8969999999999999,
            "T1": 23.9,
            "Y": 0,
            "P": 1008.14,
            "X": 0.0312,
            "EVENT": 0
        "rxInfo": [
                "gatewayId": "0xxxxxxxxxxxxxxx",
                "uplinkId": 2595316073,
                "nsTime": "2024-06-05T19:14:21.906961055+00:00",
                "fineTimeSinceGpsEpoch": "0.841145814s",
                "rssi": -108,
                "snr": 11.5,
                "channel": 4,
                "location": {
                    "latitude": 60.19754487290158,
                    "longitude": 25.123490095138553
                "context": "s2XzZw==",
                "metadata": {
                    "region_config_id": "eu868",
                    "region_common_name": "EU868"
                "crcStatus": "CRC_OK"
                "gatewayId": "1xxxxxxxxxxxxxxx",
                "uplinkId": 684694032,
                "nsTime": "2024-06-05T19:14:21.921733501+00:00",
                "fineTimeSinceGpsEpoch": "0.841145973s",
                "rssi": -49,
                "snr": 11.75,
                "channel": 4,
                "location": {
                    "latitude": 60.19750221406514,
                    "longitude": 25.12353837490082
                "context": "TMolkA==",
                "metadata": {
                    "region_config_id": "eu868",
                    "region_common_name": "EU868"
                "crcStatus": "CRC_OK"
                "gatewayId": "2xxxxxxxxxxxxxxx",
                "uplinkId": 3128025211,
                "nsTime": "2024-06-05T19:14:21.915503069+00:00",
                "fineTimeSinceGpsEpoch": "0.841145944s",
                "rssi": -42,
                "snr": 11.5,
                "channel": 4,
                "location": {
                    "latitude": 60.19750221406514,
                    "longitude": 25.123452544212345
                "context": "UQSbjg==",
                "metadata": {
                    "region_config_id": "eu868",
                    "region_common_name": "EU868"
                "crcStatus": "CRC_OK"
        "txInfo": {
            "frequency": 867300000,
            "modulation": {
                "lora": {
                    "bandwidth": 125000,
                    "spreadingFactor": 7,
                    "codeRate": "CR_4_5"

The GLSmqttcs location estimator module gets sensor message immediately when LoRaWAN network server received it. Location estimator module resolves sensor location by using high accuracy and predictive multilateral position resolver algorithm.

The GLSensor tracker server subscribes sensor location information and visualizes sensor location on the map when it was published by The GLSmqttcs location estimator module.

Open-source project?

I have considered releasing this solution as an open-source project if there is public interest. This will happen at the end of this summer at the earliest, depending on how much effort I can put into advancing this project.

Currently, the integration between ChirpStack and sensor location estimator is implemented by using mqtt, but it may change in the future. At the moment this mqtt-integration seems to be a good solution.

@Brocaar, do you have any advice or hints on what would be a good way to implement the interface between LoRa-sensor geolocation resolver and ChirpStack? Are there any documents or guides on how to implement ChirpStack integration?


Below is a link to the Real-time LoRa-sensor tracking demo application. Demo-environment has three SX1303 gateways (Base Stations) in a measurement triangle and a bunch of LoRa-sensors that usually sends some messages within 30 s period.

Link to GLSensor tracker demo

It would be nice to hear from this forum if the geolocation resolver is a generally needed feature?

Have a nice summer


I think that would be really cool!

do you have any advice or hints on what would be a good way to implement the interface between LoRa-sensor geolocation resolver and ChirpStack

The Semtech LoRa Cloud integration could be taken as an example (although there is a lot of magic happening). E.g. an uplink event is forwarded to LoRa Cloud (e.g. with GNSS or Wi-Fi data), that returns a location, which then generates a new integration event (location).

To just get an idea about the integration interface, you could take a look at the HTTP integration implementation:

In general, all integrations implement this interface / trait:

1 Like