Direct CN105 UART control of Mitsubishi mini-splits
Why I skipped Kumo Cloud, MELCloud, and every WiFi bridge to talk directly to the diagnostic port on each indoor unit. ESP32, a documented binary protocol, and an integration that keeps working when the cloud doesn't.
By Igor Riera
Mitsubishi mini-split HVAC units have a small unmarked 5-pin header on the indoor head: the CN105 connector. It’s nominally a diagnostic port used by dealers for service. It’s also a UART speaking a documented binary protocol — and that’s the part Mitsubishi doesn’t advertise to consumers.
Every commercial Mitsubishi smart-home integration I’ve evaluated goes around this port. Kumo Cloud, MELCloud, and the Home Assistant adapters that talk to those clouds all do the same thing: they talk to a Mitsubishi-controlled cloud service, which talks to a Mitsubishi-supplied WiFi bridge plugged into the unit, which talks to the unit. Three hops, two of which can fail in ways I can’t fix, one of which can be deprecated entirely on Mitsubishi’s schedule.
I skipped all of it. Each of the four mini-splits in my house has an ESP32 wired directly into the CN105 header. The ESP32 speaks the binary protocol over UART, exposes a local HTTP API on the LAN, and Home Assistant on the Pi 5 calls it. From phone tap to compressor responding: under 100 milliseconds, with no cloud in the path.
This post is the engineering rationale, the hardware, and the lessons.
The protocol
The CN105 port runs at 2400 baud, 8 data bits, even parity, 1 stop bit. It uses 5V logic (the ESP32 is 3.3V — a level shifter is required, not optional). The protocol itself is request/response with framed packets: a header byte, a packet type, a payload length, the payload, and a checksum.
The canonical reference is the SwiCago/HeatPump Arduino library, which is the result of years of reverse-engineering work by the home-automation community. It supports the operations you actually care about: read current state (mode, set temp, fan speed, vane position, room temp), set state (the same fields), and read status flags (compressor running, defrost cycle, error codes).
I won’t re-derive the protocol here — the SwiCago code is the documentation. What I’ll note is that the protocol is stable across the Mitsubishi mini-split lineup going back at least a decade. The same firmware works on units installed in 2014 and units installed last month. That stability is the engineering argument for using this port instead of anything else.
The hardware
Per unit:
- One ESP32 dev board (I’m running the WROOM-32 variant — anything ESP32-class works)
- One 5V-to-3.3V logic level shifter on the UART pins
- A 5-pin connector that mates with the CN105 header (a JST PA-series, 5-pin, 2.0mm pitch — the same connector Mitsubishi uses)
- A 5V power source inside the unit’s electrical compartment (the CN105 header provides 5V; for cleaner installs I tap the unit’s internal 5V rail directly)
- A 3D-printed bracket that holds the ESP32 inside the unit’s electrical compartment so nothing flops around when the head is opened for filter cleaning
Total parts cost: under $10 per unit at single-quantity pricing. At four units, the whole install was cheaper than a single MELCloud-compatible WiFi bridge.
The firmware is the SwiCago/HeatPump library wrapped in a small HTTP server (I use ESPHome on three of them and a custom Arduino sketch on the fourth as a fallback — both work). The HTTP API has three endpoints per unit: GET /state, POST /state (with a JSON body of fields to change), and GET /healthz.
The Home Assistant integration
Home Assistant talks to each unit as a climate entity over the local HTTP API. No cloud integration installed. No Mitsubishi account configured. The unit doesn’t know it’s being controlled by anything other than a wall-mounted thermostat.
The performance numbers matter: setting the target temperature in Home Assistant produces a CN105 command in under 100 ms (the HTTP round trip and the UART transaction are both fast). Reading current state is similarly fast. The 30-second polling cadence I run is conservative — I could poll once per second without stressing the unit.
The reliability numbers also matter: in eight months of operation, I’ve had zero integration outages caused by the units themselves and zero caused by network issues that didn’t also affect the rest of my LAN. The failure modes I’ve seen are: an ESP32 needed a restart after a long power outage (one occurrence), and a JST connector worked loose during a filter cleaning (one occurrence). Both are physical issues, both are immediately diagnosable, both took less than five minutes to fix.
The same period saw multiple reports in the Kumo Cloud subreddit and various Home Assistant forums of cloud outages, app updates breaking integrations, and Mitsubishi-side certificate changes that knocked out the official bridges. None of those events affected my setup, because none of those systems are in the path.
The engineering lesson
The most reliable integration is usually the one closest to the hardware. Cloud bridges are convenient until they aren’t. Vendor APIs are stable until they aren’t. WiFi bridges are supported until the vendor decides they aren’t.
The CN105 port is none of those things. It’s a UART; The protocol is documented, the hardware is $10. The unit doesn’t care who’s talking to it — it just responds to packets it understands.
This generalizes. When I’m doing integration work professionally, the same hierarchy applies: prefer the lowest-level interface that’s stable and documented. APIs are stable until they aren’t. SDKs are supported until they aren’t. The data format underneath the SDK is usually the thing that doesn’t change.
It also generalizes in the other direction. The reason I can run this setup with confidence is that the failure mode of every component is local and visible. The ESP32 is on my local network, not in a data center. The HTTP API is on my LAN, not behind someone’s load balancer. The protocol is documented in code I can read. There’s no escalation path for a CN105 outage because there’s no one to escalate to — but there’s also no opacity, so debugging is just reading. Most of the time, that’s the trade I want.
What to be honest about
This is not the right setup for everyone. It requires being willing to wire ESP32s into HVAC equipment, which could void the manufacturer warranty on the indoor unit (in practice the warranty rarely matters on these — the failure modes are mostly mechanical and the parts are inexpensive — but you should know). It requires running Home Assistant on your own hardware. It requires knowing what a level shifter is.
If any of those things sound like a chore rather than a weekend project, the cloud bridge is fine. The point isn’t that everyone should do this. The point is that the option exists, and that it produces a setup that’s more reliable than the off-the-shelf alternatives, in a market segment where reliability is the actual product.
The CN105 port is in every Mitsubishi indoor unit, and it will probably still be there in another decade. The Mitsubishi cloud, on the other hand, will probably look very different in 2036 than it does today. I’m betting on the connector.