9.8 KiB
Midea AC Integration Debugging
Integration Info
- Repository: https://github.com/mill1000/midea-ac-py
- Integration version: 2026.4.0
- Required library:
msmart-ng==2026.4.1 - Config flow file:
/mnt/data/supervisor/homeassistant/custom_components/midea_ac/config_flow.py - Manifest:
/mnt/data/supervisor/homeassistant/custom_components/midea_ac/manifest.json
Cloud Credentials Structure
In config_flow.py, line ~71:
_CLOUD_CREDENTIALS = {
"DE": ("midea_eu@mailinator.com", "das_ist_passwort1"),
"KR": ("midea_sea@mailinator.com", "password_for_sea1")
}
These shared credentials are used for the discover config flow step. When they expire, the flow aborts with cloud_connection_failed.
Config Flow Steps
- Initiate:
POST /api/config/config_entries/flowwith{"handler":"midea_ac"} - Menu: Choose
discoverormanual - Discover: Submit
{"host":"10.0.40.54","country_code":"DE"}— uses cloud credentials to get token/k1 - Manual: Submit
{"id":"DEVICE_ID","host":"IP","port":6444,"device_type":"AC","token":"...","k1":"..."}— skips cloud, needs pre-obtained token/k1
Library Comparison
midealocal (Python pip package)
- Import:
from midealocal.cloud import get_midea_cloud - Cloud names: "SmartHome", "NetHome Plus", "Midea Air", "美的美居", "Ariston Clima"
- Login flow:
get_midea_cloud(cloud_name=..., session=..., account=..., password=...)→await cloud.login() - List devices:
await cloud.list_home()→await cloud.list_appliances(home_id) - Get keys:
await cloud.get_cloud_keys(int(device_id))— calls/v1/iot/secure/getToken - Issue observed: getToken returns
{"code":"3004","msg":"value is illegal."}— empty result
msmart-ng (used by HA integration)
- Import:
from msmart.cloud import SmartHomeCloud, NetHomePlusCloud SmartHomeCloudhas DE shared credentials:midea_eu@mailinator.com/das_ist_passwort1SmartHomeCloudalso accepts personal user credentials — login succeeds, butgetTokenstill returns 3004NetHomePlusCloudis used byDiscover.discover_single()— hardcoded in_get_cloud()Security.udpid(data)=sha256(data).digest(), XOR first 16 bytes with second 16 bytes →.hex()(32 chars)Discover.connect()tries both"little"and"big"endians:device_id.to_bytes(6, endian)- Cloud login internally calls
/v1/user/login/id/get→/mj/user/login - CLI:
python3 -m msmart.cli -d -a "EMAIL" -p 'PASS' -i "IP" - Issue observed: getToken returns
{"code":"3004","msg":"value is illegal"}for ALL udpid variants
⚠️ Package Conflict: midealocal vs msmart-ng
Both packages claim the msmart Python namespace. Installing midealocal pulls in old msmart==0.2.5 which overwrites msmart-ng's modules. The security.py from 0.2.5 tries to import MSGTYPE_ENCRYPTED_REQUEST from msmart.const which doesn't exist in msmart-ng's const.py.
Fix:
pip uninstall -y msmart-ng midealocal msmart --break-system-packages
rm -rf ~/.local/lib/python3.*/site-packages/msmart # Remove stale namespace
pip install --break-system-packages msmart-ng==2026.4.1
Rule: Use midealocal only in throwaway/debug contexts. Never install it alongside msmart-ng in any environment that the HA integration depends on.
msmart (older version, v0.2.5)
- Different API from msmart-ng
msmart.cloud.cloudclass withlogin(),gettoken(),appliance_list()- Login fails with same "value is illegal" error
Device Details (This Homelab)
- Name: OGKlimaanlage
- Device ID: 153931628805781
- Type: 172 (AC)
- IP: 10.0.40.54 (VLAN 40)
- SN: 000000P0000000Q1102C8D344AAE0000
- SN8: 00000Q11
- Model: 00000Q11
- Model number: 524
- Manufacturer code: 0000
- Protocol: V3
- Port: 6444 (TCP, OPEN but requires auth handshake — unauthenticated connections time out) / 6445 (UDP, responds to discovery broadcast)
- Cloud account: dominik@familie-schoen.com (MSmartHome app)
- Cloud: SmartHome (not NetHome Plus)
Network Requirements
- Device is on VLAN 40 (10.0.40.x)
- HA needs direct L2 access — added third NIC (net2, VLAN 40, tag=40) to VM 106
- Interface in HAOS:
enp0s20, configured withha network update enp0s20 --ipv4-method auto - HA gets IP 10.0.40.61 via DHCP
- Device ARP is reachable (MAC 10:2c:8d34:4a:ae) — TCP 6444 is open but requires V3 authentication handshake. Unauthenticated TCP connections time out ("No response from host").
Debugging Commands
# Check config entry state
TOKEN=$(cat /tmp/ha_token.txt)
curl -s -H "Authorization: Bearer $TOKEN" \
"http://10.0.30.10:8123/api/config/config_entries/entry" | \
python3 -c "import sys,json; [print(f'{e[\"title\"]}: {e[\"state\"]}') for e in json.load(sys.stdin) if e.get('domain')=='midea_ac']"
# Check HA logs for midea errors
ssh -i ~/.ssh/id_ed25519_proxmox root@10.0.20.10 \
'qm guest exec 106 -- sh -c "ha core log 2>&1 | grep -i midea | tail -20"'
# Local discovery via midealocal
python3 -m midealocal.cli discover \
--username "EMAIL" --password 'PASS' \
--cloud-name "SmartHome" --host "10.0.40.54" --get_sn
# Cloud API debug (midealocal)
python3 << 'PYEOF'
import asyncio, aiohttp, json
from midealocal.cloud import get_midea_cloud
async def debug():
async with aiohttp.ClientSession() as session:
cloud = get_midea_cloud(
cloud_name="SmartHome", session=session,
account="EMAIL", password="PASS"
)
await cloud.login()
homes = await cloud.list_home()
for hid in homes:
apps = await cloud.list_appliances(hid)
for aid, info in (apps or {}).items():
print(f"Device {aid}: {json.dumps(info)}")
keys = await cloud.get_cloud_keys(int(aid))
print(f" Keys: {json.dumps(keys)}")
asyncio.run(debug())
PYEOF
Session Findings (2026-06-27 Deep Debug)
Cloud Login Results
| Cloud | Endpoint | Login | getToken | Notes |
|---|---|---|---|---|
| SmartHome (midealocal, shared creds) | mp-prod.appsmb.com | ✅ | ❌ 3004 | list_appliances works, returns device with btToken + btMac |
| SmartHome (msmart-ng, shared DE creds) | mp-prod.appsmb.com | ✅ | ❌ 3004 | Same API, same failure |
| SmartHome (msmart-ng, personal creds) | mp-prod.appsmb.com | ✅ | ❌ 3004 | Login OK with user account, getToken STILL fails |
| SmartHome (midealocal, personal creds) | mp-prod.appsmb.com | ✅ | ❌ 3004 | Same — confirms device-side issue, not credentials |
| NetHome Plus (midealocal) | mapp.appsmb.com | ❌ 3101 | N/A | "password error" — account doesn't exist on this cloud |
| NetHome Plus (msmart-ng) | mapp.appsmb.com | ⏳ rate-limited | N/A | Too many failed attempts from earlier msmart-ng discovery tries |
| Midea Air (midealocal) | mapp.appsmb.com | ❌ | N/A | Login failed |
Conclusion: getToken fails regardless of credentials or library. The device has no LAN token in the cloud despite being connected via WLAN and remotely controllable through the MSmartHome app. Initial BLE pairing likely explains the absence of a LAN token — re-pairing via WLAN setup should provision one.
getToken Failure — All udpid Methods Tested
msmart-ng Security.udpid(data): sha256(data).digest(), XOR first 16 bytes with second 16 bytes → .hex() (32 hex chars)
from msmart.lan import Security
for endian in ["little", "big"]:
data = device_id.to_bytes(6, endian)
udpid = Security.udpid(data).hex() # → "ad4d091264847e0f..." / "b7f074ba7343aa11..."
midealocal CloudSecurity.get_udp_id(): 3 methods (different byte slicing/reversing)
# All return {"code":"3004","msg":"value is illegal."}
methods = {
0: "REVERSED_BIG", # bytes(reversed(id.to_bytes(8, "big")))
1: "BIG", # id.to_bytes(6, "big")
2: "LITTLE", # id.to_bytes(6, "little"),
}
Also tested: 8-byte big/little endian, btMac bytes (102c8d344aae), SN string bytes — ALL return 3004.
Device Cloud Info (from list_appliances)
{
"id": "153931628805781",
"name": "OGKlimaanlage",
"type": "0xAC",
"modelNumber": "524",
"sn": "000000P0000000Q1102C8D344AAE0000",
"sn8": "00000Q11",
"onlineStatus": "1",
"connectType": "1",
"btMac": "102c8d344aaf",
"btToken": "6000001415208481",
"registerTime": "Tue Jun 17 09:40:37 UTC 2025"
}
Key insight: btToken and btMac present but NO mac field (null). connectType: "1" indicates initial BLE pairing. However, user confirmed the device IS connected via WLAN and remotely controllable through the MSmartHome app — so the device has WiFi, but the cloud has no LAN token provisioned (likely because initial pairing was via BLE, not WLAN setup).
Default Keys Test
midealocal.DEFAULT_KEYS (method 99) returns a token/key pair, but authentication via msmart.lan.LAN.authenticate() fails with "Error packet received" — these are generic placeholders, not device-specific keys.
Resolution
- Re-pair the device via WLAN setup in the MSmartHome app (not Bluetooth) — this should generate a LAN token in the Midea cloud
- After re-pairing, re-run
cloud.get_cloud_keys(153931628805781)— if it returns keys, use the manual config flow - Alternatively: use the MSmartHome app's "Gerät Startposition" (shown as
UnasBiFNEq...) — this may be the udpid, but it was truncated in the app UI - Once token+k1 obtained: use manual config flow:
POST /api/config/config_entries/flow {"handler":"midea_ac"} → choose "manual" → {"id":"153931628805781","host":"10.0.40.54","port":6444,"device_type":"AC","token":"TOKEN_HEX","k1":"KEY_HEX"}
Pending
- ✅ Midea credentials stored in 1Password (Vault "Hermes", item "Midea MSmartHome", ID jzlkqibo44e6nz6gtvcqf7dg6q)
- Verify re-pairing via WLAN setup generates a LAN token