> 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/application-guides/sdm01-g2x-and-combo-gen2-ev-charger-dlb-integration-guide.md).

# SDM01 G2X & Combo Gen2 — EV Charger DLB Integration Guide

A complete technical guide to integrate the SDM01 Combo Gen2 and SDM01 G2X smart meters via Wi-Fi for Dynamic Load Balancing (DLB)

{% hint style="info" %}
**Status:** Active| **Applies to:** SDM01 G2X and SDM01 Combo Gen2 | **Firmware:** V10+  | **Audience:** EV Charger Product Managers & Firmware Engineers| **Last Updated:** 2026-08-01
{% endhint %}

***

### TL;DR — Quick Decision Card

```
What is your target DLB polling interval?

≤ 1 second (high-frequency, fastest response)
└── Raw UDP / UDP AES  ← Strongly recommended
    Push-based, zero connection overhead, lowest latency
    See Section 5.1

1–5 seconds (mid-frequency, covers most residential DLB use cases)
├── Raw UDP (still the simplest option)
├── HTTP polling (if your MCU already has an HTTP client stack)
└── Modbus TCP (if you have an existing Modbus stack)
    ⚠️ Single-connection limit — see Section 5.2 warning

> 5 seconds (low-frequency monitoring / energy logging)
└── HTTP polling (simplest, same JSON format as UDP)
    See Section 5.4

Configuration writes (one-shot)
├── HTTP POST  ← Primary local channel
│   See Section 5.4
├── MQTT       ← Cloud / remote configuration
└── BLE API    ← Local mobile configuration (BT Powerlink app or custom app)

Security compliance required (EN 18031)?
├── UDP AES (encrypted push, maintains low latency)  ← Recommended
└── WSS or Modbus TCP over TLS
    ⚠️ Pro firmware: max 2 concurrent TLS connections total recommended
    See Section 5.3 & 5.5

Multi-charger setup?
└── See Annex A for architecture options
   (Centralized Arbiter / OCPP Cloud Coordination)
```

***

### 1. Purpose & Scope

This guide helps EV charger **product managers** and **firmware/embedded engineers** integrate the [SDM01 G2X](https://docs.bituo-technik.com/product-document/sdm-series/sdm01-g2x) and [SDM01 Combo Gen2](https://docs.bituo-technik.com/product-document/sdm-series/sdm01-combo-gen2) smart energy meters into an EV charging system over a local Wi-Fi/LAN network to implement **Dynamic Load Balancing (DLB)** — also known as anti-tripping or load management.

<figure><img src="https://68488808-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTmsWivaZjkubbVKrCezC%2Fuploads%2F4RAt3qjGdLFxUsDfgnhb%2Fimage.png?alt=media&amp;token=d7349cff-be11-492a-808f-f29828fd2093" alt=""><figcaption></figcaption></figure>

**What DLB does:** By continuously monitoring the total grid import current ($$I\_{grid}$$) at the home's main incomer, the EV charger dynamically adjusts its charging current so that the total household load never exceeds the main circuit breaker rating ($$I\_{max}$$), preventing nuisance tripping.

**What this guide covers:**

* System architecture and control flow
* Electrical installation reference
* Wi-Fi provisioning and device discovery
* Communication protocol selection (Raw UDP, HTTP, Modbus TCP, MQTT, WSS)
* DLB closed-loop control logic and fail-safe design
* Testing and validation checklist
* Advanced: Multi-charger DLB and HEMS integration
* Advanced: Custom ESP32-C6 firmware development

***

### 2. System Architecture Overview

#### 2.1 Control Flow

<table><thead><tr><th width="167">Step</th><th width="239">Actor</th><th>Action</th></tr></thead><tbody><tr><td><strong>① Provision</strong></td><td>User / Installer</td><td>Configure meter Wi-Fi via BLE (BT Powerlink app or custom app via BLE API)</td></tr><tr><td><strong>② Discover</strong></td><td>EV Charger (Main MCU)</td><td>Auto-discover meter IP on LAN via mDNS</td></tr><tr><td><strong>③ Communicate</strong></td><td>EV Charger (Main MCU)</td><td>Receive high-frequency UDP pushes (or poll via Modbus TCP / HTTP)</td></tr><tr><td><strong>④ Control</strong></td><td>EV Charger (Main MCU)</td><td>Run DLB closed-loop algorithm, adjust PWM duty cycle</td></tr><tr><td><strong>⑤ Fail-Safe</strong></td><td>EV Charger (Main MCU)</td><td>On comms timeout, immediately ramp down to safe current</td></tr></tbody></table>

> 💡 **Configuring the UDP target address:** The meter needs to know which IP:Port to push UDP data to. This can be configured via any of the following channels:
>
> * **LAN HTTP** — `POST http://<meter-ip>/save-config` with `{"cmd":"udp","IpAddress":"<charger-ip>","localUdpPort":<port>}` from the charger MCU or any LAN client
> * **BLE** — via BT Powerlink app or your own app using the BLE Secured API (local, no internet required)
> * **Cloud MQTT** — via your app → cloud MQTT broker → meter (requires meter to be online)

#### 2.2 Key Parameters

<table><thead><tr><th width="123">Symbol</th><th width="444">Description</th><th>Typical Value</th></tr></thead><tbody><tr><td><span class="math">I_{max}</span></td><td>Main circuit breaker rating (set by user)</td><td>e.g. 60 A</td></tr><tr><td><span class="math">I_{safe}</span></td><td>Safety headroom (10–20% of <span class="math">I_{max}</span>)</td><td>e.g. 6 A</td></tr><tr><td><span class="math">I_{grid}</span></td><td>Real-time total grid import current (from meter)</td><td>Live reading</td></tr><tr><td><span class="math">I_{ev}</span></td><td>Current EV charger output current</td><td>Live reading</td></tr><tr><td><span class="math">I_{available}</span></td><td>Dynamically available current for EV charging</td><td>Calculated</td></tr></tbody></table>

**Core DLB formula:**

$$I\_{available} = I\_{max} - I\_{safe} - (I\_{grid} - I\_{ev})$$

> $$(I\_{grid} - I\_{ev})$$ represents the baseline load of all other household appliances.

***

### 3. Electrical Installation

> ⚠️ **Safety Notice:** Installation must be performed by qualified electricians only. Always de-energize the circuit before wiring.

#### 3.1 Typical Installation Position

The meter should be installed at the **main incomer** (grid entry point) of the consumer unit, **upstream of all loads including the EV charger**. This ensures $$I\_{grid}$$ reflects the true total household consumption.

#### 3.2 CT Orientation

The split-core CTs must be installed with the **correct polarity** (arrow pointing toward the load / away from the grid). Reversed CT orientation will result in negative power readings during normal import, which will break the DLB logic.

* **Positive value** = importing from grid (normal consumption)
* **Negative value** = exporting to grid (e.g. solar surplus)

#### 3.3 Supported CT Ratings

<table><thead><tr><th width="354">CT Rated Current</th><th>CT Aperture</th></tr></thead><tbody><tr><td>50 A</td><td>Ø10 mm</td></tr><tr><td>120 A</td><td>Ø16 mm</td></tr><tr><td>300 A</td><td>Ø24 mm</td></tr><tr><td>400 A</td><td>Ø36 mm</td></tr></tbody></table>

***

### 4. Network Configuration & Device Discovery

#### 4.1 Wi-Fi Provisioning (BLE)

The meter connects to your **2.4 GHz Wi-Fi** network. Provisioning is done via BLE. Two paths are available:

**Path A — BT Powerlink App (End-user / Installer)**

1. Download the **BT Powerlink** app.
2. **Scan the QR code** on the meter OR scan for nearby meters via BLE → select the target device.
3. Enter your router's SSID and password → push to the meter.
4. The meter connects to Wi-Fi and obtains an IP address via DHCP.

**Path B — Integrate BLE Provisioning into Your Own App (OEM)**

If you are building your own EV charger companion app and want to provision the meter directly from within it, use Bituo's BLE API:

> 💡 For SDM01 G2X and Combo Gen2, always use the **BLE Secured API**. The BLE Basic API is for Gen1 only and is NRND (Not Recommended for New Designs).

> 💡 **Best Practice:** After provisioning, configure a **DHCP static IP reservation** on the router (bound to the meter's MAC address) to prevent IP changes after router reboots.

#### 4.2 Automatic Device Discovery (mDNS)

* **Service type:** `_http._tcp.local`
* **Hostname format:** `energysensor-{model}-{mac}.local`
* **Example:** `energysensor-SDM01-c8b0d137f7c4.local`

Resolving this hostname always returns the meter's current IP, even after a DHCP lease renewal.

**Fallback — HTTP probe:**

```
GET http://<ip>/model
GET http://<ip>/sn/
```

A valid JSON response confirms the device is an SDM01 meter.

***

### 5. Communication Protocol Reference

#### 🎯 Protocol Selection Matrix

| Protocol       | Direction              | Recommended Interval            | Best For                                               | Encryption Option              |
| -------------- | ---------------------- | ------------------------------- | ------------------------------------------------------ | ------------------------------ |
| **Raw UDP**    | Meter → Charger (Push) | **0.5–1 s**                     | High-freq DLB, lowest latency                          | UDP AES                        |
| **HTTP**       | Charger → Meter (Poll) | **3–5 s**                       | Mid/low-freq DLB, config writes                        | HTTPS (Pro only)               |
| **Modbus TCP** | Charger → Meter (Poll) | **3–5 s**                       | Existing Modbus stack; single-charger only ⚠️          | Modbus TCP over TLS (Pro only) |
| **MQTT**       | Meter → Broker (Push)  | **1–5 s**                       | Multi-charger with Linux master / HEMS controller      | MQTTS                          |
| **WebSocket**  | Bidirectional          | **Continuous real-time stream** | Persistent real-time telemetry & bidirectional control | WSS (Pro only)                 |

> ⚠️ **TLS Concurrency Limit (Pro firmware):** The Gen2 Pro firmware supports a **maximum of 2 concurrent TLS connections recommended**, selecting from: Modbus TCP over TLS, HTTPS, MQTTS, and WSS. Plan your security architecture accordingly.

> ❌ **Never use HTTPS for high-frequency polling (such as < 3 s interval).** Every HTTPS request triggers a full TLS handshake on the ESP32-C6 SoC, saturating the CPU and causing watchdog resets. HTTPS is only acceptable for low-frequency queries or one-shot configuration writes.

> 💡 **WebSocket vs WSS:** Plain WebSocket (`ws://`) is sufficient for most LAN DLB deployments. Use WSS (`wss://`) only when your security policy or compliance requirement (e.g. EN 18031) mandates encrypted transport. WSS counts as 1 TLS connection toward the Gen2 Pro 2-connection limit.

***

#### 5.1 Raw UDP — Primary Protocol for High-Frequency DLB

**Best for:** Any DLB scenario requiring ≤ 1 s data freshness. The simplest and most efficient integration path.

| Parameter            | Value                                                       |
| -------------------- | ----------------------------------------------------------- |
| Transport            | **UDP (connectionless)**                                    |
| Target IPs           | Up to **5 unicast targets** configured via BT Powerlink app |
| Direction            | Meter **pushes** JSON to each configured target IP:Port     |
| Recommended interval | **0.5–1 second** (configurable, min \~0.5 s)                |
| Encryption           | Cleartext (default) / **UDP AES** (enable via app)          |

> 📌 **How UDP targeting works:** The meter performs **5 independent unicast sends** per interval — one to each configured target. There is no broadcast or multicast. Each target is an individual `IP:Port` pair configured in the BT Powerlink app (or via HTTP API). This means a maximum of **5 simultaneous receivers** (e.g. charger A, charger B, HEMS gateway, monitoring system) can receive data directly from one meter. For more than 5 receivers, use a Leader-Follower or HEMS gateway architecture (see Annex A).

> 📌 **Multicast support:** Multicast UDP delivery is planned for a future firmware release, which will remove the 5-target limit for LAN broadcast scenarios.

**5.1.1 Full Payload Example**

```json
{
  "Post": 142,
  "Time": 1785567041,
  "IP": "192.168.50.166",
  "Rssi": -46,
  "FWVersion": "3.1.7",
  "SerialNumber": "C8B0D137F7C4",
  "ProductModel": "SDM01_3PN",
  "MCUVersion": "001.01.00",
  "TP": 8,
  "VoltageX": "225.0",
  "VoltageY": "224.8",
  "VoltageZ": "224.8",
  "CurrentX": "0.000",
  "CurrentY": "0.000",
  "CurrentZ": "0.000",
  "ActivePowerX": "0.000",
  "ActivePowerY": "0.000",
  "ActivePowerZ": "0.000",
  "ReactivePowerX": "0.000",
  "ReactivePowerY": "0.000",
  "ReactivePowerZ": "0.000",
  "ApparentPowerX": "0.000",
  "ApparentPowerY": "0.000",
  "ApparentPowerZ": "0.000",
  "PowerFactorX": "1.00",
  "PowerFactorY": "1.00",
  "PowerFactorZ": "1.00",
  "UnbalanceLineCurrents": "0",
  "OverallPowerFactor": "1.00",
  "Frequency": "50.03",
  "ForwardEnergyX": "0.33",
  "ForwardEnergyY": "0.14",
  "ForwardEnergyZ": "0.47",
  "ReverseEnergyX": "0.00",
  "ReverseEnergyY": "0.00",
  "ReverseEnergyZ": "0.00"
}
```

**5.1.2 Field Reference**

The JSON payload is self-explanatory. Fields fall into two categories:

**Device & Session Fields** — metadata about the device and this packet: `Post` (sequence counter, increments by 1 each push — use to detect missed packets), `Time` (Unix timestamp), `IP` (meter's current LAN IP), `Rssi` (Wi-Fi signal strength in dBm), `FWVersion` / `MCUVersion` (firmware versions), `SerialNumber` (MAC-based unique device ID), `ProductModel` (e.g. `SDM01_3PN` = 3-phase 4-wire), `TP` (reporting interval in seconds).

**Electrical Measurement Fields** — per-phase readings for Voltage, Current, Active/Reactive/Apparent Power, Power Factor, and Energy. Phase suffix: `X` = L1, `Y` = L2, `Z` = L3.

> ⭐ **For DLB, the only fields you need are `CurrentX`, `CurrentY`, and `CurrentZ` (unit: Amperes).** Everything else is optional telemetry.

> ⚠️ **All measurement values are strings** (quoted numbers). Always parse with `float()` before arithmetic.

**5.1.3 Derived Values for DLB**

```python
I_X = float(payload["CurrentX"])
I_Y = float(payload["CurrentY"])
I_Z = float(payload["CurrentZ"])

# Option A: Worst-phase current — RECOMMENDED default
# Protects the most loaded single-phase breaker from tripping
I_grid = max(I_X, I_Y, I_Z)

# Option B: Sum of all phases — for 3-phase symmetric load budgeting
I_grid_total = I_X + I_Y + I_Z

```

> **Recommendation:** Use **Option A** (`max`) as the default DLB strategy. It is the most conservative and protects against single-phase breaker trips in unbalanced households.

**5.1.4 Sign Convention**

* **Positive** current / active power = **importing** from grid (normal consumption)
* **Negative** current / active power = **exporting** to grid (e.g. solar surplus)

**5.1.5 UDP AES (Encrypted Variant)**

Enable via BT Powerlink app. Payload structure and field names are **identical** to cleartext UDP; only the transport layer is AES-encrypted. The encryption key is the **broadcast key** derived during BLE secure pairing, shared between the meter and the paired app.&#x20;

***

#### 5.2 Modbus TCP — Mid-Frequency Polling for Single-Charger Deployments

**Best for:** Charger platforms with an existing Modbus TCP stack, at **3–5 s polling intervals**.

> ⚠️ **Critical: Single-Connection Limitation** The firmware supports **only ONE concurrent TCP connection** and actively resets the socket after each read request. You must:
>
> * Open a new TCP connection before each read
> * Close it immediately after
> * Wait a minimum of **150 ms** between consecutive reads
>
> **Practical implication for DLB:** Modbus TCP is suitable for **single-charger + single-meter** deployments only. If any other device on the same LAN attempts to poll the meter simultaneously (e.g. a monitoring tool, HEMS gateway, or another charger), the meter will reject the concurrent connection — which may disrupt your charger's DLB data acquisition. For multi-client or multi-charger scenarios, use Raw UDP or MQTT instead.

| Parameter             | Value                                            |
| --------------------- | ------------------------------------------------ |
| Port                  | **502** (TCP)                                    |
| Role                  | EV Charger = **Master**; Meter = **Slave**       |
| Slave ID              | `1` (default)                                    |
| Byte Order            | Big-Endian (**AB CD**)                           |
| Recommended poll rate | **3–5 s** (stable); 1–2 s (acceptable with care) |
| Function Codes        | `0x03`, `0x04` (read); `0x06` (write/control)    |

**Register Map — Key DLB Registers (Float32, AB CD)**

<table><thead><tr><th width="150">Address (Dec)</th><th width="147">Address (Hex)</th><th>Description</th><th>Unit</th></tr></thead><tbody><tr><td>1006</td><td><code>0x03EE</code></td><td>Current Phase A (L1)</td><td>A</td></tr><tr><td>1008</td><td><code>0x03F0</code></td><td>Current Phase B (L2)</td><td>A</td></tr><tr><td>1010</td><td><code>0x03F2</code></td><td>Current Phase C (L3)</td><td>A</td></tr><tr><td>1012</td><td><code>0x03F4</code></td><td>Active Power Phase A</td><td>kW</td></tr><tr><td>1014</td><td><code>0x03F6</code></td><td>Active Power Phase B</td><td>kW</td></tr><tr><td>1016</td><td><code>0x03F8</code></td><td>Active Power Phase C</td><td>kW</td></tr><tr><td>1044</td><td><code>0x0414</code></td><td>Total Active Power</td><td>kW</td></tr></tbody></table>

> 💡 **Modbus TCP over TLS** is available on Gen2 Pro firmware. Note the 2-connection TLS concurrency limit.

***

#### 5.3 MQTT — Multi-Charger / HEMS Local Controller Scenarios

**Best for:** Multi-charger deployments where a **Linux-based master charger** or a dedicated **HEMS Local Controller** (e.g. Home Assistant, OpenHAB, custom Linux gateway) can run a local MQTT broker.

> 📌 **Hardware prerequisite:** Running a local MQTT broker (e.g. Mosquitto, \~5 MB RAM) requires a Linux-capable host. This is **not suitable** for resource-constrained embedded MCUs (FreeRTOS / bare-metal). If your charger MCU cannot run a broker, use Raw UDP (up to 5 unicast targets) or the Leader-Follower architecture instead (see Annex A).

| Parameter             | Value                                                   |
| --------------------- | ------------------------------------------------------- |
| Port                  | **1883** (MQTT) / **8883** (MQTTS)                      |
| Direction             | Meter **publishes** to broker; charger(s) **subscribe** |
| Configurable interval | **1–30 s** (default: 5 s; adjustable to 1 s)            |
| QoS                   | 0 (telemetry `/data`), 0/1 (commands `/cmd`)            |

**Topic Architecture**

| Topic                | Direction      | Description                                   |
| -------------------- | -------------- | --------------------------------------------- |
| `{Model}/{SN}/data`  | Meter → Broker | Periodic telemetry (energy data)              |
| `{Model}/{SN}/cmd`   | Broker → Meter | Commands to meter                             |
| `{Model}/{SN}/cdata` | Meter → Broker | Command execution responses                   |
| `{Model}/{SN}/mdata` | Meter → Broker | Device metadata (published on boot, retained) |

**Example topics for SDM01\_3PN, SN C8B0D137F7C4:**

```
SDM01_3PN/C8B0D137F7C4/data
SDM01_3PN/C8B0D137F7C4/cmd
```

**MQTT Payload**

The MQTT `/data` payload is **structurally identical** to the UDP payload, with two additions:

* `TotalActivePower` — pre-calculated sum of all three phases (kW) ✅
* `TotalForwardEnergy` — pre-calculated total imported energy (kWh) ✅

These pre-calculated totals make MQTT slightly more convenient for DLB than UDP (no need to sum phases manually).

> 💡 **MQTTS:** Supported on all firmware branches. Counts as 1 TLS connection toward the Gen2 Pro 2-connection limit.

***

#### 5.4 HTTP — Mid/Low-Frequency Polling & Primary Configuration Channel

**Best for:** 3–5 s interval DLB polling (when UDP is not implemented), one-shot configuration writes, and diagnostic queries.

| Parameter             | Value                                     |
| --------------------- | ----------------------------------------- |
| Port                  | **80** (HTTP) / **443** (HTTPS, Pro only) |
| Recommended poll rate | **3–5 s** for DLB; ≤ once/min for HTTPS   |
| Response format       | **Identical JSON to UDP payload**         |

> 📌 **HTTP is the primary local configuration channel.** All device settings (UDP target IPs, MQTT broker address, reporting intervals, etc.) are written via HTTP POST. MQTT and BLE API are alternative configuration channels — see TL;DR.

> ⚠️ **Do NOT use HTTPS for DLB polling intervals < 3 s.** Each HTTPS request requires a full TLS handshake. At 1 s intervals this will saturate the ESP32-C6 CPU. HTTPS is acceptable for ≥ 3 s intervals or one-shot config writes only.

**Key endpoints:**

```
GET  http://<ip>/data          → Returns full JSON payload (same as UDP)
GET  http://<ip>/model         → Returns device model string
GET  http://<ip>/sn/           → Returns serial number
POST http://<ip>/config        → Write configuration parameters
```

***

#### 5.5 WebSocket — Persistent Real-Time Connection

**Best for:** Scenarios requiring a persistent connection for continuous real-time data streaming and bidirectional control (e.g. Home Assistant local integration, custom dashboards).

| Parameter                   | Value                    |
| --------------------------- | ------------------------ |
| Plain WebSocket (`ws://`)   | Port **81**              |
| Secure WebSocket (`wss://`) | Port **502** (or custom) |

> 💡 **Use plain WebSocket (`ws://`) by default.** WebSocket keeps the connection open, so the meter can push data continuously at full rate — equivalent to UDP in terms of data freshness, but with a persistent TCP channel. Only upgrade to WSS when your security policy or compliance requirement (e.g. EN 18031) explicitly mandates encrypted transport.

> 💡 WSS establishes a **persistent connection** — the TLS handshake happens only once at connection setup, then data flows with negligible overhead. This is why WSS is preferred over HTTPS for encrypted real-time data when TLS is required.

> ⚠️ WSS counts as 1 TLS connection toward the Gen2 Pro 2-connection limit.

For the complete JSON message format and command reference, see the **WebSocket API Protocol** documentation.

***

### 6. DLB Control Logic Implementation

#### 6.1 Threshold Configuration

| Parameter         | How to Set                                   | Example |
| ----------------- | -------------------------------------------- | ------- |
| $$I\_{max}$$      | User sets main breaker rating in charger app | 60 A    |
| $$I\_{safe}$$     | Fixed at 10–20% of $$I\_{max}$$              | 6 A     |
| Fallback current  | User configures (min 6 A per IEC 61851)      | 6 A     |
| Timeout threshold | 5–15 s (configurable)                        | 10 s    |

#### 6.2 Control Loop (Pseudocode)

```python
# DLB Control Loop — runs every 1 second (UDP) or every poll interval (HTTP/Modbus)
def dlb_loop():
    data = receive_meter_data()   # UDP packet, HTTP response, or Modbus read

    I_X = float(data["CurrentX"])
    I_Y = float(data["CurrentY"])
    I_Z = float(data["CurrentZ"])
    I_grid = max(I_X, I_Y, I_Z)  # Worst-phase strategy (recommended default)

    I_available = I_max - I_safe - (I_grid - I_ev)

    if I_grid > (I_max - I_safe):
        # RAMP DOWN — must complete within 2 seconds (safety-critical)
        I_ev_new = max(MIN_CURRENT, I_ev - STEP_DOWN)
        set_pwm_current(I_ev_new)

    elif I_available > I_ev + STEP_UP_THRESHOLD:
        # RAMP UP — slow and gradual to prevent oscillation
        if time_since_last_increase >= RAMP_UP_INTERVAL:
            I_ev_new = min(I_ev + 1, I_available)
            set_pwm_current(I_ev_new)

    if I_available < MIN_CURRENT:   # MIN_CURRENT = 6A per IEC 61851-1
        suspend_charging()
        wait_for_headroom()
```

> 📌 **Control parameters** (STEP\_DOWN, STEP\_UP\_THRESHOLD, RAMP\_UP\_INTERVAL, etc.) are charger-side design decisions. The values above are illustrative only. Charger manufacturers should tune these based on their own product requirements, grid conditions, and EV compatibility testing.

#### 6.3 Control Strategy Summary

| Condition                            | Action                                     | Speed                           |
| ------------------------------------ | ------------------------------------------ | ------------------------------- |
| $$I\_{grid} > I\_{max} - I\_{safe}$$ | Ramp **down** PWM immediately              | **Fast: within 2 s**            |
| $$I\_{available}$$ has surplus       | Ramp **up** PWM gradually (+1A steps)      | **Slow: configurable interval** |
| $$I\_{available} < 6A$$              | **Suspend** charging (IEC 61851-1 minimum) | Immediate                       |
| Data timeout                         | Trigger **Fallback** (see Section 6.4)     | Within timeout window           |

> **Why asymmetric speed?** Fast ramp-down prevents breaker trips (safety-critical). Slow ramp-up prevents control oscillation and avoids triggering the EV's BMS protection. Specific ramp rates and intervals are charger-side design decisions.

#### 6.4 Fail-Safe / Fallback Mechanism

> ⚠️ **This section is critical.** A DLB system that silently continues full-power charging when meter comms are lost is worse than no DLB at all.

**Trigger:** No meter data received for **10 consecutive seconds** (configurable, recommended range: 5–15 s).

**Fallback actions (in order):**

1. Immediately force charging current to minimum safe value (6 A).
2. If user enabled "Stop on comms loss": open relay and suspend charging.
3. Activate fault indicator + push notification: *"DLB communication lost"*.

**Recovery:** After **3 consecutive successful data reads/packets**, automatically exit Fallback and resume dynamic regulation.

***

### 7. Custom Firmware Path (Advanced)

> For EV charger manufacturers who prefer to run **proprietary firmware** on the meter's Wi-Fi SoC instead of using Bituo's stock firmware.

#### 7.1 Why Custom Firmware?

* Full control over Wi-Fi stack, security policies, and OTA update mechanism
* Deep integration with your own cloud platform or MQTT broker
* Compliance with your own cybersecurity certification requirements
* Eliminate dependency on Bituo's firmware release cycle

#### 7.2 Hardware Architecture

```
┌─────────────────────────────────────────────────────┐
│             SDM01 G2X / Combo Gen2                  │
│                                                     │
│  ┌──────────────────┐      ┌─────────────────────┐  │
│  │  Wi-Fi/BLE SoC   │      │   Base Meter MCU    │  │
│  │   (ESP32-C6)     │◄────►│  (Metering + RS485) │  │
│  │                  │ UART │                     │  │
│  │  YOUR FIRMWARE   │      │  Calibration data   │  │
│  │  runs here       │      │  stored here        │  │
│  └──────────────────┘      └─────────────────────┘  │
│         │                           │               │
│      Wi-Fi                       RS485              │
└─────────────────────────────────────────────────────┘
```

**Key principle:** Flashing custom firmware on the ESP32-C6 **does not affect metering accuracy or calibration data**, which are stored independently in the Base Meter MCU.

#### 7.3 Internal Data Interface: Modbus over UART

The ESP32-C6 reads energy data from the Base Meter MCU via **Modbus RTU over UART** (internal bus, separate from the external RS485 port).

> **Gen2 register compatibility:** The internal UART Modbus register map is **identical to Gen1 (ESP8685)**. Refer to the [SDM01 Combo (ESP8685) Custom Firmware Guide](https://docs.bituo-technik.com/custom-firmware/sdm01-combo-esp8685) for the complete register address table and UART parameters.

> 🛑 **DANGER: LETHAL VOLTAGE.** Always disconnect from AC mains before connecting any UART adapter.&#x20;

***

### 8. Testing & Validation Checklist

> 📌 **Note:** The following checklist covers the key integration touchpoints between the SDM01 meter and the EV charger. It is intended as a **starting reference only** — each charger manufacturer will have their own validation methodology, reliability testing standards, and certification requirements that go well beyond the scope of this guide.

#### 8.1 Communication Stability

* [ ] Open a UDP socket listener; verify packets arrive at the configured interval; verify `Post` counter increments by 1 each packet
* [ ] Simulate router power cycle → verify charger re-discovers meter via mDNS within 60 s
* [ ] Simulate Wi-Fi disconnection → verify Fallback triggers within configured timeout
* [ ] **(Modbus TCP only)** Verify no second client is simultaneously polling the meter; test connection reset behavior
* [ ] **Anti-pattern test:** Poll via HTTPS at 1 Hz → verify SoC reboots (confirms why UDP/HTTP is necessary for high-frequency use)

#### 8.2 DLB Response Latency

* [ ] Connect a 3 kW resistive load suddenly to the household circuit
* [ ] Capture charger CP signal (PWM) with oscilloscope
* [ ] **Pass criterion:** PWM duty cycle reduces within **< 2 seconds** of load connection

#### 8.3 Boundary Conditions

* [ ] Test $$I\_{available}$$ oscillating around 6 A → verify no rapid suspend/resume toggling
* [ ] Test Fallback trigger → verify charger drops to 6 A within timeout
* [ ] Test Fallback recovery → verify charger exits Fallback after 3 successful reads
* [ ] Test $$I\_{available}$$ < 6 A → verify charger suspends (does not attempt sub-minimum current)

#### 8.4 Custom Firmware (if applicable)

* [ ] Verify internal UART Modbus reads match RS485 external port readings
* [ ] Verify custom OTA mechanism works independently of Bituo firmware updates

***

### 9. FAQ

| Question                                                                                                | Answer                                                                                                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **The meter's IP changed after a router reboot.**                                                       | Use mDNS: resolve `energysensor-SDM01-{mac}.local`. Or set a DHCP static IP reservation.                                                                                                                                                     |
| **Can I use HTTPS to poll every second?**                                                               | **No.** TLS handshakes will overheat the ESP32-C6 and cause reboots. Use Raw UDP for ≤ 1 s, or HTTP for 3–5 s intervals.                                                                                                                     |
| **What is the minimum charging current?**                                                               | 6 A per IEC 61851-1. If $$I\_{available}$$ < 6 A, suspend charging — do not attempt sub-minimum current.                                                                                                                                     |
| **How many chargers can receive UDP data simultaneously?**                                              | Up to **5** (5 independent unicast targets; multicast support is planned for a future firmware release). For > 5 chargers, use MQTT or Leader-Follower architecture.                                                                         |
| **If my charger is already using Modbus TCP, can another device also poll the meter at the same time?** | **Not recommended.** The meter supports only 1 concurrent Modbus TCP connection. Any second client will be rejected and may intermittently disrupt your charger's data acquisition. For multi-client scenarios, use Raw UDP or MQTT instead. |
| **Can I integrate BLE provisioning into my own app?**                                                   | Yes. Use the [BLE Secured API](https://docs.bituo-technik.com/device-api/spm-sdm-open-wi-fi-api-overview/ble-secured-api) for Gen2.                                                                                                          |
| **Does flashing custom firmware affect metering accuracy?**                                             | No. Calibration data is in the Base Meter MCU, unaffected by SoC firmware changes.                                                                                                                                                           |
| **What happens if the meter loses Wi-Fi during charging?**                                              | Charger detects data timeout (default 10 s) → Fallback: reduces to 6 A or suspends.                                                                                                                                                          |
| **How many TLS connections can Gen2 Pro handle simultaneously?**                                        | **Maximum 2 recommended**, selecting from: Modbus TCP over TLS, HTTPS, MQTTS, WSS. Plan your security architecture accordingly.                                                                                                              |

***

### Annex A — Multi-Charger DLB Architecture

#### A.1 Multi-Charger DLB Coordination — Architecture Comparison

> The two architectures below are both industry-validated and commonly seen in the field. **The "broadcast self-calculate" pattern — where each charger independently derives its own allocation from raw** $$I\_{grid}$$ **broadcast data — is generally not recommended**, as it requires real-time state synchronization between chargers and tends to be fragile when charger count changes or packets are dropped.

***

**🥇 Architecture A: Centralized Arbiter — Common for Residential & Small-Site**

Suitable for deployments where a single local controller coordinates all chargers. The **Arbiter** role can be fulfilled by:

* A designated charger (e.g., the first-installed or highest-rated unit), or
* A **local HEMS controller** or home energy gateway that already manages other loads (PV, battery, etc.)
* **Topology:** One entity acts as the **Arbiter**; all chargers it manages are **Followers**.
* **How it works:**
  * a. The Arbiter communicates with the smart meter (e.g., via UDP unicast), receiving $$I\_{grid}$$ data.
  * b. The Arbiter runs its allocation logic and determines an **individual current limit for each Follower**.
  * c. Each Follower's limit is delivered via LAN (e.g., UDP unicast, local MQTT, or a proprietary protocol).
* **SDM01 fit:** ✅ Up to 5 UDP unicast targets supported. The Arbiter (charger or HEMS controller) can receive meter push directly.
* **Typical advantages:**
  * Supports unequal power distribution and priority-based allocation
  * Fast trip-prevention response
  * Can leverage an existing HEMS controller without additional hardware

> ⚠️ **Note:** Each Follower should receive its **own dedicated current limit**, not the raw $$I\_{grid}$$ value. Allocation logic runs on the Arbiter side.

***

**🥈 Architecture B: OCPP Cloud Coordination — Common for Commercial Sites**

Suitable for commercial deployments or where multi-brand interoperability is required.

* **Topology:** All chargers connect to a cloud-based Charging Station Management System (CSMS) via OCPP 1.6J / 2.0.1.
* **How it works:**
  * a. The CSMS issues individual power/current limit schedules to each charger via `SetChargingProfile` (Smart Charging Profile).
  * b. Meter data is forwarded to the CSMS via MQTT/HTTP (directly or through a local HEMS gateway), allowing the CSMS to adjust profiles dynamically.
* **SDM01 fit:** ✅ Meter can publish data to a cloud CSMS via MQTT or HTTP, or via a local HEMS gateway.
* **Typical advantages:**
  * Open industry standard; cross-brand compatible
  * Supports advanced features: billing, scheduling, remote management
  * Scales well to larger sites

***

#### A.2 Architecture Comparison Summary

|                        | **Architecture A: Centralized Arbiter**    | **Architecture B: OCPP Cloud** |
| ---------------------- | ------------------------------------------ | ------------------------------ |
| **Arbiter**            | Charger or local HEMS controller           | Cloud CSMS                     |
| **Meter → Arbiter**    | UDP unicast (LAN)                          | MQTT / HTTP (cloud)            |
| **Arbiter → Chargers** | UDP unicast × N / local MQTT / proprietary | OCPP `SetChargingProfile`      |
| **SDM01 fit**          | ✅ Native                                   | ✅ Via MQTT / HTTP              |
| **Works offline**      | ✅ Yes                                      | ❌ No (cloud dependency)        |
| **Cross-brand**        | ❌ Typically same-ecosystem                 | ✅ OCPP standard                |
| **Best for**           | Residential / small site                   | Commercial / large site        |

***

#### A.3 Multi-Charger Current Distribution

This section outlines a **common approach** to current allocation in Architecture A. Charger manufacturers will typically implement their own allocation logic based on their product requirements — the following is provided as a reference pattern only.

**A.3.1 Available Current Calculation**

A typical starting point for the Arbiter's allocation calculation:

$$I\_{available} = I\_{max} - I\_{grid} + I\_{ev\_total}$$

Where:

* $$I\_{max}$$ — main breaker rated current
* $$I\_{grid}$$ — current grid import reading from the meter (e.g., worst phase)
* $$I\_{ev\_total}$$ — sum of current limits currently assigned to all active chargers (to avoid double-counting EV load already reflected in $$I\_{grid}$$)

**A.3.2 Common Allocation Strategies**

| Strategy                     | Description                                                     | Typical Use Case                           |
| ---------------------------- | --------------------------------------------------------------- | ------------------------------------------ |
| **Equal Share**              | $$I\_{available}$$ divided equally among all active sessions    | Simple same-charger deployments            |
| **Priority-Based**           | Higher-priority chargers receive allocation first               | VIP parking, fleet with SLA                |
| **Rated-Power Proportional** | Allocation proportional to each charger's rated maximum current | Mixed charger types (e.g., 7.4 kW + 22 kW) |

**A.3.3 Minimum Current Consideration (IEC 61851)**

Per IEC 61851-1, the minimum signalled current is **6 A**. Charger implementations typically handle the case where a calculated allocation falls below this threshold by suspending that session (signalling State B) and redistributing the quota — but the specific handling is left to the charger manufacturer's discretion.

**A.3.4 Ramp Behaviour Considerations**

* **Ramp-down** is typically applied quickly to all chargers when $$I\_{grid}$$ approaches the limit.
* **Ramp-up** is often staggered across chargers to reduce simultaneous inrush current risk.

The specific ramp rates and step sizes are implementation-defined by the charger manufacturer.

***

#### A.4 Multi-Level Fail-Safe Considerations

Single-charger fail-safe (§6) covers meter communication loss. In multi-charger deployments, additional failure scenarios are worth considering during system design.

**A.4.1 Common Failure Scenarios**

| Scenario                      | Typical Handling                                                                              |
| ----------------------------- | --------------------------------------------------------------------------------------------- |
| **Meter → Arbiter link lost** | Arbiter falls back to a conservative current limit for all chargers until meter comms recover |
| **Arbiter unavailable**       | Followers fall back to a safe local current limit (e.g., 6 A) after a timeout                 |
| **Follower goes offline**     | Arbiter may release that Follower's quota back to the pool for redistribution                 |
| **Meter + Arbiter both lost** | Followers suspend or reduce to minimum current independently                                  |

> 💡 The specific timeout values, fallback currents, and recovery sequences are implementation decisions for the charger manufacturer. The key principle is that **each layer should have an independent fallback** so that a single point of failure does not result in an uncontrolled overcurrent condition.

**A.4.2 Arbiter Recovery — General Considerations**

When the Arbiter recovers from a fault, it is generally advisable to:

1. Verify meter data is stable before resuming full allocation.
2. Re-query Follower states before recalculating limits.
3. Restore charging current gradually rather than all at once, to avoid simultaneous inrush from multiple EVs.
