67 lines
2.1 KiB
PHP
67 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Events\DeviceDiscovered;
|
|
use App\Models\DiscoveryFinding;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Queue\Queueable;
|
|
|
|
/**
|
|
* Ingests a discovery finding published by the sidecar to homeos/discovery/<source>/<id>.
|
|
* Upserts discovery_findings (preserving an assigned/ignored status) and announces new ones.
|
|
*/
|
|
class IngestDiscoveryMessage implements ShouldQueue
|
|
{
|
|
use Queueable;
|
|
|
|
public function __construct(
|
|
public string $topic,
|
|
public string $payload,
|
|
) {}
|
|
|
|
public function handle(): void
|
|
{
|
|
if (! preg_match('#^homeos/discovery/(?<source>[^/]+)/(?<id>.+)$#', $this->topic, $m)) {
|
|
return;
|
|
}
|
|
|
|
$data = json_decode($this->payload, true);
|
|
if (! is_array($data)) {
|
|
return;
|
|
}
|
|
|
|
$existing = DiscoveryFinding::where('source', $m['source'])->where('identifier', $m['id'])->first();
|
|
|
|
$finding = DiscoveryFinding::updateOrCreate(
|
|
['source' => $m['source'], 'identifier' => $m['id']],
|
|
[
|
|
'name' => $data['name'] ?? null,
|
|
'vendor' => $data['vendor'] ?? $this->guessVendor($data),
|
|
'model' => $data['model'] ?? data_get($data, 'properties.model'),
|
|
'ip' => $data['ip'] ?? null,
|
|
'raw' => $data,
|
|
'last_seen_at' => now(),
|
|
'status' => $existing?->status ?? 'new', // keep assigned/ignored once set
|
|
],
|
|
);
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
private function guessVendor(array $data): ?string
|
|
{
|
|
$service = ($data['service'] ?? '').' '.($data['name'] ?? '');
|
|
|
|
return match (true) {
|
|
str_contains(strtolower($service), 'shelly') => 'Shelly',
|
|
str_contains(strtolower($service), 'googlecast') => 'Google',
|
|
default => null,
|
|
};
|
|
}
|
|
}
|