Skip to content
Get started

Xiaomi Body Scale

The xiaomi_body_scale sensor platform lets you track the output of the Xiaomi Smart Scale S200 and the Xiaomi Body Composition Scale S400 using a BLE tracker hub such as the ESP32 BLE Tracker. This component listens passively to BLE advertisement packets and does not pair with the device, so ESPHome has no impact on battery life.

The scale broadcasts encrypted MiBeacon packets (UUID 0xFE95). A bindkey is required to decrypt the payload; see Getting the Bindkey.

The S200 reports weight and profile ID only. The S400 also measures impedance and heart rate. A bare feet S400 measurement produces two BLE packets; with socks, only the first packet is sent:

  • Packet 1 — weight + heart rate + impedance_low only (50 kHz, low frequency, larger value)
  • Packet 2 — impedance_high (250 kHz, high frequency, smaller value)

NOTE

Impedance naming convention follows the BIA standard used by bodymiscale: low/high refers to the measurement frequency, not the numerical value. At 50 kHz, current flows only through extracellular fluid → higher resistance. At 250 kHz, current penetrates cell membranes → lower resistance.


Device IDModelName
0x45C9MJTZC02YMSmart Scale S200
0x4C04MJTZC02YMSmart Scale S200
0x4DCBMJTZC02YMSmart Scale S200
0x30D9MJTZC01YMBody Composition Scale S400
0x3BD5MJTZC01YMBody Composition Scale S400 White
0x48CFMJTZC01YMBody Composition Scale S400 Blue
0x4B05MJTZC03YMBody Composition Scale S400 Pro

# Example configuration entry
esp32_ble_tracker: # or another BLE tracker hub
sensor:
- platform: xiaomi_body_scale
mac_address: "XX:XX:XX:XX:XX:XX"
bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight:
name: "Scale Weight"

  • mac_address (Required, MAC Address): The MAC address of the scale.
  • bindkey (Required, string): 32-character hex key to decrypt the BLE payload.
  • weight (Optional): Stabilized weight in kg.
  • impedance_low (Optional, S400 only): Low-frequency impedance at 50 kHz in Ω. Numerically larger value (~558 Ω). Published together with weight and heart rate.
  • impedance_high (Optional, S400 only): High-frequency impedance at 250 kHz in Ω. Numerically smaller value (~503 Ω). Published in the second packet without weight or heart rate.
  • heart_rate (Optional, S400 only): Heart rate in bpm.
  • profile_id (Optional): User profile slot (1–5, matches the Xiaomi Home app user assignment).
  • stabilized (Optional, S400 only): Binary sensor that turns ON when the measurement cycle is complete (last BLE packet received). Turns OFF during the measurement.

A timeout filter without a value publishes NaN when no new measurement arrives, so Home Assistant shows the sensor as unknown instead of keeping the last weigh-in. Unlike resetting to 0, this keeps fake readings out of the history and statistics. Add the same filter to any other numeric sensor.

sensor:
- platform: xiaomi_body_scale
mac_address: "XX:XX:XX:XX:XX:XX"
bindkey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
weight:
name: "Scale Weight"
filters:
- timeout: 30s

The S400 broadcasts encrypted MiBeacon packets of 24 bytes over UUID 0xFE95:

Byte(s) Content
0-1 Frame control (0x48 59 = has_data + has_encryption + MiBeacon v5)
2-3 Device type (e.g. 0x3BD5, little-endian)
4 Frame counter (used for deduplication)
5-16 Encrypted payload (12 bytes, AES-CCM, cipher_pos=5)
17-19 Payload counter (used in AES-CCM nonce construction)
20-23 MIC — AES-CCM authentication tag (4 bytes)

After decryption, the S400 payload at offset 5 contains object ID 0x6E16 + length 0x09 + 9 data bytes:

data[0] Profile ID (uint8, 1–5)
data[1-4] Compressed metrics (uint32, little-endian):
bits 0-10 Weight × 10 (0.1 kg, uint11)
bits 11-17 Heart rate − 50 (1 bpm, uint7)
bits 18-31 Impedance × 10 (0.1 Ω, uint14)
data[5-8] UNIX timestamp (uint32, requires Xiaomi Home app — not published)

The S200 sends object ID 0x4E16 with the same layout, except that data[1-4] holds only the weight × 100 (0.01 kg).

Impedance packet routing (BIA frequency convention):

Packet contentFrequencySensorTypical value
with weight + heart rate50 kHzimpedance_low~558 Ω
without weight250 kHzimpedance_high~503 Ω

  1. Install token_extractor

  2. Run it and log in with your Xiaomi account

  3. Find your scale in the generated list.

    NOTE

    In the Xiaomi Cloud, the S400 variants (MJTZC01YM / MJTZC03YM) do not appear by their commercial model name. Instead, they are identified as yunmai.scales.ms103, ms104, ms107, or xiaomi.scales.ms110. This mapping is for the S400 only.

  4. Copy the BLE KEY field (32 hex characters); this is your bindkey.


The S400 provides raw biometric data (weight + dual-frequency impedance). To compute body composition scores (BMI, body fat %, muscle mass, ECW/ICW, BCM, skeletal muscle mass, etc.) based on weight, impedance, age, height and gender, see: