14 KiB
Main Gate Controller
Eine vollständig über die Home-Assistant-UI konfigurierbare Custom Integration für
ein elektrisches Fußgängertor. Die Integration ersetzt eine bestehende Lösung aus
Skripten, Timern und Helpern und steuert das Tor indirekt über eine bereits
vorhandene Switch-Entity (z. B. switch.shellyplusuni_8c4f00a6ce94_output_0).
Vor der ersten Veröffentlichung müssen die Platzhalter in
manifest.json,hacs.json, dieser README und inLICENSEdurch die tatsächlichen Werte (GitHub-Benutzername, Klarname) ersetzt werden. Die Platzhalter tragen das PräfixYOUR_GITHUB_USERNAME.
Features
- Mehrere Tore – pro Tor wird ein eigener Config Entry angelegt.
- Konfiguration über die UI – inklusive modernem Entity-Selector für die Switch-Entity, NumberSelectorn für Zeiten und EntitySelector für Notify-Entities.
- Config Flow + Options Flow – alle Parameter lassen sich nachträglich in
Settings → Devices & Services → Main Gate Controller → Configureändern. - Mode: single – ein laufender Ablauf kann nicht durch einen zweiten Button-Press unterbrochen werden.
- Robuste State Machine –
closed → opening → open → closing → closedmit Debug-Log auf jedem Übergang. Eine fehlgeschlagene Benachrichtigung führt nicht zum Abbruch. Ein fehlgeschlagener Switch-Service bricht den Ablauf ab und setzt den Status zurück aufclosed. - Synchronisation mit dem Sensor –
remaining_secondswird während der Offen-Phase jede Sekunde aktualisiert und steht sofort im Dashboard zur Verfügung. - Restart-sicher – nach einem Home-Assistant-Neustart beginnt der Status
mit
closed,running=false. Ein ggf. unterbrochener Ablauf wird protokolliert. - Diagnostics –
home-assistant://developer-tools/...Diagnose-Export ohne sensible Daten.
Ablauf
Wenn ein Tor geöffnet wird, führt die Integration exakt die folgende Sequenz
aus und nutzt ausschließlich Service-Calls auf switch.turn_on /
switch.turn_off:
1. Status: opening
2. (optional) Notification „Opening Main Gate (Pedestrians)“
3. switch.turn_off
4. warten (pulse_duration, Standard 1 s)
5. switch.turn_on
6. warten (pulse_duration)
7. switch.turn_off
8. Status: open
9. Countdown (open_duration, Standard 20 s), remaining_seconds zählt sekündlich herunter
10. Status: closing
11. (optional) Notification „Closing Main Gate“
12. switch.turn_on
13. warten (pulse_duration)
14. switch.turn_off
15. warten (pulse_duration)
16. Status: closed
Installation via HACS (Custom Repository)
- HACS in der Sidebar öffnen.
- Auf das ⋮-Menü → Custom repositories klicken.
- Die URL dieses GitHub-Repositories eintragen, z. B.
https://github.com/<your-username>/ha-main-gate-controller. - Typ auf
Integrationstehen lassen. - Repository hinzufügen klicken.
- In der HACS-Übersicht erscheint Main Gate Controller und kann über Download installiert werden.
- Falls erforderlich Home Assistant neu starten.
- Settings → Devices & Services → Add Integration öffnen.
- Main Gate Controller auswählen.
- Das Gate konfigurieren (Name, Switch-Entity, Zeiten, optional Notifications).
Manuelle Installation (ohne HACS)
custom_components/main_gate_controller/
in das Home-Assistant-Konfigurationsverzeichnis kopieren, Home Assistant neu starten und denselben UI-Pfad ab Schritt 8 verwenden.
Einrichtung
Config Flow
Der Config Flow ist ein einzelner Schritt. Die folgenden Felder werden abgefragt:
| Feld | Pflicht | Default | Beschreibung |
|---|---|---|---|
Gate name |
✅ | Main Gate |
Anzeigename – wird als Device-Name und Sensor-Entity-ID-Basis verwendet |
Gate switch |
✅ | — | Switch-Entity zur Torsteuerung (Selector: EntitySelector(domain="switch")) |
Open duration (seconds) |
✅ | 20 |
Wie lange das Tor offengehalten wird |
Pulse duration (seconds) |
✅ | 1.0 |
Ein-/Aus-Pulsdauer der Switch-Impulse |
Send notifications |
✅ | false |
Aktiviert/deaktiviert alle Benachrichtigungen |
Notification targets |
⛔ | leer | Notify-Entities (Selector: EntitySelector(domain="notify", multiple=True)) |
Opening notification text |
⛔ | Opening Main Gate (Pedestrians) |
Text der Öffnungs-Benachrichtigung |
Closing notification text |
⛔ | Closing Main Gate |
Text der Schließ-Benachrichtigung |
Wird Send notifications aktiviert ohne dass Targets ausgewählt sind, meldet
der Flow einen Fehler. Außerdem wird verhindert, dass dieselbe Switch-Entity
an mehrere Config Entries gebunden wird (Unique-ID-Schutz).
Options Flow
Über Settings → Devices & Services → Main Gate Controller → Configure
lassen sich Open duration, Pulse duration, Send notifications,
Notification targets und beide Notification-Texte jederzeit nachjustieren.
Der Name und die Switch-Entity sind im Options Flow bewusst nicht editierbar;
dafür ist das Löschen und Neuanlegen eines Gates der vorgesehene Weg.
Switch- und Notify-Domain
Die Integration geht davon aus, dass die ausgewählte Switch-Entity und die ausgewählten Notify-Entities bereits in Home Assistant existieren (z. B. Shelly, Sonoff, MQTT, Companion-App). Es gibt keine direkte Geräte-Abhängigkeit.
Entities
Für jedes Gate (jeden Config Entry) wird ein gemeinsames Device angelegt mit
manufacturer = Custom und model = Main Gate Controller. Folgende Entities
gehören zum Device:
Button button.<gate>_open
Startet den kompletten Ablauf. Friendly-Name: Open. Ist bereits ein Ablauf
aktiv, wird der Druck ignoriert (logischer mode: single). Wird sauber
protokolliert, nicht als Fehler.
Sensor sensor.<gate>_status
Maschinenlesbarer State, standardmäßig einer von closed, opening, open,
closing. Attribute (immer vorhanden):
| Attribut | Typ | Beschreibung |
|---|---|---|
remaining_seconds |
int | null |
Sekunden bis zum automatischen Schließen |
duration |
number |
Konfigurierte Open duration |
running |
bool |
True, solange ein Ablauf läuft |
started_at |
string|null |
ISO 8601 UTC – Zyklusstart |
finishes_at |
string|null |
ISO 8601 UTC – berechnetes Ende der Öffnungsphase |
Während der open-Phase wird remaining_seconds ungefähr jede Sekunde
aktualisiert.
Bewusste Designentscheidung: Es wird kein zusätzlicher
binary_sensor.<gate>_runningerzeugt. Dasrunning-Attribut am Statussensor liefert dieselbe Information ohne eine weitere Entity, undsensor.<gate>_status.optionsenthält ohnehin alle Zustände.
Beispiel Dashboard
Eine kompakte, einzelne Tile-Card reicht aus. Die Tile-Card unterstützt
das state_content-Feld, das beliebige Attribute der Entity anzeigen kann.
Wir übergeben den maschinenlesbaren State und die verbleibenden Sekunden:
type: tile
entity: sensor.main_gate_status
name: Main Gate
icon: mdi:gate
state_content:
- state
- remaining_seconds
Wer das Ergebnis in der „sprechenden“ Variante sehen will
Da der Sensor-State closed/opening/open/closing maschinenlesbar bleibt,
werden die deutschen Bezeichnungen „Geschlossen/Öffnet/Offen/Schließt“ nicht
im State selbst, sondern als Übersetzung im Frontend angezeigt. Auf einer
Tile-Card sieht man also je nach Frontend-Sprache entweder die englische
oder die lokalisierte Variante – aber derselbe Sensor.
Wer auf den englischen Buttons-State explizit verzichten will, kann alternativ
mit dem mdi:clock-digital-Icon und einer Text-Karte arbeiten:
type: conditional
conditions:
- entity: sensor.main_gate_status
state: open
card:
type: markdown
content: >-
Open · {{ state_attr('sensor.main_gate_status', 'remaining_seconds') }}s
Update-Prozess
HACS markiert neue Releases automatisch. Nach einer Aktualisierung empfiehlt sich ein Home-Assistant-Neustart, weil die Integration während eines laufenden Ablaufs nicht in-place ausgetauscht werden kann.
Aktuell ist keine Reload-Annotation aktiv: ein bereits laufender Zyklus geht beim Update verloren und der Status wird auf
closedzurückgesetzt. Das ist mit einem schief gestellten Tor-Position fehlertolerant (siehe Einschränkungen).
Entwicklung
git clone https://github.com/<your-username>/ha-main-gate-controller
cd ha-main-gate-controller
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements_test.txt
# Statische Prüfung
ruff check custom_components tests
# Tests
pytest
Die Tests verwenden das Standard-Testwerkzeug
pytest-homeassistant-custom-component,
welches eine bestimmte Version von Home Assistant pinnt. Damit lassen sich
Config-Flow, Entity-Lebenszyklus und asynchrone Service-Calls mit dem
echten HA-Testkern testen. Die Integration wird über den
custom_components/-Ordner direkt neben den Tests gefunden.
Release-Prozess
- Änderungen hochladen und prüfen, dass alle CI-Checks grün sind (HACS validation, Hassfest, pytest).
- Im Repository die Versionsnummer in
manifest.jsonund im Tag synchron anpassen. Der Release-Workflow (.github/workflows/release.yml) erzwingt das. Ziel:version: 0.1.0im Manifest ↔ Git-Tagv0.1.0. - Tag setzen und pushen:
git tag v0.1.0 git push origin v0.1.0 - GitHub Actions baut das Release-Artefakt (Zip der Integration) und veröffentlicht es auf der GitHub-Releases-Seite.
Troubleshooting
„cannot add entities“ / Integration lädt nicht
- Home Assistant neu starten, damit
custom_components/main_gate_controllereinmal frisch gelesen wird. - Logs:
logger: logs: custom_components.main_gate_controller: debug
Button bleibt ohne Wirkung
- Konfiguration prüfen: Settings → Devices & Services → Main Gate Controller →
Gerät → Entity → Status sollte
closedsein. Wenn nicht, einmal manuell über die Switch-Entity steuern, um sicher zu sein, dass das Relais überhaupt reagiert.
Benachrichtigungen kommen nicht an
Send notificationsaktiviert? Targets ausgewählt?- Die Entity-Selector-Suche zeigt nur
notify.*-Entities; bei Companion-Apps darauf achten, dass die Mobile-App bereits einnotify.mobile_app_<phone>angelegt hat.
Status bleibt nach Stromausfall auf einer Phase hängen
- Die Integration ist blind für die reale Tor-Position: nach einem
Neustart beginnt
sensor.<gate>_statusmitclosed. Wenn das Tor während des Ausfalls halb offen geblieben ist, muss es von Hand abgeschlossen werden.
Architektur
custom_components/main_gate_controller/
├── __init__.py # async_setup_entry, async_unload_entry, DeviceInfo
├── manifest.json # Domain, Version, Codeowners, iot_class=calculated
├── const.py # Konstanten / Defaults
├── coordinator.py # MainGateController ← Zustandsmaschine, Countdown, Service-Calls
├── config_flow.py # MainGateConfigFlow + MainGateOptionsFlow + Selectors
├── button.py # button.<gate>_open
├── sensor.py # sensor.<gate>_status + Attribute
├── diagnostics.py # anonymisierter Diagnose-Export
├── strings.json # Übersetzungs-Schlüssel
└── translations/
├── en.json
└── de.json
Alle Service-Calls (switch.turn_on/off, notify.send_message) laufen
ausschließlich gegen die ausgewählten Home-Assistant-Entities. Es findet kein
direkter Zugriff auf Hersteller-Integrationen (z. B. Shelly) statt.
Bekannte Einschränkungen / Design-Entscheidungen
- Kein Binary-Sensor „Running“. Der Statussensor liefert
runningbereits als Attribut; eine zweite Entity würde keinen Mehrwert bieten. - Blind-Betrieb. Die Integration hat keine Rückmeldung über die tatsächliche Tor-Position. Wenn das Relais angezogen hat, heißt das nicht zwingend, dass das Tor offen ist. Wer eine echtzeitnahe Statusanzeige benötigt, sollte die Tor-Endlage zusätzlich an einen Home-Assistant-Sensor melden und diesen Automations-Auslöser verwenden.
- Restart mitten im Zyklus. Beim Reload/Unload wird der laufende Zyklus
abgebrochen und der Status auf
closedzurückgesetzt. Die reale Tor-Position muss im Zweifel per Hand geprüft werden. - Switch-Fehler → safe default. Schlägt ein
switch.turn_*-Aufruf fehl, wird der Zyklus abgebrochen und der Status aufclosedgesetzt; ein Alarm bleibt im Log. Im Zweifel ist das Relais möglicherweise trotzdem ein- oder ausgeschaltet worden, das lässt sich aber nicht garantiert ermitteln.