isEmpty()) { // Don't bother logging — no work, no audit value. return self::SUCCESS; } $triggeredBy = $this->option('triggered-by') ?: 'schedule'; $run = UnifiCronRun::record('sync-ppsk-schedules', $triggeredBy, null, function () use ($unifi, $ppsks) { $globalEnabled = (bool) Setting::get('unifi.ppsk_scheduling.enabled'); $tz = \App\Support\Timezone::current(); $now = now($tz); $day = $now->dayOfWeek; $slot = $now->hour * 2 + ($now->minute >= 30 ? 1 : 0); $networksByVlan = []; try { foreach ($unifi->getNetworkConfs() as $n) { if (isset($n['vlan'])) { $networksByVlan[(int) $n['vlan']] = $n; } } } catch (\Throwable $e) { $this->warn("Could not fetch network configs: {$e->getMessage()}"); } $enabled = []; $disabled = []; $errors = []; foreach ($ppsks as $ppsk) { $shouldBeOn = true; if ($globalEnabled && $ppsk->schedule) { $shouldBeOn = (bool) ($ppsk->schedule[$day * 48 + $slot] ?? true); } try { if ($shouldBeOn && $ppsk->state === 'held') { $this->enablePpsk($ppsk, $unifi, $networksByVlan); $enabled[] = $ppsk->name; } elseif (! $shouldBeOn && $ppsk->state === 'active' && $ppsk->unifi_id) { $this->disablePpsk($ppsk, $unifi); $disabled[] = $ppsk->name; } } catch (\Throwable $e) { $errors[] = ['ppsk' => $ppsk->name, 'error' => $e->getMessage()]; } } $hasActions = count($enabled) + count($disabled) > 0; $status = count($errors) > 0 ? ($hasActions ? 'partial' : 'failed') : ($hasActions ? 'succeeded' : 'skipped'); return [ 'status' => $status, 'global_enabled' => $globalEnabled, 'enabled_ppsks' => $enabled, 'disabled_ppsks' => $disabled, 'errors' => $errors, ]; }); return $run->status === 'failed' ? self::FAILURE : self::SUCCESS; } private function enablePpsk(UnifiPpsk $ppsk, UnifiApiClient $unifi, array $networksByVlan): void { try { $data = [ 'name' => $ppsk->name, 'x_passphrase' => $ppsk->x_passphrase, 'wlan_id' => $ppsk->wlan_id, ]; if ($ppsk->vlan && isset($networksByVlan[$ppsk->vlan])) { $data['networkconf_id'] = $networksByVlan[$ppsk->vlan]['_id']; } $result = $unifi->createPpsk($data); $raw = $result[0] ?? $result; $newId = $raw['_id'] ?? null; $ppsk->update(['state' => 'active', 'unifi_id' => $newId]); $this->info("Enabled: {$ppsk->name} (wlan {$ppsk->wlan_id})"); } catch (\Throwable $e) { $this->error("Failed to enable PPSK \"{$ppsk->name}\": {$e->getMessage()}"); } } private function disablePpsk(UnifiPpsk $ppsk, UnifiApiClient $unifi): void { try { $kicked = $unifi->kickClientsForPpsk($ppsk->unifi_id); $unifi->deletePpsk($ppsk->unifi_id); $ppsk->update(['state' => 'held', 'unifi_id' => null]); $suffix = $kicked > 0 ? " — kicked {$kicked} client(s)" : ''; $this->info("Disabled: {$ppsk->name}{$suffix}"); } catch (\Throwable $e) { $this->error("Failed to disable PPSK \"{$ppsk->name}\": {$e->getMessage()}"); } } }