Skip to content

MQTT specification

This document provides a comprehensive technical guide for working with the MQTT interface of the TAC-B series industrial radar sensor.


1. General Connection Parameters and Architecture

1.1. Supported Connection Types

The device settings (parameter mqtt_connection_type) support the following connection types to the broker:

  • Use Credentials (0): Standard unencrypted TCP connection with username and password authentication.
  • SSL/TLS without certificate (6): Secure SSL/TLS connection with encryption, but without mandatory verification of the broker certificate on the device side.
  • SSL/TLS (2): Secure connection with server validation via CA certificate (client.crt is used as CA).
  • Two-way authentication (3): Two-way SSL/TLS authentication (the device verifies the broker, and the broker verifies the device using the client.crt / client.key pair).
  • Mutual authentication (4): Mutual authentication with strict verification of the entire chain of trust (client.crt, server.crt, client.key).
  • WebSocket (5): Data transmission over WebSockets (without encryption).
  • WebSocket Secure (7): Secure data transmission over WebSockets with encryption.
  • Azure IoT (7 in the mqtt_settings enumeration, internal type _AZURE_IOT): Integration with Microsoft Azure IoT Hub via MQTT protocol using a device certificate (azure.crt) and an intermediate CA (azure-ca.crt).
  • AWS IoT (8 in the enumeration, internal type _AWS_IOT): Integration with Amazon Web Services IoT Core with authentication via client certificate (client.crt / client.key).

1.2. Unique Device Client ID

To avoid conflicts on the broker, the Client ID of each sensor is formed strictly according to the following scheme: $$\text{Client ID} = \text{DEVICE_ID_PREFIX} + \text{DeviceSerialNrASCII}$$ Example: sensmax-tac-b-141000222

1.3. Basic Topic Structure

The formation of publish and subscribe topics depends on the selected integration profile (Azure IoT, AWS IoT, or standard MQTT).

Standard Broker (SensWeb or User's Own Server)

To publish data, the device uses the following template:

{mqtt_prefix}smx/device/{DeviceSerialNr}/{message_type}[/{YYYYMMDD}][/{sensor_serial}]
  • {mqtt_prefix}: User-defined topic prefix (from mqtt_prefix settings). For SensWeb, it is absent (empty string).
  • {DeviceSerialNr}: Serial number of the ESP32 controller (e.g., 141000222).
  • {message_type}: Type of the sent packet (e.g., single_ts, ping, 5_min_data, advanced_settings, log).
  • {YYYYMMDD}: Optionally added date (for packets requiring date pinning, e.g., ping/20260520).
  • {sensor_serial}: Optional serial number of a specific gate or zone (e.g., 141000222G1 for Gate 1 or 241000222Z1 for Zone 1).

To subscribe (receive commands), the following topic is used:

{mqtt_prefix}smx/server/{DeviceSerialNr}/#

Azure IoT Hub Profile

  • Subscription Topic (C2D messages): devices/{MQTT_CLIENT_ID}/messages/devicebound/# (QoS 1 is used)
  • Publication Topic (D2C messages): devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType={message_type}

AWS IoT Core Profile

  • Subscription Topic (Commands): cmd/smx/{MQTT_CLIENT_ID}/# (QoS 1 is used)
  • Publication Topic (Data): dt/smx/{MQTT_CLIENT_ID}/{message_type}

2. Basic JSON Message Format

All messages sent and received by the device are JSON documents. Any outgoing message from the sensor contains the following basic set of fields:

{
  "messageType": "message_type",
  "id": "UNIQUE_HEX_ID_OF_MESSAGE",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "date": "2026-05-20",
  "time": "09:15:30.124"
}

Description of Basic Fields:

Field Type Description
messageType String Packet type (defines the structure of nested data).
id String Unique HEX identifier of the message (a random 32-bit number in HEX format generated by the sensor).
collector_id String Identifier of the device's main controller.
collector_serial String Serial number of the device's main controller.
collector_frm String Firmware version of the installed ESP32-S3 controller.
date String Message generation date on the device in YYYY-MM-DD format.
time String Exact message generation time with milliseconds in HH:MM:SS.sss format.

3. Outgoing Packets (Events and Data from Device to Server)

The sensor supports the publication of a wide range of data, from real-time people passage events to complex coordinate telemetry from the radar sensor.

3.1. info: Device Status on Connection

Sent once upon successful connection to the broker with the Retain flag (saved on the server).

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/info
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=info
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/info
  • JSON Structure:
{
  "messageType": "info",
  "id": "A4F23D9E",
  "sensor_id": "TAC-B-141000222",
  "sensor_model": "TAC-B_ETH_SENSOR",
  "sensor_serial": "141000222",
  "sensor_frm": "5.5.0",
  "radar_frm": "304",
  "supply_voltage": "12.2",
  "sd_status": "ok",
  "sd_total_mb": 7652,
  "sd_free_mb": 7629,
  "sd_used_pct": 0.29,
  "date": "2026-05-20",
  "time": "09:15:30.124"
}
  • Specific Fields:
  • sensor_id - Identifier of the main controller (matches collector_id).
  • sensor_model - Physical model name of the device (e.g., "TAC-B_ETH_SENSOR").
  • sensor_serial - Serial number of the main controller.
  • sensor_frm - Firmware version of the installed ESP32-S3 controller.
  • radar_frm - Firmware version of the TI IWR6843AOP radar module (MSS/DSS).
  • supply_voltage - Supply voltage of the sensor (only present in builds with the ENABLE_LOW_POWER_MODE flag or for outdoor versions DEVICE_TACB_OUTDOOR).
  • sd_status - Status of the mounted SD card (string: "ok" or "not_mounted").
  • sd_total_mb - Total SD card capacity in megabytes (number). If no card is present, 0 is sent.
  • sd_free_mb - Free space on the SD card in megabytes (number). If no card is present, 0 is sent.
  • sd_used_pct - Percentage of used space on the SD card (floating-point number mathematically rounded to the nearest hundredth, e.g., 0.29). If no card is present, 0.0 is sent.

3.2. ping: Gate and Zone Availability Control

Sent periodically to confirm the activity of configured gates and zones.

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/ping/{YYYYMMDD}/{sensor_serial}
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=ping
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/ping
  • JSON Structure:
{
  "messageType": "ping",
  "id": "B1E9C3A4",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "sensor_serial": "141000222G1",
  "sensor_name": "Main Entrance",
  "date": "2026-05-20",
  "time": "09:20:00.005"
}
  • Specific Fields:
  • sensor_serial - Serial number of the polled gate (*G1, *G2...) or zone (*Z1, *Z2...).
  • sensor_name - User-defined name of the gate/zone.

3.3. single_ts: Real-Time Passage Detection Event

Published immediately when an object crosses the counting line (gate). Not sent in low-power network mode LOW_POWER_NETWORK_MODE.

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/single_ts/{YYYYMMDD}/{sensor_serial}
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=single_ts
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/single_ts
  • JSON Structure:
{
  "messageType": "single_ts",
  "id": "7D41E2F3",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "sensor_serial": "141000222G1",
  "sensor_name": "Entrance Group 1",
  "direction": "IN",
  "date": "2026-05-20",
  "time": "09:21:44.385",
  "five-min": 112,
  "in_today": 342,
  "out_today": 298,
  "object_id": 1405,
  "object_speed": "4.2",
  "object_class": "pedestrian",
  "last_5min_sum": 12,
  "first_entry_time": "08:00:12",
  "last_entry_time": "09:21:44"
}
  • Specific Fields:
  • direction - Crossing direction: "IN" (entrance) or "OUT" (exit).
  • five-min - Index of the 5-minute interval in the day (from 0 to 287).
  • in_today / out_today - Accumulated daily total of incoming and outgoing objects through this gate.
  • object_id - Unique sequential track ID of the object from the radar side.
  • object_speed - Object speed at the moment of passage (km/h, rounded to tenths). Passed as a string.
  • object_class - Recognized object class: "pedestrian", "cyclist", "car", "adult", "child", "unknown".
  • last_5min_sum - Total number of passages in the current 5-minute interval.
  • first_entry_time / last_entry_time - Time of the first and last passage through this gate for the current day.

Specifics for Zones:

If an event is registered in the occupancy zone, additional real-time metrics are automatically injected:

  "inside_now": 5,
  "avg_occupancy_per_visitor": 120,
  "total_zone_occupancy": 3600
}
  • inside_now - Number of people currently inside the zone.
  • avg_occupancy_per_visitor - Average time spent by a single visitor in the zone (in seconds).
  • total_zone_occupancy - Cumulative total time of people presence in the zone for the current day (in seconds).

3.4. sync_list: Current List of Gates and Zones

Sent to the broker upon device startup, configuration changes, or once a day with the Retain flag.

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/sync_list
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=sync_list
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/sync_list
  • JSON Structure:
{
  "messageType": "sync_list",
  "id": "FA10C5D2",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "device_list": {
    "141000222G1": "Main Door",
    "141000222G2": "Emergency Exit",
    "241000222Z1": "Reception Area"
  }
}
  • device_list contains a dictionary mapping hardware addresses of gates (*G1, *G2...) and zones (*Z1, *Z2...) to their human-readable names.

3.5. settings: Standard Device Settings

Sent upon initial connection and during any changes to basic parameters with the Retain flag.

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/settings
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=settings
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/settings
  • JSON Structure:
{
  "messageType": "settings",
  "id": "C8D9E1B2",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "date": "2026-05-20",
  "time": "09:25:00.001",
  "time_zone": "UTC+03:00",
  "dst": true,
  "power_profile": "ImmediateDelivery",
  "make_beep": true,
  "reboot_schedule": "02:00",
  "startup_sound": true,
  "led_indication": true,
  "request_settings_update": false
}
  • Specific Fields:
  • time_zone - Time zone in UTC±HH:MM format.
  • dst - Flag to enable automatic daylight saving time transition.
  • power_profile - Current power consumption profile (always "ImmediateDelivery" for Ethernet versions).
  • make_beep - Enable buzzer sound on the sensor upon passage detection.
  • reboot_schedule - Daily automatic reboot time in "HH:00" format (or "OFF").
  • startup_sound - Allow melody playback when the device powers on.
  • led_indication - Allow LED indication during crossings.
  • request_settings_update - Request for settings update by the broker (reset to false after processing).

3.6. 5_min_data: Aggregated Occupancy Statistics (Gates)

Sent upon closing of a 5-minute interval or upon history request (data_request).

  • Publication Topic:
  • SensWeb / Standalone: {mqtt_prefix}smx/device/{collector_serial}/5_min_data/{YYYYMMDD}/{sensor_serial}
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=5_min_data
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/5_min_data
  • JSON Structure:
{
  "messageType": "5_min_data",
  "id": "E1D2C3B4",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "sensor_serial": "141000222G1",
  "sensor_name": "Checkout 1",
  "date": "2026-05-20",
  "direction": "IN",
  "in_today": 1205,
  "out_today": 1190,
  "first_entry_time": "08:00:15",
  "last_entry_time": "21:58:43",
  "visits": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 18, 22, 15, 30]
}
  • Specific Fields:
  • visits - An array of 288 integer elements containing the number of passages for each 5-minute interval of the current day (starting from 00:00 to 23:55).

3.7. Aggregated Zone Presence Statistics

For zones, instead of a single 5_min_data packet, an entire group of packets is sent, representing different slices of data. Each packet contains an array of 288 elements.

  • Publication Topics (SensWeb / Standalone):
  • Average number of people (inside_avg): {mqtt_prefix}smx/device/{collector_serial}/inside_avg/{YYYYMMDD}/{sensor_serial}
  • Maximum number of people (inside_max): {mqtt_prefix}smx/device/{collector_serial}/inside_max/{YYYYMMDD}/{sensor_serial}
  • First zone occupancy in seconds (occupancy_begin): {mqtt_prefix}smx/device/{collector_serial}/occupancy_begin/{YYYYMMDD}/{sensor_serial}
  • Zone occupancy duration in seconds (occupancy_duration): {mqtt_prefix}smx/device/{collector_serial}/occupancy_duration/{YYYYMMDD}/{sensor_serial}
  • Publication Topics (Azure IoT): devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType={inside_avg|inside_max|occupancy_begin|occupancy_duration}
  • Publication Topics (AWS IoT): dt/smx/{MQTT_CLIENT_ID}/{inside_avg|inside_max|occupancy_begin|occupancy_duration}

Example of inside_avg packet:

{
  "messageType": "inside_avg",
  "id": "E1D2C3B5",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "collector_frm": "5.5.0",
  "sensor_serial": "241000222Z1",
  "sensor_name": "Reception",
  "date": "2026-05-20",
  "inside_avg": [0, 0, 1, 2, 2, 4, 3, 1, 0, 0]
}

3.8. position: Hardware Coordinates of Targets

Sent periodically when targets are present in the scanning area of the TI IWR6843AOP radar (only for custom brokers). Depending on the short_coordinates_packet setting, it has two formats.

  • Publication Topic:
  • Standalone: {mqtt_prefix}smx/device/{collector_serial}/position
  • Azure IoT: devices/{MQTT_CLIENT_ID}/messages/events/$.ct=application%2Fjson&$.ce=utf-8&messageType=position
  • AWS IoT: dt/smx/{MQTT_CLIENT_ID}/position

Short Format (Without Track History)

  • JSON Structure:
{
  "messageType": "position",
  "id": "1D2E3F4A",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "total_detected_objects": 2,
  "object_list": {
    "object0": [1405, -120, 340, 0, 12],
    "object1": [1406, 45, 210, 0, 8]
  }
}
  • Coordinate Array Format: [ID, X (cm), Y (cm), Z (cm), Speed (dm/s)]

Long Format (With Tracking History)

  • JSON Structure:
{
  "messageType": "position",
  "id": "1D2E3F4B",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "total_detected_objects": 1,
  "object_list": {
    "object0": {
      "ID": 1405,
      "speed": 1.2,
      "X": [-140, -135, -130, -125, -120],
      "Y": [360, 355, 350, 345, 340]
    }
  }
}

3.9. notification: System and User Notifications

Published upon critical events or when notification rules are triggered.

System Notifications (Topic: .../notifications/system)

  1. Power On (POWER ON):
{
  "messageType": "notification",
  "id": "ABC12345",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "date": "2026-05-20",
  "time": "09:30:15.000",
  "reason": "POWER ON"
}
  1. Device blocked due to password brute-force (DEVICE BLOCKED):
{
  "messageType": "notification",
  "id": "CDE56789",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "date": "2026-05-20",
  "time": "09:30:15.000",
  "reason": "DEVICE BLOCKED"
}

User Notifications (Topic: .../notifications/user)

Triggered by the built-in notification logic (upon activation of configured triggers for people count, speed, etc.):

{
  "messageType": "notification",
  "id": "EF32D12B",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "date": "2026-05-20",
  "time": "09:30:15.000",
  "sensor_name": "Entrance Zone",
  "reason": "Warning! People limit exceeded (6 people)"
}

3.10. error_notification: Error Notifications

Sent by the device when there is an invalid syntax in the incoming request or when the requested information is missing.

  • Publication Topic: {mqtt_prefix}smx/device/{collector_serial}/errors
  • JSON Structure:
{
  "messageType": "error_notification",
  "id": "E8F9A1B2",
  "collector_id": "TAC-B-141000222",
  "collector_serial": "141000222",
  "description": "data not found"
}
  • Possible values for description:
  • "syntax error" - Invalid format of the incoming JSON packet (parsing error or invalid data types).
  • "data not found" - Requested historical data in data_request is missing on the SD card.
  • "unknown command" - The device received an unknown command.

4. Incoming Commands (Device Control from Server Side)

The device constantly listens to the registered subscription topic. Commands are accepted strictly in JSON format. Before processing any command, the device verifies if the "collector_serial" key matches its hardware serial number. If the serial number does not match, the command is ignored.

[!IMPORTANT] To prevent device looping (for example, when receiving an incoming command with the retained = 1 flag set), the device completely ignores any commands arriving within the first 3 seconds after establishing the MQTT connection (parameter MQTT_IGNORE_PERIOD_ms = 3000).


4.1. sync_list: Updating Gate/Zone Names and Composition

The server sends this command to overwrite the names of gates and zones stored in the non-volatile storage (NVS) of the sensor.

  • Inbound Topic: {mqtt_prefix}smx/server/{collector_serial}/sync_list
  • JSON Request Format:
{
  "collector_serial": "141000222",
  "messageType": "sync_list",
  "device_list": {
    "141000222G1": "Main Entrance (New Name)",
    "141000222G2": "Service Entrance",
    "241000222Z1": "Sales Floor Zone"
  }
}
  • Sensor Behavior:
  • Serial number verification is performed.
  • All items in device_list are iterated through.
  • Names are saved to the ZONE_NVS NVS partition.
  • Hardware gates or zones that are not listed in the incoming device_list are automatically deleted from the device's memory!
  • In response, the device sends the updated sync_list packet to the publication topic.

4.2. settings: Configuring General Settings

This command is used to remotely configure the basic parameters of the sensor.

  • Inbound Topic: {mqtt_prefix}smx/server/{collector_serial}/settings
  • JSON Request Format:
{
  "collector_serial": "141000222",
  "messageType": "settings",
  "time_zone": "UTC+03:00",
  "dst": true,
  "make_beep": true,
  "reboot_schedule": "03:00",
  "startup_sound": false,
  "led_indication": true,
  "premium_days": 365
}
  • Parameter Description and Validation:
  • time_zone - Sets the device's time zone. Only UTC±HH:MM format is allowed (e.g., UTC+03:00 or UTC-05:00). If formatted incorrectly, _SYNTAX_ERROR is returned.
  • dst - Flag to enable automatic daylight saving time transition (boolean).
  • make_beep - Enable buzzer sound on the sensor upon people crossing the line (boolean).
  • reboot_schedule - Daily automatic reboot time of the sensor in "HH:00" format. To disable reboot, send "OFF". If a value greater than "23:00" is sent, the reboot is disabled.
  • startup_sound - Allow melody playback upon device startup (boolean).
  • led_indication - Allow LED indicator operation upon crossings (boolean).
  • premium_days - Number of paid subscription days (number or string). Saved in DEVICE_STATUS.PREMIUM_DAYS.

4.3. data_request: Requesting Historical Data

Used by the server to remotely download archived 5-minute data for a specific day.

  • Inbound Topic: {mqtt_prefix}smx/server/{collector_serial}/data_request
  • JSON Request Format:
{
  "collector_serial": "141000222",
  "messageType": "data_request",
  "date": "20/05/26"
}
  • Sensor Behavior:
  • The day, month, and year are extracted from the incoming date string (strictly DD/MM/YY format is expected, e.g., 20/05/26 for May 20, 2026).
  • Date validity is checked. If the date is invalid, _SYNTAX_ERROR is returned.
  • The device searches for a binary log file for this date on the internal SD card.
  • If the file is found, all recorded 5-minute intervals for that day are read sequentially for all gates/zones, and 5_min_data packets (and/or zone packets inside_avg, inside_max, occupancy_begin, occupancy_duration) are formed and sent.
  • If there is no data on the SD card, the device returns an error_notification packet with the description "data not found" to the publication topic.

4.4. reset: Forced Device Reboot

Sending this command immediately triggers a software reboot of the sensor.

  • Inbound Topic: {mqtt_prefix}smx/server/{collector_serial}/reset
  • JSON Request Format:
{
  "collector_serial": "141000222",
  "messageType": "reset"
}