> For the complete documentation index, see [llms.txt](https://docs.bituo-technik.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.bituo-technik.com/device-api/spm-sdm-open-wi-fi-api-overview/mqtt-api-reference.md).

# MQTT API Reference

## MQTT API Reference

{% hint style="info" %}
**Status:** Draft | **Applies to:** SPM/SDM Open WiFi (ESP32-8685)  | **Firmware:** Basic 5.1.14+ (SPM/SDM) / Basic 6.1.4+(SDM01 UART Flashing PIN) | **Updated:** 2026-06-23
{% endhint %}

### 1. Overview

The Bituo SPM/SDM series smart meters can communicate over MQTT using a **publish/subscribe** model. The device pushes telemetry data periodically and responds to JSON commands sent from the server.

**Important Notes for Firmware Basic 5.1.14+/6.1.4+:**

* Command architecture is unified with the BLE API.
* The `seq` (sequence) field is **deprecated** and no longer used in requests or responses.
* Command responses follow a standardized `ok/msg/event/d` structure.

***

### 2. Topic Architecture

All MQTT topics follow this default pattern: `{ProductModel}/{SerialNumber}/{TopicType}`

<table><thead><tr><th>Topic Suffix</th><th>Direction</th><th>Description</th><th width="142">QoS</th><th>Retain</th></tr></thead><tbody><tr><td><code>/data</code></td><td>Device → Server</td><td>Periodic telemetry data (e.g., Voltage, Current)</td><td>0</td><td>No</td></tr><tr><td><code>/cmd</code></td><td>Server → Device</td><td>Commands to device</td><td>0/1</td><td>No</td></tr><tr><td><code>/cdata</code></td><td>Device → Server</td><td>Command execution responses</td><td>0</td><td>No</td></tr><tr><td><code>/mdata</code></td><td>Device → Server</td><td>Device metadata (published on boot)</td><td>0</td><td><strong>Yes</strong></td></tr></tbody></table>

**Example Topics (for SPM02, SN: 9D1024BD51F1):**

* `SPM02/9D1024BD51F1/data`
* `SPM02/9D1024BD51F1/cmd`

***

### 3. Telemetry Data (`/data`)

The device publishes measurement data to the `/data` topic at a configurable interval (default: 30 seconds).

* **Note:** All measurement values are formatted as **Strings** (e.g., `"227.7"`).
* The `TP` field indicates the phase type (`1` for Single-Phase, `3` for Three-Phase). **Developers should parse the payload structure based on the `TP` value.**

#### 3.1 System Information Fields (Common)

These fields are included in all `/data` payloads regardless of the model:

| Field          | Type   | Description                                        |
| -------------- | ------ | -------------------------------------------------- |
| `Post`         | number | Packet sequence counter                            |
| `Time`         | number | Unix timestamp (seconds)                           |
| `IP`           | string | Device IP address                                  |
| `Rssi`         | number | Wi-Fi signal strength (dBm)                        |
| `FWVersion`    | string | Firmware version (e.g., `"5.1.12"`)                |
| `MCUVersion`   | string | MCU firmware version (e.g., `"001.01.10"`)         |
| `SerialNumber` | string | Device MAC/Serial Number                           |
| `ProductModel` | string | Product model (e.g., `"SPM01"`, `"SPM02"`)         |
| `TP`           | number | Phase Type (`1` = Single-Phase, `3` = Three-Phase) |

#### 3.2 Single-Phase Payload (TP: 1)

For single-phase devices (e.g., SPM01), measurement fields have no suffix.

```json
{
  "Post": 927,
  "Time": 1782313081,
  "IP": "192.168.50.188",
  "Rssi": -68,
  "FWVersion": "5.1.14",
  "SerialNumber": "9C0024BD51F1",
  "ProductModel": "SPM01",
  "MCUVersion": "003.00.13",
  "TP": 1,
  "Voltage": "227.6",
  "Current": "0.000",
  "ActivePower": "0.000",
  "ApparentPower": "0.000",
  "PowerFactor": "1.00",
  "Frequency": "50.09",
  "ForwardEnergy": "0.00",
  "ReverseEnergy": "0.00",
  "TotalEnergy": "0.00"
}
```

#### 3.3 Three-Phase Payload (TP: 3)

For three-phase devices (or devices operating in 3-phase mode like SPM02), measurement fields use **X/Y/Z** suffixes.

```json
{
  "Post": 1842,
  "Time": 1782312995,
  "IP": "192.168.50.238",
  "Rssi": -72,
  "FWVersion": "5.1.14",
  "SerialNumber": "50701B597664",
  "ProductModel": "SPM02",
  "MCUVersion": "001.01.01",
  "TP": 3,
  "VoltageX": "226.3",
  "VoltageY": "226.2",
  "VoltageZ": "226.2",
  "CurrentX": "0.000",
  "CurrentY": "0.000",
  "CurrentZ": "0.000",
  "ActivePowerX": "0.000",
  "ActivePowerY": "0.000",
  "ActivePowerZ": "0.000",
  "TotalActivePower": "0.000",
  "ReactivePowerX": "0.000",
  "ReactivePowerY": "0.000",
  "ReactivePowerZ": "0.000",
  "ApparentPowerX": "0.000",
  "ApparentPowerY": "0.000",
  "ApparentPowerZ": "0.000",
  "PowerFactorX": "0.00",
  "PowerFactorY": "0.00",
  "PowerFactorZ": "1.00",
  "UnbalanceLineCurrents": "0",
  "OverallPowerFactor": "0.00",
  "Frequency": "50.01",
  "ForwardEnergyX": "0.85",
  "ForwardEnergyY": "0.02",
  "ForwardEnergyZ": "0.02",
  "TotalForwardEnergy": "0.89",
  "ReverseEnergyX": "0.00",
  "ReverseEnergyY": "0.00",
  "ReverseEnergyZ": "0.00",
  "TotalReverseEnergy": "0.00"
}
```

***

### 4. Metadata (`/mdata`)

Published once upon device boot with the **Retain** flag set. Useful for discovering device basic info without waiting for telemetry.

```json
{
  "product": "EnergySensor-SPM01-9C0024BD51F1",
  "Serialnumber": "9C0024BD51F1",
  "fwVer": "5.1.12"
}
```

***

### 5. Command & Control (`/cmd` & `/cdata`)

#### 5.1 Standard Message Format

**Request (`/cmd`):** A JSON object containing at least the `cmd` string.

```json
{
  "cmd": "location"
}
```

**Response (`/cdata`):** A standardized JSON object returning the execution result.

```json
{
  "ok": true,
  "msg": "location received",
  "event": "location",
  "d": {} 
}
```

* `ok` (boolean): Success or failure.
* `msg` (string): Result description or error message.
* `event` (string): Echoes the requested command.
* `d` (object): Optional. Contains requested data payload.

#### 5.2 Supported Commands Reference

**`getFunctionMap` - Read Device Capabilities**

Reads the 16-bit function bitmap indicating enabled services (e.g., MQTT, HTTP).

* **Request:** `{"cmd": "getFunctionMap"}`
* **Response:**

  ```json
  {
    "ok": true,
    "msg": "",
    "event": "getFunctionMap",
    "d": { "functionMap": 640 }
  }
  ```

**`model` - Read Device Configuration**

Returns a snapshot of the device's network and MQTT configuration.

* **Request:** `{"cmd": "model"}`
* **Response:**

  ```json
  {
    "ok": true,
    "msg": "",
    "event": "model",
    "d": {
      "WN": "Bituo-ext",
      "MH": "broker.emqx.io",
      "MF": true,
      "MP": 8883,
      "MS": true
    }
  }
  ```

**`location` - Identify Device**

Triggers the device LED/Buzzer to flash/beep for 15 seconds.

* **Request:** `{"cmd": "location"}`
* **Response:** `{"ok": true, "msg": "location received", "event": "location"}`

**`zero` - Reset Energy Counters**

⚠️ **Irreversible.** Resets all accumulated energy counters to zero.

* **Request:** `{"cmd": "zero"}`
* **Response:** `{"ok": true, "msg": "zero received", "event": "zero"}`

**`restart` - Reboot Device**

Triggers a soft reboot.

* **Request:** `{"cmd": "restart"}`
* **Response:** `{"ok": true, "msg": "restart received", "event": "restart"}`

**`wifi` - Configure Wi-Fi**

Updates Wi-Fi credentials.

* **Request:**

  ```json
  {
    "cmd": "wifi",
    "ssid": "YourSSID",
    "pass": "YourPassword"
  }
  ```

**`mqtt` - Configure MQTT Broker**

Updates MQTT broker settings.

* **Request:**

  ```json
  {
    "cmd": "mqtt",
    "data": "broker.emqx.io|client_id|1|8883|30|user|pwd"
  }
  ```

  *(Format: `host|clientid|ssl(1/0)|port|interval|username|password`)*

***

### 6. How to Configure MQTTS (TLS/SSL)

The device supports secure MQTT connections over **TLS 1.2** and **TLS 1.3** to ensure data encryption and prevent man-in-the-middle attacks. Follow these steps to configure MQTTS via the embedded Web UI.

#### Step 1: Access the Embedded Web UI

1. Open a web browser and enter the device's IP address (e.g., `http://192.168.50.208`).
2. **Troubleshooting:** If the web page is inaccessible, the HTTP service might be disabled on the device. You can enable it using the **BT Powerlink APP** or the **WeChat Mini APP**:
   * Open the App and connect to the device via Bluetooth.
   * Navigate to **Settings** -> **Forwarding**.
   * Turn on the **HTTP** toggle.

#### Step 2: Upload the CA Certificate

To establish a trusted TLS connection, the device needs the Root CA certificate of your MQTT broker.

1. In the Web UI, navigate to **Edit** -> **Forwarding** -> **Upload MQTT CA certificate**.
2. Click **Choose File** and select your CA certificate file (must be in PEM format, usually `.pem` or `.crt`).
3. Click **Upload**.

#### Step 3: Configure MQTT Broker Settings

1. Navigate to **Edit** -> **Forwarding** -> **MQTT broker**.
2. **Check the `SSL / TLS` box** at the top.
3. Fill in your broker details.

**Example using EMQX Public Broker:**

* **Host:** `broker.emqx.io`
* **Port:** `8883` *(Standard secure MQTT port)*
* **Client ID / Username / Password:** Fill according to your needs.
* **ReportFrequency:** Set your desired interval (e.g., `30` seconds).
* Click **Save MQTT**.

> 💡 **Tip: How to get the EMQX CA Certificate?** If you are using `broker.emqx.io`, you can download their Root CA certificate directly from the EMQX official website (search for "EMQX Public Broker CA download"). Alternatively, you can visit `https://broker.emqx.io` in your browser, click the "Lock" icon in the address bar, view the certificate details, and export the Root CA as a Base64 encoded `.cer` or `.crt` file.

#### Step 4: Reboot to Apply Changes

After saving the configuration, the device must be rebooted for the new TLS settings and certificates to take effect.

1. Look at the top right corner of the Web UI dashboard.
2. You will see a notification: *"Configuration was sent. Enable restart when you are ready to reboot the device."*
3. Check the **"Send restart command"** box. The device will reboot immediately and attempt to connect to your broker using MQTTS.
4. Once rebooted, you can verify the connection status at the top right of the dashboard (it should display `MQTT: Online`).

***

### 7. Appendix: Major Changes from Legacy API (v5.1.14-)

For developers migrating from the older firmware (e.g., v1.1.8) to the new Basic Firmware (5.1.12+), please note the following breaking changes. The architecture has been unified with the BLE standard to improve efficiency and reduce payload sizes.

#### 7.1 Quick Comparison Table

<table><thead><tr><th width="233">Feature / Concept</th><th>Legacy API (v5.1.13-)</th><th>Basic Firmware (v5.1.14+)</th></tr></thead><tbody><tr><td><strong>Topic Prefix</strong></td><td><code>bituotechnik/{Model}/...</code></td><td><code>{Model}/...</code> <em>(Prefix removed)</em></td></tr><tr><td><strong>Command Format</strong></td><td>Uppercase (e.g., <code>RDATA</code>, <code>WINT</code>)</td><td>Lowercase / BLE semantics (e.g., <code>location</code>)</td></tr><tr><td><strong>Request Tracking</strong></td><td>Uses <code>seq</code> (Sequence Number)</td><td><strong>Deprecated</strong>. Uses <code>event</code> field in response</td></tr><tr><td><strong>Response Format</strong></td><td><code>{"result": "SUCCESS", "seq": ...}</code></td><td><code>{"ok": true, "msg": "...", "event": "...", "d": {...}}</code></td></tr><tr><td><strong>Phase Indicator</strong></td><td>Implicit (relies on <code>DeviceType</code>)</td><td>Explicit <code>TP</code> field (<code>1</code> = Single, <code>3</code> = Three-Phase)</td></tr><tr><td><strong>New Telemetry Fields</strong></td><td>N/A</td><td><code>Time</code>, <code>IP</code>, <code>MCUVersion</code></td></tr><tr><td><strong>Metadata (<code>/mdata</code>)</strong></td><td><code>macAddr</code>, <code>fwVer</code></td><td><code>product</code>, <code>Serialnumber</code>, <code>fwVer</code></td></tr></tbody></table>

#### 7.2 Detailed Change Notes

* **Command Architecture (BLE Unification):** The `seq` field is completely removed. Request/response matching is now handled via the `event` field in the response payload. Commands now strictly follow the BLE API semantics.
* **Telemetry Payload (`/data`):** Added the `TP` field to explicitly indicate phase type, replacing the old `DeviceType` logic. Payloads now include `Time` (Unix timestamp), `IP`, and `MCUVersion`. *(Note: Starting from v5.1.14, calculated totals like `TotalActivePower`, `TotalForwardEnergy`, and `TotalReverseEnergy` have been re-introduced to the 3-phase payload).*
* **Metadata (`/mdata`):** The JSON schema has been updated. The legacy `macAddr` field is replaced by `Serialnumber`, and a new `product` string is included.
