diff --git a/app/Livewire/Modals/RingConnect.php b/app/Livewire/Modals/RingConnect.php deleted file mode 100644 index a0c92fa..0000000 --- a/app/Livewire/Modals/RingConnect.php +++ /dev/null @@ -1,61 +0,0 @@ -first(); - $config = $addon?->config ?? []; - $this->email = $config['email'] ?? ''; - $this->hasStoredPassword = filled($config['password'] ?? null); - } - - public function save() - { - $this->validate([ - 'email' => 'required|email|max:190', - // Password may be left blank to keep a previously stored one. - 'password' => $this->hasStoredPassword ? 'nullable|string|max:190' : 'required|string|max:190', - 'code' => 'nullable|string|max:12', - ]); - - app(AddonService::class)->saveConnection('ring', [ - 'email' => $this->email, - 'password' => $this->password, - 'code' => $this->code, - ]); - - $this->closeModal(); - - return redirect()->route('addons.index'); - } - - public function render() - { - return view('livewire.modals.ring-connect'); - } -} diff --git a/app/Livewire/Modals/RingSetup.php b/app/Livewire/Modals/RingSetup.php new file mode 100644 index 0000000..32585eb --- /dev/null +++ b/app/Livewire/Modals/RingSetup.php @@ -0,0 +1,36 @@ +first(); + + // The bridge UI runs on the HomeOS host at its configured port. + $host = explode(':', HostAddress::broker())[0]; + + return view('livewire.modals.ring-setup', [ + 'status' => $addon?->status ?? 'disconnected', + 'statusDetail' => $addon?->status_detail, + 'connectedAt' => $addon?->connected_at, + 'bridgeUrl' => 'http://'.$host.':'.config('homeos.ring.ui_port', 55123), + ]); + } +} diff --git a/app/Services/AddonRegistry.php b/app/Services/AddonRegistry.php index 1191413..f90d7f9 100644 --- a/app/Services/AddonRegistry.php +++ b/app/Services/AddonRegistry.php @@ -21,18 +21,15 @@ class AddonRegistry 'vendor' => 'Ring', 'icon' => 'doorbell', // Ring has no local API — the established bridge is ring-mqtt (cloud, token auth). + // The BRIDGE does the Ring login (email/password/2FA) in its own web UI; HomeOS never + // handles Ring credentials. So the addon's job is to guide setup + reflect the + // bridge's real MQTT status — not to collect a password. 'cloud' => true, 'summary_key' => 'addons.ring.summary', 'body_key' => 'addons.ring.body', - // The ring-mqtt sidecar generates a refresh token from an interactive Ring login - // (email + password + 2FA). We store that token; the sidecar does the rest. 'backend' => 'ring-mqtt', 'docs' => 'https://github.com/tsightler/ring-mqtt', - 'fields' => [ - ['name' => 'email', 'type' => 'email', 'label_key' => 'addons.ring.email', 'secret' => false], - ['name' => 'password', 'type' => 'password', 'label_key' => 'addons.ring.password', 'secret' => true], - ['name' => 'code', 'type' => 'text', 'label_key' => 'addons.ring.code', 'secret' => false, 'optional' => true], - ], + 'setup_modal' => 'modals.ring-setup', ], ]; } diff --git a/config/homeos.php b/config/homeos.php index 44b8eec..ce9c980 100644 --- a/config/homeos.php +++ b/config/homeos.php @@ -38,4 +38,10 @@ return [ // rides out brief phone WLAN sleeps without leaving you "home" long after you left. 'away_debounce_minutes' => (int) env('PRESENCE_AWAY_DEBOUNCE', 3), ], + + 'ring' => [ + // Port of the ring-mqtt bridge's own setup/login web UI (where the Ring account login + // and 2FA happen). Linked from the Ring add-on setup guide. + 'ui_port' => (int) env('RING_UI_PORT', 55123), + ], ]; diff --git a/lang/de/addons.php b/lang/de/addons.php index c4545cf..85807a6 100644 --- a/lang/de/addons.php +++ b/lang/de/addons.php @@ -9,6 +9,7 @@ return [ 'uninstall_title' => ':name entfernen?', 'uninstall_body' => 'Die Integration wird deaktiviert und gespeicherte Zugangsdaten werden gelöscht. Geräte bleiben erhalten, empfangen aber keine Aktualisierungen mehr.', 'connect' => 'Konto verbinden', + 'setup' => 'Einrichten', 'reconnect' => 'Erneut verbinden', 'cloud' => 'Cloud', 'cloud_hint' => 'Diese Integration benötigt eine Cloud-Verbindung zum Hersteller.', @@ -20,13 +21,16 @@ return [ 'ring' => [ 'summary' => 'Türklingel, Kameras und Sensoren über die ring-mqtt-Bridge.', - 'body' => 'Ring bietet keine lokale Schnittstelle. Die Anmeldung läuft über dein Ring-Konto; die Verbindung stellt der ring-mqtt-Dienst im Hintergrund her.', - 'email' => 'Ring E-Mail', - 'password' => 'Ring Passwort', - 'code' => '2FA-Code (falls aktiv)', - 'password_stored' => 'Ein Passwort ist gespeichert. Leer lassen, um es zu behalten.', - 'connect_title' => 'Ring-Konto verbinden', - 'backend_note' => 'Zugangsdaten werden verschlüsselt gespeichert und an den ring-mqtt-Dienst übergeben. Der eigentliche Login inkl. 2FA passiert im Backend.', - 'save' => 'Speichern & verbinden', + 'body' => 'Ring bietet keine lokale Schnittstelle. Die Anmeldung inkl. 2FA passiert in der eigenen Weboberfläche der ring-mqtt-Bridge — HomeOS speichert keine Ring-Zugangsdaten.', + 'setup' => 'Einrichten', + 'setup_title' => 'Ring einrichten', + 'setup_intro' => 'Ring wird über die separate ring-mqtt-Bridge angebunden. So richtest du sie ein:', + 'step1' => 'Bridge starten (einmalig, am Server):', + 'step2' => 'Bridge-Oberfläche öffnen und mit deinem Ring-Konto anmelden (inkl. 2FA). Die Bridge speichert das Token.', + 'step3' => 'Fertig — deine Ring-Geräte erscheinen automatisch unter „Geräte" (Badge „Cloud").', + 'open_bridge' => 'Bridge-Oberfläche öffnen', + 'status_title' => 'Bridge-Status', + 'status_hint_disconnected' => 'Noch keine Verbindung von der Bridge empfangen. Starte die Bridge und melde dich an.', + 'connected_since' => 'Verbunden seit', ], ]; diff --git a/lang/en/addons.php b/lang/en/addons.php index 3882759..e97d0eb 100644 --- a/lang/en/addons.php +++ b/lang/en/addons.php @@ -9,6 +9,7 @@ return [ 'uninstall_title' => 'Remove :name?', 'uninstall_body' => 'The integration is disabled and stored credentials are deleted. Devices are kept but stop receiving updates.', 'connect' => 'Connect account', + 'setup' => 'Set up', 'reconnect' => 'Reconnect', 'cloud' => 'Cloud', 'cloud_hint' => 'This integration needs a cloud connection to the vendor.', @@ -20,13 +21,16 @@ return [ 'ring' => [ 'summary' => 'Doorbell, cameras and sensors via the ring-mqtt bridge.', - 'body' => 'Ring has no local API. Sign in with your Ring account; the connection is established by the ring-mqtt service in the background.', - 'email' => 'Ring email', - 'password' => 'Ring password', - 'code' => '2FA code (if enabled)', - 'password_stored' => 'A password is stored. Leave blank to keep it.', - 'connect_title' => 'Connect Ring account', - 'backend_note' => 'Credentials are stored encrypted and handed to the ring-mqtt service. The actual login incl. 2FA happens in the backend.', - 'save' => 'Save & connect', + 'body' => 'Ring has no local API. The login incl. 2FA happens in the ring-mqtt bridge\'s own web UI — HomeOS never stores Ring credentials.', + 'setup' => 'Set up', + 'setup_title' => 'Set up Ring', + 'setup_intro' => 'Ring connects through the separate ring-mqtt bridge. Set it up like this:', + 'step1' => 'Start the bridge (once, on the server):', + 'step2' => 'Open the bridge UI and sign in with your Ring account (incl. 2FA). The bridge stores the token.', + 'step3' => 'Done — your Ring devices appear automatically under “Devices” (with a “Cloud” badge).', + 'open_bridge' => 'Open bridge UI', + 'status_title' => 'Bridge status', + 'status_hint_disconnected' => 'No connection received from the bridge yet. Start the bridge and sign in.', + 'connected_since' => 'Connected since', ], ]; diff --git a/resources/views/livewire/addons/index.blade.php b/resources/views/livewire/addons/index.blade.php index dd26253..2ea3e60 100644 --- a/resources/views/livewire/addons/index.blade.php +++ b/resources/views/livewire/addons/index.blade.php @@ -45,9 +45,9 @@ {{ __('addons.install') }} @else - - {{ $addon['status'] === 'connected' ? __('addons.reconnect') : __('addons.connect') }} + {{ __('addons.setup') }} diff --git a/resources/views/livewire/modals/ring-connect.blade.php b/resources/views/livewire/modals/ring-connect.blade.php deleted file mode 100644 index 718b9e7..0000000 --- a/resources/views/livewire/modals/ring-connect.blade.php +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - {{ __('addons.ring.backend_note') }} - - - - {{ __('addons.ring.email') }} - - @error('email') {{ $message }} @enderror - - - - {{ __('addons.ring.password') }} - - @if ($hasStoredPassword) - {{ __('addons.ring.password_stored') }} - @endif - @error('password') {{ $message }} @enderror - - - - {{ __('addons.ring.code') }} - - @error('code') {{ $message }} @enderror - - - - - {{ __('common.cancel') }} - {{ __('addons.ring.save') }} - - - diff --git a/resources/views/livewire/modals/ring-setup.blade.php b/resources/views/livewire/modals/ring-setup.blade.php new file mode 100644 index 0000000..7ca9766 --- /dev/null +++ b/resources/views/livewire/modals/ring-setup.blade.php @@ -0,0 +1,54 @@ + + + {{ __('addons.ring.setup_intro') }} + + + + 1 + + {{ __('addons.ring.step1') }} + docker compose --profile addons up -d ring-mqtt + + + + 2 + {{ __('addons.ring.step2') }} + + + 3 + {{ __('addons.ring.step3') }} + + + + + {{ __('addons.ring.open_bridge') }} + {{ $bridgeUrl }} + + + {{-- Real bridge status --}} + + @php + $pill = match ($status) { 'connected' => 'online', 'connecting' => 'warning', 'error' => 'offline', default => 'neutral' }; + @endphp + + {{ __('addons.ring.status_title') }} + {{ __('addons.status_'.$status) }} + + + @if ($status === 'connected' && $connectedAt) + {{ __('addons.ring.connected_since') }} + {{ $connectedAt->diffForHumans() }} + @elseif ($statusDetail) + {{ $statusDetail }} + @else + {{ __('addons.ring.status_hint_disconnected') }} + @endif + + + + + + {{ __('common.close') }} + +
- - {{ __('addons.ring.backend_note') }} -
{{ $message }}
{{ __('addons.ring.password_stored') }}
{{ __('addons.ring.setup_intro') }}
{{ __('addons.ring.step1') }}
docker compose --profile addons up -d ring-mqtt
{{ __('addons.ring.step2') }}
{{ __('addons.ring.step3') }}