Releases: blues-sechseck/Mitsubishi-WF-RAC-Integration
Release list
2026.9.6
The theme of this release is getting out of the way of everything else that talks to your air conditioner.
The Smart M-Air app could be locked out entirely
Enabling a single operation-data sensor made the integration ask the unit for values once a minute. Each of those requests takes the unit's 60-second write lock — and with the request cadence and the lock length both at 60 seconds, the lock never lapsed. The app, and the infrared remote, could not get a command in at all. Reported by daveywf in #294.
The module has no clock of its own: it dates the lock from the timestamp on the request that took it. Operation-data requests are now stamped 55 seconds in the past, so the lock they take runs 5 of its 60 seconds and the rest of every minute stays free. A command you send from Home Assistant is stamped honestly and keeps its full protection — verified on hardware, including the case where an operation-data request follows a command within the same minute.
Once another client does get a command through, the integration stands down for three minutes and the new External Control entity says so while it lasts. The operation-data sensors hold their last values meanwhile.
Hot Gas Temperature now reads unknown when the outdoor unit is idle
Worth knowing before you see it, because it looks like a broken sensor. The discharge-pipe conversion only holds from raw byte 18 upwards; below that the sensor is telling us "30 °C or colder" and nothing more precise. It used to convert that anyway and report a plausible-looking 36–40 °C on a completely idle outdoor unit — which is where the suspicion of a permanently running crankcase heater came from (#288). It now reports unknown there instead of a number the protocol never sent. Hot Gas Temperature (raw) still shows the byte.
If you only want the operation-data channel switched on, Indoor Coil Temperature is the better entity to enable — it always has a reading.
Quieter, and more useful when something is wrong
- Refusals the integration recovers from by itself no longer produce warnings. They were running at about a dozen a day on a healthy setup. The tally now rides along in the diagnostics download instead, so nothing is lost for anyone actually investigating.
getAirconStatrefusals no longer blame the write lock. That command never touches it — the message said otherwise and sent a tester looking in the wrong place.- The stale-operation-data warning now points at the network, which is what every measured occurrence turned out to be.
- Discovery falls back to the module's fixed port when the announced one does not answer (#290), and says so, instead of failing setup.
- A command refused because the account was not registered is re-registered and retried once.
- The repair issue for a full account table says what that actually means: slots never free themselves, and only the holding account can remove itself.
Also
The README explains how to remove the integration, and says plainly that the Indoor Coil Outlet name describes the cooling case. There is a code of conduct. Internally the coordinator has moved out of wfrac/device.py into its own module and the integration now declares its quality-scale status — groundwork, no behaviour change.
If you ran the betas
Nothing to do. Everything from beta1 through beta4 is included, plus the quieter logging and the discovery port fallback, which are new here.
There's a Sponsor button in the sidebar if this saved you a support ticket or an evening of guessing.
2026.9.6-beta4
Follow-up to 2026.9.6-beta3, for the case reported in #294.
beta3 backdates the operation-data request by 30 seconds, so the 60-second write lock it takes runs half its length and leaves the other half of every poll free for the Smart M-Air app or the IR remote. That works, but a first command from the app still has to fall inside the free half — roughly a coin flip per attempt.
This raises the backdate to 55 seconds. The lock now runs 5 of its 60, so the wait for a first command to land is a few seconds instead of up to thirty.
What to check
- With an operation-data entity enabled (
Hot Gas Temperature, compressor frequency, …), a first tap in the Smart M-Air app should land almost straight away rather than after a wait. - The operation-data sensors should keep updating once a minute, as before.
- A command sent from Home Assistant should still stick. It keeps its full 60 seconds of protection, and an operation-data request following within that minute must not cut it short.
Verified before release
On a WF-RAC-HTTPS 025/200 unit: an operation-data request 7 seconds after a Home Assistant command was stamped honestly and renewed that command's lock to a full 60 seconds, while one 78 seconds after was backdated as usual. Across 35 consecutive polls the lock had already lapsed by 25 to 28 seconds each time the next poll read it.
2026.9.6-beta3 — write-lock fix, take 2
Replaces beta1's approach to the app-lockout issue (#294). Instead of asking for operation data every other poll, the request now goes out every poll but backdates its own timestamp so the module's 60-second write lock expires halfway through — leaving a free window every minute for the app (or the IR remote) to get a command in, at the full operation-data rate.
Once a command from the app does get through, the integration notices and stops asking for operation data entirely for three minutes, restarted by every further command — so the unit stays yours for as long as you are using the app, plus three minutes after you stop.
(Supersedes 2026.9.6-beta2, which was published without its install archive and could not be downloaded.)
Please test: with a diagnostic/operation-data entity enabled, confirm the app can still control the unit, and that operation-data sensors keep updating. A command from Home Assistant right after using the app should still hold.
2026.9.6-beta1
What's new
The unit only lets one client write at a time, and we were hogging it. Every command the air conditioner accepts gives the sending device 60 seconds of exclusive write access; everyone else is refused until it lapses. Asking for operation data is itself such a command — it changes no setting, but it takes the lock all the same. With a diagnostic sensor enabled, the integration was asking once a minute against a 60-second lock, which meant it held that lock permanently and left the Smart M-Air app unable to control the unit at all (#294).
The integration now notices when another client has written and stands down for three minutes: no operation-data requests while someone else is using the unit. Your own commands from Home Assistant are never held back — if one is refused because the app just wrote, it now waits and retries instead of being lost.
A new diagnostic sensor, External Control, is on for as long as the integration is holding back, so the pause is visible instead of silent. There is a matching log line at info level each time it starts and stops. The operation-data sensors keep their last values throughout — a pause is not an outage, and they refresh as soon as it ends.
Commands refused right after using the app now go through. Previously a command sent moments after the Smart M-Air app was used could be dropped with nothing but a debug-log line to show for it.
Changed
wfrac/device.py moved to coordinator.py, where Home Assistant expects an integration's update coordinator. Purely structural — no behaviour depends on it — but it moves a lot of code, so it is worth a beta before it ships in a final. The protocol client stays in wfrac/.
The refusal codes the unit sends back are now told apart properly. 1, 11 and 12 mean "declined, wait and retry" — usually the write lock above. Only 2 is about the account table, and only that one triggers a re-registration. Previously 1 was treated as an account problem and answered by re-registering, which cannot help when the real cause is another client's lock.
Also: a quality_scale.yaml declaring where the integration stands against Home Assistant's quality rules, and a section in the README on removing the integration cleanly.
Correction to what 2026.9.5 said
That release described the module's account table as something the official app can evict Home Assistant from. Looking into the firmware more closely for #294, that turns out not to be how it works: registrations are never evicted, and a full table refuses the new client rather than displacing an existing one. The repair issue for a genuinely full table is still correct and still useful — but if you saw commands failing shortly after using the app, that was the write lock, not the account table.
Testing this beta
The interesting case is: change something in the Smart M-Air app, then within a minute change something in Home Assistant. That should now work. With a diagnostic sensor such as Compressor Frequency enabled, the app should stay usable — External Control will turn on while you are using it, and the operation-data readings will simply stop updating for a few minutes rather than disappearing.
2026.9.5
What's new
Raw operation-data sensors are back, built properly this time. Eight new diagnostic sensors expose the undecoded bytes behind the operation data — compressor frequency, operating current, hot gas temperature, both indoor coil thermistors, the outdoor coil, discharge superheat and the protection number. All fifteen operation-data sensors are now created unconditionally and are diagnostic/disabled by default; enabling one is what makes the integration ask the unit for that value, so leaving them all off costs nothing extra on the wire. That replaces the old "Service Data" option entirely — visibility is now a per-entity choice on the device page instead of one switch for all of them.
Reconfigure flow. Host, port and name can now be changed via "Reconfigure" on the integration's device page, without removing and re-adding it. This also closes a gap in the options form: host used to be editable there with zero validation, so a typo or a stale IP just surfaced later as silent retry failures.
Repair issue when the account table stays full. The module's account table is small and fixed-size — opening the official app or adding another phone can evict Home Assistant from it, and the integration already re-registers automatically when that happens. If the table is genuinely full rather than just evicted, re-registration itself fails, and until now that only showed up as a debug-level log line with every poll failing forever. It now raises a Home Assistant repair issue instead, cleared automatically once registration next succeeds.
Diagnostics download. Every device and config-entry page now offers "Download diagnostics" — config data, device state and the last received status, with anything that could identify or control the unit (operator ID, device ID, host) redacted. Useful for bug reports; previously that meant asking reporters to open specific entities one at a time and copy the values across.
Translated error messages. User-facing errors (bad temperature values, setup failures) now resolve through Home Assistant's translation system instead of showing raw English text regardless of the configured language.
The discovered port is editable. Zeroconf discovery used to trust whatever port the mDNS advertisement reported and show it as read-only text. #290 hit a real case where the advertisement carried 5353 — the mDNS port itself — instead of the fixed 51443 every firmware branch actually serves on. The confirm dialog now shows the port as an editable field, pre-filled with the discovered value, and notes 51443 as the expected default so a wrong value is easy to spot.
Changed
The Horizontal Swing, Vertical Swing and Fan Speed selects are now always created, the same way the raw sensors are — a setup-time option used to decide whether they existed at all, which meant toggling it later silently deleted the entities, their history and every dashboard/automation reference to them. If you had switched that option off, the three selects now exist but start out disabled.
Airco ID and Account Expires — protocol-internal diagnostic sensors — are now off by default on new installations, matching Operator ID, Device ID, IP and Accounts. Existing installations are unaffected.
Fixed
- A command could be silently discarded. The Home Leave status request could merge with a real command queued in the same 500 ms window, and the merged frame carried none of the real command's set-bits — a setpoint change sent at the wrong moment simply had no effect, with nothing in the log to say why. This was live since
2026.9.4. Thanks to SoftwareSchmied for tracking it down. - The Target Temperature sensor could disagree with the thermostat card. With
target_offset_coolortarget_offset_heatconfigured, the sensor applied the global offset while the climate entity resolved the per-mode one, so the two showed different setpoints. Both now go through the same resolver. - Missing translations for the raw diagnostic sensors and the target-offset options are filled in.
If you ran the betas
Nothing to do. If you had any of the raw byte sensors enabled already, they stay enabled — Home Assistant restores registry entries exactly as you left them. Everything above that shipped incrementally in beta2/beta3 is included here as-is.
There's a Sponsor button in the sidebar if this saved you a support ticket or an evening of guessing.
2026.9.5-beta3
What's new
Reconfigure flow. Host, port and name can now be changed via "Reconfigure" on the integration's device page, without removing and re-adding it. This also closes a gap in the options form: host used to be editable there with zero validation, so a typo or a stale IP just surfaced later as silent retry failures.
Repair issue when the account table stays full. The module's account table is small and fixed-size — opening the official app or adding another phone can evict Home Assistant from it, and the integration already re-registers automatically when that happens. If the table is genuinely full rather than just evicted, re-registration itself fails, and until now that only showed up as a debug-level log line with every poll failing forever. It now raises a Home Assistant repair issue instead, cleared automatically once registration next succeeds.
Diagnostics download. Every device and config-entry page now offers "Download diagnostics" — config data, device state and the last received status, with anything that could identify or control the unit (operator ID, device ID, host) redacted. Useful for bug reports; previously that meant asking reporters to open specific entities one at a time and copy the values across.
Translated error messages. User-facing errors (bad temperature values, setup failures) now resolve through Home Assistant's translation system instead of showing raw English text regardless of the configured language.
Changed
The Horizontal Swing, Vertical Swing and Fan Speed selects are now always created. Previously a setup-time option decided whether they existed at all, which meant toggling it later silently deleted the entities, their history and every dashboard/automation reference to them. If you had switched that option off, the three selects now exist but start out disabled — switch them on if you want them.
Fixed
- Missing translations for the raw diagnostic sensors and the target-offset options are filled in.
- The LED status sensor's description was wrong: it reflects the unit's own LED on/off toggle from the Smart M-Air app options screen, not any Wi-Fi module state. It stays off by default.
2026.9.5-beta2
What's new
Raw operation-data sensors. Eight new diagnostic sensors expose the undecoded bytes behind the operation data: compressor frequency, operating current, hot gas temperature, both indoor coil thermistors, the outdoor coil, discharge superheat and the protection number. The raw byte is what you need to work out a conversion, and for the coil temperatures it is the only honest reading outside the calibrated band. All are off by default.
Operation data is only read when something is listening. The integration now asks the unit only for the segments its enabled entities actually need. Enable one sensor and its segment gets requested; enable none and no operation-data request is made at all. That matters on this hardware — the module takes one connection at a time with about a second between requests, so a request that nothing needs is a request that gets in the way of one that does.
Removed
The "Service Data" option is gone. It had become redundant: it no longer decided whether the data is fetched, only whether the entities exist, and that is a per-entity question. Nothing disappears — if you had the option on, your sensors are already registered and enabled and stay exactly as they are. What you lose is the single switch: hiding all of them at once is now seven clicks on the device page instead of one.
Worth knowing
If you enabled the raw byte sensors back in 2026.9.3, before they were withdrawn, they come back enabled. Home Assistant restores registry entries it deleted earlier, including whether they were on. New installations get them switched off.
Airco ID and Account Expires are now off by default, in line with the other internal values. Existing installations keep them.
Fixed
- The Home Leave status request could merge with a real command inside the same 500 ms window; the command then went out without its set bits and was silently discarded. This was live in
2026.9.4. Thanks to SoftwareSchmied for the report. (#264) - The target temperature sensor now resolves its offset per mode. (#267)
2026.9.4
What the two betas were building towards. The headline fix only shows up with the optional Service Data option on; the rest applies to every install.
Changes made at the unit are no longer undone
With Service Data on, anything changed at the unit itself — IR remote or the Smart M-Air app — could be silently written back about a minute later. A self-clean cycle started from the remote turned into an ordinary fan run within minutes. Found by @c-scoot in #241 and #250.
The protocol offers no way to ask for the operation data on its own, so the request rode on a write carrying the unit's complete state — taken from the previous poll, which is why anything changed in between was overwritten. It now carries none of the bits that apply a setting. Measured on both of my indoor units, running and switched off: the full operation data comes back, and power, mode, fan speed, setpoint and both vane axes stay untouched. This closes the known issue listed under 2026.9.3.
New: what the indoor coil is doing
Two new sensors with Service Data on, Indoor Coil Temperature and Indoor Coil Outlet Temperature (MHI's THI-R1 and THI-R3). Unlike compressor frequency, which is an outdoor-unit value shared across a multi-split, these are per indoor unit: in cooling the coil temperature drops as the coil gets cold and returns to room temperature once the compressor stops, and the gap between the two while it runs is the evaporator superheat.
The conversion is not a lookup table. The sensor is a ~5 kΩ NTC in a divider, and inverting that covers the whole byte range — heating included, where the coil runs past 45 °C. It is anchored against a thermometer through a heating run, RMS 0.25 K between 23 and 46 °C. Two limits are documented rather than hidden: above byte 170 the curve is extrapolation, and at the cold end it reads a few degrees above the manual's frost cut-off. @alexnikgr supplied the sensor's part data in #223, which is what made the curve checkable in the first place.
The log only speaks up when something changed
Two things used to warn about once an hour per unit, neither with any consequence: a poll landing in the module's hourly WiFi restart, and a refused operation-data request. Both are debug lines now. A warning is written when the integration's state actually changes — a unit crossing the availability threshold, operation data expiring to unknown — and once more when it recovers. On a healthy system that should mean a quiet log.
Also in here
- Offline handling and automatic recovery, contributed by @SoftwareSchmied: the last working protocol is remembered and tried first, so a unit that only answers one of the two can recover on its own. He also found that the per-request and per-poll timeouts left room for only one attempt where discovery needs two.
- A command the unit accepts but refuses is now visible. Every response carries a
resultfield that nothing read, soHTTP 200plus "operation prohibited" passed as success — a candidate for the "nothing happens, and nothing in the log" reports.result: 2names both of its causes: a full account table, or an expired registration. - Translations caught up — Dutch, Japanese, Lithuanian and both Chinese variants were missing everything added since the home-leave controls. Corrections from native speakers are welcome.
- The energy counter's resolution is documented. The unit reports in 0.25 kWh steps, so short runs round away; the README now says so instead of leaving it to be discovered. Raised by @bert-58 in #214.
If you ran the betas
The raw byte sensors are gone from this release — indoor and outdoor coil, discharge superheat, protection number. The two indoor-coil ones did their job: the curve above is what they were for. The other three carry bytes with no established conversion, and a unitless number in a temperature's place is only useful to someone decoding the protocol, so a stable release is the wrong place for them.
They return in the next beta, which is where working them out belongs. The outdoor coil is the same thermistor as the indoor one behind a different resistor, and the first defrost cycle of the winter pins its curve for free — the coil sits at 0 °C then. The protection number is answered by every module I have seen but has read 0 on all of them, including units that have been throttled by their own overload protection, so what is still missing is one reading taken inside a protective state (#225). Discharge superheat has read a constant 0 on three units, and I would like to know whether any model reports it at all.
The parser keeps requesting all of it either way, so nothing is lost from the polls in the meantime.
There's a sponsor button in the sidebar now, in case this saved you an afternoon.
2026.9.3
This release is about the operation-data sensors and the log noise around them. Reported in #230 by @alexnikgr and @hunter-nl, who both ran the betas: the operation data now arrives far more reliably, and the refusals that remain mostly recover on their own.
Operation data (the optional "Service Data" sensors)
- The request carrying the operation-data codes went out about a second behind the status poll, and modules refuse a second request that soon with
HTTP 501 Not supported this command— roughly one poll in seven on one of the reported units. It now lands in the quiet middle of the cycle and is retried once after five seconds. (#233) - The rate limit guarding that request was measured against the full poll interval but compared against the time a poll finished, so a poll that answered a few milliseconds faster than the one before it dropped the whole cycle — 6 of 36 cycles in one log, every one short by under 100 ms. (#239)
- Values are no longer carried forward for ever. After three missed cycles the sensors fall back to
unknowninstead of reporting a frozen number that looks live. (#233)
Connection handling
- A command the unit declines no longer counts as a dead connection, so the next request doesn't pay for a protocol rediscovery. (#231)
- These modules restart their WiFi roughly once an hour on their own. A poll landing in that window is now a single line in the log instead of an aiohttp traceback plus a second warning from the account re-registration behind it. (#231)
- The per-request timeout is 25 s and the poll timeout is derived from it (55 s), so one poll has room for both legs of protocol discovery. A unit that accepts a plaintext connection without answering it used to consume the whole window on the first leg and could never recover on its own. Found by @SoftwareSchmied. (#237)
- A poll that runs past its timeout now names the device and the wait, instead of appearing as
Error fetching … data:with nothing after the colon.
Error codes
- Protective stop codes (
M…) resolve through the same table as the displayed fault codes, taken from the MHI databooks, and are prefixed so a stop the unit recovered from stays distinguishable from a fault it is displaying. Seven codes added, three corrected. Raised by @mungojam in #225. (#235)
Known issue
With "Service Data" switched on, a change made at the unit itself — IR remote or the Smart M-Air app — can be written back from the last poll about a minute later. The option is off by default; see #241 for the detail and the fix under consideration.
2026.9.2
Home Leave Mode: real read/write, and editable on the device page
The Home Leave Mode switch from 2026.9 is replaced by a select entity (Home Leave Mode — off / away cooling / away heating). The official app's away mode has two independently configurable targets, heating and cooling, not the single direction a switch could represent.
The thresholds and airflow settings behind it are now editable directly on the device's Controls page (4 number + 2 select entities, disabled by default) instead of being read-only diagnostics plus a service call.
Breaking: switch.<device>_home_leave_mode is gone. Automations using it need select.select_option with off / away_cool / away_heat.
Energy Usage: the counter was never cumulative
If your Energy Usage sensor kept dropping back to zero, or sat at 0 while the unit was clearly running (#214) — that is the unit, not a bug.
The kWh counter the module reports is a per-run counter: it counts up while the indoor unit runs, holds while it is off, and clears to 0 the moment the unit is switched on again. I confirmed that across two units over two days — six resets, every one within a minute of an off→on transition, none without one, including one switched on at the unit itself. On a unit that cycles often it may never even reach the counter's first 0.25 kWh step.
New: Energy Usage Total adds the counter's upward steps into a real lifetime total and keeps it across restarts. This is the one for the Energy dashboard.
- Reset Energy Usage Total button on the device page sets it back to 0.
mitsubishi_wf_rac.set_energy_totalsets it to a specific value — useful if autility_meterhelper was doing this job and you want to carry its reading over.- Resetting does not erase what long-term statistics already recorded.
The original sensor stays as Energy Usage (current run).
New: operation-data sensors (opt-in)
Five sensors read from the CNS bus's operation-data segments: compressor frequency [Hz], operating current [A], hot gas temperature [°C], EEV pulses and EEV position [%]. They are queried as an extra segment on the regular status request — same connection, same poll, no second round trip.
They are created only while Service Data is enabled in the integration's options (Settings → Devices & Services → Mitsubishi WF-RAC → Configure), which is off by default because it adds a small write on top of an otherwise read-only poll.
On a multi-split, compressor frequency, current and hot gas temperature are outdoor-unit values and read identically across every indoor unit; EEV is per indoor unit.
Known limitation, thanks to @FrankAlbers for the data: on the older firmware branch (mcu131/wireless010) compressor frequency and operating current read a constant 0 even with the compressor confirmed running, while hot gas and EEV read real values on the same units (#207). Still open.
New: Compressor Demand binary sensor
binary_sensor.<device>_compressor reports whether this indoor unit is calling for the compressor. On a multi-split the shared compressor can keep running for a sibling unit while this reads off — so it is demand, not outdoor-unit state, which is what the display name now says (#226).
Per-model capability table (#187)
A real per-model feature table, ported from the official app's own model database, replaces the previous ModelNr == 1 guesswork that gated self-clean, occupancy, Home Leave and others. Models such as ZT-2025 should stop silently losing features that the wire-protocol grouping alone could not place.
Plaintext error codes
binary_sensor.problem carries an error_description attribute for documented E codes (and a few M codes, flagged as lower confidence), taken from the MHI manuals. Undocumented codes get no attribute rather than a guess (#82).
Optional firmware-update check
Off by default: checks the manufacturer's getFirmware endpoint — the same call the official app makes — and surfaces an update entity when a newer wireless-module firmware is available. It is the only outbound internet call in an otherwise fully local integration, which is why it stays opt-in.
Availability: one option less, and a floor on the other (#217)
Check availability is gone. It had no defensible setting: the module reassociates to WiFi about once an hour and is unreachable while it does, so some tolerance is always right — switching it off only turned a known transient event into a reported outage, which is the complaint behind #173 and #146. It was also arithmetically identical to a retry limit of 1.
Retry limit stays, because raising it is a real choice on a weak link — one setup here runs all four units at 5. It now has a floor of 3: below that it was equivalent to switching tolerance off. Entries below the floor are lifted on upgrade; a higher value you set deliberately is kept.
Fixes
- Reset Energy Usage Total marked the whole device unavailable on every poll (#219). The button had no state of its own to report while a recent refactor asked every entity for one. That mismatch produced frequent, short, self-recovering drops for anyone on beta3 — fixed in beta4, and confirmed by @alexnikgr and @sharpme512 (#173).
- Diagnostic sensor defaults were inverted, from long before I took the repo over: the internal plumbing (IP, Operator ID, Device ID, Accounts) was enabled by default while Error, Airco ID, Updated By, Account Expires and Auto Heating were not. Now the other way round, as the README always claimed. This affects newly added devices only; existing entities keep whatever state you gave them. LED Status stays off — it reads a constant 1 on both of my units regardless of what the machine does.
Upgrade notes
Two things to check after updating:
switch.<device>_home_leave_modeno longer exists — see above.- Check availability no longer exists, and a retry limit below 3 is raised to 3. A higher value you set yourself is kept.
The Self-Clean switch removed in 2026.9.1 stays removed: the unit's real self-clean cycle can only be started from the IR remote, the WiFi module has no way to trigger it (#209).