From 7d4c9c024ef8c1c214b4fe01b33ddc69826221aa Mon Sep 17 00:00:00 2001 From: HomeOS Bootstrap Date: Sat, 18 Jul 2026 00:34:56 +0200 Subject: [PATCH] Fix R15: Shelly prefix from mDNS instance, discovery broadcast once, targeted confirm - AssignDevice derives the Shelly MQTT prefix from the mDNS service instance name (the device id) instead of the slugified topic identifier (which carries the _shelly._tcp suffix); non-Shelly devices get no prefix. - IngestDiscoveryMessage broadcasts DeviceDiscovered only on first creation, not on every retained/periodic re-publish. - The generic Confirm modal can target its event at the opening component (->to), so a shared event name can't be caught by an unrelated component. Co-Authored-By: Claude Opus 4.8 --- app/Jobs/IngestDiscoveryMessage.php | 4 +++- app/Livewire/Modals/AssignDevice.php | 9 +++++++-- app/Livewire/Modals/Confirm.php | 10 ++++++++-- resources/views/livewire/devices/show.blade.php | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/Jobs/IngestDiscoveryMessage.php b/app/Jobs/IngestDiscoveryMessage.php index 7979899..ef5aeab 100644 --- a/app/Jobs/IngestDiscoveryMessage.php +++ b/app/Jobs/IngestDiscoveryMessage.php @@ -46,7 +46,9 @@ class IngestDiscoveryMessage implements ShouldQueue ], ); - if (($existing?->status ?? 'new') === 'new') { + // Announce only on FIRST discovery — the sidecar re-publishes retained/periodic + // messages, so broadcasting on every message would spam the "Neue Geräte" panel. + if ($existing === null) { DeviceDiscovered::dispatch($finding->uuid); } } diff --git a/app/Livewire/Modals/AssignDevice.php b/app/Livewire/Modals/AssignDevice.php index 4e65682..b0afe20 100644 --- a/app/Livewire/Modals/AssignDevice.php +++ b/app/Livewire/Modals/AssignDevice.php @@ -42,13 +42,18 @@ class AssignDevice extends ModalComponent ]); $finding = $this->finding(); + $isShelly = $finding->vendor === 'Shelly'; + + // The Shelly MQTT topic prefix is its device id — the mDNS service INSTANCE name + // (finding->name), not the slugified topic identifier which carries the _shelly._tcp suffix. + $prefix = $isShelly ? ($finding->name ?: $finding->identifier) : null; $device = Device::create([ 'name' => $this->name, 'vendor' => $finding->vendor, 'model' => $finding->model, - 'protocol' => $finding->vendor === 'Shelly' ? 'mqtt' : null, - 'config' => ['mqtt_prefix' => $finding->identifier], + 'protocol' => $isShelly ? 'mqtt' : null, + 'config' => $prefix ? ['mqtt_prefix' => $prefix] : null, 'room_id' => $this->roomId ?: null, 'status' => 'active', ]); diff --git a/app/Livewire/Modals/Confirm.php b/app/Livewire/Modals/Confirm.php index 8479379..5a18404 100644 --- a/app/Livewire/Modals/Confirm.php +++ b/app/Livewire/Modals/Confirm.php @@ -17,6 +17,7 @@ class Confirm extends ModalComponent public string $body = ''; public string $confirmLabel = ''; public string $event = ''; + public string $to = ''; public bool $danger = false; public static function modalMaxWidth(): string @@ -24,18 +25,23 @@ class Confirm extends ModalComponent return 'md'; } - public function mount(string $title, string $body, string $confirmLabel, string $event, bool $danger = false): void + public function mount(string $title, string $body, string $confirmLabel, string $event, string $to = '', bool $danger = false): void { $this->title = $title; $this->body = $body; $this->confirmLabel = $confirmLabel; $this->event = $event; + $this->to = $to; $this->danger = $danger; } public function confirm(): void { - $this->dispatch($this->event); + // Target the opener (if given) so an event name can't collide with another component. + $this->to !== '' + ? $this->dispatch($this->event)->to($this->to) + : $this->dispatch($this->event); + $this->closeModal(); } diff --git a/resources/views/livewire/devices/show.blade.php b/resources/views/livewire/devices/show.blade.php index 3b87b85..af9a807 100644 --- a/resources/views/livewire/devices/show.blade.php +++ b/resources/views/livewire/devices/show.blade.php @@ -93,7 +93,7 @@