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 in LICENSE durch die tatsächlichen Werte (GitHub-Benutzername, Klarname) ersetzt werden. Die Platzhalter tragen das Präfix YOUR_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 → closed mit 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 auf closed.
  • Synchronisation mit dem Sensor – remaining_seconds wird 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)

  1. HACS in der Sidebar öffnen.
  2. Auf das ⋮-Menü → Custom repositories klicken.
  3. Die URL dieses GitHub-Repositories eintragen, z. B. https://github.com/<your-username>/ha-main-gate-controller.
  4. Typ auf Integration stehen lassen.
  5. Repository hinzufügen klicken.
  6. In der HACS-Übersicht erscheint Main Gate Controller und kann über Download installiert werden.
  7. Falls erforderlich Home Assistant neu starten.
  8. Settings → Devices & Services → Add Integration öffnen.
  9. Main Gate Controller auswählen.
  10. 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>_running erzeugt. Das running-Attribut am Statussensor liefert dieselbe Information ohne eine weitere Entity, und sensor.<gate>_status.options enthä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 closed zurü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

  1. Änderungen hochladen und prüfen, dass alle CI-Checks grün sind (HACS validation, Hassfest, pytest).
  2. Im Repository die Versionsnummer in manifest.json und im Tag synchron anpassen. Der Release-Workflow (.github/workflows/release.yml) erzwingt das. Ziel: version: 0.1.0 im Manifest ↔ Git-Tag v0.1.0.
  3. Tag setzen und pushen:
    git tag v0.1.0
    git push origin v0.1.0
    
  4. 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_controller einmal 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 closed sein. Wenn nicht, einmal manuell über die Switch-Entity steuern, um sicher zu sein, dass das Relais überhaupt reagiert.

Benachrichtigungen kommen nicht an

  • Send notifications aktiviert? Targets ausgewählt?
  • Die Entity-Selector-Suche zeigt nur notify.*-Entities; bei Companion-Apps darauf achten, dass die Mobile-App bereits ein notify.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>_status mit closed. 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 running bereits 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 closed zurü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 auf closed gesetzt; 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.
S
Description
Public Repo for MASS HACS Integrations
Readme
53 KiB
Languages
Python 100%