Files
hermes-skills/smart-home/smart-home-automation/references/midea-ac-debugging.md
T

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

  1. Initiate: POST /api/config/config_entries/flow with {"handler":"midea_ac"}
  2. Menu: Choose discover or manual
  3. Discover: Submit {"host":"10.0.40.54","country_code":"DE"} — uses cloud credentials to get token/k1
  4. 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
  • SmartHomeCloud has DE shared credentials: midea_eu@mailinator.com / das_ist_passwort1
  • SmartHomeCloud also accepts personal user credentials — login succeeds, but getToken still returns 3004
  • NetHomePlusCloud is used by Discover.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.cloud class with login(), 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 with ha 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

  1. Re-pair the device via WLAN setup in the MSmartHome app (not Bluetooth) — this should generate a LAN token in the Midea cloud
  2. After re-pairing, re-run cloud.get_cloud_keys(153931628805781) — if it returns keys, use the manual config flow
  3. 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
  4. 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