diff --git a/composer.json b/composer.json index e278210..0879a2d 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "dashboard/unifi", "description": "UniFi network management, WiFi stats, and captive portal authentication for the Dashboard platform", - "version": "1.11.0", + "version": "1.11.1", "type": "library", "license": "MIT", "autoload": { diff --git a/src/Services/WebhookCheckService.php b/src/Services/WebhookCheckService.php index ef23178..3198031 100644 --- a/src/Services/WebhookCheckService.php +++ b/src/Services/WebhookCheckService.php @@ -181,7 +181,11 @@ class WebhookCheckService $prev = DeviceState::where('device_mac', $mac)->first(); if (! $prev) continue; - // Skip planned reboots — these are intentional, not alerts + // Skip planned reboots — these are intentional, not alerts. + // Two layers: a global suppression window set by RebootAllAps + // (Setting, survives any cache driver), plus the per-MAC + // cache keys for finer granularity. + if ($this->inGlobalRebootSuppression()) continue; if (Cache::has('unifi:planned_reboot:' . strtolower($mac))) continue; if ($comingOnline) { @@ -509,6 +513,8 @@ class WebhookCheckService private function checkReboot($aps, array $filter): array { $alerts = []; + if ($this->inGlobalRebootSuppression()) return $alerts; + foreach ($aps as $ap) { if (! empty($filter) && ! in_array($ap['mac'], $filter)) continue; if (Cache::has('unifi:planned_reboot:' . strtolower($ap['mac']))) continue; @@ -584,6 +590,24 @@ class WebhookCheckService return self::buildPlatformPayload($url, $message, $fullPayload); } + /** + * Is a fleet reboot in progress right now? RebootAllAps stamps a + * suppression-until timestamp as a Setting; while that timestamp + * is in the future, we skip all device-offline / device-online / + * unexpected-reboot alerts to avoid flooding webhooks during the + * known maintenance window. + */ + private function inGlobalRebootSuppression(): bool + { + $until = \App\Models\Setting::get('unifi.reboot_suppression_until'); + if (! $until) return false; + try { + return \Carbon\Carbon::parse($until)->isFuture(); + } catch (\Throwable) { + return false; + } + } + /** * Public/static helper so the test-webhook endpoint produces the * same per-platform payload shape that real events do.