feat(nightlight): using our own manual scheduling to allow more flexibility

This commit is contained in:
Lemmy
2026-03-25 18:27:42 -04:00
parent 2623f081d6
commit 6d08fd1a0b
+129 -11
View File
@@ -17,6 +17,9 @@ Singleton {
property int _crashCount: 0
property int _maxCrashes: 5
// Manual schedule tracking
property bool _manualNightPhase: false
// Kill any stale wlsunset processes on startup to prevent issues after shell restart
Component.onCompleted: {
killStaleProcess.running = true;
@@ -42,17 +45,115 @@ Singleton {
onTriggered: {
if (root.params.enabled && !runner.running) {
Logger.w("NightLight", "Restarting after crash...");
runner.running = true;
if (root.isManualMode()) {
root.applyManualSchedule();
} else {
runner.running = true;
}
}
}
}
Timer {
id: manualScheduleTimer
repeat: false
onTriggered: {
Logger.i("NightLight", "Manual schedule: phase boundary reached");
root.applyManualSchedule();
}
}
function timeToMinutes(timeStr) {
var parts = timeStr.split(":").map(Number);
return parts[0] * 60 + parts[1];
}
function isManualMode() {
return !params.forced && !params.autoSchedule;
}
function isCurrentlyNight() {
var now = new Date();
var nowMin = now.getHours() * 60 + now.getMinutes();
var sunsetMin = timeToMinutes(params.manualSunset);
var sunriseMin = timeToMinutes(params.manualSunrise);
if (sunsetMin < sunriseMin) {
// Inverted: e.g. sunset=03:00, sunrise=07:00 → night is [03:00, 07:00)
return nowMin >= sunsetMin && nowMin < sunriseMin;
} else {
// Normal: e.g. sunset=18:00, sunrise=06:00 → night is [18:00, 06:00)
return nowMin >= sunsetMin || nowMin < sunriseMin;
}
}
function msUntilNextBoundary() {
var now = new Date();
var nowMin = now.getHours() * 60 + now.getMinutes();
var sunsetMin = timeToMinutes(params.manualSunset);
var sunriseMin = timeToMinutes(params.manualSunrise);
var targetMin = isCurrentlyNight() ? sunriseMin : sunsetMin;
var diffMin = targetMin - nowMin;
if (diffMin <= 0)
diffMin += 1440;
return diffMin * 60 * 1000 - now.getSeconds() * 1000 - now.getMilliseconds();
}
function applyManualSchedule() {
if (!params.enabled) {
manualScheduleTimer.stop();
runner.running = false;
return;
}
var night = isCurrentlyNight();
_manualNightPhase = night;
if (night) {
var cmd = ["wlsunset"];
cmd.push("-t", `${params.nightTemp}`, "-T", `${params.dayTemp}`);
cmd.push("-S", "23:59");
cmd.push("-s", "00:00");
cmd.push("-d", 1);
if (JSON.stringify(cmd) !== JSON.stringify(lastCommand) || !runner.running) {
lastCommand = cmd;
runner.command = cmd;
runner.running = false;
runner.running = true;
}
Logger.i("NightLight", "Manual schedule: night phase - wlsunset forced on");
} else {
lastCommand = [];
runner.running = false;
Logger.i("NightLight", "Manual schedule: day phase - wlsunset stopped");
}
var ms = msUntilNextBoundary();
manualScheduleTimer.interval = Math.max(ms, 1000);
manualScheduleTimer.restart();
Logger.i("NightLight", "Manual schedule: next boundary in " + Math.round(ms / 1000) + "s");
}
function apply(force = false) {
// If using LocationService, wait for it to be ready
if (!params.forced && params.autoSchedule && !LocationService.coordinatesReady) {
return;
}
// Manual mode: handle scheduling ourselves
if (isManualMode() && params.enabled) {
_crashCount = 0;
restartTimer.stop();
applyManualSchedule();
return;
}
// Not in manual mode - clean up manual timer
manualScheduleTimer.stop();
var command = buildCommand();
// Compare with previous command to avoid unnecessary restart
@@ -77,16 +178,9 @@ Singleton {
cmd.push("-s", "00:00"); // sunset at midnight
// Near-instant transition
cmd.push("-d", 1);
} else {
} else if (params.autoSchedule) {
cmd.push("-t", `${params.nightTemp}`, "-T", `${params.dayTemp}`);
if (params.autoSchedule) {
cmd.push("-l", `${LocationService.stableLatitude}`, "-L", `${LocationService.stableLongitude}`);
} else {
cmd.push("-S", params.manualSunrise);
// Avoid midnight edge case - 00:00 causes wlsunset issues at day transition
var sunset = params.manualSunset === "00:00" ? "23:59" : params.manualSunset;
cmd.push("-s", sunset);
}
cmd.push("-l", `${LocationService.stableLatitude}`, "-L", `${LocationService.stableLongitude}`);
cmd.push("-d", 60 * 15); // 15min progressive fade at sunset/sunrise
}
return cmd;
@@ -113,6 +207,15 @@ Singleton {
function onDayTempChanged() {
apply();
}
function onManualSunriseChanged() {
apply();
}
function onManualSunsetChanged() {
apply();
}
function onAutoScheduleChanged() {
apply();
}
}
Connections {
@@ -155,7 +258,22 @@ Singleton {
}
}
onExited: function (code, status) {
if (root.params.enabled) {
if (root.params.enabled && root.isManualMode()) {
// Manual mode: only treat as crash if we're in the night phase
if (root._manualNightPhase) {
root._crashCount++;
if (root._crashCount <= root._maxCrashes) {
Logger.w("NightLight", "Wlsunset exited unexpectedly during manual night phase (code: " + code + "), restarting in 2s... (attempt " + root._crashCount + "/" + root._maxCrashes + ")");
restartTimer.start();
} else {
Logger.e("NightLight", "Wlsunset crashed too many times (" + root._maxCrashes + "), giving up");
}
} else {
Logger.i("NightLight", "Wlsunset exited (manual day phase):", code, status);
root._crashCount = 0;
}
} else if (root.params.enabled) {
// Non-manual mode: any exit while enabled is a crash
root._crashCount++;
if (root._crashCount <= root._maxCrashes) {
Logger.w("NightLight", "Wlsunset exited unexpectedly (code: " + code + "), restarting in 2s... (attempt " + root._crashCount + "/" + root._maxCrashes + ")");