feat(device): replace daily wakeHour with multi-time wakeTimes (minutes)
CI / test (push) Has been cancelled
CI / test (push) Has been cancelled
Frame settings now offer two update-frequency modes: "at specific times" or "every X minutes". Times are stored as an int[] of minutes-since-midnight, allowing multiple slots per day at minute granularity. Backend computes the earliest upcoming slot for X-Interval-Ms and uses the most-recent-past slot as the rotation-due boundary. PWA settings sheet has hour/minute/AM-PM dropdowns with + Add / trash, a live "next update" preview, and a note that changes only take effect at the device's next sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -119,11 +119,11 @@ class AdvanceRotationMessageHandlerTest extends AppKernelTestCase
|
||||
$this->assertNotNull($reloaded->getCurrentImage());
|
||||
}
|
||||
|
||||
// AR-04: wakeHour=0 (midnight, always past) + no history today → rotation occurs
|
||||
public function test_ar04_wake_hour_past_no_history_rotates(): void
|
||||
// AR-04: wakeTimes=[00:00] (always past) + no history today → rotation occurs
|
||||
public function test_ar04_wake_time_past_no_history_rotates(): void
|
||||
{
|
||||
$device = $this->makeDevice();
|
||||
$device->setWakeHour(0)->setTimezone('UTC');
|
||||
$device->setWakeTimes([0])->setTimezone('UTC');
|
||||
$image = $this->makeReadyImage($device);
|
||||
$this->em()->flush();
|
||||
|
||||
@@ -138,11 +138,11 @@ class AdvanceRotationMessageHandlerTest extends AppKernelTestCase
|
||||
$this->assertSame($imageId, $reloaded->getCurrentImage()->getId());
|
||||
}
|
||||
|
||||
// AR-05: wakeHour=0 (midnight) + history exists since midnight → already served today → not due
|
||||
public function test_ar05_wake_hour_already_served_today_is_skipped(): void
|
||||
// AR-05: wakeTimes=[00:00] + history exists since midnight → already served today → not due
|
||||
public function test_ar05_wake_time_already_served_today_is_skipped(): void
|
||||
{
|
||||
$device = $this->makeDevice();
|
||||
$device->setWakeHour(0)->setTimezone('UTC');
|
||||
$device->setWakeTimes([0])->setTimezone('UTC');
|
||||
$image = $this->makeReadyImage($device);
|
||||
$this->em()->flush();
|
||||
|
||||
@@ -163,10 +163,10 @@ class AdvanceRotationMessageHandlerTest extends AppKernelTestCase
|
||||
$this->assertSame($imageId, $reloaded->getCurrentImage()?->getId());
|
||||
}
|
||||
|
||||
// AR-06: wakeHour in future → isDue returns false → no rotation
|
||||
// Uses 'Etc/GMT+11' (UTC-11) so local time is always before wakeHour=22
|
||||
// AR-06: wakeTime in future → isDue returns false → no rotation
|
||||
// Uses 'Etc/GMT+11' (UTC-11) so local time is always before 23:00 local
|
||||
// except during UTC 09:00-10:59; test is skipped then.
|
||||
public function test_ar06_wake_hour_in_future_is_not_due(): void
|
||||
public function test_ar06_wake_time_in_future_is_not_due(): void
|
||||
{
|
||||
$utcHour = (int)(new \DateTimeImmutable('now', new \DateTimeZone('UTC')))->format('G');
|
||||
if ($utcHour >= 9 && $utcHour <= 10) {
|
||||
@@ -174,8 +174,8 @@ class AdvanceRotationMessageHandlerTest extends AppKernelTestCase
|
||||
}
|
||||
|
||||
$device = $this->makeDevice();
|
||||
// UTC-11: local time is at most 12:59 when UTC is 23:59 → wakeHour=23 is always future
|
||||
$device->setWakeHour(23)->setTimezone('Etc/GMT+11');
|
||||
// UTC-11: local time is at most 12:59 when UTC is 23:59 → 23:00 always future
|
||||
$device->setWakeTimes([23 * 60])->setTimezone('Etc/GMT+11');
|
||||
$image = $this->makeReadyImage($device);
|
||||
$this->em()->flush();
|
||||
|
||||
@@ -183,6 +183,27 @@ class AdvanceRotationMessageHandlerTest extends AppKernelTestCase
|
||||
|
||||
$this->em()->clear();
|
||||
$reloaded = $this->em()->find(Device::class, $device->getId());
|
||||
$this->assertNull($reloaded->getCurrentImage(), 'Rotation must not happen when wakeHour is still in the future');
|
||||
$this->assertNull($reloaded->getCurrentImage(), 'Rotation must not happen when wake time is still in the future');
|
||||
}
|
||||
|
||||
// AR-07: multiple wakeTimes — 00:00 has passed, so device is due even
|
||||
// though later slots haven't fired yet. Validates that we use the most
|
||||
// recent past slot as the boundary, not the earliest.
|
||||
public function test_ar07_multiple_wake_times_uses_most_recent_past_slot(): void
|
||||
{
|
||||
$device = $this->makeDevice();
|
||||
// 00:00 always past, 23:00 future for most of the day
|
||||
$device->setWakeTimes([0, 23 * 60])->setTimezone('UTC');
|
||||
$image = $this->makeReadyImage($device);
|
||||
$this->em()->flush();
|
||||
|
||||
$this->invokeHandler();
|
||||
|
||||
$this->em()->clear();
|
||||
$reloaded = $this->em()->find(Device::class, $device->getId());
|
||||
$this->assertNotNull(
|
||||
$reloaded->getCurrentImage(),
|
||||
'Device with multiple wake times should rotate when at least one has passed today and no history exists since',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user