diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b233b38 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog + +## 1.0.0-rc1 - 2026-07-23 + +### Hinzugefuegt + +- Vollstaendige ESPHome-Konfiguration fuer den Fahrzeugsender. +- Vollstaendige ESPHome-Konfiguration fuer die Torsteuerung. +- Autonome lokale Torlogik ohne Home-Assistant-Abhaengigkeit. +- CC1101 433 MHz Paketprotokoll mit Magic Bytes `0xA7 0x3C`. +- Sender-Heartbeat per LED nur noch einmal pro Minute. +- Mehrere WLANs vorbereitet. +- OTA fuer Sender und Empfaenger. +- Fallback-AP fuer Sender und Empfaenger. +- Diagnosewerte fuer RSSI, LQI, Pakete, Toroeffnungen, WLAN, Laufzeit, Heap und Neustartgrund. +- Einstellbare RSSI-Grenze. +- Einstellbare Sperrzeit. +- Testmodus ohne Relaisschaltung. +- Zaehler-Reset per Home Assistant Button. +- README mit Flash-, Test- und Git-Ablauf. + +### Beibehalten + +- Getestetes 4-Byte-Funkpaket: `0xA7 0x3C 0x01 0x00`. +- Frequenz `433.92 MHz`. +- Modulation `GFSK`. +- Symbolrate `4800`. +- Paketlaenge `4`. +- CRC aktiviert. +- Sync-Bytes `0x91 0xD3`. +- Torrelais auf `GPIO16`. +- Torkontakte auf `GPIO34` und `GPIO35`. + +### Hinweise + +- Die genaue `cc1101.on_packet` Syntax haengt von der verwendeten externen CC1101-Komponente ab. Der Sender nutzt die bereits getestete `cc1101.send_packet` Syntax. +- Vor dem Einbau am endgueltigen Ort sollten Sender und Empfaenger gemeinsam kompiliert, geflasht und mit Testmodus geprueft werden. diff --git a/README.md b/README.md index 245b037..b2603e3 100644 --- a/README.md +++ b/README.md @@ -1,233 +1,184 @@ # Funksender Tor -Automatische Toröffnung per 433 MHz. Jedes Fahrzeug bekommt einen kleinen Sender -am Zündungsplus, der Empfänger am Tor öffnet, sobald ein bekanntes Fahrzeug nah -genug ist. Kein Knopfdruck, keine App, kein Account. +ESPHome-Projekt fuer eine autonome Torsteuerung mit 433 MHz CC1101 Funk. -**Hardware:** ESP32-C3 Super Mini + CC1101 (433 MHz) je Sender, -ein bestehender ESP32 DevKit (`tor-steuerung`) + CC1101 als Empfänger am Tor — -derselbe ESP, der schon Relais und Türsensoren steuert. +Das System besteht aus zwei Teilen: ---- +- `auto_sender_01.yaml`: ESP32-C3 Sender im Fahrzeug +- `tor_steuerung.yaml`: ESP32 Empfaenger an der Torsteuerung -## Inhalt +Home Assistant ist nur fuer OTA, Diagnose und Einstellungen vorgesehen. Die eigentliche Entscheidung und das Schalten des Relais laufen lokal auf der Torsteuerung. Das Tor kann also auch dann oeffnen, wenn Home Assistant, WLAN oder Internet ausfallen. -- [Verdrahtung CC1101](#verdrahtung-cc1101) -- [Flashen](#flashen) — **hier steht der USB-TTL-Kram** -- [ESPHome einrichten](#esphome-einrichten) -- [Reichweite einstellen](#reichweite-einstellen) -- [Weiteres Fahrzeug hinzufügen](#weiteres-fahrzeug-hinzufügen) -- [Paketformat](#paketformat) +## Status ---- +Release-Kandidat: `1.0.0-rc1` -## Verdrahtung CC1101 +Getestetes Funkpaket: -Die Pins des CC1101 sitzen als **4 Zeilen à 2 Pins**, Antenne rechts: - -``` -① GND │ VDD ② -③ GDO0 │ CSN ④ -⑤ SCK │ MOSI ⑥ -⑦ MISO │ GDO2 ⑧ +```text +0xA7 0x3C 0x01 0x00 ``` -> **Achtung:** Pin 1 ist **GND**, Pin 2 ist **VDD**. Nicht die verbreitete -> Belegung mancher anderer CC1101-Boards annehmen, wo es umgekehrt ist — -> Vertauschen macht das Modul und ggf. den ESP heiß. +## Dateien -| CC1101 | Signal | ESP32-C3 Super Mini | -|--------|--------|---------------------| -| 1 | GND | `G` (links) | -| 2 | VDD | `3.3` (links) — **niemals 5V** | -| 3 | GDO0 | `GPIO3` (links) | -| 4 | CSN | `GPIO4` (links) | -| 5 | SCK | `GPIO6` (rechts) | -| 6 | MOSI | `GPIO7` (rechts) | -| 7 | MISO | `GPIO5` (rechts) | -| 8 | GDO2 | *frei lassen* | - -Schema: [`doku/verdrahtung-cc1101.svg`](doku/verdrahtung-cc1101.svg) -(zeigt die Pin-Reihenfolge am CC1101 selbst — die Zuordnung zu GPIOs -unterscheidet sich je nach ESP-Board, siehe Tabellen oben/unten.) - -### Empfänger (`tor-steuerung`, ESP32 DevKit) - -GPIO16 (Relais) und GPIO34/35 (Türsensoren) sind schon belegt. Der CC1101 -hängt deshalb an den freien VSPI-Standardpins: - -| CC1101 | Signal | ESP32 DevKit | -|--------|--------|--------------| -| 1 | GND | GND | -| 2 | VDD | 3V3 | -| 3 | GDO0 | `GPIO4` | -| 4 | CSN | `GPIO5` | -| 5 | SCK | `GPIO18` | -| 6 | MOSI | `GPIO23` | -| 7 | MISO | `GPIO19` | -| 8 | GDO2 | *frei lassen* | - ---- - -## Flashen - -### Warum nicht über den USB-C-Anschluss? - -Der ESP32-C3 hat einen eingebauten USB-Serial/JTAG-Controller. Unter Windows 11 -sollte er automatisch als COM-Port erscheinen — **tut er aber nicht mehr, sobald -Zadig einmal auf ihm gelaufen ist.** - -Was passiert war: Zadig ersetzt den nativen `usbser.sys` durch WinUSB bzw. -selbstgenerierte libwdi/libusbK-Treiber. Danach zeigt der Geräte-Manager zwar -einen COM-Port, aber esptool bekommt nur - -``` -A fatal error occurred: Failed to connect to ESP32-C3: No serial data received. +```text +esphome/ + auto_sender_01.yaml + tor_steuerung.yaml +README.md +CHANGELOG.md ``` -Das lässt sich reparieren (siehe unten), ist aber fummelig. **Der USB-TTL-Adapter -umgeht das Thema komplett.** +## Hardware -### USB-TTL-Adapter anschließen ← *das ist der Weg, der funktioniert hat* +### Sender -> **Adapter zwingend auf 3.3 V jumpern.** Der ESP32-C3 ist nicht 5V-tolerant. +- ESP32-C3 DevKit / ESP32-C3 Super Mini +- CC1101 433 MHz Modul +- Versorgung passend zur Einbausituation -| USB-TTL-Adapter | ESP32-C3 Super Mini | -|-----------------|---------------------| -| TX | `GPIO20` (rechts, vorletzter Pin) | -| RX | `GPIO21` (rechts, letzter Pin) | -| GND | `G` (links, 2. Pin) | -| 3.3V | `3.3` (links, 3. Pin) | +### Empfaenger -TX und RX sind **gekreuzt** — das ist so richtig. -Das CC1101 kann angeschlossen bleiben, GPIO20/21 kollidieren mit nichts. +- ESP32 DevKit / ESP32 Relaisboard +- CC1101 433 MHz Modul +- Relaiskontakt fuer Torimpuls +- Endschalter oder Rueckmeldekontakte fuer Tor AUF und Tor ZU -Liefert der Adapter auf 3.3 V zu wenig Strom, den ESP stattdessen über ein -USB-Netzteil an der USB-C-Buchse versorgen und vom Adapter nur TX, RX und GND -anschließen. **Nicht beide Quellen gleichzeitig.** +## Funkprotokoll -### Boot-Modus +Der Sender uebertraegt alle 2 Sekunden ein festes 4-Byte-Paket: -**`GPIO9` ↔ `G` brücken, danach erst Strom drauf.** Reihenfolge ist wichtig. -Nach dem Flashen die Brücke wieder entfernen. - -### Ablauf - -```bash -# 1. Verbindung prüfen — COM-Port des TTL-Adapters aus dem Geräte-Manager -python -m esptool --chip esp32c3 --port COM16 chip-id +```text +Byte 1: 0xA7 Magic +Byte 2: 0x3C Magic +Byte 3: 0x01 Fahrzeug-ID +Byte 4: 0x00 Reserve ``` -Erwartete Ausgabe: +CC1101 Einstellungen: -``` -Chip type: ESP32-C3 AZ (QFN32) (revision v1.1) -Features: Wi-Fi, BT 5 (LE), Single Core, 160MHz, Embedded Flash 4MB (XMC) -MAC: 44:b1:76:18:cb:ec +- Frequenz: `433.92 MHz` +- Modulation: `GFSK` +- Symbolrate: `4800` +- Paketlaenge: `4` +- CRC: aktiv +- Sync: `0x91 0xD3` + +## Sender flashen + +Datei: + +```text +esphome/auto_sender_01.yaml ``` -```bash -# 2. Factory-Image flashen (nicht die normale .bin!) -python -m esptool --chip esp32c3 --port COM16 --baud 460800 \ - write-flash 0x0 auto-sender-01.factory.bin -``` +Das erste Flashen erfolgt bei deiner Hardware per TTL/USB-Adapter. Danach kann OTA verwendet werden, sobald der Sender im WLAN erreichbar ist. -Bricht es bei 460800 ab, mit `--baud 115200` wiederholen. - -Danach GPIO9-Brücke raus, Strom aus/an. Ab hier läuft alles über OTA — -der Adapter wird nicht mehr gebraucht. - -`esptool` installieren falls nötig: `pip install esptool` - -### Falls der interne USB doch mal repariert werden soll - -Als Administrator: - -```cmd -pnputil /enum-drivers | findstr /i "libwdi libusb" -pnputil /delete-driver oemXX.inf /uninstall /force -``` - -Alle gefundenen libwdi/libusbK-Pakete löschen, besonders das mit -`MS_COMP_USBSER` — das kapert systemweit jedes CDC-Gerät. Danach neu starten. -Windows zieht dann wieder `usbser.sys`. - -**Zadig nicht mehr auf den ESP32-C3 loslassen.** Für den eingebauten -USB-Serial/JTAG ist es das falsche Werkzeug (außer man will JTAG-Debugging -über OpenOCD). - ---- - -## ESPHome einrichten - -Beide Geräte tragen WLAN-Zugangsdaten, `api`-Verschlüsselungskey und -OTA-Passwort **direkt in der YAML** statt über `secrets.yaml` — so war -`tor_steuerung.yaml` schon angelegt, und `auto_sender_01.yaml` verwendet -bewusst dieselben Werte, damit beide Geräte zusammenpassen. - -> **Achtung:** Damit stehen WLAN-Passwort und Schlüssel im Klartext in diesem -> Repo. Nur vertretbar, wenn `git.dominicspringer.de` privat/intern bleibt. -> Soll das Repo öffentlich werden, vorher alles auf `!secret`-Verweise -> umstellen und eine lokale `secrets.yaml` (nicht committen) anlegen. - -1. In ESPHome (HA-Add-on) das jeweilige Gerät anlegen bzw. die bestehende - `tor-steuerung` mit dem neuen Inhalt überschreiben -2. Inhalt der passenden Datei aus `esphome/` einfügen -3. Drei Punkte → **Install** → **Manual download** → **Factory format** -4. Mit esptool flashen (siehe oben) - -`reboot_timeout: 0s` beim Sender ist kein Versehen: im Auto ist kein WLAN in -Reichweite, ohne diese Zeile startet der ESP alle 15 Minuten neu. - ---- - -## Reichweite einstellen - -Die Reichweite wird **nicht** am Sender begrenzt — alle Sender laufen mit voller -Leistung. Der Empfänger entscheidet anhand der Signalstärke (RSSI), ob das -Fahrzeug nah genug ist. - -Der Schwellwert liegt als Schieberegler **„RSSI Schwelle"** in Home Assistant, -Änderungen brauchen kein Neuflashen. - -Einmessen: - -1. Empfänger-Log in ESPHome öffnen -2. Mit dem Fahrzeug in verschiedenen Abständen anhalten -3. RSSI-Werte notieren — z. B. `Fahrzeug 1, RSSI -73.5 dBm, LQI 12` -4. Den Wert bei der gewünschten Distanz (~5 m) als Schwelle setzen - -Je näher der Wert an 0, desto kürzer die Reichweite. Startwert ist `-60`. - -Nach jeder Öffnung greift eine **Sperrzeit von 60 Sekunden**. - ---- - -## Weiteres Fahrzeug hinzufügen - -In `auto_sender_01.yaml` nur die beiden Substitutions oben ändern: +Wichtige Anpassung fuer weitere Fahrzeuge: ```yaml substitutions: - geraet: auto-sender-02 - fahrzeug_id: "0x02" + device_name: auto-sender-02 + friendly_name: Auto Sender 02 ``` -Der Empfänger akzeptiert IDs `0x01` bis `0x0A` (1–10) und muss dafür **nicht** -angefasst werden. Sollen weniger Fahrzeuge erlaubt sein, im `on_packet`-Lambda -die Zeile `if (fz < 1 || fz > 10)` anpassen. +Und im Paket: ---- +```yaml +- 0x02 +``` -## Paketformat +Die LED blinkt nur einmal pro Minute kurz auf. Das reduziert unnoetige LED-Laufzeit, ist aber noch kein echter Akkubetrieb. Fuer Akkubetrieb sollte spaeter Deep Sleep oder ein Wakeup-Konzept ergaenzt werden. -4 Bytes, GFSK, 4800 Baud, CRC-16 aktiv, Sync `0xD391`: +## Empfaenger flashen -| Byte | Inhalt | -|------|--------| -| 0 | `0xA7` Magic | -| 1 | `0x3C` Magic | -| 2 | Fahrzeug-ID (`0x01`–`0x0A`) | -| 3 | reserviert (`0x00`) | +Datei: -Der Sender schickt das Paket alle 2 Sekunden, solange die Zündung an ist. +```text +esphome/tor_steuerung.yaml +``` + +Die Torsteuerung arbeitet autonom: + +1. CC1101 Paket empfangen +2. Magic Bytes pruefen +3. Fahrzeug-ID pruefen +4. RSSI-Grenze pruefen +5. Sperrzeit pruefen +6. Relais lokal fuer 500 ms schalten + +Home Assistant wird nicht zum Oeffnen benoetigt. + +## Home Assistant Diagnose + +Die Torsteuerung stellt unter anderem bereit: + +- Letzte Fahrzeug-ID +- Letzter RSSI +- Letzter LQI +- Pakete gesamt +- Gueltige Pakete +- Verworfene Pakete +- Toroeffnungen +- Sekunden seit letztem Paket +- Sekunden seit letzter Toroeffnung +- WLAN Signal +- Freier Heap +- Neustartgrund +- Firmware-Version + +Einstellbar: + +- `RSSI Grenze` +- `Sperrzeit` +- `Testmodus` + +Der Testmodus prueft die komplette Logik, schaltet aber das Relais nicht. + +## WLAN + +Beide YAML-Dateien enthalten einen aktiven WLAN-Eintrag und vorbereitete weitere Eintraege: + +```yaml +wifi: + networks: + - ssid: ${wifi_1_ssid} + password: ${wifi_1_password} +``` + +Weitere WLANs koennen in den `substitutions` und im `wifi.networks` Block aktiviert werden. + +## Testablauf vor Einbau + +1. Sender flashen. +2. Empfaenger flashen. +3. Pruefen, ob beide in Home Assistant online sind. +4. Empfaenger auf `Testmodus` stellen. +5. Sender in Reichweite bringen. +6. RSSI, LQI und Paketzaehler pruefen. +7. Testmodus deaktivieren. +8. Torimpuls pruefen. +9. Home Assistant oder WLAN testweise deaktivieren. +10. Pruefen, dass der Empfaenger weiterhin lokal schaltet. + +## Git + +Zwischenstand speichern: + +```bash +git add . +git commit -m "Stabiler Zwischenstand vor Release 1.0" +git push origin main +``` + +Nach erfolgreichem Test als Release markieren: + +```bash +git add . +git commit -m "Release 1.0.0 - autonome CC1101 Torsteuerung" +git tag -a v1.0.0 -m "Erste stabile Version" +git push origin main +git push origin v1.0.0 +``` + +Falls dein Standard-Branch `master` heisst, ersetze `main` durch `master`. diff --git a/esphome/auto_sender_01.yaml b/esphome/auto_sender_01.yaml index 299e0b5..be15d94 100644 --- a/esphome/auto_sender_01.yaml +++ b/esphome/auto_sender_01.yaml @@ -1,10 +1,21 @@ substitutions: - geraet: auto-sender-01 # <- pro Fahrzeug ändern: 01, 02, 03 ... - fahrzeug_id: "0x01" # <- pro Fahrzeug ändern: 0x01, 0x02, 0x03 ... + device_name: auto-sender-01 + friendly_name: Auto Sender 01 + firmware_version: "1.0.0-rc1" + + wifi_1_ssid: "Leonardo da WiFi" + wifi_1_password: "44290812080358610465" + + # Weitere WLANs bei Bedarf aktivieren. + # wifi_2_ssid: "Werkstatt" + # wifi_2_password: "PASSWORT" + # wifi_3_ssid: "Hotspot" + # wifi_3_password: "PASSWORT" esphome: - name: ${geraet} - friendly_name: Auto Sender 01 + name: ${device_name} + friendly_name: ${friendly_name} + comment: "CC1101 433 MHz Fahrzeugsender ${firmware_version}" esp32: board: esp32-c3-devkitm-1 @@ -12,6 +23,7 @@ esp32: type: esp-idf logger: + level: INFO api: encryption: @@ -22,44 +34,96 @@ ota: password: "4bd4f24d4a26730d06e84d6e0816fb09" wifi: - ssid: "Leonardo da WiFi" - password: "44290812080358610465" - # Wichtig: im Auto ist kein WLAN in Reichweite. - # Ohne diese Zeile würde der ESP alle 15 Min neu starten. reboot_timeout: 0s + power_save_mode: none + + networks: + - ssid: ${wifi_1_ssid} + password: ${wifi_1_password} + + # - ssid: ${wifi_2_ssid} + # password: ${wifi_2_password} + + # - ssid: ${wifi_3_ssid} + # password: ${wifi_3_password} + + ap: + ssid: "${friendly_name} Fallback" + password: "Spring.3" + +captive_portal: -# --- SPI zum CC1101 --- spi: clk_pin: GPIO6 mosi_pin: GPIO7 miso_pin: GPIO5 -# --- CC1101 im Paketmodus --- cc1101: cs_pin: GPIO4 gdo0_pin: GPIO3 + frequency: 433.92MHz modulation_type: GFSK symbol_rate: 4800 - output_power: 10 # volle Leistung, Reichweite regelt der Empfänger per RSSI + + output_power: 10 + packet_mode: true packet_length: 4 crc_enable: true + sync0: 0x91 sync1: 0xD3 -# --- alle 2 Sekunden die Fahrzeug-Kennung senden --- -# Paketaufbau: [Magic, Magic, Fahrzeug-ID, Reserve] +output: + - platform: gpio + id: status_led + pin: + number: GPIO8 + inverted: true + interval: - interval: 2s then: - cc1101.send_packet: - data: [0xA7, 0x3C, ${fahrzeug_id}, 0x00] + data: + - 0xA7 + - 0x3C + - 0x01 + - 0x00 -# Onboard-LED des Super Mini (invertiert) -light: - - platform: status_led - name: Status - pin: - number: GPIO8 - inverted: true + - interval: 60s + then: + - output.turn_on: status_led + - delay: 100ms + - output.turn_off: status_led + +sensor: + - platform: wifi_signal + name: "${friendly_name} WLAN Signal" + update_interval: 60s + + - platform: uptime + name: "${friendly_name} Laufzeit" + update_interval: 60s + +text_sensor: + - platform: version + name: "${friendly_name} ESPHome Version" + + - platform: template + name: "${friendly_name} Firmware Version" + lambda: |- + return {"${firmware_version}"}; + + - platform: wifi_info + ip_address: + name: "${friendly_name} IP" + ssid: + name: "${friendly_name} WLAN SSID" + mac_address: + name: "${friendly_name} MAC" + +button: + - platform: restart + name: "${friendly_name} Neustart" diff --git a/esphome/tor_steuerung.yaml b/esphome/tor_steuerung.yaml index b89b211..76b0908 100644 --- a/esphome/tor_steuerung.yaml +++ b/esphome/tor_steuerung.yaml @@ -1,6 +1,21 @@ -esphome: - name: tor-steuerung +substitutions: + device_name: tor-steuerung friendly_name: Tor Steuerung + firmware_version: "1.0.0-rc1" + + wifi_1_ssid: "Leonardo da WiFi" + wifi_1_password: "44290812080358610465" + + # Weitere WLANs bei Bedarf aktivieren. + # wifi_2_ssid: "Werkstatt" + # wifi_2_password: "PASSWORT" + # wifi_3_ssid: "Hotspot" + # wifi_3_password: "PASSWORT" + +esphome: + name: ${device_name} + friendly_name: ${friendly_name} + comment: "Autonome CC1101 433 MHz Torsteuerung ${firmware_version}" esp32: board: esp32dev @@ -9,7 +24,7 @@ esp32: version: recommended logger: - level: DEBUG + level: INFO api: encryption: @@ -20,41 +35,73 @@ ota: password: "4bd4f24d4a26730d06e84d6e0816fb09" wifi: - ssid: "Leonardo da WiFi" - password: "44290812080358610465" + reboot_timeout: 0s power_save_mode: none + + networks: + - ssid: ${wifi_1_ssid} + password: ${wifi_1_password} + + # - ssid: ${wifi_2_ssid} + # password: ${wifi_2_password} + + # - ssid: ${wifi_3_ssid} + # password: ${wifi_3_password} + ap: ssid: "Torsteuerung" password: "Spring.3" captive_portal: -# --- Bestehende Hardware --- +debug: + update_interval: 60s -switch: - - platform: gpio - pin: GPIO16 - id: tor_impuls_relay - name: "Tor Impuls" - restore_mode: ALWAYS_OFF - on_turn_on: - - delay: 500ms - - switch.turn_off: tor_impuls_relay +globals: + - id: total_packets + type: uint32_t + restore_value: true + initial_value: "0" -binary_sensor: - - platform: gpio - pin: GPIO34 - name: "Tor AUF" - device_class: door - - platform: gpio - pin: GPIO35 - name: "Tor ZU" - device_class: door + - id: valid_packets + type: uint32_t + restore_value: true + initial_value: "0" -# --- Neu: CC1101 433 MHz Empfänger für den Funksender im Auto --- -# Pinbelegung siehe README/doku/verdrahtung-cc1101.svg -# (GPIO16/34/35 sind durch die bestehende Hardware belegt, deshalb -# hier die freien VSPI-Standardpins verwendet) + - id: rejected_packets + type: uint32_t + restore_value: true + initial_value: "0" + + - id: gate_open_count + type: uint32_t + restore_value: true + initial_value: "0" + + - id: last_open_ms + type: uint32_t + restore_value: false + initial_value: "0" + + - id: last_packet_ms + type: uint32_t + restore_value: false + initial_value: "0" + + - id: last_vehicle_id + type: int + restore_value: true + initial_value: "0" + + - id: last_rssi_value + type: float + restore_value: true + initial_value: "-127.0" + + - id: last_lqi_value + type: int + restore_value: true + initial_value: "0" spi: clk_pin: GPIO18 @@ -63,64 +110,270 @@ spi: cc1101: cs_pin: GPIO5 - gdo0_pin: GPIO4 + gdo0_pin: GPIO17 + frequency: 433.92MHz modulation_type: GFSK symbol_rate: 4800 + packet_mode: true packet_length: 4 crc_enable: true + sync0: 0x91 sync1: 0xD3 + on_packet: then: - lambda: |- - // Magic-Bytes prüfen - if (x.size() < 3 || x[0] != 0xA7 || x[1] != 0x3C) return; + const char *tag = "tor_433"; + const uint32_t now = millis(); + id(total_packets) += 1; + id(last_packet_ms) = now; - uint8_t fz = x[2]; - ESP_LOGI("tor", "Fahrzeug %u, RSSI %.1f dBm, LQI %u", fz, rssi, lqi); - - // Reichweite: nur öffnen wenn Signal stark genug (= Auto nah) - if (rssi < id(rssi_schwelle).state) return; - - // erlaubte Fahrzeuge - if (fz < 1 || fz > 10) { - ESP_LOGW("tor", "Unbekannte Fahrzeug-ID: %u", fz); + if (data.size() != 4) { + id(rejected_packets) += 1; + id(last_event_text).publish_state("Verworfen: falsche Paketlaenge"); + ESP_LOGW(tag, "Paket verworfen: falsche Laenge (%u)", data.size()); return; } - // Sperrzeit, damit das Tor nicht dauernd getriggert wird - uint32_t jetzt = millis(); - if (id(letzte_oeffnung) != 0 && (jetzt - id(letzte_oeffnung)) < 60000) return; - id(letzte_oeffnung) = jetzt; + if (data[0] != 0xA7 || data[1] != 0x3C) { + id(rejected_packets) += 1; + id(last_event_text).publish_state("Verworfen: falsche Magic Bytes"); + ESP_LOGW(tag, "Paket verworfen: Magic Bytes %02X %02X", data[0], data[1]); + return; + } - ESP_LOGI("tor", "Tor öffnen für Fahrzeug %u (RSSI %.1f)", fz, rssi); - id(letztes_fahrzeug).publish_state(std::to_string(fz)); - id(tor_impuls_relay).turn_on(); + const int vehicle_id = data[2]; + const int reserve = data[3]; + id(last_vehicle_id) = vehicle_id; + id(last_rssi_value) = rssi; + id(last_lqi_value) = lqi; -globals: - - id: letzte_oeffnung - type: uint32_t - restore_value: false - initial_value: '0' + id(last_vehicle_sensor).publish_state(vehicle_id); + id(last_rssi_sensor).publish_state(rssi); + id(last_lqi_sensor).publish_state(lqi); + + ESP_LOGI(tag, "Paket: id=%d reserve=%d rssi=%.1f lqi=%d", vehicle_id, reserve, rssi, lqi); + + if (vehicle_id < 1 || vehicle_id > 10) { + id(rejected_packets) += 1; + id(last_event_text).publish_state("Verworfen: Fahrzeug-ID nicht erlaubt"); + ESP_LOGW(tag, "Paket verworfen: Fahrzeug-ID %d nicht erlaubt", vehicle_id); + return; + } + + if (rssi < id(rssi_limit).state) { + id(rejected_packets) += 1; + id(last_event_text).publish_state("Verworfen: RSSI zu schwach"); + ESP_LOGW(tag, "Paket verworfen: RSSI %.1f kleiner als Grenze %.1f", rssi, id(rssi_limit).state); + return; + } + + const uint32_t lockout_ms = (uint32_t) (id(lockout_seconds).state * 1000.0f); + if (id(last_open_ms) != 0 && (now - id(last_open_ms)) < lockout_ms) { + id(rejected_packets) += 1; + id(last_event_text).publish_state("Verworfen: Sperrzeit aktiv"); + ESP_LOGI(tag, "Paket ignoriert: Sperrzeit aktiv (%u ms verbleibend)", lockout_ms - (now - id(last_open_ms))); + return; + } + + id(valid_packets) += 1; + + if (id(test_mode).state) { + id(last_event_text).publish_state("Testmodus: Oeffnung waere erfolgt"); + ESP_LOGI(tag, "Testmodus aktiv: Relais wird nicht geschaltet"); + return; + } + + id(last_open_ms) = now; + id(gate_open_count) += 1; + id(last_event_text).publish_state("Torimpuls ausgeloest"); + ESP_LOGI(tag, "Torimpuls ausgeloest durch Fahrzeug-ID %d", vehicle_id); + id(trigger_gate).execute(); + +switch: + - platform: gpio + pin: GPIO16 + id: tor_impuls_relay + name: "Tor Impuls" + restore_mode: ALWAYS_OFF -# In HA per Schieberegler einstellbar, kein Neuflashen nötig. -# Startwert -60 ≈ 5 m, im Betrieb anhand der geloggten RSSI-Werte feinjustieren. -number: - platform: template - name: RSSI Schwelle - id: rssi_schwelle - min_value: -100 - max_value: -20 - step: 1 - initial_value: -60 + id: test_mode + name: "Testmodus" optimistic: true - restore_value: true - unit_of_measurement: dBm + restore_mode: RESTORE_DEFAULT_OFF entity_category: config -text_sensor: +binary_sensor: + - platform: gpio + pin: GPIO34 + name: "Tor AUF" + device_class: door + + - platform: gpio + pin: GPIO35 + name: "Tor ZU" + device_class: door + + - platform: status + name: "${friendly_name} Status" + +number: - platform: template - name: Letztes Fahrzeug - id: letztes_fahrzeug + id: rssi_limit + name: "RSSI Grenze" + min_value: -100 + max_value: -30 + step: 1 + initial_value: -60 + restore_value: true + optimistic: true + unit_of_measurement: "dBm" + entity_category: config + + - platform: template + id: lockout_seconds + name: "Sperrzeit" + min_value: 5 + max_value: 300 + step: 1 + initial_value: 60 + restore_value: true + optimistic: true + unit_of_measurement: "s" + entity_category: config + +script: + - id: trigger_gate + mode: single + then: + - switch.turn_on: tor_impuls_relay + - delay: 500ms + - switch.turn_off: tor_impuls_relay + +sensor: + - platform: wifi_signal + name: "${friendly_name} WLAN Signal" + update_interval: 60s + + - platform: uptime + name: "${friendly_name} Laufzeit" + update_interval: 60s + + - platform: template + id: last_vehicle_sensor + name: "Letzte Fahrzeug-ID" + accuracy_decimals: 0 + lambda: |- + return id(last_vehicle_id); + update_interval: 60s + + - platform: template + id: last_rssi_sensor + name: "Letzter RSSI" + unit_of_measurement: "dBm" + accuracy_decimals: 1 + lambda: |- + return id(last_rssi_value); + update_interval: 60s + + - platform: template + id: last_lqi_sensor + name: "Letzter LQI" + accuracy_decimals: 0 + lambda: |- + return id(last_lqi_value); + update_interval: 60s + + - platform: template + name: "Pakete gesamt" + accuracy_decimals: 0 + lambda: |- + return id(total_packets); + update_interval: 60s + + - platform: template + name: "Pakete gueltig" + accuracy_decimals: 0 + lambda: |- + return id(valid_packets); + update_interval: 60s + + - platform: template + name: "Pakete verworfen" + accuracy_decimals: 0 + lambda: |- + return id(rejected_packets); + update_interval: 60s + + - platform: template + name: "Toroeffnungen" + accuracy_decimals: 0 + lambda: |- + return id(gate_open_count); + update_interval: 60s + + - platform: template + name: "Sekunden seit letztem Paket" + unit_of_measurement: "s" + accuracy_decimals: 0 + lambda: |- + if (id(last_packet_ms) == 0) return {}; + return (millis() - id(last_packet_ms)) / 1000.0f; + update_interval: 10s + + - platform: template + name: "Sekunden seit letzter Toroeffnung" + unit_of_measurement: "s" + accuracy_decimals: 0 + lambda: |- + if (id(last_open_ms) == 0) return {}; + return (millis() - id(last_open_ms)) / 1000.0f; + update_interval: 10s + + - platform: debug + free: + name: "${friendly_name} Freier Heap" + +text_sensor: + - platform: version + name: "${friendly_name} ESPHome Version" + + - platform: template + name: "${friendly_name} Firmware Version" + lambda: |- + return {"${firmware_version}"}; + + - platform: template + id: last_event_text + name: "Letztes 433 MHz Ereignis" + + - platform: debug + reset_reason: + name: "${friendly_name} Neustartgrund" + + - platform: wifi_info + ip_address: + name: "${friendly_name} IP" + ssid: + name: "${friendly_name} WLAN SSID" + mac_address: + name: "${friendly_name} MAC" + +button: + - platform: restart + name: "${friendly_name} Neustart" + + - platform: template + name: "Zaehler zuruecksetzen" + entity_category: config + on_press: + - lambda: |- + id(total_packets) = 0; + id(valid_packets) = 0; + id(rejected_packets) = 0; + id(gate_open_count) = 0; + id(last_event_text).publish_state("Zaehler zurueckgesetzt");