incr('metrics:mqtt:count'); } catch (\Throwable) { // metrics are best-effort } $parsed = ShellyTopics::parseStatus($this->topic); if ($parsed === null) { return; } [$prefix, $component] = $parsed; // Unknown devices are handled by discovery (Phase 4), not silently created here. $device = Device::where('config->mqtt_prefix', $prefix)->first(); if ($device === null) { return; } $data = json_decode($this->payload, true); if (! is_array($data)) { return; } $observedAt = $this->observedAt ?? (int) round(microtime(true) * 1_000_000); $observedTime = \Illuminate\Support\Carbon::createFromTimestampMs(intdiv($observedAt, 1000)); // Presence reflects when the message was RECEIVED, and only ever advances. The guard // lives in the WHERE clause (one atomic UPDATE), so concurrent workers can't rewind it // via read-then-write — queue latency, retries or stale messages never mark it wrong. Device::whereKey($device->id) ->where(fn ($q) => $q->whereNull('last_seen_at')->orWhere('last_seen_at', '<', $observedTime)) ->update(['last_seen_at' => $observedTime, 'updated_at' => now()]); foreach (ShellyNormalizer::normalize($component, $data) as $update) { $entity = $device->entities()->firstOrCreate( ['key' => $update['key']], ['type' => $update['type']], ); if ($this->applyState($entity->id, $update['state'], $observedAt)) { DeviceStateChanged::dispatch($device->uuid, $entity->key, $update['state']); } } } }