Entrixy v2 — endgültige Architektur

Abgestimmt am 13. April 2026. Ein Arbeitsdokument für die Umsetzung.

Inhalt
  1. Privatsphäre: Der Server weiß nichts
  2. Vier Objekttypen: Anruf, URL, Gerät (WS), BLE-Controller
  3. Webhook (URL) im Detail
  4. Gerät (ESP32 / ESP8266, WebSocket) im Detail
  5. BLE-Controller (ESP32) im Detail
  6. Auslöser: GPS und WLAN
  7. Drei Stufen der Bestätigung
  8. Besitzer gegen Gast — die Aufteilung der Einstellungen
  9. Die Oberfläche der App
  10. Tarifgrenzen
  11. Objektsymbole für Gäste
  12. Lastprognose
  13. Struktur der Datenbank
  14. Umsetzungsplan

1. Privatsphäre: Der Server weiß nichts (standardmäßig)

Das Versprechen, das wir geben: „Wir kennen weder die Rufnummern unserer Nutzer noch ihre Koordinaten“

Alle sensiblen Daten bleiben nur auf dem Telefon. Einen Teil davon kann der Besitzer auf Wunsch über den Server leiten — mit ausdrücklicher Warnung.

DatenStandardmäßigOptional über den Server
Koordinaten (lat, lon)Nur auf dem TelefonKann mit Gästen geteilt werden (mit Warnung)
WLAN-Fingerabdruck (BSSID[])Nur auf dem TelefonWird nie übertragen
Webhook-Adresse und -GeheimnisNur auf dem TelefonKann auf dem Server gespeichert werden (mit Warnung)
Radius, Zeit, BestätigungsstufeÜber den Server
Ein WLAN-Fingerabdruck ist so gut wie Koordinaten. Anhand einer Menge von BSSIDs orten Dienste auf 20–50 m genau. Das WLAN-Bild passiert unter keinen Umständen den Server.

2. Vier Objekttypen

Beim Hinzufügen eines Objekts wählt der Besitzer den Verbindungstyp. Danach öffnet sich das Einstellungsfenster dieses Typs.

IconNameSo funktioniert esFeedbackExample
📞CallEin Telefonanruf vom Telefon des BesitzersKeine (der Anruf ging hinaus oder nicht)Eine Schranke, eine Türsprechanlage
🌐URL (Webhook)Eine HTTP-Anfrage an die Adresse des Geräts, vom Telefon oder vom Entrixy-ServerJa — eine JSON-Antwort mit StatusEin smartes Schloss mit API, Tasmota, Shelly Cloud
📟Internet-Controller (WS)Ein Befehl über WebSocket an einen verbundenen ControllerJa — eine Antwort über den WebSocketSelbstbau ESP32 / ESP8266, Shelly Plus 1, NodeMCU
📶BLE-ControllerEin direkter Bluetooth-Kanal zwischen Telefon und Controller, ohne InternetJa — eine Antwort über BLE (notify)Ein batteriebetriebener Controller am Tor ohne WLAN

Der Firmware-Konfigurator für die letzten beiden Typen: /controller/ (BLE und Internet, im Browser).

Für den Nutzer sehen alle Typen gleich aus: eine Karte, eine Anruf-Schaltfläche, ein Status. Nur der Zustellmechanismus unterscheidet sich.

3. Webhook (URL) im Detail

Zwei Sendemodi

Im Einstellungsfenster des Webhooks gibt es einen Umschalter, Vor- und Nachteile stehen direkt auf dem Bildschirm:

◉ Vom Telefon des Besitzers (Standard)
Die Anfrage geht von Ihrem Telefon aus. Adresse und Geheimnis des Geräts bleiben bei Ihnen — der Entrixy-Server erfährt sie nie.
Plus: maximale Privatsphäre
Minus: Ihr Telefon muss online sein
○ Vom Entrixy-Server
Unser Server sendet die Anfrage. Das funktioniert auch, wenn Ihr Telefon offline ist.
Plus: funktioniert ohne das Telefon des Besitzers
Minus: die Adresse des Geräts liegt auf dem Server

Wo die Daten liegen

ModeWo Adresse und Geheimnis liegenKennt der Server die Adresse?
Vom TelefonPrefs auf dem Telefon des BesitzersNo
Vom ServerDie Tabelle numbers in der DatenbankYes

Anfrageprotokoll

Sicherheit: eine HMAC-Signatur. Gerät und Entrixy teilen sich ein webhook_secret.

POST https://device-url.com/open
Content-Type: application/json

{
  "action": "open",
  "object_id": 42,
  "timestamp": 1713020000,
  "nonce": "a1b2c3",
  "signature": "hmac-sha256(secret, timestamp + nonce + action)"
}

Das Gerät prüft, dass die Signatur gültig ist, der Zeitstempel jünger als 30 Sekunden und die Nonce keine Wiederholung. Passt alles, handelt es und antwortet:

{"status": "ok", "message": "Door opened"}
or
{"status": "error", "message": "Lock jammed"}

Der Status wird dem Nutzer in der App angezeigt.

Datenfluss (Telefonmodus)

The guest presses Call
  → the server receives the request
  → sends it to the owner over the WebSocket: {type: "do_webhook", ...}
  → the owner's phone makes the HTTP call to the device
  → receives the JSON response
  → sends it to the server: {type: "webhook_result", status, message}
  → the server passes it to the guest
  → both see the status in the log

Logging

In beiden Modi hält das Protokoll auf dem Telefon von Besitzer und Gast fest, wer, wann, welches Objekt und mit welchem Status.

4. Gerät (ESP32 / ESP8266, WebSocket) im Detail

So funktioniert es

Der Controller — unterstützt werden ESP32, ESP32-S3, ESP32-C3 und ESP8266 — hat keine öffentliche IP. Er hält eine ausgehende WebSocket-Verbindung zum Entrixy-Server, genau wie das Telefon des Besitzers.

Firmware und Konfigurator liegen unter /esp/socket/. Quellen: ESP32, ESP8266.

Das WebSocket-Protokoll des Geräts

// Device → server: connect
{"type": "device_hello", "device_key": "xyz789", "device_secret": "..."}

// Server → device: OK
{"type": "device_ok"}

// Server → device: command
{"type": "device_command", "action": "open", "command_id": "abc123"}

// Device → server: result
{"type": "device_response", "command_id": "abc123", "status": "ok", "message": "Opened"}

Der Server leitet den Status über deren WebSocket-Verbindungen an die Clients weiter — Besitzer und Gast.

Ein Gerät registrieren

  1. In der App wählt der Besitzer Objekt hinzufügen → Typ Gerät
  2. Dabei entstehen device_key + device_secret
  3. Ein QR-Code mit den Firmware-Daten wird angezeigt
  4. Der Nutzer flasht den ESP32 oder ESP8266 (siehe configurator), und das Gerät verbindet sich mit wss://entrixy.com/ws

Indication

Auf der Objektkarte ist der Verbindungsstatus des Geräts zu sehen — online oder offline —, genau wie Gäste den Status des Besitzers sehen.

4a. BLE-Controller (ESP32) im Detail

So funktioniert es

Ein Controller auf ESP32, S3, C3, C6 oder H2 braucht zum Auslösen weder WLAN noch Server. Er liegt im Tiefschlaf, wacht einmal pro Sekunde für etwa 200 ms auf und sendet ein BLE-Advertisement mit signiertem Zähler. Kommt ein Telefon mit gültigem Schlüssel in die Nähe, fängt Android — oder die App, wenn sie im Vordergrund ist — das Advertisement ab, verbindet sich per GATT, schickt einen Fire-Befehl mit einmaliger Nonce, und der Controller schließt das Relais für einen kurzen Impuls. Für bistabile Antriebe und Schlösser gibt es einen Modus mit getrenntem Öffnen und Schließen sowie Positionsverfolgung, bei dem offen/geschlossen als verschlüsseltes Byte im Advertisement mitreist.

Der Entrixy-Server ist an diesem Kanal nicht beteiligt. Er wird nur beim Erstellen eines Gastschlüssels gebraucht: Der Besitzer signiert ein GuestToken und übergibt es dem Gast über den Ende-zu-Ende verschlüsselten Kanal. Danach arbeitet der Gast offline.

Das BLE-Protokoll in Kürze

Die vollständige Protokollspezifikation, das Bit-Layout und die Testvektoren stehen unter entrixy.com/ble. Das Bedrohungsmodell steht in einem eigenen Dokument.

Wann BLE dem WebSocket überlegen ist

Wann der WebSocket dem BLE überlegen ist

An denselben Antrieb lassen sich BLE und WebSocket zugleich setzen — in der App erscheinen sie als zwei getrennte Objekte. BLE zum Öffnen aus der Nähe ohne Internet, WebSocket für die Zeiten, in denen Sie weit weg sind.

Ein Gerät registrieren

  1. In der App wählt der Besitzer Objekt hinzufügen → Typ BLE-Controller
  2. Die App durchsucht den Funk nach Geräten im Kopplungsmodus (mit dem Namen entrixy-pair)
  3. Die Auswahl eines Geräts startet einen ECDH-Austausch über GATT; das gemeinsame Geheimnis wird in den Prefs des Telefons und im NVS des Controllers gespeichert
  4. Kein QR-Code und keine Tastendrücke — ein neues Gerät geht nach dem Laden des Programms von selbst in den Kopplungsmodus

Firmware und Konfigurator liegen unter /esp/ble/. Quelle: /esp32-example/.

Indication

Auf der Objektkarte: Grau heißt im Funk nicht sichtbar, zu weit weg oder ausgeschaltet; Orange heißt sichtbar, aber die Automatik hat nicht ausgelöst; Grün heißt ausgelöst oder löst gerade aus; Grau mit grünem Rand heißt: kürzlich ausgelöst, ein Tippen öffnet erneut.

Database

CREATE TABLE devices (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  host_id INT UNSIGNED NOT NULL,
  device_key VARCHAR(64) NOT NULL UNIQUE,
  secret_hash VARCHAR(64) NOT NULL,
  label VARCHAR(128) DEFAULT '',
  last_seen DATETIME NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

In server.php kommt eine dritte WebSocket-Rolle hinzu: device (neben host und guest).

5. Auslöser: GPS und WLAN

GPS und WLAN arbeiten unabhängig. Sind beide eingerichtet, löst die Bedingung aus, die zuerst erfüllt ist. Die gemeinsame Pause zwischen den Auslösungen beträgt 20 Sekunden.

GPS — wie es heute ist

WLAN — zwei Modi

Modus 1: das WLAN-Bild (Fingerabdruck)

Modus 2: mit einem Netz verbunden

Energieverbrauch

Speicherung (Prefs, verlässt das Telefon nie)

wifi_trigger_<actionKey> = {
  "mode": "fingerprint" | "connect",
  "bssids": ["AA:BB:CC:DD:EE:FF", ...],
  "min_match": 5,
  "connect_bssid": "AA:BB:CC:DD:EE:FF",
  "connect_ssid": "TP-Link_5G",
  "enabled": true
}

6. Drei Stufen der Bestätigung

Der Besitzer entscheidet, ob eine Bestätigung nötig ist. Wie die Identität bestätigt wird, entscheidet der Client — aus dem, was das Gerät bietet.

LevelWas der Nutzer siehtExample
AutomaticNichts — das Objekt öffnet sich von selbstSchranken, Tore
ConfirmEine Benachrichtigung in der Leiste: „[Objekt] öffnen?“ → ein TippenEine Garage, eine Pforte, Schutz vor Fehlauslösungen
Identität bestätigenBiometrie, die PIN des Telefons oder die PIN der AppEine Haustür

„Bestätigen“ ist kein verschwendeter Schritt. Die Benachrichtigung erscheint im richtigen Moment von selbst in der Leiste. Kein Suchen der App, kein Entsperren, kein Finden des Objekts. Ein Tippen, und die Tür ist offen.

Rangfolge der Methoden zur Identitätsbestätigung

  1. Biometrie, sofern ein Sensor vorhanden ist → BiometricPrompt
  2. PIN oder Passwort des Telefons, wenn es keine Biometrie gibt → KeyguardManager
  3. Die eigene PIN der App auf einem Gerät ohne Sperre → unser eigener Dialog

Das Zeitfenster — ein zusätzlicher Faktor

Der Besitzer setzt „Erlaubte Stunden: 07:00–23:00“. Außerhalb des Fensters wird die Bedingung still ignoriert. Ein Nachtintervall funktioniert ebenso (22:00–06:00).

Drei unabhängige Schutzfaktoren

  1. WHERE — GPS, ein WLAN-Fingerabdruck oder eine Verbindung
  2. WHO — automatisch, Bestätigung oder Biometrie
  3. WHEN — das Zeitfenster
Eine Haustür: WLAN-Fingerabdruck plus Identitätsbestätigung plus 07:00–23:00 — stabiler als die meisten „smarten Schlösser“.

7. Besitzer gegen Gast — die Aufteilung der Einstellungen

SettingBesitzer (eigenes)Besitzer → GästeGast
ObjekttypChoosesGibt weiterReceives
CoordinatesLegt sie festOptional (mit Warnung)Legt sie fest oder erhält sie
GPS-RadiusLegt ihn festGibt weiterReceives
WLAN-FingerabdruckScansNeverScannt selbst
Mindestübereinstimmungen beim WLANLegt ihn festGibt weiterReceives
ZeitfensterLegt ihn festGibt weiterReceives
BestätigungLegt ihn festGibt weiterReceives
GPS ein/ausyesyes
WLAN ein/ausyesyes

8. Die Oberfläche der App

Ein Objekt hinzufügen (SettingsScreen)

Der erste Schritt ist die Wahl des Verbindungstyps:

┌────────────────────────────┐
│  Connection type           │
│                            │
│  📞  Call                  │
│  Opening with a phone      │
│  call                      │
│                            │
│  🌐  URL                   │
│  Sending a command to      │
│  a device address          │
│                            │
│  📟  Device                │
│  Connected through Entrixy │
│  (ESP32, Arduino)          │
└────────────────────────────┘

Nach der Wahl öffnet sich das Einstellungsfenster dieses Typs.

Die ausgeklappte Objektkarte (ActionCard)

┌──────────────────────────────────────────┐
│  Corner barrier             📶 3/5  312m │
│  Mine • ●                                │
├──────────────────────────────────────────┤
│  [Edit]  [Icon]                          │
│  ─────────────────────────               │
│  [📍 Geo]   [📶 Wi-Fi]                   │
└──────────────────────────────────────────┘

Das Fenster 📍 Geo

Das Fenster 📶 WLAN

◉ Nach dem WLAN-Bild

○ Nach der Verbindung mit einem Netz

Darunter: Zeitfenster und Bestätigung, gemeinsam mit Geo

Das Webhook-Fenster (🌐 URL)

◉ Vom Telefon (Standard)
Die Adresse liegt allein auf Ihrem Telefon. Der Entrixy-Server erfährt sie nie.
Plus: maximale Privatsphäre
Minus: Ihr Telefon muss online sein
○ Vom Entrixy-Server
Der Server sendet die Anfrage. Das funktioniert ohne Ihr Telefon.
Plus: funktioniert immer
Minus: die Adresse des Geräts liegt auf dem Server

Anzeige auf der eingeklappten Karte

TriggerIndicator
GPS"312 m"
WLAN-Fingerabdruck📶 Balken (0–4 nach Übereinstimmungen)
WLAN-Verbindung📶 grün oder grau
Webhook/Device● grün (online) oder grau (offline)

9. Tarifgrenzen

Interne Tarife. Sie werden dem Nutzer nicht gezeigt, die Grenzen gelten dennoch.

StandardtarifLimit
Objekte (numbers)10
Gäste (user_keys)10

Bei Überschreitung eine sanfte Meldung: „Die Zahl der Objekte ist begrenzt. Wenden Sie sich an den Support, um sie zu erhöhen.“

CREATE TABLE plans (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(64) NOT NULL,
  max_numbers INT NOT NULL DEFAULT 10,
  max_keys INT NOT NULL DEFAULT 10
);
INSERT INTO plans (name) VALUES ('default');

ALTER TABLE hosts ADD COLUMN plan_id INT UNSIGNED DEFAULT 1;

10. Datenbank — der vollständige Satz an Änderungen

-- Plans
CREATE TABLE plans (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(64) NOT NULL,
  max_numbers INT NOT NULL DEFAULT 10,
  max_keys INT NOT NULL DEFAULT 10
);
INSERT INTO plans (name) VALUES ('default');

ALTER TABLE hosts ADD COLUMN plan_id INT UNSIGNED DEFAULT 1;

-- Object type and settings
ALTER TABLE numbers
  ADD COLUMN type ENUM('call','webhook','device') DEFAULT 'call',
  ADD COLUMN radius INT DEFAULT 80,
  ADD COLUMN time_from TIME NULL,
  ADD COLUMN time_to TIME NULL,
  ADD COLUMN security_level ENUM('auto','confirm','identity') DEFAULT 'auto',
  ADD COLUMN geo_available TINYINT(1) DEFAULT 1,
  ADD COLUMN wifi_available TINYINT(1) DEFAULT 1,
  ADD COLUMN wifi_min_match INT DEFAULT 5,
  ADD COLUMN share_lat DOUBLE NULL,
  ADD COLUMN share_lon DOUBLE NULL,
  ADD COLUMN webhook_url VARCHAR(512) NULL,
  ADD COLUMN webhook_secret VARCHAR(64) NULL,
  ADD COLUMN webhook_mode ENUM('phone','server') DEFAULT 'phone',
  ADD COLUMN device_id INT UNSIGNED NULL;

-- Devices (ESP32)
CREATE TABLE devices (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  host_id INT UNSIGNED NOT NULL,
  device_key VARCHAR(64) NOT NULL UNIQUE,
  secret_hash VARCHAR(64) NOT NULL,
  label VARCHAR(128) DEFAULT '',
  last_seen DATETIME NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

share_lat / share_lon — nur befüllt, wenn der Besitzer „Koordinaten mit Gästen teilen“ aktiviert hat.

webhook_url / webhook_secret — nur im Servermodus befüllt. Im Telefonmodus liegen sie in den Prefs.

11. Objektsymbole für Gäste

Der Besitzer setzt einem Objekt ein eigenes Symbol, und der Gast soll es sehen. Doch das Symbol wird nicht auf dem Server gespeichert — der Server ist Postbote: Er stellt zu und vergisst.

Vorbereitung auf Seiten des Besitzers

Beim Setzen wird das Symbol sofort verkleinert auf 64×64 PNG (etwa 3–5 KB) und lokal in den Prefs oder als Datei gehalten.

Wie es reist

1. The guest connects
   → guest_ok carries has_avatar: true for objects that have an icon

2. The guest client checks: has_avatar=true but no icon locally?
   → Yes → it asks the server

3. The server has no icon
   → it asks the owner over the WebSocket: {type: "avatar_request", number_id: 42}

4. The owner's phone
   → reads the local file
   → sends: {type: "avatar_data", number_id: 42, data: "base64..."}

5. The server passes it to the guest
   → {type: "avatar_data", number_id: 42, data: "base64..."}

6. The guest stores it locally and never asks again

7. The server stored nothing — the data merely passed through

Randfälle

SituationBehaviour
Der Besitzer ist offlineDer Gast sieht das Standardsymbol, bis der Besitzer online geht.
50 Gäste fragen gleichzeitig50 × 5 KB = 250 KB über den WebSocket — vernachlässigbar.
Der Besitzer wechselt das Symbolhas_avatar_hash ändert sich und die Gäste fordern es erneut an
Der Besitzer löscht das Symbolhas_avatar: false, und die Gäste zeigen das Standardsymbol
Die Privatsphäre bleibt gewahrt. Das Symbol einer Schranke sind keine sensiblen Daten, doch selbst es setzt sich nicht auf dem Server ab: Es läuft im Transit über den WebSocket und wird nie auf die Platte geschrieben.

12. Lastprognose

Ein aktiver Besitzer erzeugt

Ein aktiver Gast

Scaling

SubscribersGleichzeitig online (~15 %)WebSocket-VerbindungenServer
1 000~150~150Easy
10 000~1 500~1 500Easy
50 000~7 500~7 500ein Worker am Limit
100 000~15 000~15 0002–3 Worker

Workerman auf einem Worker: 5.000–10.000 gleichzeitige Verbindungen zu je rund 20 KB.

Webhook und Gerät

Der Engpass

ist MySQL, nicht die WebSockets. Doch 250.000 Inserts pro Tag — 50.000 Abonnenten × 5 Aufrufe — sind für MySQL auf einer SSD nichts.

Conclusion: до 50 000 абонентов текущий сервер справится без изменений. После — увеличиваем worker->erhöhen und Indizes ergänzen.

13. Umsetzungsplan

  1. Database — Tarife, die neuen Spalten in numbers und hosts, die Tabelle devices
  2. Serverseitige Grenzen — Prüfungen in number_add und key_create
  3. Objekttyp — Typwahl beim Hinzufügen, unterschiedliche Dialoge
  4. API — host_sync und guest_ok mit den neuen Profilfeldern
  5. Webhook — das HMAC-Protokoll, zwei Sendemodi, der Antwortstatus
  6. Geräte-WS — device_hello, device_command und device_response in server.php
  7. Der WLAN-Auslöser — Fingerabdruck und Verbindung
  8. Zeitfenster — time_from/time_to
  9. Bestätigung — drei Stufen: automatisch, bestätigen, Identität bestätigen
  10. Icons — Transitzustellung über den WebSocket, komprimiert auf 64×64
  11. UI — die Schaltflächen Geo und WLAN, die Dialoge, die Anzeigen, die Typwahl
  12. Koordinaten teilen — eine Option mit Warnung
  13. Bauen und veröffentlichen
PWA: Der WLAN-Auslöser ist nicht verfügbar — Browser haben keine WLAN-API. Webhook und Gerät laufen über die PWA: Taste → Server → Gerät. Zeitfenster und Bestätigung gibt es nur in der nativen App.
Rückwärtskompatibilität: Alte Clients gibt es kaum. Wir machen es so, wie es bequem ist, und erzwingen bei Bedarf ein Update über version_check.

Entrixy — endgültige Architektur v2, abgestimmt am 13. April 2026