# Cron Job: Klima ausschalten in 15min

**Job ID:** 8179d7c82c74
**Run Time:** 2026-06-18 20:25:49
**Schedule:** once in 15m

## Prompt

[IMPORTANT: The user has invoked the "home-assistant" skill, indicating they want you to follow its instructions. The full skill content is loaded below.]

---
name: home-assistant
description: Inspect, manage, and troubleshoot Home Assistant (Docker on ZimaOS) — config, devices, integrations, automations, and Zigbee.
version: 1.0.0
author: Hermes Agent
license: MIT
metadata:
  hermes:
    tags: [home-assistant, smart-home, zigbee, docker, zimaos]
    related_skills: [openhue, zimaos-camofox-browser]
---

# Home Assistant (ZimaOS Docker)

Manage a Home Assistant instance running as a Docker container on ZimaOS. Covers inspection (with and without API access), device management, Zigbee, and troubleshooting.

## Quick Status Check

```bash
# Is it running?
docker ps --filter name=homeassistant --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"

# Version and uptime
docker inspect homeassistant --format '{{.Config.Image}} | Started: {{.State.StartedAt}}'

# Config path on ZimaOS
# /DATA/AppData/homeassistant/config/
```

Port: **8123** (internal). API requires authentication — use a long-lived token from the HA UI (Profile → Security → Long-Lived Access Tokens).

## Inspection WITHOUT API Token (read filesystem directly)

When no API token is available, read the `.storage/` JSON files directly. Every integration, device, entity, area, and automation is stored as clean JSON.

**CRITICAL: Always use `docker cp` + `docker exec` for Python scripts.** Inline Python one-liners in shell commands break on quote/escape nesting (f-strings, Unicode escapes, nested quotes). The reliable pattern is:

```bash
# 1. Write the script on the host (via write_file or heredoc)
# 2. Copy it into the container
docker cp /tmp/script.py homeassistant:/tmp/script.py
# 3. Run it
docker exec homeassistant python3 /tmp/script.py
```

Hermes' `execute_code` / `read_file` tools cannot reliably read HA storage files from the ZimaOS host — files are owned by the container's internal user and may have permission issues. Always go through the container.

### Key Files (in /DATA/AppData/homeassistant/config/.storage/)

| File | Contains |
|---|---|
| `core.config_entries` | All integrations (integrations installed, their config, connection params) |
| `core.device_registry` | All physical/virtual devices (manufacturer, model, area assignment, MAC) |
| `core.entity_registry` | All entities (switches, sensors, buttons, notifications — with entity_id) |
| `core.area_registry` | Rooms/zones (name, icon, ID) |
| `core.config` | Global HA config (unit system, language, timezone, elevation, lat/lon) |
| `auth` + `auth_provider.homeassistant` | User accounts, tokens |
| `http.auth` | Trusted proxies, CORS |
| `automations.yaml` | Automation definitions (separate YAML file, not in .storage/) |
| `scripts.yaml` | Script definitions |
| `configuration.yaml` | Main config (what's included, themes, etc.) |

### Common Inspection Queries

For quick one-off queries, use `docker exec` with a simple inline script. For complex queries, use the `docker cp + exec` pattern described above.

```bash
# List all integrations with titles
docker exec homeassistant python3 -c "
import json
with open('/config/.storage/core.config_entries') as f:
    data = json.load(f)
for e in data['data']['entries']:
    print(e['domain'], '|', e.get('title',''), '|',
          'DISABLED' if e.get('disabled_by') else 'active')
"

# List devices by area
docker exec homeassistant python3 -c "
import json
with open('/config/.storage/core.device_registry') as f:
    data = json.load(f)
with open('/config/.storage/core.area_registry') as f2:
    areas = {a['id']: a['name'] for a in json.load(f2)['data']['areas']}
for d in data['data']['devices']:
    area = areas.get(d.get('area_id'), '-')
    print(d['name'], '|', area, '|', d.get('manufacturer',''), d.get('model',''))
"

# List all entity_ids by domain
docker exec homeassistant python3 -c "
import json
from collections import defaultdict
with open('/config/.storage/core.entity_registry') as f:
    entities = json.load(f)['data']['entities']
by_domain = defaultdict(list)
for e in entities:
    by_domain[e.get('domain','?')].append(e['entity_id'])
for domain in sorted(by_domain):
    print('---', domain, '({})'.format(len(by_domain[domain])), '---')
    for eid in sorted(by_domain[domain]):
        print(' ', eid)
"
```

### Reading Alexa Integration Token

The `core.config_entries` contains the Alexa access token (for `alexa_devices` integration) — it's stored in `data.login_data.access_token`. Useful for debugging, but handle carefully.

## Docker Management

```bash
# Container mounts
docker inspect homeassistant --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'

# Restart
docker restart homeassistant

# Logs (last 100 lines)
docker logs --tail 100 homeassistant

# Follow logs
docker logs -f homeassistant
```

On ZimaOS, the container stores everything at `/DATA/AppData/homeassistant/config/`. The Docker socket is at `/var/run/docker.sock` (shared with ZimaOS host).

## Adding Devices

### Zigbee Devices

For Zigbee-based devices (Philips Hue, IKEA Trådfri, Aqara, Sonoff sensors, etc.) you need a Zigbee coordinator (USB dongle) — the ZimaOS server's built-in Bluetooth adapter is NOT Zigbee-compatible.

**Recommended dongles (20–40 €):**
- **Sonoff Zigbee 3.0 USB Dongle Plus** (~25 €, most popular)
- **SkyConnect** (official Nabu Casa, ~35 €)
- **ConBee II** (~35 €)

**Setup:**
1. Buy dongle, plug into ZimaOS USB port
2. Pass the USB device to the HA container (add `--device /dev/ttyUSB0:/dev/ttyUSB0` to docker run, or add `devices:` in docker-compose)
3. In HA UI: Settings → Devices & Services → Add Integration → **ZHA** (or Zigbee2MQTT for advanced users)
4. Select the USB dongle as coordinator
5. Add devices: click "Add Device" in ZHA, then put the bulb in pairing mode (usually power-cycle 5× quickly)

**Alternative: Alexa Echo with built-in Zigbee hub**
- Echo Plus, Echo Show 10, Echo 4th Gen have Zigbee hubs built in
- Echo Dot, Echo Pop, Echo Spot do NOT
- If you have a compatible Echo, pair the bulb through the Alexa app and it appears in HA via the Alexa integration

### Amazon Basics Smart Bulbs (WiFi/Tuya — NOT Zigbee!)

**IMPORTANT:** Amazon Basics Smart Light Bulbs (A60/E27, color changing) use **WiFi (Tuya platform)**, not Zigbee. They ship with Amazon's cloud firmware. The Alexa integration does NOT pass them through to HA — they'll appear as Alexa-paired but won't show up in HA entities.

**Alexa-paired vs Tuya-paired firmware behavior:**

| Attribute | Alexa-paired (out of box) | Smart Life app-paired |
|---|---|---|
| Tuya LAN ports (6667/6668) | **Closed** — no local access | **Open** — `tinytuya` scan works |
| UDP broadcast response | **None** — `deviceScan()` silent | Responds to discovery |
| Cloud API login | May fail ("Username or password error") | Works with Smart Life account |
| LocalTuya setup | **Impossible** without re-pairing | Direct Local Key extraction |

**If bulbs are currently Alexa-paired, you MUST factory-reset at least one bulb and re-pair it via the Smart Life app** to enable the Tuya LAN protocol. Without this step, no local integration is possible — the bulbs are cloud-locked to Alexa.

**Three integration options (best to worst):**

1. **LocalTuya (RECOMMENDED — fully local, no cloud):** Install HACS → install LocalTuya → get Local Keys from iot.tuya.com → configure each bulb with Device ID + Local Key + IP. See full workflow below.
2. **Official Tuya Cloud integration (simple but cloud-dependent):** Settings → Integrations → Tuya → log in with Smart Life account. Works immediately but every command goes through Tuya's cloud.
3. **HA-native tuya-local (middle ground):** Requires Local Keys but no HACS needed. Available in the Tuya integration setup dialog.

### WiFi/Tuya Devices (TP-Link Kasa/KP105, Amazon Basics, etc.)

Already natively supported — autodiscovered via DHCP or added manually: Settings → Devices & Services → Add Integration → TP-Link Smart Home.

#### Full LocalTuya Setup (for Amazon Basics WiFi bulbs and other Tuya devices)

**Prerequisites:**
- Bulb is configured in Smart Life / Tuya Smart app and working
- Bulb is on the same subnet as the HA server (192.168.178.x in this setup)

**Step 1: Install HACS (if not already present)**

```bash
cd /DATA/AppData/homeassistant/config
mkdir -p custom_components
curl -sL "https://github.com/hacs/integration/releases/latest/download/hacs.zip" -o /tmp/hacs.zip
unzip -o /tmp/hacs.zip -d custom_components/hacs/
docker restart homeassistant
# Wait ~15s for HA to come back up
```

After restart, HACS appears in the HA sidebar. Complete the setup wizard (it'll need GitHub auth).

**Step 2: Install LocalTuya**

```bash
cd /DATA/AppData/homeassistant/config
curl -sL "https://github.com/rospogrigio/localtuya/archive/refs/heads/master.zip" -o /tmp/localtuya.zip
unzip -o /tmp/localtuya.zip -d /tmp/localtuya_extract/
cp -r /tmp/localtuya_extract/localtuya-master/custom_components/localtuya custom_components/
docker restart homeassistant
```

**Step 3: Get Local Keys (two approaches)**

**Approach A: tinytuya CLI (FAST — when bulbs are Smart Life-paired)**

```bash
# Install
python3 -m pip install tinytuya

# Quick scan — discovers Tuya devices on the same subnet via UDP broadcast (ports 6666/6667)
python3 -c 'import tinytuya; print(tinytuya.deviceScan())'

# If scan succeeds, extract Local Key for each device:
python3 -c '
import tinytuya, json
for dev in tinytuya.deviceScan():
    d = tinytuya.Device(dev["id"], dev["ip"], dev["key"])
    print(f"Device ID: {dev[\"id\"]}  IP: {dev[\"ip\"]}  Key: {dev[\"key\"]}")
'
```

This works ONLY if bulbs are paired via Smart Life/Tuya Smart app (Tuya LAN protocol active). Alexa-paired bulbs have Tuya LAN ports closed and will not respond.

**Tuya Cloud API endpoints (tested):**

| Endpoint | URL | Result |
|---|---|---|
| Home Assistant bridge (EU) | `px1.tuyaeu.com/homeassistant/auth.do` | 200 — but rejects if no Tuya account exists |
| Home Assistant bridge (US) | `px1.tuyaus.com/homeassistant/auth.do` | Same — region doesn't matter for auth |
| IoT OpenAPI login | `openapi.tuyaeu.com/v1.0/iot-01/users/login` | 200 — but needs Client ID/Secret from Cloud project |
| IoT token endpoint | `openapi.tuyaeu.com/v1.0/token` | 200 — requires timestamp signature |

No endpoint accepts bare username/password without prior project registration. The IoT Platform requires a Cloud project with Client ID/Secret.

**Approach B: IoT Platform Web UI (MANUAL — always works)**

User must visit [iot.tuya.com](https://iot.tuya.com):
1. Register free developer account
2. Cloud → Create Project (name doesn't matter)
3. Cloud → Devices → Link App Account → scan QR code with Smart Life app
4. All bulbs appear with Device ID
5. Click each Device ID → Debug Device → note the **Local Key**

**Step 4: Configure in HA UI**

Settings → Devices & Services → Add Integration → **LocalTuya** → configure each bulb:
- Host: static IP of bulb (find via router DHCP table)
- Device ID: from iot.tuya.com
- Local Key: from iot.tuya.com
- Protocol: usually 3.3 (auto-detect)
- Device type: for color bulbs use `RGBTW` or `RGB+WW`

**Key pitfalls:**
- Bulbs must have static IPs (or DHCP reservations) — if IP changes, they drop offline
- The Local Key is unique per device — you must repeat the iot.tuya.com flow for each bulb
- Bulb must be on the same subnet as HA (no VLAN isolation)
- Amazon Basics bulbs are plain Tuya whitelabel products — no Amazon-specific protocol

**Alexa integration note:** The Alexa integration in HA imports Echo devices, alarms, timers, and routines as entities, but does NOT pass through individual Zigbee/WiFi bulbs paired to Alexa. For those, use LocalTuya (WiFi) or ZHA (Zigbee).

### WiFi Devices (TP-Link Kasa/KP105)

Already natively supported — autodiscovered via DHCP or added manually: Settings → Devices & Services → Add Integration → TP-Link Smart Home.

### HomeKit Devices

HA has a built-in HomeKit Controller integration (to control HomeKit devices) AND a HomeKit Bridge (to expose HA devices to Apple Home). Both in Integrations.

## API Control (curl + REST)

HA exposes a REST API on port 8123. All calls need `Authorization: Bearer <token>`.

### Getting a Token

Long-Lived Access Tokens stored in `.storage/auth` are **SHA256-hashed** — the raw string cannot be recovered from disk. Two options:

**Option A: User creates one via UI (recommended for permanent use)**
HA UI → Profile (bottom-left) → Security → Long-Lived Access Tokens → Create Token. Store it as an env var.

**Option B: Exchange a refresh token (headless, no UI needed)**
The `auth` JSON contains unhashed refresh tokens. Exchange one for a 30-min JWT access token:

```bash
docker exec homeassistant python3 -c "
import json, urllib.request, urllib.parse
with open('/config/.storage/auth') as f:
    auth = json.load(f)
for rt in auth['data']['refresh_tokens']:
    if rt['token_type'] == 'normal' and rt.get('last_used_at'):
        params = {'grant_type': 'refresh_token', 'refresh_token': rt['token']}
        cid = rt.get('client_id')
        if cid:
            params['client_id'] = cid  # MUSS exakt aus dem Store sein!
        data = urllib.parse.urlencode(params).encode()
        req = urllib.request.Request('http://localhost:8123/auth/token', data=data,
            headers={'Content-Type': 'application/x-www-form-urlencoded'})
        with urllib.request.urlopen(req) as resp:
            print(json.loads(resp.read())['access_token'])
        break
"
# Store in shell: TOKEN="eyJ..."
# Use with: curl -H "Authorization: Bearer $TOKEN" ...
```

The JWT expires after 30 minutes. For persistent use, create a Long-Lived Token via the UI.

### Sending Commands

```bash
# Get entity state
curl -s -H "Authorization: Bearer $TOKEN" "http://localhost:8123/api/states/<entity_id>"

# Call a service
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"entity_id": "<entity_id>", <other_params>}' \
  "http://localhost:8123/api/services/<domain>/<service>"
```

### Pitfalls

- **Long-Lived Tokens in `.storage/auth` are hashed** — they cannot be extracted as raw strings. Use the refresh-token exchange or create one via UI.
- **Refresh tokens have ~6 month expiry** — any `normal` token with `last_used_at` is likely still valid for exchange.
- **Don't create tokens via raw JSON injection** — they get hashed and the raw string is lost. Only the HA auth endpoint can issue usable tokens.

## Full Inventory Script

A proven Python script that reads all `.storage/` JSON files and prints a complete inventory: devices (with areas, MACs), integrations, and entities grouped by domain. See `scripts/ha-full-inventory.py`.

Usage:
```bash
docker cp /tmp/ha_full_inventory.py homeassistant:/tmp/
docker exec homeassistant python3 /tmp/ha_full_inventory.py
```

## Device & Entity Cleanup (No API)

Devices and entities can be removed by directly editing `.storage/` JSON files — no API token needed. Useful for bulk cleanup of decommissioned devices or spammy auto-created entities (e.g., Alexa Speaker Groups that aren't used).

**Pattern:** Identify `device_id` values, then filter them out of both `core.device_registry` and `core.entity_registry`:

```python
import json

device_ids = ['id1', 'id2', 'id3']  # from inventory output

# Remove devices
with open('/config/.storage/core.device_registry', 'r') as f:
    dev_data = json.load(f)
dev_data['data']['devices'] = [
    d for d in dev_data['data']['devices']
    if d['id'] not in device_ids
]
with open('/config/.storage/core.device_registry', 'w') as f:
    json.dump(dev_data, f, indent=2)

# Remove their entities (entities reference device_id)
with open('/config/.storage/core.entity_registry', 'r') as f:
    ent_data = json.load(f)
ent_data['data']['entities'] = [
    e for e in ent_data['data']['entities']
    if e.get('device_id') not in device_ids
]
with open('/config/.storage/core.entity_registry', 'w') as f:
    json.dump(ent_data, f, indent=2)
```

**Pitfalls:**
- No HA restart needed — changes take effect on next state refresh
- Don't edit JSON while HA is writing to the files (safe during normal operation, avoid during integration setup)
- Some entities may lack `device_id` — they won't be caught by this filter. Check the inventory output first.

## Device-Specific Integrations

- **Midea Klimaanlage:** See `midea-ac-ha` skill — integration setup, HA 2026 patches, token discovery via msmart-ng, and API control (note: `turn_on` is NOT supported — use `set_hvac_mode` directly to switch on/off).

## Troubleshooting

| Problem | Check |
|---|---|
| Container won't start | `docker logs homeassistant` — often a YAML syntax error in configuration.yaml |
| Integration fails to load | `core.config_entries` — look for `disabled_by` field. Remove and re-add in UI. |
| Zigbee device not discovered | USB passthrough working? `ls -la /dev/ttyUSB*` inside container. Try ZHA → Add Device again. |
| 401 from API | Token missing/expired — use refresh-token exchange (above) or create a Long-Lived Token in the UI |
| Config changes not taking effect | `docker restart homeassistant` or use Developer Tools → Check Configuration in UI |

## ZimaOS-Specific Notes

- Config lives at `/DATA/AppData/homeassistant/config/` (Docker bind mount)
- Files are owned by the container's internal user — use `docker exec homeassistant cat /config/...` if permissions block direct reads
- HA port 8123 is exposed on the host — access via `http://zimaos-ip:8123` on the local network
- The ZimaOS Docker UI manages the container lifecycle; docker CLI commands work but may conflict with ZimaOS's own management
- Long-Lived Access Tokens in `.storage/auth` are **SHA256-hashed** — the raw string cannot be recovered. Use the refresh-token exchange method (see API Control section) or create one via the HA UI (Profile → Security → Long-Lived Access Tokens)

## Device-Specific Integrations

- **Midea Klimaanlage:** See `midea-ac-ha` skill — integration setup, HA 2026 patches, token discovery via msmart-ng, and API control (note: `turn_on` is NOT supported — use `set_hvac_mode` directly to switch on/off).

[IMPORTANT: The user has invoked the "midea-ac-ha" skill, indicating they want you to follow its instructions. The full skill content is loaded below.]

---
name: midea-ac-ha
description: Midea Porta Split Klimaanlage in Home Assistant 2026 einbinden — Integration, Patches, Token-Beschaffung und Diagnose.
version: 1.0.1
author: Claude (via Hermes, 2026-06-04)
license: MIT
metadata:
  hermes:
    tags: [home-assistant, midea, climate, hvac, smart-home]
    related_skills: [home-assistant, zimaos-administration]
    source: Claude Code handover 2026-06-04
---

# Midea Klimaanlage in Home Assistant 2026

Einbindung einer Midea Porta Split Klimaanlage in Home Assistant 2026.5.4 auf ZimaOS Docker.

## Integration

**georgezhao2010/midea_ac_lan** (GitHub, master branch). Download über lokalen Mac + SCP — git auf ZimaOS funktioniert nicht.

```bash
curl -L "https://github.com/georgezhao2010/midea_ac_lan/archive/refs/heads/master.zip" -o /tmp/midea_ac_lan.zip
cd /tmp && unzip -q midea_ac_lan.zip
scp -i ~/.ssh/id_ed25519 -r /tmp/midea_ac_lan-master/custom_components/midea_ac_lan \
  root@100.113.239.44:/DATA/AppData/homeassistant/config/custom_components/
```

## 4 Pflicht-Patches für HA 2026

**Diese Patches MÜSSEN vor dem HA-Start angewendet werden.**

### A) midea_devices.py — Veraltete Einheits-Konstanten ersetzen

```python
from homeassistant.const import (
    Platform, PERCENTAGE, CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
    CONCENTRATION_PARTS_PER_MILLION, UnitOfTime, UnitOfTemperature,
    UnitOfPower, UnitOfVolume, UnitOfEnergy,
)
TIME_DAYS = UnitOfTime.DAYS
TIME_HOURS = UnitOfTime.HOURS
TIME_MINUTES = UnitOfTime.MINUTES
TIME_SECONDS = UnitOfTime.SECONDS
TEMP_CELSIUS = UnitOfTemperature.CELSIUS
POWER_WATT = UnitOfPower.WATT
VOLUME_LITERS = UnitOfVolume.LITERS
ENERGY_KILO_WATT_HOUR = UnitOfEnergy.KILO_WATT_HOUR
```

### B) climate.py + water_heater.py — TEMP_CELSIUS → UnitOfTemperature

```python
from homeassistant.const import UnitOfTemperature
# Alle return TEMP_CELSIUS ersetzen durch:
return UnitOfTemperature.CELSIUS
```

### C) climate.py — AUX_HEAT entfernen

`ClimateEntityFeature.AUX_HEAT` komplett aus den Feature-Flags entfernen. **Achtung:** Kein `| \ ` am Zeilenende stehen lassen (SyntaxError!).

### D) __init__.py — Config Entry API umbenannt

```python
# ALT (funktioniert nicht mehr in HA 2026):
for platform in ALL_PLATFORM:
    hass.async_create_task(hass.config_entries.async_forward_entry_setup(config_entry, platform))
for platform in ALL_PLATFORM:
    await hass.config_entries.async_forward_entry_unload(config_entry, platform)

# NEU:
hass.async_create_task(hass.config_entries.async_forward_entry_setups(config_entry, ALL_PLATFORM))
await hass.config_entries.async_unload_platforms(config_entry, ALL_PLATFORM)
```

## Token-Problem — der wichtigste Trick

Die MSmartHome Cloud-API gibt für viele Geräte Fehler **3004: value is illegal**. Der eingebaute Fallback-Token (`key_id=99`) wird vom Gerät mit ERROR abgewiesen.

**Lösung: msmart-ng** — holt den Token direkt aus der UDP-Discovery-Antwort, kein Cloud-Login nötig:

```bash
docker exec homeassistant pip install msmart-ng
docker exec homeassistant python3 -m msmart.cli discover <GERAET_IP>
# Ausgabe enthält direkt: token, key, device_id
```

Token anschließend in beide Dateien eintragen + Protokoll auf 3 setzen:

```python
import json

REAL_TOKEN = '<token aus msmart-ng>'
REAL_KEY   = '<key aus msmart-ng>'
DEVICE_ID  = <device_id>

# Device-Config:
with open(f'/DATA/AppData/homeassistant/config/.storage/midea_ac_lan/{DEVICE_ID}.json', 'r') as f:
    dev = json.load(f)
dev.update({'token': REAL_TOKEN, 'key': REAL_KEY, 'protocol': 3})
with open(f'/DATA/AppData/homeassistant/config/.storage/midea_ac_lan/{DEVICE_ID}.json', 'w') as f:
    json.dump(dev, f, indent=2)

# Config Entry:
with open('/DATA/AppData/homeassistant/config/.storage/core.config_entries', 'r') as f:
    data = json.load(f)
for entry in data['data']['entries']:
    if entry.get('domain') == 'midea_ac_lan':
        entry['data'].update({'token': REAL_TOKEN, 'key': REAL_KEY, 'protocol': 3})
with open('/DATA/AppData/homeassistant/config/.storage/core.config_entries', 'w') as f:
    json.dump(data, f, indent=2)
```

## Diagnose-Schnellreferenz

```bash
# Midea-Gerät im Netz finden (Port 6444):
for ip in 192.168.178.{1..254}; do
  (timeout 0.3 bash -c "echo >/dev/tcp/$ip/6444" 2>/dev/null && echo "Midea: $ip") &
done; wait

# Logs nach Neustart prüfen:
docker logs homeassistant 2>&1 | grep -iE '(midea|handshak|auth|ERROR)' | grep -v pyhap | tail -30
```

## V2 vs V3 Protokoll

V2-Verbindung sieht erfolgreich aus, liefert aber bei V3-Geräten **nie Status-Updates**. **Immer Protokoll 3 + richtigen Token verwenden.**

## Bonus: Celsius + Raum-Zuweisung

```python
# Celsius (in core.config):
config['data']['unit_system_v2'] = 'metric'  # statt 'us_customary'

# Raum (in core.device_registry):
dev['area_id'] = 'schlafzimmer'  # area_id aus core.area_registry
```

## Steuerung per HA API

Die Midea-Integration unterstützt `climate.turn_on` NICHT — der Service wirft `ServiceNotSupported`. Stattdessen einfach den Mode setzen, das schaltet implizit ein:

```bash
# FALSCH (500 Error):
curl -X POST .../api/services/climate/turn_on -d '{"entity_id": "climate.152832117784908_climate"}'

# RICHTIG — nur set_hvac_mode (kein turn_on, kein set_temperature gleichzeitig):
curl -X POST .../api/services/climate/set_hvac_mode \
  -d '{"entity_id": "climate.152832117784908_climate", "hvac_mode": "cool"}'
# Klima geht automatisch an. Kein Chainen von Services.
```

HVAC modes: `off`, `auto`, `cool`, `dry`, `heat`, `fan_only`.

### API-Token beschaffen (wenn kein Long-Lived Token da)

Long-Lived Access Tokens aus dem Auth-Store sind SHA256-gehasht und als API-Token unbrauchbar. Stattdessen einen normalen Refresh-Token nehmen und per `/auth/token` austauschen:

```python
import json, urllib.request, urllib.parse
with open('/config/.storage/auth') as f:
    auth = json.load(f)
for rt in auth['data']['refresh_tokens']:
    if rt['token_type'] == 'normal' and rt.get('last_used_at'):
        data = urllib.parse.urlencode({
            'grant_type': 'refresh_token',
            'refresh_token': rt['token'],
            'client_id': rt.get('client_id', 'http://localhost:8123/'),
        }).encode()
        req = urllib.request.Request('http://localhost:8123/auth/token', data=data)
        with urllib.request.urlopen(req) as resp:
            access = json.loads(resp.read())['access_token']
        break
# access ist ein JWT, gültig für 30 Minuten
```

Alle API-Calls dann mit `Authorization: Bearer $access`.

### Status abfragen

```bash
curl -s -H "Authorization: Bearer $TOKEN" \
  "http://localhost:8123/api/states/climate.152832117784908_climate"
# Wichtige Felder: state (off/cool/heat/...), attributes.temperature, attributes.current_temperature, attributes.hvac_modes
```

## Pitfalls

- **Patches VOR dem ersten HA-Start** — sonst crasht die Integration beim Laden
- **AUX_HEAT-Flag entfernen, aber kein `| \ ` am Zeilenende lassen** — sonst SyntaxError
- **Niemals git clone auf ZimaOS** — git funktioniert dort nicht. Immer Mac + SCP
- **V2-Protokoll = keine Status-Updates** — sieht verbunden aus, tut aber nichts
- **msmart-ng ist der einzige zuverlässige Weg** an echte Tokens zu kommen — MSmartHome Cloud API gibt 3004
- **`climate.turn_on` wird nicht unterstützt!** Nur `set_hvac_mode` verwenden — das schaltet implizit ein. Kein Chainen von Services (kein turn_on + mode + temperature in schneller Folge)
- **Long-Lived Access Token sind gehashed** — nicht direkt als API-Token verwendbar. Stattdessen Refresh-Token-Austausch nutzen (normale Refresh-Tokens brauchen exakt ihre gespeicherte `client_id` im Form-Body)

The user has provided the following instruction alongside the skill invocation: [IMPORTANT: You are running as a scheduled cron job. DELIVERY: Your final response will be automatically delivered to the user — do NOT use send_message or try to deliver the output yourself. Just produce your report/output as your final response and the system handles the rest. SILENT: If there is genuinely nothing new to report, respond with exactly "[SILENT]" (nothing else) to suppress delivery. Never combine [SILENT] with content — either report your findings normally, or say [SILENT] and nothing more.]

Schalte die Midea Klimaanlage in Home Assistant aus. Nutze den Home Assistant API Token per Refresh-Token-Austausch (docker exec homeassistant python3 -c "..."). Entity: climate.152832117784908_climate. Schalte sie aus per set_hvac_mode mit hvac_mode: "off". Bestätige danach den Status (state sollte "off" sein). Sag dem User: "Klima ist jetzt ausgeschaltet, Boss! 🌬️"

## Response

Klima ist jetzt ausgeschaltet, Boss! 🌬️

- **State:** `off` ✅
- **Raumtemperatur:** 22.0 °C (bleibt unverändert)
- **Zieltemperatur:** 20.0 °C (wird beim nächsten Einschalten wieder aktiv)
