Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/upstream-last-seen
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cf8916bc90340fc2f70438e899202443f835c707
86 changes: 86 additions & 0 deletions .github/workflows/upstream-watch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Upstream Watch

# Wachhund auf patrickweh/ha-wibutler: meldet via ntfy.sh, sobald Upstream
# neue Commits hat, die in diesem Fork noch nicht gesehen wurden. Letzter
# gesehener Upstream-SHA wird in .github/upstream-last-seen persistiert.
#
# ntfy-Topic: srv-homelab-pve-a5bb56e899af66e2 (pve-Topic, ntfy.sh)
# Strategie-Doku: docs/decisions/001-fork-pflege-strategie.md
#
# Manuell triggerbar via "Run workflow"-Button im Actions-Tab.

on:
schedule:
- cron: '0 9 * * 1' # Jeden Montag 09:00 UTC (~10/11:00 CET/CEST)
workflow_dispatch:

permissions:
contents: write

jobs:
check-upstream:
runs-on: ubuntu-latest
steps:
- name: Checkout fork
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Fetch upstream
id: fetch
run: |
git remote add upstream https://github.com/patrickweh/ha-wibutler.git
git fetch upstream main --quiet

NEW_SHA=$(git rev-parse upstream/main)
if [ -f .github/upstream-last-seen ]; then
LAST_SEEN=$(cat .github/upstream-last-seen | tr -d '[:space:]')
else
LAST_SEEN=$(git merge-base HEAD upstream/main)
fi

echo "last_seen=$LAST_SEEN" >> "$GITHUB_OUTPUT"
echo "new_sha=$NEW_SHA" >> "$GITHUB_OUTPUT"

if [ "$LAST_SEEN" = "$NEW_SHA" ]; then
echo "Upstream unverändert seit $LAST_SEEN — keine Notification."
echo "no_new=true" >> "$GITHUB_OUTPUT"
else
git log --oneline --no-merges "$LAST_SEEN..upstream/main" > /tmp/new_commits.txt
COMMIT_COUNT=$(wc -l < /tmp/new_commits.txt | tr -d '[:space:]')
UPSTREAM_VERSION=$(git show upstream/main:custom_components/wibutler/manifest.json | grep -oE '"version":\s*"[^"]+"' | grep -oE '"[^"]+"$' | tr -d '"' || echo "?")
echo "commit_count=$COMMIT_COUNT" >> "$GITHUB_OUTPUT"
echo "upstream_version=$UPSTREAM_VERSION" >> "$GITHUB_OUTPUT"
echo "no_new=false" >> "$GITHUB_OUTPUT"
echo "Upstream hat $COMMIT_COUNT neue Commits seit $LAST_SEEN:"
cat /tmp/new_commits.txt
fi

- name: Notify via ntfy
if: steps.fetch.outputs.no_new != 'true'
run: |
BODY="$(cat /tmp/new_commits.txt)

Upstream-Version: ${{ steps.fetch.outputs.upstream_version }}
Fork: https://github.com/philw113/ha-wibutler
Upstream: https://github.com/patrickweh/ha-wibutler/compare/${{ steps.fetch.outputs.last_seen }}...${{ steps.fetch.outputs.new_sha }}

Naechster Schritt: git fetch upstream && git merge upstream/main (climate.py-Konflikte erwartet)
Doku: docs/decisions/001-fork-pflege-strategie.md"

curl -sS -X POST \
-H "Title: Wibutler Upstream: ${{ steps.fetch.outputs.commit_count }} neue Commit(s)" \
-H "Priority: default" \
-H "Tags: zap,wibutler,upstream" \
-d "$BODY" \
https://ntfy.sh/srv-homelab-pve-a5bb56e899af66e2

- name: Update last-seen marker
if: steps.fetch.outputs.no_new != 'true'
run: |
echo "${{ steps.fetch.outputs.new_sha }}" > .github/upstream-last-seen
git config user.name "upstream-watch-bot"
git config user.email "actions@users.noreply.github.com"
git add .github/upstream-last-seen
git commit -m "chore(upstream-watch): mark ${{ steps.fetch.outputs.new_sha }} as seen [skip ci]"
git push
73 changes: 73 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# srv-home-pve-ha-home-wibutler · CLAUDE.md

@../CLAUDE.md

## Repo-spezifisch
Sub-Projekt im Workspace `srv-homelab`. Workspace = Concept-Repo (eine Ebene drüber). Vollständige Workspace-Anweisungen in `../CLAUDE.md` (via `@`-Import oben).

**Dieses Repo ist ein Fork** von [patrickweh/ha-wibutler](https://github.com/patrickweh/ha-wibutler) mit lokalen Anpassungen. Siehe `FORK-NOTES.md` für die Drift zum Upstream.

## Kontext
Fachliche Ressourcen im Workspace + Parent-Sub-Projekt:
- Aktueller Workspace-Stand: `../STATUS.md`
- Service-Übersicht: `../docs/services.md`
- HA-Sub-Projekt: `../srv-home-pve-ha-home/`
- HA-Inventur: `../srv-home-pve-ha-home/docs/inventur.md`

## Notion
- Projekt-Workspace: https://www.notion.so/35a7f820f55c815d93b5d6eb881d4ccd (PRJ-10)
- Notion-Sub-Projekt: [REP-26](https://www.notion.so/3657f820f55c814ba31ace4847bbe88f) (in Projekte-DB)
- GitHub (Fork): https://github.com/philw113/ha-wibutler
- GitHub (Upstream): https://github.com/patrickweh/ha-wibutler
- Projekt-Workspaces-DB: 761164c1-160c-4861-8985-32e9ffc8a1cf
- Projekte-DB: 19abc847-fe0a-40f2-ac71-b49f63f055ff
- Aufgaben-DB: 61266c90-ed14-4aa7-8f44-df3024884be6

## Was ist drin
Fork der Custom-Integration **Wibutler** für Home Assistant. Wird in der laufenden HA-Instanz unter `/config/custom_components/wibutler/` (auf HAOS: `/mnt/data/supervisor/homeassistant/custom_components/wibutler/`) deployed und ist damit der Code-Stand, der die Wibutler-Hub-Anbindung in HA realisiert.

## Stack
- Custom HACS-Integration, Python 3.x (in HA-Container 3.14)
- aiohttp REST + WebSocket gegen Wibutler-Hub-API
- Komponenten: binary_sensor, climate, cover, light, sensor, switch (+ rocker im Upstream, lokal noch nicht)

## Beziehung zum Upstream
- **Letzter Sync-Punkt:** `cab4be0` (2025-08-26, Merge PR #9 von Fochest)
- **Eigene Commits über Sync-Punkt:** `1e950af` (WiButler 1 Lights), `78a2713` (Ignore BTNRECON)
- **Upstream-Stand seit Sync:** v1.2.0 (Refactor `WibutlerEntity` base class, neue `rocker.py`, `strings.json` + translations, api.py-verify_ssl-Fix). Merge bewusst aufgeschoben — siehe `FORK-NOTES.md`.
- **Lokal nicht committed:** signifikante `climate.py`-Erweiterungen (Mode-Komponenten-Logik) — werden mit AUF-* nachgeholt.

## Deploy
Der Code lebt produktiv in der HAOS-VM 110 unter `/mnt/data/supervisor/homeassistant/custom_components/wibutler/`. Aktuell **kein automatisches Deploy** — nach Commits wird per `scp`/`qm guest exec` von Hand übertragen und HA neugestartet.

## ⚠️ Read-only-Default (vom Parent-Sub-Repo geerbt)
Default: keine Änderungen am laufenden HA. Code-Änderungen hier im Repo committen erst — Deploy auf VM nur auf explizite Philipp-Freigabe, Plan Mode + Proxmox-Snapshot Pflicht vor Deploy.

## ⚠️ Keine Secrets
Wibutler-Hub-Zugangsdaten (Username/Passwort/IP) leben in der HA-Config-Entry, nicht im Code. `.env` für lokale Tests ist via `.gitignore` raus.

## Modul-Architektur
Siehe `MODULES.md`.

## Test-Strategie
Keine automatisierten Tests. Verifikation auf der laufenden HA-Instanz (Wibutler-Entitäten verfügbar, Statuswechsel kommen an).

## Auto-Push-Policy
**Auto-Commit:** ja
**Auto-Push:** ja
**Begründung:** Sub-Projekt-Typ `service` — Code-Repo, lokal entwickelt, gepushter Stand wird per Hand auf HA deployed (Deploy ist separater Schritt mit Freigabe).

Sicherheitsnetz: Pre-Commit-Scan auf Secrets, sensible Datei-Endungen Bestätigung, Force-Push nie automatisch.

## Auto-Maintenance Routine

**Bei Beginn der Session:**
- `../STATUS.md` lesen
- `FORK-NOTES.md` lesen (Drift-Stand)
- Aktive Notion-AUFs für dieses Sub-Projekt prüfen

**Bei signifikanter Änderung:**
1. Committen (Conventional Commits)
2. `FORK-NOTES.md` aktualisieren, falls Drift zum Upstream verändert
3. `../STATUS.md` aktualisieren (kurze Zeile)
4. Auto-Push aktiv — Deploy auf HA bleibt separate Freigabe
59 changes: 59 additions & 0 deletions FORK-NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Fork-Notes — Drift zum Upstream

**Letztes Update:** 2026-05-19
**Notion-REP:** [REP-26](https://www.notion.so/3657f820f55c814ba31ace4847bbe88f)
**Pflege-Strategie:** [ADR-001](docs/decisions/001-fork-pflege-strategie.md)

## Sync-Punkt
Letzter Merge-from-Upstream: `cab4be0` (2025-08-26, Merge PR #9 von Fochest).

## Eigene Commits über Sync-Punkt (im Fork-`main`)
- `1e950af` (2025-11-04) — Improve WiButler 1 lights and button handling
- `78a2713` (2025-11-04) — Ignore BTNRECON in binary sensor setup
- `de49e3f` (2026-05-19) — docs: sub-project documentation
- `47e46d5` (2026-05-19) — feat(climate): extended mode/preset handling with CTSP/ETSP fallbacks
- `d21626d` (2026-05-19) — fix(api): work around aiohttp response.json() crash on large responses
- `8b523a8` (2026-05-19) — fix(light): migrate SUPPORT_BRIGHTNESS to ColorMode for HA 2026.5

## Upstream-Stand vs. Fork
- Upstream `main` ist auf v1.2.0 (Stand 2026-03-07): mehrere Commits voraus, 2 zurück, status `diverged`.
- Wesentliche Upstream-Änderungen seit Sync-Punkt:
- `fcb02db` (2026-01-22) — Update api.py: verify_ssl-Fix + Content-Type-Check
- `d189ef4` (2026-03-05) — Refactor: WibutlerEntity base class (16 Files berührt)
- `5d58fb3` (2026-03-07) — Neue `rocker.py` (Rocker-Button-Events + Options-Flow)
- Neue Files: `entity.py`, `rocker.py`, `strings.json`, `translations/de.json`, `translations/en.json`

## Pflege-Strategie (siehe [ADR-001](docs/decisions/001-fork-pflege-strategie.md))
- **HACS-Custom-Repo pollt diesen Fork**, nicht Upstream → kein „Update verfügbar"-Banner-Spam
- **Manifest-`version`-Schema:** `<upstream-base>+philw113-fork-<YYYY-MM-DD>` (PEP-440-Build-Metadata, vom Semver-Vergleich ignoriert). Aktuell: `1.0.1+philw113-fork-2026-05-19`.
- **Upstream-Awareness via GitHub-Action** `.github/workflows/upstream-watch.yml` → ntfy-Push an `srv-homelab-pve-...`-Topic (Montags 09:00 UTC, manuell triggerbar im Actions-Tab)
- **Letzter gesehener Upstream-SHA** in `.github/upstream-last-seen` (aktuell: `cf8916bc` = Patrick's „Bump version to 1.2.0" vom 2026-03-07)
- **Reagier-Karte in Notion:** [AUF-208](https://www.notion.so/3667f820f55c81ceba2ae2747d3d97b2) (Status: Wartet) — Sync-Prozess, Festlegungen, Diskussions-Log bei ntfy-Hits

## Sync-Prozess (wenn ntfy meldet)
```bash
cd srv-home-pve-ha-home-wibutler
git fetch upstream main
git merge upstream/main # Konflikte in climate.py erwartet
# Konflikte auflösen (lokale Anpassungen drüber)
# manifest-version bumpen: <neue-upstream-version>+philw113-fork-<heute>
git commit && git push
# HACS bietet Update im HA-UI an → bestätigen → HACS pullt Fork → HA Restart
```

## Warum kein Upstream-Merge jetzt
- `climate.py` ist stark divergiert (96 Z. Upstream vs. 426 Z. lokal) — Upstream-Refactor (`WibutlerEntity`-Basisklasse) garantiert konfliktreich
- Aktuell läuft alles stabil seit Bugfix-Welle 2026-05-19, kein akuter Sync-Anlass
- Sync wird ausgelöst, wenn die GitHub-Action eine ntfy-Notification schickt (= Patrick hat einen neuen Commit gepusht)

## Convention-Abweichung: kein notify-on-failure.yml (CI)
`PROJEKT-PLAYBOOK §12.4 Schritt 4` verlangt für `service`-Repos ein `.github/workflows/notify-on-failure.yml` + Health-Check-Skript-Stub. **Hier bewusst übersprungen**, da:
- Dieses Repo ist ein passiver Fork-Mirror einer HA Custom-Integration — kein klassisches CI/CD
- Der einzige laufende Workflow ist `upstream-watch.yml` (Polling-Bot ohne Build/Test/Deploy), Failures dort sind unkritisch (im Worst Case verpassen wir einen Upstream-Hinweis, der sich beim nächsten Lauf nachholt)
- Der „Live"-Stand läuft in der HA-VM 110 (`/config/custom_components/wibutler/`), nicht im Repo — Health-Monitoring der Integration findet auf HA-Ebene statt (HA Repairs, Logs, Entity-States)

Falls künftig CI (Pre-Deploy-Lint, Tests, etc.) hinzukommt: nachpflegen.

## Bekannte Probleme
- ~~**JSONDecodeError beim Setup** seit HA Core 2026.5.1~~ — gefixt 2026-05-19 via `api.py`-Patch (`response.json()` → `json.loads(await response.text())`).
- ~~**ImportError `SUPPORT_BRIGHTNESS`** in `light.py` seit HA Core 2026.5~~ — gefixt 2026-05-19: migriert auf `_attr_supported_color_modes = {ColorMode.BRIGHTNESS}` + `_attr_color_mode = ColorMode.BRIGHTNESS`.
29 changes: 29 additions & 0 deletions MODULES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Module dieses Repos

**Letztes Update:** 2026-05-19 durch Claude Code

## Modul-Übersicht

### `custom_components/wibutler/` – HA Custom-Integration
**Zweck:** Code der Wibutler-Integration für Home Assistant
**Abhängigkeiten:** Home Assistant Core, aiohttp
**Optional:** nein
**Status:** Aktiv (Fork-Stand 2025-11-04 + lokale climate.py-Erweiterungen)

Sub-Dateien:
- `__init__.py` – Integration-Bootstrap
- `manifest.json` – HA-Manifest (Domain, Version, Codeowner)
- `config_flow.py` – Setup-UI
- `api.py` – aiohttp REST + WebSocket gegen Wibutler-Hub
- `const.py` – Konstanten
- `binary_sensor.py`, `climate.py`, `cover.py`, `light.py`, `sensor.py`, `switch.py` – Entity-Plattformen

### `FORK-NOTES.md` – Drift-Doku zum Upstream
**Zweck:** Stand der Abweichungen zum Upstream `patrickweh/ha-wibutler` festhalten — was lokal anders, was bewusst nicht gemergt
**Status:** Aktiv

## Modul-Erstellung
Bei neuer Funktionalität durch Claude Code zuordnen:
1. Code-Änderung an Integration → in passendes File unter `custom_components/wibutler/`
2. Doku zur Abweichung → in `FORK-NOTES.md`
3. NIEMALS „irgendwo" einbauen ohne Modul-Klarheit
5 changes: 4 additions & 1 deletion custom_components/wibutler/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ async def _request(self, method: str, endpoint: str, data: Optional[Dict[str, An
try:
async with self.session.request(method, url, headers=headers, json=data) as response:
if response.status in (200, 201):
return await response.json()
# Workaround: aiohttp's response.json() bricht in HA 2026.5+
# (Python 3.14 / neueres aiohttp) bei grossen Wibutler-Responses
# mit JSONDecodeError ab. response.text() + json.loads ist robust.
return json.loads(await response.text())
elif response.status == 401:
_LOGGER.warning("Token abgelaufen, erneute Authentifizierung erforderlich.")
self.token = None
Expand Down
Loading