mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
feat: Night Mode Automation
This commit is contained in:
@@ -921,6 +921,40 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: 60
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
StyledText {
|
||||
text: "Clear"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
stateColor: Theme.error
|
||||
cornerRadius: parent.radius
|
||||
onClicked: {
|
||||
console.log("PersonalizationTab: Clearing location coordinates via UI")
|
||||
SessionData.setLatitude(0.0);
|
||||
SessionData.setLongitude(0.0);
|
||||
latitudeField.text = "";
|
||||
longitudeField.text = "";
|
||||
// Also call the service clear function
|
||||
if (typeof globalThis !== 'undefined' && globalThis.clearNightModeLocation) {
|
||||
globalThis.clearNightModeLocation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
11
README.md
11
README.md
@@ -89,7 +89,7 @@ https://github.com/user-attachments/assets/5ad934bb-e7aa-4c04-8d40-149181bd2d29
|
||||
- **Process List** A process list, with system metrics and information. More detailed modal available via IPC.
|
||||
- **Notification Center** A center for notifications that has support for grouping.
|
||||
- **Dock** A dock with pinned apps support, recent apps support, and currently running application support.
|
||||
- **Control Center** A full control center with user profile information, network, bluetooth, audio input/output, and display controls.
|
||||
- **Control Center** A full control center with user profile information, network, bluetooth, audio input/output, display controls, and night mode automation.
|
||||
- **Lock Screen** Using quickshell's WlSessionLock
|
||||
|
||||
**Features:**
|
||||
@@ -100,6 +100,7 @@ https://github.com/user-attachments/assets/5ad934bb-e7aa-4c04-8d40-149181bd2d29
|
||||
- Audio/media controls
|
||||
- Grouped notifications
|
||||
- Brightness control for internal and external displays
|
||||
- Automated night mode with time-based and location-based scheduling
|
||||
- Qt and GTK app theming synchronization, as well as [Ghostty](https://ghostty.org/) auto-theme support.
|
||||
|
||||
## Installation
|
||||
@@ -323,6 +324,10 @@ binds {
|
||||
XF86MonBrightnessDown allow-when-locked=true {
|
||||
spawn "qs" "-c" "dms" "ipc" "call" "brightness" "decrement" "5" "";
|
||||
}
|
||||
// Night mode toggle
|
||||
Mod+Shift+N allow-when-locked=true {
|
||||
spawn "qs" "-c" "dms" "ipc" "call" "night" "toggle";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -366,6 +371,9 @@ bindl = , XF86AudioMicMute, exec, qs -c dms ipc call audio micmute
|
||||
bindl = , XF86MonBrightnessUp, exec, qs -c dms ipc call brightness increment 5 ""
|
||||
# You can override the default device for e.g. keyboards by adding the device name to the last param
|
||||
bindl = , XF86MonBrightnessDown, exec, qs -c dms ipc call brightness decrement 5 ""
|
||||
|
||||
# Night mode toggle
|
||||
bind = SUPERSHIFT, N, exec, qs -c dms ipc call night toggle
|
||||
```
|
||||
|
||||
### IPC Commands
|
||||
@@ -388,6 +396,7 @@ qs -c dms ipc call powermenu toggle
|
||||
```
|
||||
qs -c dms ipc call wallpaper set /path/to/image.jpg
|
||||
qs -c dms ipc call theme toggle
|
||||
qs -c dms ipc call night toggle
|
||||
qs -c dms ipc call lock lock
|
||||
```
|
||||
# Media control
|
||||
|
||||
@@ -18,14 +18,80 @@ Singleton {
|
||||
property real latitude: 0.0
|
||||
property real longitude: 0.0
|
||||
|
||||
// Expose these functions to global scope for console debugging
|
||||
function testGeoclueConnection() {
|
||||
console.log("NightModeAutomationService: Testing geoclue2 connection...")
|
||||
if (geoclueTestProcess.running) {
|
||||
geoclueTestProcess.running = false
|
||||
}
|
||||
|
||||
geoclueTestProcess.command = [
|
||||
"timeout", "32", // Increased to 32 seconds for geoclue location fix
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-O", "6500", // One-shot mode to test location quickly
|
||||
"-v"
|
||||
]
|
||||
geoclueTestProcess.running = true
|
||||
}
|
||||
|
||||
function debugTimeBasedMode() {
|
||||
const now = new Date()
|
||||
const currentHour = now.getHours()
|
||||
const currentMinute = now.getMinutes()
|
||||
const currentTime = currentHour * 60 + currentMinute
|
||||
|
||||
const startTime = SessionData.nightModeStartTime || "20:00"
|
||||
const endTime = SessionData.nightModeEndTime || "06:00"
|
||||
|
||||
console.log("=== DEBUG TIME BASED MODE ===")
|
||||
console.log("Current time:", now.toLocaleTimeString())
|
||||
console.log("Current minutes since midnight:", currentTime)
|
||||
console.log("Night mode start time:", startTime)
|
||||
console.log("Night mode end time:", endTime)
|
||||
console.log("Auto enabled:", SessionData.nightModeAutoEnabled)
|
||||
console.log("Auto mode:", SessionData.nightModeAutoMode)
|
||||
console.log("Temperature:", SessionData.nightModeTemperature + "K")
|
||||
console.log("isAutomaticNightTime:", isAutomaticNightTime)
|
||||
console.log("automationTimer running:", automationTimer.running)
|
||||
console.log("gammaStepProcess running:", gammaStepProcess.running)
|
||||
console.log("gammaStepProcess type:", gammaStepProcess.processType)
|
||||
|
||||
// Force a check
|
||||
console.log("Forcing checkTimeBasedMode()...")
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("NightModeAutomationService: Component completed")
|
||||
// Kill any straggling gammastep processes to prevent conflicts
|
||||
pkillProcess.running = true
|
||||
checkAvailability()
|
||||
updateFromSessionData()
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
console.log("NightModeAutomationService: Auto-starting automation on init")
|
||||
startAutomation()
|
||||
|
||||
// Debug current SessionData values
|
||||
console.log("NightModeAutomationService: === SESSIONDATA DEBUG ===")
|
||||
console.log("NightModeAutomationService: nightModeAutoEnabled:", SessionData.nightModeAutoEnabled)
|
||||
console.log("NightModeAutomationService: nightModeAutoMode:", SessionData.nightModeAutoMode)
|
||||
console.log("NightModeAutomationService: nightModeStartTime:", SessionData.nightModeStartTime)
|
||||
console.log("NightModeAutomationService: nightModeEndTime:", SessionData.nightModeEndTime)
|
||||
console.log("NightModeAutomationService: nightModeTemperature:", SessionData.nightModeTemperature)
|
||||
console.log("NightModeAutomationService: nightModeEnabled:", SessionData.nightModeEnabled)
|
||||
console.log("NightModeAutomationService: === END SESSIONDATA DEBUG ===")
|
||||
|
||||
// Expose debug functions globally
|
||||
if (typeof globalThis !== 'undefined') {
|
||||
globalThis.debugNightMode = debugTimeBasedMode
|
||||
globalThis.testNightMode = manualNightModeTest
|
||||
globalThis.resetNightMode = manualResetTest
|
||||
globalThis.clearNightModeLocation = clearLocation
|
||||
globalThis.debugLocationMode = debugLocationMode
|
||||
globalThis.nightModeService = root
|
||||
}
|
||||
|
||||
// Don't start automation here - wait for Gammastep availability check to complete
|
||||
// The gammaStepTestProcess.onExited will start automation when ready
|
||||
}
|
||||
|
||||
function checkAvailability() {
|
||||
@@ -38,6 +104,9 @@ Singleton {
|
||||
return
|
||||
}
|
||||
|
||||
// Stop any existing automation processes first
|
||||
stopAutomation()
|
||||
|
||||
const mode = SessionData.nightModeAutoMode || "manual"
|
||||
|
||||
switch (mode) {
|
||||
@@ -57,55 +126,108 @@ Singleton {
|
||||
function stopAutomation() {
|
||||
automationTimer.stop()
|
||||
locationTimer.stop()
|
||||
if (gammaStepAutomationProcess.running) {
|
||||
gammaStepAutomationProcess.kill()
|
||||
|
||||
// Stop the unified process
|
||||
if (gammaStepProcess.running) {
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
isAutomaticNightTime = false
|
||||
}
|
||||
|
||||
function startTimeBasedMode() {
|
||||
console.log("NightModeAutomationService: Starting time-based automation")
|
||||
console.log("NightModeAutomationService: === Starting time-based automation ===")
|
||||
console.log("NightModeAutomationService: automationTimer.running before start:", automationTimer.running)
|
||||
automationTimer.start()
|
||||
console.log("NightModeAutomationService: automationTimer.running after start:", automationTimer.running)
|
||||
console.log("NightModeAutomationService: automationTimer.interval:", automationTimer.interval, "ms")
|
||||
console.log("NightModeAutomationService: Now calling initial checkTimeBasedMode...")
|
||||
checkTimeBasedMode()
|
||||
console.log("NightModeAutomationService: === Time-based automation startup complete ===")
|
||||
}
|
||||
|
||||
function startLocationBasedMode() {
|
||||
if (!locationProviderAvailable) {
|
||||
console.warn("NightModeAutomationService: No location provider available, falling back to time-based mode")
|
||||
startTimeBasedMode()
|
||||
return
|
||||
}
|
||||
|
||||
console.log("NightModeAutomationService: Starting location-based automation")
|
||||
|
||||
// Stop the process first, then change command, then start
|
||||
if (gammaStepProcess.running) {
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
|
||||
// Check manual coordinates first (highest priority)
|
||||
if (latitude !== 0.0 && longitude !== 0.0) {
|
||||
gammaStepAutomationProcess.command = [
|
||||
console.log(`NightModeAutomationService: Using manual coordinates: ${latitude.toFixed(6)},${longitude.toFixed(6)}`)
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-l", `${latitude.toFixed(6)}:${longitude.toFixed(6)}`,
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
]
|
||||
} else {
|
||||
gammaStepAutomationProcess.command = [
|
||||
gammaStepProcess.running = true
|
||||
locationTimer.start()
|
||||
return
|
||||
}
|
||||
|
||||
// Check if location providers are available
|
||||
if (!locationProviderAvailable) {
|
||||
console.warn("NightModeAutomationService: No location provider available, falling back to time-based mode")
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
return
|
||||
}
|
||||
|
||||
// Use automatic location provider (geoclue2)
|
||||
if (currentProvider === "geoclue2") {
|
||||
console.log("NightModeAutomationService: Starting geoclue2 location provider...")
|
||||
|
||||
// Kill any existing gammastep processes to prevent conflicts
|
||||
pkillProcess.running = true
|
||||
|
||||
// Wait longer for geoclue2 to be ready and acquire location
|
||||
cleanupTimer.interval = 5000 // 5 second delay for geoclue2 location acquisition
|
||||
cleanupTimer.repeat = false // Single shot
|
||||
cleanupTimer.triggered.connect(function() {
|
||||
console.log("NightModeAutomationService: Starting geoclue2 after cleanup...")
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-l", currentProvider || "manual",
|
||||
"-l", "geoclue2",
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
]
|
||||
}
|
||||
|
||||
gammaStepAutomationProcess.running = true
|
||||
console.log("NightModeAutomationService: Geoclue2 command:", gammaStepProcess.command.join(" "))
|
||||
gammaStepProcess.running = true
|
||||
locationTimer.start()
|
||||
})
|
||||
cleanupTimer.start()
|
||||
return
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: No working location provider, falling back to time-based mode")
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function checkTimeBasedMode() {
|
||||
console.log("NightModeAutomationService: === checkTimeBasedMode CALLED ===")
|
||||
console.log("NightModeAutomationService: nightModeAutoEnabled:", SessionData.nightModeAutoEnabled)
|
||||
console.log("NightModeAutomationService: nightModeAutoMode:", SessionData.nightModeAutoMode)
|
||||
|
||||
if (!SessionData.nightModeAutoEnabled || SessionData.nightModeAutoMode !== "time") {
|
||||
console.log("NightModeAutomationService: checkTimeBasedMode - not enabled or wrong mode")
|
||||
console.log("NightModeAutomationService: - autoEnabled:", SessionData.nightModeAutoEnabled)
|
||||
console.log("NightModeAutomationService: - autoMode:", SessionData.nightModeAutoMode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,6 +239,11 @@ Singleton {
|
||||
const startTime = SessionData.nightModeStartTime || "20:00"
|
||||
const endTime = SessionData.nightModeEndTime || "06:00"
|
||||
|
||||
console.log("NightModeAutomationService: Raw start time from SessionData:", SessionData.nightModeStartTime)
|
||||
console.log("NightModeAutomationService: Raw end time from SessionData:", SessionData.nightModeEndTime)
|
||||
console.log("NightModeAutomationService: Using start time:", startTime)
|
||||
console.log("NightModeAutomationService: Using end time:", endTime)
|
||||
|
||||
const startParts = startTime.split(":")
|
||||
const endParts = endTime.split(":")
|
||||
|
||||
@@ -126,25 +253,36 @@ Singleton {
|
||||
let shouldBeNight = false
|
||||
|
||||
if (startMinutes > endMinutes) {
|
||||
// Crosses midnight (e.g., 20:00 to 06:00)
|
||||
shouldBeNight = (currentTime >= startMinutes) || (currentTime < endMinutes)
|
||||
console.log("NightModeAutomationService: Time range crosses midnight")
|
||||
} else {
|
||||
// Same day (e.g., 16:00 to 18:36)
|
||||
shouldBeNight = (currentTime >= startMinutes) && (currentTime < endMinutes)
|
||||
console.log("NightModeAutomationService: Time range within same day")
|
||||
}
|
||||
|
||||
console.log(`NightModeAutomationService: Time check - Current: ${currentHour}:${currentMinute.toString().padStart(2, '0')} (${currentTime}), Range: ${startTime}-${endTime} (${startMinutes}-${endMinutes}), Should be night: ${shouldBeNight}`)
|
||||
console.log(`NightModeAutomationService: === TIME CALCULATION ===`)
|
||||
console.log(`NightModeAutomationService: Current: ${currentHour}:${currentMinute.toString().padStart(2, '0')} (${currentTime} minutes)`)
|
||||
console.log(`NightModeAutomationService: Range: ${startTime} (${startMinutes} minutes) to ${endTime} (${endMinutes} minutes)`)
|
||||
console.log(`NightModeAutomationService: Should be night: ${shouldBeNight}`)
|
||||
console.log(`NightModeAutomationService: Current isAutomaticNightTime: ${isAutomaticNightTime}`)
|
||||
|
||||
if (shouldBeNight !== isAutomaticNightTime) {
|
||||
isAutomaticNightTime = shouldBeNight
|
||||
console.log("NightModeAutomationService: Automatic night time status changed to:", shouldBeNight)
|
||||
console.log("NightModeAutomationService: *** NIGHT TIME STATUS CHANGED TO:", shouldBeNight, "***")
|
||||
|
||||
if (shouldBeNight) {
|
||||
console.log("NightModeAutomationService: >>> ACTIVATING NIGHT MODE <<<")
|
||||
requestNightModeActivation()
|
||||
} else {
|
||||
console.log("NightModeAutomationService: >>> DEACTIVATING NIGHT MODE <<<")
|
||||
requestNightModeDeactivation()
|
||||
}
|
||||
} else {
|
||||
console.log("NightModeAutomationService: No change needed, isAutomaticNightTime already:", isAutomaticNightTime)
|
||||
}
|
||||
console.log("NightModeAutomationService: === checkTimeBasedMode END ===")
|
||||
}
|
||||
|
||||
function requestNightModeActivation() {
|
||||
@@ -152,30 +290,77 @@ Singleton {
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
console.log("NightModeAutomationService: Using temperature:", temperature + "K")
|
||||
|
||||
gammaStepOneTimeProcess.command = [
|
||||
// Stop process first, change command, then start
|
||||
if (gammaStepProcess.running) {
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
// For time-based mode, use continuous process like location mode
|
||||
if (SessionData.nightModeAutoMode === "time") {
|
||||
gammaStepProcess.processType = "automation" // Use automation type for continuous process
|
||||
} else {
|
||||
gammaStepProcess.processType = "activate" // Keep activate for other modes
|
||||
}
|
||||
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-O", String(temperature),
|
||||
"-P"
|
||||
"-O", String(temperature)
|
||||
// This runs continuously, no timeout needed
|
||||
]
|
||||
console.log("NightModeAutomationService: Running gamma command:", gammaStepOneTimeProcess.command.join(" "))
|
||||
gammaStepOneTimeProcess.running = true
|
||||
console.log("NightModeAutomationService: Running gamma command:", gammaStepProcess.command.join(" "))
|
||||
gammaStepProcess.running = true
|
||||
|
||||
// Only update SessionData manual toggle if we're in automation mode
|
||||
// This prevents automation from interfering with manual UI settings
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode !== "manual") {
|
||||
console.log("NightModeAutomationService: Updating SessionData nightModeEnabled to true (automation mode)")
|
||||
SessionData.setNightModeEnabled(true)
|
||||
} else {
|
||||
console.log("NightModeAutomationService: Not updating SessionData (manual mode or automation disabled)")
|
||||
}
|
||||
}
|
||||
|
||||
function requestNightModeDeactivation() {
|
||||
console.log("NightModeAutomationService: Requesting night mode deactivation")
|
||||
|
||||
gammaStepResetProcess.command = [
|
||||
// Always stop any running process first
|
||||
if (gammaStepProcess.running) {
|
||||
console.log("NightModeAutomationService: Stopping current gamma process")
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
// For time-based mode, we need to explicitly reset gamma
|
||||
if (SessionData.nightModeAutoMode === "time") {
|
||||
console.log("NightModeAutomationService: Time-based deactivation - resetting gamma to normal")
|
||||
// Use automation type for continuous reset process (no timeout)
|
||||
gammaStepProcess.processType = "automation"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-O", "6500",
|
||||
"-P"
|
||||
"-O", "6500"
|
||||
// This will run continuously to maintain normal temperature
|
||||
]
|
||||
gammaStepResetProcess.running = true
|
||||
gammaStepProcess.running = true
|
||||
} else {
|
||||
// For other modes, use the reset approach with timeout protection
|
||||
gammaStepProcess.processType = "reset"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-O", "6500"
|
||||
]
|
||||
gammaStepProcess.running = true
|
||||
}
|
||||
|
||||
// Only update SessionData manual toggle if we're in automation mode
|
||||
// This prevents automation from interfering with manual UI settings
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode !== "manual") {
|
||||
console.log("NightModeAutomationService: Updating SessionData nightModeEnabled to false (automation mode)")
|
||||
SessionData.setNightModeEnabled(false)
|
||||
} else {
|
||||
console.log("NightModeAutomationService: Not updating SessionData (manual mode or automation disabled)")
|
||||
}
|
||||
}
|
||||
|
||||
function setLocation(lat, lon) {
|
||||
@@ -188,10 +373,77 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function clearLocation() {
|
||||
console.log("NightModeAutomationService: === CLEARING LOCATION COORDINATES ===")
|
||||
console.log("NightModeAutomationService: Before - service lat:", latitude, "lng:", longitude)
|
||||
console.log("NightModeAutomationService: Before - SessionData lat:", SessionData.latitude, "lng:", SessionData.longitude)
|
||||
|
||||
// Clear local service coordinates
|
||||
latitude = 0.0
|
||||
longitude = 0.0
|
||||
currentLocation = ""
|
||||
|
||||
// Update SessionData to reflect cleared coordinates
|
||||
SessionData.setLatitude(0.0)
|
||||
SessionData.setLongitude(0.0)
|
||||
|
||||
console.log("NightModeAutomationService: After clearing - service lat:", latitude, "lng:", longitude)
|
||||
console.log("NightModeAutomationService: After clearing - SessionData lat:", SessionData.latitude, "lng:", SessionData.longitude)
|
||||
|
||||
// Force SessionData to save changes
|
||||
SessionData.saveSettings()
|
||||
|
||||
console.log("NightModeAutomationService: Settings saved")
|
||||
console.log("NightModeAutomationService: Current automation mode:", SessionData.nightModeAutoMode)
|
||||
console.log("NightModeAutomationService: Automation enabled:", SessionData.nightModeAutoEnabled)
|
||||
|
||||
// If location mode is active, restart it (will fallback to provider or time-based)
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
console.log("NightModeAutomationService: Restarting location automation after clearing coordinates")
|
||||
startLocationBasedMode()
|
||||
} else {
|
||||
console.log("NightModeAutomationService: Not in location mode, coordinates cleared but automation not restarted")
|
||||
}
|
||||
|
||||
console.log("NightModeAutomationService: === LOCATION CLEARING COMPLETE ===")
|
||||
}
|
||||
|
||||
function debugLocationMode() {
|
||||
console.log("=== DEBUG LOCATION MODE ===")
|
||||
console.log("Manual coordinates - lat:", latitude, "lng:", longitude)
|
||||
console.log("SessionData coordinates - lat:", SessionData.latitude, "lng:", SessionData.longitude)
|
||||
console.log("Current location string:", currentLocation)
|
||||
console.log("Location providers available:", locationProviderAvailable)
|
||||
console.log("Available providers:", availableProviders)
|
||||
console.log("Current provider:", currentProvider)
|
||||
console.log("Auto enabled:", SessionData.nightModeAutoEnabled)
|
||||
console.log("Auto mode:", SessionData.nightModeAutoMode)
|
||||
console.log("Temperature:", SessionData.nightModeTemperature + "K")
|
||||
console.log("gammaStepProcess running:", gammaStepProcess.running)
|
||||
console.log("gammaStepProcess type:", gammaStepProcess.processType)
|
||||
console.log("gammaStepProcess command:", gammaStepProcess.command)
|
||||
|
||||
// Force location mode test if enabled
|
||||
if (SessionData.nightModeAutoMode === "location") {
|
||||
console.log("Forcing startLocationBasedMode()...")
|
||||
startLocationBasedMode()
|
||||
}
|
||||
console.log("=== END DEBUG LOCATION MODE ===")
|
||||
}
|
||||
|
||||
function updateFromSessionData() {
|
||||
console.log("NightModeAutomationService: Updating from SessionData - lat:", SessionData.latitude, "lng:", SessionData.longitude)
|
||||
|
||||
// Only update coordinates if they're non-zero (user has set manual coordinates)
|
||||
// If they're 0.0, leave them cleared to allow automatic location detection
|
||||
if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
|
||||
console.log("NightModeAutomationService: Loading manual coordinates from SessionData")
|
||||
setLocation(SessionData.latitude, SessionData.longitude)
|
||||
} else {
|
||||
console.log("NightModeAutomationService: No manual coordinates in SessionData, keeping coordinates cleared for auto-detection")
|
||||
latitude = 0.0
|
||||
longitude = 0.0
|
||||
currentLocation = ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,19 +454,73 @@ Singleton {
|
||||
function testAutomationNow() {
|
||||
console.log("NightModeAutomationService: Manual test triggered")
|
||||
console.log("NightModeAutomationService: Current settings - autoEnabled:", SessionData.nightModeAutoEnabled, "mode:", SessionData.nightModeAutoMode)
|
||||
console.log("NightModeAutomationService: Time range:", SessionData.nightModeStartTime, "to", SessionData.nightModeEndTime)
|
||||
console.log("NightModeAutomationService: Temperature:", SessionData.nightModeTemperature + "K")
|
||||
|
||||
if (SessionData.nightModeAutoMode === "time") {
|
||||
console.log("NightModeAutomationService: Testing time-based mode now...")
|
||||
checkTimeBasedMode()
|
||||
} else if (SessionData.nightModeAutoMode === "location") {
|
||||
console.log("NightModeAutomationService: Location mode - coordinates:", latitude, longitude)
|
||||
}
|
||||
}
|
||||
|
||||
function manualNightModeTest() {
|
||||
console.log("NightModeAutomationService: Manual night mode test - forcing activation")
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
|
||||
if (gammaStepProcess.running) {
|
||||
console.log("NightModeAutomationService: Stopping existing process first...")
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
gammaStepProcess.processType = "test"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-O", String(temperature)
|
||||
// Removed -P flag to prevent hanging
|
||||
]
|
||||
console.log("NightModeAutomationService: Test gamma command:", gammaStepProcess.command.join(" "))
|
||||
gammaStepProcess.running = true
|
||||
|
||||
// Use the existing timer approach
|
||||
testFeedbackTimer.interval = 2000
|
||||
testFeedbackTimer.feedbackMessage = "NightModeAutomationService: Night mode test command sent. Check if screen temperature changed."
|
||||
testFeedbackTimer.start()
|
||||
}
|
||||
|
||||
function manualResetTest() {
|
||||
console.log("NightModeAutomationService: Manual reset test - forcing reset to 6500K")
|
||||
|
||||
if (gammaStepProcess.running) {
|
||||
console.log("NightModeAutomationService: Stopping existing process first...")
|
||||
gammaStepProcess.running = false
|
||||
}
|
||||
|
||||
gammaStepProcess.processType = "test"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-O", "6500"
|
||||
// Removed -P flag to prevent hanging
|
||||
]
|
||||
console.log("NightModeAutomationService: Test reset command:", gammaStepProcess.command.join(" "))
|
||||
gammaStepProcess.running = true
|
||||
|
||||
// Use the existing timer approach
|
||||
testFeedbackTimer.interval = 2000
|
||||
testFeedbackTimer.feedbackMessage = "NightModeAutomationService: Reset test command sent. Screen should return to normal temperature."
|
||||
testFeedbackTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: automationTimer
|
||||
interval: 60000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
console.log("NightModeAutomationService: *** AUTOMATION TIMER FIRED ***", new Date().toLocaleTimeString())
|
||||
checkTimeBasedMode()
|
||||
}
|
||||
}
|
||||
@@ -231,6 +537,16 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: pkillProcess
|
||||
command: ["pkill", "gammastep"]
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
console.log("NightModeAutomationService: Cleaned up straggling gammastep processes")
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepTestProcess
|
||||
command: ["which", "gammastep"]
|
||||
@@ -241,6 +557,12 @@ Singleton {
|
||||
if (automationAvailable) {
|
||||
console.log("NightModeAutomationService: Gammastep available")
|
||||
detectLocationProviders()
|
||||
|
||||
// Start automation now that Gammastep is confirmed available
|
||||
if (SessionData.nightModeAutoEnabled) {
|
||||
console.log("NightModeAutomationService: Starting automation after confirming Gammastep availability")
|
||||
startAutomation()
|
||||
}
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: Gammastep not available")
|
||||
}
|
||||
@@ -255,14 +577,27 @@ Singleton {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim()) {
|
||||
availableProviders = text.trim().split('\n').filter(line => line.trim().length > 0)
|
||||
locationProviderAvailable = availableProviders.length > 0
|
||||
// Parse provider names - they start with whitespace and are single words
|
||||
const lines = text.trim().split('\n')
|
||||
const providers = lines.filter(line => {
|
||||
const trimmed = line.trim()
|
||||
// Provider names are single words that start with whitespace in original line
|
||||
return line.startsWith(' ') &&
|
||||
trimmed.length > 0 &&
|
||||
!trimmed.includes(' ') &&
|
||||
!trimmed.includes(':') &&
|
||||
!trimmed.includes('.')
|
||||
}).map(line => line.trim())
|
||||
|
||||
availableProviders = providers
|
||||
locationProviderAvailable = providers.length > 0
|
||||
|
||||
if (locationProviderAvailable && !currentProvider) {
|
||||
currentProvider = availableProviders[0]
|
||||
currentProvider = providers[0]
|
||||
}
|
||||
|
||||
console.log("NightModeAutomationService: Available providers:", availableProviders)
|
||||
console.log("NightModeAutomationService: Parsed providers:", providers)
|
||||
console.log("NightModeAutomationService: Location provider available:", locationProviderAvailable)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -276,35 +611,140 @@ Singleton {
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepAutomationProcess
|
||||
id: geoclueTestProcess
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location" && exitCode !== 0) {
|
||||
console.log("NightModeAutomationService: Geoclue2 test exited with code:", exitCode)
|
||||
|
||||
if (exitCode === 0) {
|
||||
console.log("NightModeAutomationService: Geoclue2 working, starting location automation")
|
||||
// Start the actual location automation
|
||||
const temperature = SessionData.nightModeTemperature || 4500
|
||||
const dayTemp = 6500
|
||||
|
||||
gammaStepProcess.processType = "automation"
|
||||
gammaStepProcess.command = [
|
||||
"gammastep",
|
||||
"-m", "wayland",
|
||||
"-l", "geoclue2",
|
||||
"-t", `${dayTemp}:${temperature}`,
|
||||
"-v"
|
||||
]
|
||||
gammaStepProcess.running = true
|
||||
locationTimer.start()
|
||||
} else {
|
||||
console.warn(`NightModeAutomationService: Geoclue2 test failed with exit code ${exitCode}, falling back to time-based mode`)
|
||||
if (exitCode === 124) {
|
||||
console.warn("NightModeAutomationService: Geoclue2 timed out - likely no location services available")
|
||||
} else if (exitCode === 15) {
|
||||
console.warn("NightModeAutomationService: Geoclue2 terminated - permission or service issues")
|
||||
}
|
||||
|
||||
// Fallback to time-based mode
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepProcess
|
||||
running: false
|
||||
|
||||
property string processType: "" // "automation", "activate", "reset", "test"
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim()) {
|
||||
console.log("NightModeAutomationService: Gammastep stdout:", text.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim()) {
|
||||
console.warn("NightModeAutomationService: Gammastep stderr:", text.trim())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRunningChanged: {
|
||||
if (running) {
|
||||
// Start timeout only for one-shot commands, not continuous location automation
|
||||
if (processType !== "automation") {
|
||||
processTimeoutTimer.start()
|
||||
}
|
||||
} else {
|
||||
// Stop timeout when process ends
|
||||
processTimeoutTimer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
onExited: function(exitCode) {
|
||||
console.log(`NightModeAutomationService: Process ${processType} exited with code:`, exitCode)
|
||||
processTimeoutTimer.stop() // Ensure timeout is stopped
|
||||
|
||||
if (exitCode !== 0) {
|
||||
switch(processType) {
|
||||
case "automation":
|
||||
if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "location") {
|
||||
console.warn("NightModeAutomationService: Location-based automation failed, exit code:", exitCode)
|
||||
if (exitCode === 15 || exitCode === 124) {
|
||||
console.warn("NightModeAutomationService: Location service issues detected, falling back to time-based mode")
|
||||
SessionData.setNightModeAutoMode("time")
|
||||
startTimeBasedMode()
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: Attempting to restart location automation in 10 seconds")
|
||||
restartTimer.start()
|
||||
}
|
||||
} else if (SessionData.nightModeAutoEnabled && SessionData.nightModeAutoMode === "time") {
|
||||
console.warn("NightModeAutomationService: Time-based automation process exited unexpectedly, restarting...")
|
||||
restartTimer.start()
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepOneTimeProcess
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
break
|
||||
case "activate":
|
||||
console.warn("NightModeAutomationService: Failed to enable night mode, exit code:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: gammaStepResetProcess
|
||||
running: false
|
||||
|
||||
onExited: function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
break
|
||||
case "reset":
|
||||
console.warn("NightModeAutomationService: Failed to reset gamma, exit code:", exitCode)
|
||||
break
|
||||
case "test":
|
||||
console.warn("NightModeAutomationService: Test command failed, exit code:", exitCode)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
// Success case
|
||||
switch(processType) {
|
||||
case "activate":
|
||||
console.log("NightModeAutomationService: Night mode activated successfully")
|
||||
break
|
||||
case "reset":
|
||||
console.log("NightModeAutomationService: Gamma reset successfully")
|
||||
break
|
||||
case "test":
|
||||
console.log("NightModeAutomationService: Test command completed successfully")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: processTimeoutTimer
|
||||
interval: 30000 // 30 second timeout (increased from 10s for one-shot commands)
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (gammaStepProcess.running) {
|
||||
console.warn("NightModeAutomationService: Process", gammaStepProcess.processType, "timed out, killing process")
|
||||
// Only timeout one-shot commands, not continuous automation
|
||||
if (gammaStepProcess.processType !== "automation") {
|
||||
gammaStepProcess.running = false
|
||||
} else {
|
||||
console.warn("NightModeAutomationService: Automation process running longer than expected, but not killing continuous process")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,6 +761,27 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: testFeedbackTimer
|
||||
interval: 2000
|
||||
running: false
|
||||
repeat: false
|
||||
property string feedbackMessage: ""
|
||||
onTriggered: {
|
||||
if (feedbackMessage.length > 0) {
|
||||
console.log(feedbackMessage)
|
||||
feedbackMessage = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: cleanupTimer
|
||||
interval: 1000
|
||||
running: false
|
||||
repeat: false
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
|
||||
23
docs/IPC.md
23
docs/IPC.md
@@ -119,10 +119,33 @@ Night mode (gamma/color temperature) control.
|
||||
- `value` - Optional temperature in Kelvin (2500-6000, steps of 500)
|
||||
- Returns: Current or newly set temperature
|
||||
|
||||
**`automation [mode]`**
|
||||
- Get or set night mode automation mode
|
||||
- Parameters:
|
||||
- `mode` - Optional automation mode: "manual", "time", or "location"
|
||||
- Returns: Current or newly set automation mode
|
||||
|
||||
**`schedule <start> <end>`**
|
||||
- Set time-based automation schedule
|
||||
- Parameters:
|
||||
- `start` - Start time in HH:MM format (e.g., "20:00")
|
||||
- `end` - End time in HH:MM format (e.g., "06:00")
|
||||
- Returns: Confirmation of schedule update
|
||||
|
||||
**`location <latitude> <longitude>`**
|
||||
- Set manual coordinates for location-based automation
|
||||
- Parameters:
|
||||
- `latitude` - Latitude coordinate (e.g., 40.7128)
|
||||
- `longitude` - Longitude coordinate (e.g., -74.0060)
|
||||
- Returns: Confirmation of coordinates update
|
||||
|
||||
### Examples
|
||||
```bash
|
||||
qs -c dms ipc call night toggle
|
||||
qs -c dms ipc call night temperature 4000
|
||||
qs -c dms ipc call night automation time
|
||||
qs -c dms ipc call night schedule 20:00 06:00
|
||||
qs -c dms ipc call night location 40.7128 -74.0060
|
||||
```
|
||||
|
||||
## Target: `mpris`
|
||||
|
||||
Reference in New Issue
Block a user