Arduino firmware for capturing telemetry from the diagnostic port on Midea mini-splits, located on the outdoor inverter board. Midea sells a handheld inverter tester that plugs into this port. This project reproduces that tester with a cheap ESP32S3 microcontroller, so you can log the same data yourself and explore the inner workings of your unit.
The prototype has 3 capabilities:
- Emulate the inverter tester to capture data from the ODU (primary use case)
- Sniff the communication between the inverter tester and ODU (used during protocol reverse engineering)
- Emulate the ODU to send custom responses to the inverter tester (used to track down the meaning and encoding of individual bytes)
Example: The prototype connected to the inverter tester and diagnostic bus to sniff the communication:
Initial tests indicate that this is a robust way to extract telemetry data from my mini-splits:
⚠️ Safety. The outdoor unit runs on mains voltage and can retain a dangerous charge after being unplugged. Only plug a connector into the diagnostic port if you know what you are doing. You are responsible for your own hardware and safety.
Midea is a trademark of Midea Group. This is an independent, unofficial hobby project and is not affiliated with, authorized, endorsed by, or sponsored by Midea. The name is used only to describe which hardware the project interoperates with. All product names and trademarks are the property of their respective owners.
I reverse-engineered the communication between the inverter tester and the diagnostic port and wrote it up on Medium: Reverse Engineering Midea's ODU Diagnostic Port. The sketches in this repository are based on those findings. Start there if you want to understand the protocol.
In short: the bus is a two-wire (clock + data) 5V bus. The tester drives the clock in both directions and exchanges 80-bit frames with the ODU, LSB-first. A request starts with 0xAA, a response with 0x55; the second byte selects one of seven response types, and the last byte is a checksum that makes all ten bytes sum to zero modulo 256.
The only thing you need to connect an ESP32 to the diagnostic port is a level shifter. The 5V bus lines (CLK, DAT) are level-shifted to 3V3; the ODU supplies the 5V reference and the XIAO supplies the 3V3 reference. All sketches expect the clock line on D2 and the data line on D1 (see the PIN_CLK / PIN_DAT defines at the top of each sketch).
⚠️ Use a USB isolator. The diagnostic port's ground is not referenced to earth. Whenever you connect the ESP32 to a computer over USB while it's plugged into the ODU (e.g. to flash or read the serial monitor), go through a USB isolator so the floating bus ground isn't tied to your earthed computer.
BOM:
The assembled prototype:
An adapter PCB for this — a bare carrier board you solder the two connectors, the level shifter and the XIAO into — lives in the companion repo: midea-telemetry-esphome/pcb (KiCad project, schematic, and orderable gerbers). Note it is untested — designed and rule-checked, but not yet fabricated.
⚠️ Only the ODU side connects to your mini-split, and only through the low-voltage diagnostic port. Re-read the safety note above before plugging anything into the outdoor unit.
| Sketch | Role on the bus | Use it to... |
|---|---|---|
| inverter-tester-emulator | drives the bus like the tester | capture telemetry without owning the tester |
| bus-sniffer | passive listener | reverse-engineer tester ↔ ODU traffic |
| odu-emulator | answers like the ODU | map response bytes to tester display fields |
Emulates Midea's inverter tester: it drives the bus, sending diagnostic requests and logging the ODU's responses. This lets you capture telemetry without owning the inverter tester.
The set of request messages to send is defined in the requests table in loop(). Edit it to send different requests. Each request/response pair is printed to serial:
req=0xAA000000000000000056, res=0xFFFFFFFFFFFFFFFFFFFF, status=NO_RESPONSE_FROM_ODU
req=0xAA000000000000000056, res=0xFFFFFFFFFFFFFFFFFFFF, status=NO_RESPONSE_FROM_ODU
req=0xAA000000000000000056, res=0x55006D457671401F03B0, status=OK
req=0xAA010000000000000055, res=0x550128A7B3E8006002DE, status=OK
req=0xAA0200000000FF000055, res=0x55022C2A000000000152, status=OK
req=0xAA030000000000000053, res=0x55030000160EA20000E2, status=OK
req=0xAA000000000000000056, res=0x550400000000002C2C4F, status=OK
req=0xAA010000000000000055, res=0x55054F00000000000057, status=OK
req=0xAA0200000000FF000055, res=0x550600000000000000A5, status=OK
...
req=0xAA030000000000000053, res=0x55030000160BA00000E3, status=CHECKSUM_ERROR
...
Passively listens on the bus while the inverter tester is plugged in, decoding the request/response cycles between the tester and the ODU. Useful for reverse-engineering the protocol. Each request/response pair is printed to serial in the same format as above.
When a request or response fails to decode, you'll see a line like:
req= , res= , status=INCOMPLETE
Note: I initially used an ESP32C3 and regularly encountered messages that don't decode fully — some bits are lost when loop() isn't called fast enough. There are ways around this, but I prefer to keep the sketch simple, and I can still capture enough data for analysis (even if it takes a couple of tries). Switching to an ESP32S3 has resolved those issues for me.
Emulates the ODU: it waits for the inverter tester to clock out a request, then answers with a configurable response frame. By changing individual response bytes and watching what changes on the tester's display, you can map each byte to a display field and work out the conversion between raw byte and displayed value.
The seven response payloads (bytes 0–8 of each frame) are defined in the responsePayloads table at the top of the sketch. The checksum (byte 9) is always generated automatically, so any payload byte can be changed freely.
Payloads can also be changed at runtime over USB serial — no reflashing between experiments:
show print all response frames (checksum included)
set <slot> <18 hex> replace bytes 0-8 of a frame, e.g. set 2 55022C2A0000000001
poke <slot> <byte> <value> change a single byte (0-8); value is decimal,
or hex with a 0x prefix, e.g. poke 2 2 0x2B
A typical session — bump one byte, watch the tester display:
2: 0x55022C2A000000000152
> poke 2 2 0x2B
2: 0x55022B2A000000000153
Tip: the two emulator sketches are exact counterparts, so you can bench-test them against each other with two boards (clock-to-clock, data-to-data, ground-to-ground) before connecting real hardware — no external pull-ups needed.
midea-telemetry-esphome is an ESPHome external component that emulates the inverter tester and exposes all currently known telemetry fields (temperatures, compressor frequencies, fan speed, EEV steps, voltage, current, mode, set-point) as Home Assistant sensors. Same hardware as the sketches — see its README for a full example configuration.
external_components:
- source: github://fmck3516/midea-telemetry-esphome
components: [midea_telemetry]
midea_telemetry:
clk_pin: GPIO3 # D2 on the XIAO ESP32S3
dat_pin: GPIO2 # D1
sensor:
- platform: midea_telemetry
outdoor_coil_temperature:
name: Outdoor coil temperature
compressor_frequency_actual:
name: Compressor frequency
# ... see the midea-telemetry-esphome README for all 13 sensorsdashboard/index.html is a self-contained, browser-based visualizer for captured telemetry — no build step, just open it in a browser. Pick a capture file and it plots every response byte (bytes 2–9) over time, grouped by response type (byte 1), with synced zoom/pan across charts. Bytes that never change are hidden automatically. By default it shows the twelve decoded fields ("known bytes" — temperatures, frequencies, fan speed, EEV steps, voltage, current), converted with the formulas from the article; an "all bytes" toggle switches to the raw per-byte charts.
It expects capture files with one req=..., res=..., status=... line per cycle, prefixed with a Unix timestamp — see data/bus.txt for an example. A capture like that can be recorded straight from the serial port:
cat /dev/ttyACM0 | while IFS= read -r line; do echo "$(date +%s) $line"; done >> data/$(date +%F).bus.txt- Install the Arduino IDE and the esp32 by Espressif Systems boards package (3.x) via the Boards Manager.
- Open the sketch you want.
- Select your board (e.g., XIAO_ESP32S3) and serial port, then upload.
- Open the Serial Monitor to view the captured telemetry. The sketches print over the native USB port (
HWCDCSerial), so any baud rate works.
Early / experimental. The protocol is still being reverse-engineered, and the meaning of individual bytes is not yet fully documented.



