device = $device; $this->name = $device->name; $this->roomId = $device->room_id; } /** * Advanced: generate a dedicated MQTT credential for THIS device (username = its prefix), * bound to just its own topics by the `pattern %u` ACL. The default onboarding uses the * shared `shelly` account (Settings → Geräte-MQTT); this is opt-in hardening. */ public function generateMqttCredential(): void { $prefix = data_get($this->device->config, 'mqtt_prefix'); if (blank($prefix)) { $this->flashMessage(__('devices.mqtt_no_prefix')); return; } $password = app(MqttCredentialProvisioner::class)->provision($prefix); $this->mqttCredential = [ 'username' => $prefix, 'password' => $password, 'host' => config('homeos.mqtt.device_host') ?: __('devices.mqtt_host_hint'), 'port' => (int) config('mqtt-client.connections.default.port', 1883), ]; } public function saveName(): void { $this->validate(); $this->device->update(['name' => $this->name]); $this->flashMessage(__('devices.saved')); } public function saveRoom(): void { $this->validate(['roomId' => ['nullable', 'integer', 'exists:rooms,id']]); $this->device->update(['room_id' => $this->roomId ?: null]); $this->flashMessage(__('devices.saved')); } public function toggleStatus(): void { $this->device->update([ 'status' => $this->device->status === 'active' ? 'ignored' : 'active', ]); $this->flashMessage(__('devices.saved')); } /** Live update: refresh when this device's state changes on the bus. */ #[On('echo-private:home,.DeviceStateChanged')] public function onDeviceStateChanged(): void { // no-op — triggers a re-render with fresh entity state. } /** Toggle a switch/light entity through the command service (H1 — audited + driver). */ public function toggleEntity(int $entityId): void { $entity = $this->device->entities()->with('state')->find($entityId); if ($entity === null || ! in_array($entity->type, ['switch', 'light'], true)) { return; } $command = app(DeviceCommandService::class)->toggle($entity); $this->flashCommand($command->result); } #[On('restartDevice')] public function restart(): void { $command = app(DeviceCommandService::class)->reboot($this->device); $this->flashCommand($command->result); } protected function flashCommand(string $result): void { $ok = $result === 'ok'; $this->flashOk = $ok; $this->flash = $ok ? __('devices.command_sent') : __('devices.command_failed'); } public function checkUpdate(): void { $this->flashMessage(__('devices.no_update_demo')); } protected function flashMessage(string $message): void { $this->flash = $message; $this->flashOk = true; } public function render() { $this->device->load(['entities.state', 'room']); return view('livewire.devices.show', [ 'rooms' => Room::orderBy('sort')->orderBy('name')->get(), ]); } }