chore(hass): add one-off playbook to repoint tplink entries at IoT VLAN

The IoT WiFi moved from Default (192.168.1.x) to the IoT VLAN
(192.168.2.x) with fixed IPs reserved in UniFi. HA 2026.9.3's tplink
reconfigure flow ignores the entered host and reconnects to the stored
one, so this edits data.host in .storage/core.config_entries with HA
stopped, matching entries by MAC and refusing to write unless all 9
match. Backs up core.config_entries first and always restarts hass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bastian de Byl
2026-10-01 15:45:59 -04:00
co-authored by Claude Opus 5.5
parent 339d4b150c
commit f575f8f62d
2 changed files with 122 additions and 0 deletions
@@ -0,0 +1,50 @@
"""Point HA's 9 TP-Link (Kasa) config entries at their new IoT VLAN addresses.
Run on galactica as the podman user while HA is STOPPED:
python3 /tmp/fix_tplink.py # dry run, prints what would change
python3 /tmp/fix_tplink.py apply # writes the change (refuses unless all 9 match)
Only data.host is changed; entries are matched by MAC (unique_id).
"""
import json
import os
import re
import sys
path = "/home/podman/.local/share/volumes/hass/config/.storage/core.config_entries"
new = {
"54af970a5d01": "192.168.2.220", # Printer Plug KP115
"788cb56955b4": "192.168.2.146", # Driveway String Lights HS200
"2887ba1bd687": "192.168.2.199", # Kitchen Wall Light KS230
"5ce9319dc5d6": "192.168.2.38", # Kitchen Lights HS220
"5ce9319da5e0": "192.168.2.200", # Dining Hall HS220
"5ce9319dd193": "192.168.2.159", # Dining Room HS220
"5ce931a23a6e": "192.168.2.61", # Bathroom Hallway HS220
"f0a731771227": "192.168.2.55", # Stair Light KS230
"788cb5694e4a": "192.168.2.252", # Bedroom Light HS200
}
apply = len(sys.argv) > 1 and sys.argv[1] == "apply"
with open(path) as f:
d = json.load(f)
n = 0
for e in d["data"]["entries"]:
if e.get("domain") != "tplink":
continue
mac = re.sub(r"[^0-9a-f]", "", (e.get("unique_id") or "").lower())
ip = new.get(mac)
print(f'{e["title"]:<36} host={e["data"].get("host")} -> {ip}')
if ip:
e["data"]["host"] = ip
n += 1
print("matched", n, "of 9")
if apply:
if n != 9:
sys.exit("refusing to write: not all 9 matched")
tmp = path + ".tmp"
with open(tmp, "w") as f:
json.dump(d, f, indent=4, ensure_ascii=False)
os.replace(tmp, path)
print("written")