Introduction

Once the system is set up, you can start extracting positioning data. You can do this by using the popular MQTT protocolMQTT is a publish/subscribe protocol, so you get the newest positions as soon as they are available.

By default the MQTT packet only includes positions, but it's possible to add more sensor data from the tag by using the Pozyx Device Configurator. In combination with the developer tag you could even send your own data over the Pozyx UWB network and access it through the MQTT stream.

Data structure

The full MQTT JSON output data structure can be found on the MQTT data structure page.

Connect with the local stream

On your Local Area Network (LAN), you can connect directly with the Pozyx gateway. We recommend this for real-time applications as it provides a low latency connection.

Connection info

The connection info can be found in the Pozyx web application under Settings > Connectivity > Local API.

Examples

The following Python program subscribes to the local MQTT stream using the paho-mqtt MQTT library:

import paho.mqtt.client as mqtt
import ssl

host = "192.168.1.27" # fill in the IP of your gateway
port = 1883
topic = "tags" 

def on_connect(client, userdata, flags, rc):
    print(mqtt.connack_string(rc))

# callback triggered by a new Pozyx data packet
def on_message(client, userdata, msg):
    print("Positioning update:", msg.payload.decode())

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed to topic!")

client = mqtt.Client()

# set callbacks
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.connect(host, port=port)
client.subscribe(topic)

# works blocking, other, non-blocking, clients are available too.
client.loop_forever()
PY

The following C# program subscribes to the cloud MQTT stream using the MQTTnet MQTT library:

using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace mqtt_c
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = "192.168.1.27";
            var port = 1883;
            var topic = "tags";

            var options = new MqttClientOptionsBuilder()
                .WithTcpServer(host, port)
                .Build();

            var mqttClient = new MqttClient(options, topic);
            Task.Run(() => mqttClient.StartAsync());
            Thread.Sleep(Timeout.Infinite);
        }
    }

    class MqttClient
    {
        private IMqttClient mqttClient;
        private IMqttClientOptions options;
        private string topic;

        public MqttClient(IMqttClientOptions options, String topic)
        {
            this.options = options;
            this.topic = topic;
            this.mqttClient = new MqttFactory().CreateMqttClient();
            this.mqttClient.UseConnectedHandler(ConnectedHandler);
            this.mqttClient.UseApplicationMessageReceivedHandler(MessageHandler);
            this.mqttClient.UseDisconnectedHandler(DisconnectedHandler);
        }

        public async void ConnectedHandler(MqttClientConnectedEventArgs e)
        {
            Console.WriteLine("Connected with server!");
            await this.mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(this.topic).Build());
            Console.WriteLine("Subscribed to topic");
        }

        public void DisconnectedHandler(MqttClientDisconnectedEventArgs eventArgs)
        {
            Console.WriteLine("Disconnected from server");
        }

        public void MessageHandler(MqttApplicationMessageReceivedEventArgs eventArgs)
        {
            Console.WriteLine(Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload));
        }

        public async Task StartAsync()
        {
            await this.mqttClient.ConnectAsync(this.options, CancellationToken.None);
        }
    }
}

C#

MQTT over WebSocket

The local MQTT stream is also provided over a WebSocket. You can connect to it by using the IP address of the gateway and adding the /api/mqtt-over-ws path to it.

Connect through the cloud

By connecting through the cloud, you can retrieve positioning data from anywhere. The Pozyx cloud offers the MQTT data in a secure way.

Please note that using the cloud MQTT the maximum update rate is 20 Hz.
More information about this can be found below under MQTT data rate.

Connection info

The cloud MQTT uses a WebSocket connection for which the connection information can be found in the Pozyx web application under Settings > Connectivity > Cloud API.

Examples

The following Python program subscribes to the cloud MQTT stream using the paho-mqtt MQTT library:

import paho.mqtt.client as mqtt
import ssl

host = "mqtt.cloud.pozyxlabs.com"
port = 443
topic = ""
username = ""
password = ""

def on_connect(client, userdata, flags, rc):
    print(mqtt.connack_string(rc))

# Callback triggered by a new Pozyx data packet
def on_message(client, userdata, msg):
    print("Positioning update:", msg.payload.decode())

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed to topic!")

client = mqtt.Client(transport="websockets")
client.username_pw_set(username, password=password)

# sets the secure context, enabling the WSS protocol
client.tls_set_context(context=ssl.create_default_context())

# set callbacks
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.connect(host, port=port)
client.subscribe(topic)

# works blocking, other, non-blocking, clients are available too.
client.loop_forever()
PY

The following C# program subscribes to the cloud MQTT stream using the MQTTnet MQTT library:

using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Options;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace mqtt_c
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = "mqtt.cloud.pozyxlabs.com";
            var port = 443;
            var topic = "";
            var username = "";
            var password = "";

            var options = new MqttClientOptionsBuilder()
                .WithWebSocketServer(host + ":" + port)
                .WithTls()
                .WithCredentials(username, password)
                .Build();

            var mqttClient = new MqttClient(options, topic);
            Task.Run(() => mqttClient.StartAsync());
            Thread.Sleep(Timeout.Infinite);
        }
    }

    class MqttClient
    {
        private IMqttClient mqttClient;
        private IMqttClientOptions options;
        private string topic;

        public MqttClient(IMqttClientOptions options, String topic)
        {
            this.options = options;
            this.topic = topic;
            this.mqttClient = new MqttFactory().CreateMqttClient();
            this.mqttClient.UseConnectedHandler(ConnectedHandler);
            this.mqttClient.UseApplicationMessageReceivedHandler(MessageHandler);
            this.mqttClient.UseDisconnectedHandler(DisconnectedHandler);
        }

        public async void ConnectedHandler(MqttClientConnectedEventArgs e)
        {
            Console.WriteLine("Connected with server!");
            await this.mqttClient.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(this.topic).Build());
            Console.WriteLine("Subscribed to topic");
        }

        public void DisconnectedHandler(MqttClientDisconnectedEventArgs eventArgs)
        {
            Console.WriteLine("Disconnected from server");
        }

        public void MessageHandler(MqttApplicationMessageReceivedEventArgs eventArgs)
        {
            Console.WriteLine(Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload));
        }

        public async Task StartAsync()
        {
            await this.mqttClient.ConnectAsync(this.options, CancellationToken.None);
        }
    }
}
C#


MQTT data rate

The data rate of the cloud MQTT stream can be defined in the settings: Settings > Connectivity > Push to cloud, with a maximum of 20 Hz. The position updates from multiple tags are then batched in MQTT packets according to this frequency. Only the last position update of each tag is kept in memory for batching, so each MQTT packet will have maximum 1 position update per tag ID. This means that as long as an individual tag does not update at a faster rate then the MQTT data rate you should not lose any data, but if your tag is updating at a faster rate than the data rate of the MQTT stream then you will only receive the latest position for a tag:

ℹ️ Example without data loss

In this example we have 40 tags operating at 1 Hz and the MQTT data rate set to 5 Hz. The MQTT data rate is set higher than the update rate of each individual tag, so there won't be any data loss. Every 200ms an MQTT packet will be sent over the MQTT stream which will contain on average 8 tag updates each. On average because this depends on when each tag blinks: If each tag would blink at the same time then it could be that 1 MQTT packet contains the updates for all 40 tags and the other 4 packets within that second do not contain any information. But this is of course highly improbable. The update rate of the tags also have a variation mechanism built in, so they don't blink at exact 1 Hz. Which means that even if this event would occur, it would not continuously occur.

⚠️ Example with data loss

In this example we have 2 tags operating at 20 Hz and the MQTT data rate set to 5 Hz. The MQTT data rate is set lower than the update rate of each individual tag, so there will be data loss. Every 200ms an MQTT packet will be sent over the MQTT stream which will contain 2 tag updates each. Each MQTT packet will only contain the last position update for each tag, and not all the position updates since the last MQTT packet was sent out.

MQTT example

The below MQTT excerpt was taken from a cloud MQTT stream with:

  • The data rate set to 2 Hz
  • Tag #222 running at 2 Hz
  • Tag #7051 running at 10 Hz
[
  {
    "version": "2.0",
    "tagId": "222",
    "timestamp": 1616000449.155912,
    "data": {
      "tagData": {
        "blinkIndex": 26401976
      },
      "metrics": {
        "latency": 42,
        "rates": {
          "success": 0,
          "update": 2.06,
          "packetLoss": 0
        }
      }
    }
  },
  {
    "version": "2.0",
    "tagId": "7051",
    "timestamp": 1616000449.5236182,
    "data": {
      "tagData": {
        "blinkIndex": 390568
      },
      "metrics": {
        "latency": 19,
        "rates": {
          "success": 9.69,
          "update": 9.66,
          "packetLoss": 0
        }
      }
    }
  }
]
JS
[
  {
    "version": "2.0",
    "tagId": "222",
    "timestamp": 1616000450.1082623,
    "data": {
      "tagData": {
        "blinkIndex": 26401978
      },
      "metrics": {
        "latency": 39,
        "rates": {
          "success": 0,
          "update": 2.07,
          "packetLoss": 0
        }
      }
    }
  },
  {
    "version": "2.0",
    "tagId": "7051",
    "timestamp": 1616000450.040604,
    "data": {
      "tagData": {
        "blinkIndex": 390572
      },
      "metrics": {
        "latency": 26,
        "rates": {
          "success": 8.81,
          "update": 8.79,
          "packetLoss": 0
        }
      }
    }
  }
]
JS
[
  {
    "version": "2.0",
    "tagId": "222",
    "timestamp": 1616000450.584033,
    "data": {
      "tagData": {
        "blinkIndex": 26401979
      },
      "metrics": {
        "latency": 29,
        "rates": {
          "success": 0,
          "update": 2.07,
          "packetLoss": 0
        }
      }
    }
  },
  {
    "version": "2.0",
    "tagId": "7051",
    "timestamp": 1616000450.612532,
    "data": {
      "tagData": {
        "blinkIndex": 390578
      },
      "metrics": {
        "latency": 25,
        "rates": {
          "success": 9.51,
          "update": 9.48,
          "packetLoss": 0
        }
      }
    }
  }
]
JS
[
  {
    "version": "2.0",
    "tagId": "222",
    "timestamp": 1616000451.0252686,
    "data": {
      "tagData": {
        "blinkIndex": 26401980
      },
      "metrics": {
        "latency": 25,
        "rates": {
          "success": 0,
          "update": 2.09,
          "packetLoss": 0
        }
      }
    }
  },
  {
    "version": "2.0",
    "tagId": "7051",
    "timestamp": 1616000451.1700604,
    "data": {
      "tagData": {
        "blinkIndex": 390584
      },
      "metrics": {
        "latency": 20,
        "rates": {
          "success": 10.12,
          "update": 10.09,
          "packetLoss": 0
        }
      }
    }
  }
]
JS

We can see that:

  • Every MQTT packet contains a tag position update for each tag because there is no tag operating at a lower update rate than the MQTT data rate (if we waited long enough it could be that tag #222 is missing in some MQTT packets because of slight variations in the actual rates).
  • For tag #222 almost all blinks are sent out over the MQTT stream because the update rates of the tag is very similar to the data rate of the MQTT stream (they're set to the same value but there's always a slight variation in the actual rates).
  • The blinkIndex of tag #7051 is 390568 in the first MQTT packet and 390584 in the fourth MQTT packet. It went up by 16, which is in line with an expected blink increase of ± 5 per MQTT packet as the update rate of the tag (10 Hz) is 5 times the data rate of the MQTT stream (2 Hz).

Using your own MQTT broker

It's also possible to configure the Gateway to use your own MQTT broker, but only MQTT brokers with a similar authentication scheme as AWS Greengrass are supported. This means that JWT authentication is currently not supported.

If you want to use your own MQTT broker, feel free to reach out to us on enterprise@pozyx.io to configure this for you.

We'll need the following information / files:

  • The MQTT endpoint
  • The CA file
  • The CERT file
  • The KEY file
  • The Client ID
  • The MQTT topic

When you use your own MQTT broker the positioning data will also be batched in MQTT packets, and these MQTT packets will go out at a data rate of 10 Hz (or in batches of 50 position updates, whichever comes first). These parameters can be configured by us, the settings defined on the Push to cloud page do not apply when you're using your own MQTT broker. In contrast to when you use our cloud MQTT broker there's never data loss when you use your own broker: A single MQTT packet can contain multiple position updates from a single tag.