16 KiB
TP17 — Shelly VLAN1→VLAN30 Go-Runbook
Stand: 2026-07-11 (live-verifiziert, go-ready). Morgen = nur noch ausführen.
Steuerung/Scope: docs/teilprojekte.md → TP17 · Tooling: mcp/shelly/ · Memory: project_shelly_migration_tp17.
TL;DR
Alles Nicht-Disruptive ist gestellt. Morgen früh nur noch: die 16 verbliebenen VLAN1-Shellys
per WiFi.SetConfig auf dirtyvader-iot umklemmen (Batch), je Gerät auf .30.x verifizieren,
dann HA/ioBroker gegenchecken. Pilot ist faktisch schon bestanden (5 Geräte laufen seit ~2,5 Tagen stabil auf VLAN30).
Ist-Stand Shelly-Flotte (live 2026-07-11)
26 Shellys total (25 mit MAC + s24 ohne MAC-Eintrag). Verteilung jetzt:
| Gruppe | Anzahl | Geräte | Status |
|---|---|---|---|
| ✅ Schon auf VLAN30 | 5 (+1?) | s14 .30.221, s16 .30.223, s18 .30.225, s22 .30.202, s23 .30.203 (+ .30.204 unbekannt, evtl. s24) |
stabil ~2,5 d, reservierte IP getroffen |
| 🔜 Noch auf VLAN1 → morgen | 16 | s4–s11, s13, s15, s17, s19, s20, s21, s25, s26 | live auf 10.40.41.2xx, alle Gen3/4 |
| ⏸️ Aus (später) | 4 | s1/s2/s3 weihnachten_* (saisonal ausgesteckt), s12 dieleug_steckdosen |
migrieren beim nächsten Einstecken |
Was heute schon gestellt ist (Prereqs ✅)
- DHCP-Reservierungen aller Shellys in
dhcp-v30angelegt (letztes Oktett erhalten,.30.2xx, außerhalb Pool.100–.200→ kollisionsfrei). - s6-Reservierung
.30.213MAC korrigiert (war falsch0C:72:74:36:90:9E→ realD0:CF:13:D8:18:FC) — 2026-07-11. - IOT-SSID live verifiziert:
w2-iot(ap1, 2,4 GHz, VLAN30)running:true, 8 echte Clients authorized, Signal −26…−68 dBm. ⚠️wifi2-Master zeigtrunning:false— kosmetisch, VAP trägt nachweislich Traffic. - Tooling
mcp/shelly/fertig:discover.py(read-only Sweep) +server.py(MCP:discover/get/set_sta/verify/reservation_plan), PSK in.envgesetzt.
Migrationsliste — die 16 (morgen)
Ziel-IP = letztes Oktett erhalten; alle Reservierungen existieren & MAC-verifiziert.
| id | Name | jetzt (VLAN1) | MAC | Ziel (VLAN30) |
|---|---|---|---|---|
| s4 | kueche_mikrowelle | 10.40.41.211 | e4:b0:63:e4:0f:30 | 10.40.30.211 |
| s5 | kueche_backofen | 10.40.41.212 | d8:85:ac:0c:5c:c8 | 10.40.30.212 |
| s6 | kueche_kuehlschrank | 10.40.41.213 | d0:cf:13:d8:18:fc | 10.40.30.213 |
| s7 | kueche_tiefkuehlschrank | 10.40.41.214 | d0:cf:13:d9:94:e8 | 10.40.30.214 |
| s8 | kueche_geschirrspueler | 10.40.41.215 | e4:b0:63:fa:fd:e0 | 10.40.30.215 |
| s9 | wohnzimmer_sideboard | 10.40.41.216 | e8:f6:0a:61:88:08 | 10.40.30.216 |
| s10 | bad_sonos | 10.40.41.217 | e4:b0:63:fc:57:e4 | 10.40.30.217 |
| s11 | kinderzimmer_sonos | 10.40.41.218 | e4:b0:63:fa:6c:00 | 10.40.30.218 |
| s13 | arbeitszimmer_technik | 10.40.41.220 | 48:f6:ee:dd:6a:f4 | 10.40.30.220 |
| s15 | technik_pve | 10.40.41.222 | e4:b0:63:fa:d5:34 | 10.40.30.222 |
| s17 | bad_steckdosen | 10.40.41.224 | 10:20:ba:fb:6d:64 | 10.40.30.224 |
| s19 | kueche_steckdosen3 | 10.40.41.226 | 10:20:ba:fb:70:fc | 10.40.30.226 |
| s20 | kueche_steckdosen2 | 10.40.41.206 | 98:a3:16:7c:5f:ec | 10.40.30.206 |
| s21 | kueche_steckdosen4 | 10.40.41.207 | 20:6e:f1:01:f9:f8 | 10.40.30.207 |
| s25 | bad_lichtschalter | 10.40.41.205 | 98:a3:16:79:38:50 | 10.40.30.205 |
| s26 | bad_luefter | 10.40.41.233 | 98:a3:16:7a:a3:54 | 10.40.30.233 |
GO-Sequenz (morgen)
- Baseline-Sweep (beweist Ausgangslage):
python3 discover.py 10.40.41.180-250→ 16 erwartet. - Frischer Pilot 1 Gerät (unkritisch, always-on): s26 bad_luefter
.41.233.set_sta(confirm) → Gerät rebootet → nach ~30–60 s aufdirtyvader-iot.- Verify:
python3 discover.py 10.40.30.233→ muss antworten; SSID=dirtyvader-iot, IP.30.233. - Gegencheck HA/ioBroker: Entity
bad_luefterwieder erreichbar (neue IP).
- Batch Rest (15) — Küche-Cluster ggf. in 2 Wellen, damit nicht die halbe Küche gleichzeitig kurz offline ist. Reihenfolge unkritisch; Kühl-/Tiefkühlschrank (s6/s7) sind nur kurz WLAN-offline (Kompressor läuft weiter).
- Verify-Sweep:
python3 discover.py 10.40.30.100-250→ erwartet 5 (alt) + 16 (neu) = 21 (+ evtl. s24). - HA/ioBroker re-point aller 16 (+ die 5 bereits migrierten gegenchecken): neue
.30.2xx-IPs. - cudy-Alt-WLAN abbauen (erst wenn keine Shelly/Streu-Clients mehr in VLAN1 hängen).
- Nachziehen:
inventory/bf.csv,docs/ip-plan.md, ap1bf.lan-DNS (falls Shelly-Namen), SSoT TP17.
Pro Gerät: 3 Änderungen (nicht nur 2!)
Der User-Auftrag ist WLAN + IP + Geräte-Passwort vereinheitlichen — nicht nur WLAN/IP. Reihenfolge je Gerät, damit Recovery immer möglich bleibt:
(1) WLAN→VLAN30 mit STATISCHER IP (Gen2+ RPC, identisch für alle Gen3/4, auth=off).
Entscheidung (User 2026-07-11): alle Shellys bekommen ausnahmslos eine statische IP (letztes Oktett erhalten → 10.40.30.<octet>, gw/dns .30.1), plus die passende in-pool DHCP-Reservierung als Backup:
curl -s -X POST http://<VLAN1-IP>/rpc \
-H 'Content-Type: application/json' \
-d '{"id":1,"method":"WiFi.SetConfig","params":{"config":{"sta":{
"ssid":"dirtyvader-iot","pass":"<IOT-PSK>","enable":true,
"ipv4mode":"static","ip":"10.40.30.<octet>","netmask":"255.255.255.0",
"gw":"10.40.30.1","nameserver":"10.40.30.1"}}}}'
curl -s -X POST http://<VLAN1-IP>/rpc -d '{"id":1,"method":"Shelly.Reboot"}'
Oder via shelly-mcp set_sta {ip, confirm:true} (Default static=true, rechnet die Ziel-IP aus dem Oktett).
→ Gerät kommt exakt auf 10.40.30.<octet>. Verify (discover.py <neue-IP>).
Pool-Konvention: pool-v30 wurde 2026-07-11 auf 10.40.30.100-.250 erweitert, damit die Reservierungen (.202–.244) in-pool liegen (eine DHCP-Neuconfig liefert dann sofort brauchbare IPs).
(2) Einheitliches Geräte-Passwort (erst NACH erfolgreichem VLAN30-Verify):
# realm = Geräte-ID (shellyXXXX-<mac>), ha1 = SHA256("admin:<realm>:<PW>")
curl -s -X POST http://<VLAN30-IP>/rpc \
-d '{"id":1,"method":"Shelly.SetAuth","params":{"user":"admin","realm":"<device-id>","ha1":"<sha256>"}}'
⚠️ Realm ist geräteindividuell (shellyplugsg3-<mac> etc.) → ha1 muss pro Gerät berechnet werden (gleiches Klartext-PW, unterschiedlicher Hash). Das gehört als Tool set_auth in shelly-mcp/server.py (heute noch nicht drin — die Migration selbst braucht es nicht, nur der Passwort-Schritt).
(3) HA-Credential nachziehen: Shelly-Integration im HA-Config-Entry Username admin + PW eintragen (sonst werden die Entities nach Schritt 2 unavailable). Entity-IDs bleiben unverändert (HA keyt per Geräte-MAC, nicht IP/PW) — genau wie gefordert.
ENTSCHIEDEN (User 2026-07-11): eigenes Shelly-Admin-PW, bewusst getrennt vom WLAN-PSK.
→ Christoph liefert den Wert bzw. legt ihn selbst als SHELLY_DEVICE_PW in mcp/shelly/.env ab (chmod600),
nicht ins Repo/Log. PW/PSK niemals spiegeln. (User admin, Klartext-PW einheitlich, ha1 pro Gerät gehasht.)
Alternativ Schritt 1 via shelly-mcp set_sta {ip, confirm:true} (Dry-Run ohne confirm); IOT-PSK in mcp/shelly/.env (SHELLY_IOT_PSK).
Risiken & Rollback
- Falsches PSK → Gerät in AP-Mode (
Shelly*-SSID) → physischer Reset am Gerät nötig. Deshalb: immer erst Dry-Run/1 Pilot, PSK aus.env(verifiziert gesetzt, len 12). - Gerät kurz offline während Reboot (~30–60 s) → HA/ioBroker zeigen es kurz
unavailable, kommt selbst zurück. - Coverage: IOT ist 2,4-GHz-only. ap1
w2-iotträgt bereits 8 Clients gut (−26…−68 dBm), ap2 spiegelt die SSID. Küche/Bad = nah an ap1 → unkritisch. Falls ein Gerät nachset_stanicht auf.30.xauftaucht: an VLAN1-IP zurück-pingen (kommt es nach Timeout in AP-Mode zurück?), Signal/Standort prüfen. - Rollback je Gerät:
WiFi.SetConfigzurück auf altes cudy-WLAN/SSID (nur solange cudy noch steht). Nach cudy-Abbau kein WLAN-Rollback mehr → dann nur AP-Mode/Reset.
HA-Cross-Check (2026-07-11, alle Geräte mit IPv4 in Home Assistant)
Sweep über configuration_url aller HA-Devices (Container/Portainer/pve-„Geräte" zeigen alle auf .41.100/.126 = deren UI-URL, keine echten LAN-Hosts → ignoriert). Physische LAN-Geräte:
- Shellys: vollständig deckungsgleich mit dem Netz-Sweep.
.30.204aufgelöst: = Shelly „Bad/Spiegelschrank" (Shelly Plus RGBW PM,14:33:5c:d8:2d:7c) → sehr wahrscheinlich das inventarlose s24; damit 6 Shellys bereits auf VLAN30 (s14/16/18/22/23/24). ✅ Inventarbf.csvergänzen (s24-MAC). - Naming-Drift (nur kosmetisch, KEINE Entity-Änderung ohne Freigabe): s10 HA-Label „schlafzi/teststecker" vs. Inventar
bad_sonos; s18-Label „küche/steckdose 3-2" bei.30.202(=s22-Reservierung). Vor cudy-Abbau Labels/Inventar konsolidieren. - Sonos ×7 → VLAN40
.40.19x(korrekt, MEDIA). Brother MFC-J5720DW.10.199(VLAN10), Brother PT-P750W.30.5(VLAN30) — beide korrekt platziert. CCU/RaspberryMatic.20.232(VLAN20/INFRA, korrekt). - ⚠️
tasmota_plug9(Nous A1, Tasmota) in HA mit.41.206— aber.41.206gehört per ARP s20 (Shelly), also stale. Vollständiger Scan 2026-07-11: Tasmota-MAC08:f9:e0:72:12:b6ist nicht in ap1-ARP → kein aktives Gerät (bestätigt User-Ruling) → kein VLAN30-Mover; stale HA-Device entfernen (User).
Nachtrag — vollständiger HA-Device-Scan (alle Geräte mit MAC-Connection, nicht nur configuration_url): fördert 2 Media-Geräte ohne IP in der URL zutage, die der erste Sweep verpasst hat:
- Apple TV 4K (
2a:77:fe:14:ad:5f, „Wohnzimmer (2)") und Philips TV 50PUS7304 (44:d8:78:30:b8:d5) — beide aktuell aus/Standby (nicht in ap1-ARP). Zielnetz = VLAN40/MEDIA. ⚠️ Vor cudy-Abschuss verifizieren, ob sie schon aufdirtyvader-mediahängen oder noch am cudy/VLAN1 — sonst fällt der Wohnzimmer-TV/AppleTV mit dem cudy weg. (Einschalten → ap1-ARP prüfen.) - Apple TV 4K = sehr wahrscheinlich der aktive Thread-Border-Router für die bestehende IKEA-Matter-over-Thread-Flotte (22 Matter-Geräte in HA) → relevant für TP17.1 (Thread-Onboarding liefe über diesen BR bzw. einen HA-eigenen OTBR).
- Alle übrigen MAC-Geräte sind zugeordnet: Shellys, Sonos ×7 (VLAN40), Brother MFC (VLAN10). Radio-only-Geräte (Zigbee/Matter-over-Thread/BLE) haben keine IP → kein VLAN-Thema.
Netzweite Aufstellung → „ist VLAN1 danach leer?" (Netz-Wahrheit via ap1 ARP+DHCP, 2026-07-11)
Live in VLAN1 (bridge), klassifiziert nach Ziel-VLAN (Phantom-/failed-ARP-Leichen weggelassen):
| Gerät | VLAN1-IP | MAC | Ziel | Move-Trigger |
|---|---|---|---|---|
| 16 Shellys | .41.205–.233 | s.o. | VLAN30 | morgen (dieses Runbook) |
| SwitchBot floor-lamp | .41.184 | b8:f8:62:09:f2:04 | VLAN30 | Nicht-Shelly (Reservierung .30.227 steht) |
| Twinkly-Girlande | (saisonal off) | 98:f4:ab:2c:a7:88 | VLAN30 | Nicht-Shelly (Reservierung .30.228 steht); beim Einstecken |
| Creality Ender (3D-Drucker) | (aktuell off?) | ? | VLAN30 | Nicht-Shelly, „fehlt noch" (User) — beim nächsten Einschalten verorten + reservieren |
| MacBook-Air-M5 (Christoph) | .41.182 | c0:c7:db:de:71:be | VLAN10 | joint dirtyvader-main / cudy-Abbau |
| iPhone (Christoph) | .41.186 | f2:62:4c:e1:af:09 | VLAN10 | dito |
| pve-Host-Mgmt | .41.100 | 00:d0:b4:04:19:24 | VLAN20 | Host-Migration (nach Shellys) |
| sw1 ALLNET | .41.11 | 00:08:54:71:98:2d | VLAN99 | MGMT-Cutover (eigener Schritt) |
| sw2 Omada | .41.12 | a8:29:48:ee:b9:04 | VLAN99 | MGMT-Cutover |
| ap2-Mgmt | .41.2 | — | VLAN99 | MGMT-Cutover |
| ❓ unidentifiziert | .41.246 | 80:af:ca:7d:e5:b1 | ? | morgen identifizieren (nicht in HA) |
Nicht-Shelly-Mover (User-bestätigt 2026-07-11): SwitchBot floor-lamp + Twinkly-Girlande + Creality Ender (fehlt noch, off). Withings = schon übersiedelt (nicht mehr offen). Tasmota = existiert nicht mehr (kein aktives Gerät). EOS-Smartwatches / eBook-Reader kommen später und macht Christoph selbst (eBook-Reader gehört lt. VLAN-Modell eher nach VLAN50/UNTRUSTED, nicht VLAN30) — nicht Teil dieses Go.
.41.246/.247 identifiziert (User): = cudy1/cudy2 (die alten WLAN-APs, zum Abbau freigegeben, nur für VLAN1). Kein Fremdkörper → das ist der cudy-Teardown selbst.
Verdikt: Nach TP17 (16 Shellys + SwitchBot/Twinkly/Ender → VLAN30) + pve-Host → VLAN20 + Christophs Endgeräte → VLAN10 ist VLAN1 frei von Endgeräten. Prüf-Prereq vor cudy-Abschuss: Apple TV + Philips TV (aktuell aus) einschalten und verifizieren, dass sie auf dirtyvader-media/VLAN40 hängen und nicht noch am cudy/VLAN1 — sonst mit umziehen. Nicht automatisch leer bleiben: die Switch-/AP-Mgmt-IPs (sw1/sw2/ap2) sind by design interim in VLAN1 bis zum separaten MGMT-VLAN99-Cutover (kein TP17-Scope). defconf/pool-v1-DHCP erst abschalten, wenn all das erledigt ist.
Projektion: Gen4-Shellys auf Thread/Matter (experimentell, separate Spur)
User-Wunsch: prüfen, ob die Gen4-Geräte (S4PL Power-Strip-4, S4SW 2PM Gen4 — ~11 Stück: s9,s13,s16,s17,s18,s19,s20,s21,s24?,s25,s26) auf Thread-Firmware geflasht und dann via Matter-over-Thread in HA eingebunden werden können.
- Voraussetzung/Recherche (offen): Ob/welche Shelly-Gen4-Modelle offizielle Thread-/Matter-Firmware haben (Shelly kündigte Matter/Thread für Gen4 an — pro Modell verifizieren, Firmware-Verfügbarkeit + Rückweg zu WiFi-FW prüfen). Ohne verfügbare Firmware: Spur ruht.
- Infra-Voraussetzung: ein Thread Border Router (HA-fähig: z.B. Home Assistant Connect ZBT / SkyConnect mit OTBR, oder Apple-TV/HomePod als BR) — im Netz vorhanden? Muss geklärt werden.
- Konsequenz Netz: Thread-Geräte hängen NICHT im WLAN/VLAN30, sondern im Thread-Mesh (802.15.4) → sie fallen aus der
dirtyvader-iot-WLAN-Migration heraus. D.h. erst entscheiden welche Gen4 auf Thread gehen, bevor man sie unnötig aufs WLAN migriert (sonst doppelte Arbeit). - ⚠️ KONFLIKT mit „Entities bleiben unverändert": Matter-Onboarding erzeugt in HA neue Entities (andere Integration) → die alten Shelly-WiFi-Entity-IDs würden brechen. Vor jedem Thread-Flash klären, ob Entity-Stabilität oder Thread-Migration Vorrang hat (ggf. Entity-
unique_idmanuell übernehmen / bewusst neu benennen). Solange „Entities unverändert" gilt, ist die Thread-Spur nachrangig zur WiFi-Migration. - Reihenfolge-Empfehlung: morgen erst die WiFi+IP+PW-Migration komplett durchziehen (stabiler Zielzustand, HA unverändert). Thread als eigene Folge-Spur (TP17.1) danach evaluieren — nichts davon blockt den Go.
Erledigt heute (2026-07-11, nicht-disruptiv)
- ✅ s24 MAC (
14:33:5c:d8:2d:7c) insinventory/bf.csv+.30.204-Reservierung angelegt. - ✅ pool-v30 →
.100-.250erweitert (Reservierungen in-pool). - ✅
set_staauf statische IP umgestellt (Default),set_auth-Tool vorhanden (Digest-Auth-Fallback). - ✅ Tasmota als nicht-existent bestätigt (MAC nicht im Netz).
Offen / To-verify (nicht go-blockierend)
- Apple TV + Philips TV (aus): beim Einschalten VLAN prüfen (Ziel VLAN40) — vor cudy-Abschuss (s.o.).
- Creality Ender (3D-Drucker) beim nächsten Einschalten verorten (MAC/IST-IP) +
.30.x-Reservierung anlegen. - Stale HA-Device
tasmota_plug9entfernen (kein reales Gerät mehr) — macht Christoph. SHELLY_DEVICE_PW(eigenes Admin-PW, Wert liegt vor) von Christoph inmcp/shelly/.envablegen (chmod600).- Die 6 bereits Migrierten: Reservierung
waiting/nevertrotz Erreichbarkeit auf reservierter IP → wahrscheinlich statische IP am Gerät. Entscheiden: auf DHCP-Reservierung vereinheitlichen (Konsistenz) oder statisch belassen (funktional egal).