96 lines
3.1 KiB
PHP
96 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Modals;
|
|
|
|
use App\Models\Device;
|
|
use App\Models\DiscoveryFinding;
|
|
use App\Models\Room;
|
|
use App\Services\ShellyLocalOnboarder;
|
|
use Livewire\Attributes\Computed;
|
|
use LivewireUI\Modal\ModalComponent;
|
|
|
|
class AssignDevice extends ModalComponent
|
|
{
|
|
public string $findingUuid = '';
|
|
|
|
public string $name = '';
|
|
|
|
public ?int $roomId = null;
|
|
|
|
public static function modalMaxWidth(): string
|
|
{
|
|
return 'lg';
|
|
}
|
|
|
|
public function mount(string $finding): void
|
|
{
|
|
$model = DiscoveryFinding::where('uuid', $finding)->firstOrFail();
|
|
$this->findingUuid = $model->uuid;
|
|
$this->name = $model->name ?? $model->identifier;
|
|
}
|
|
|
|
#[Computed]
|
|
public function finding(): DiscoveryFinding
|
|
{
|
|
return DiscoveryFinding::where('uuid', $this->findingUuid)->firstOrFail();
|
|
}
|
|
|
|
public function assign()
|
|
{
|
|
$this->validate([
|
|
'name' => 'required|string|max:100',
|
|
'roomId' => 'nullable|integer|exists:rooms,id',
|
|
]);
|
|
|
|
$finding = $this->finding();
|
|
$isShelly = $finding->vendor === 'Shelly';
|
|
|
|
// Preferred path (like HA): if it's a Shelly we can reach over its local API, onboard it
|
|
// there — control + status run over HTTP, no MQTT setup on the device.
|
|
if ($isShelly && filled($finding->ip)) {
|
|
try {
|
|
$device = app(ShellyLocalOnboarder::class)->onboard($finding->ip, $this->name, $this->roomId ?: null);
|
|
$finding->update(['status' => 'assigned', 'device_id' => $device->id]);
|
|
$this->closeModal();
|
|
|
|
return redirect()->route('devices.show', $device);
|
|
} catch (\Throwable) {
|
|
// Unreachable over HTTP — fall through to the MQTT-style record below.
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
// Reuse an already-onboarded row by prefix so assigning just names it (no duplicate).
|
|
$device = ($prefix ? Device::where('config->mqtt_prefix', $prefix)->first() : null)
|
|
?? new Device;
|
|
|
|
$device->fill([
|
|
'name' => $this->name,
|
|
'vendor' => $finding->vendor,
|
|
'model' => $finding->model ?: $device->model,
|
|
'protocol' => $isShelly ? 'mqtt' : $device->protocol,
|
|
'room_id' => $this->roomId ?: null,
|
|
'status' => 'active',
|
|
]);
|
|
$device->config = array_merge($device->config ?? [], $prefix ? ['mqtt_prefix' => $prefix] : []);
|
|
$device->save();
|
|
|
|
$finding->update(['status' => 'assigned', 'device_id' => $device->id]);
|
|
|
|
$this->closeModal();
|
|
|
|
return redirect()->route('devices.show', $device);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.modals.assign-device', [
|
|
'finding' => $this->finding(),
|
|
'rooms' => Room::orderBy('sort')->orderBy('name')->get(),
|
|
]);
|
|
}
|
|
}
|