Estimate sunup/sundown times for earlier wallpaper changes in winter, update for Qtile 0.34.x
This commit is contained in:
parent
27b41f975d
commit
fa5bbee56e
3 changed files with 161 additions and 9 deletions
|
|
@ -80,6 +80,11 @@ class Config(BaseConfig):
|
||||||
{'title': 'Transaction splits', 'wm_class': 'homebank'},
|
{'title': 'Transaction splits', 'wm_class': 'homebank'},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Location
|
||||||
|
loc_latitude = 52.357603
|
||||||
|
loc_longitude = 6.663761
|
||||||
|
loc_timezone = "Europe/Amsterdam"
|
||||||
|
|
||||||
# Autostart applications
|
# Autostart applications
|
||||||
apps_autostart_group = [
|
apps_autostart_group = [
|
||||||
{'group': "", 'command': ["firefox"]},
|
{'group': "", 'command': ["firefox"]},
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ import time
|
||||||
import datetime
|
import datetime
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from dateutil import tz
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from libqtile.backend.base import Window
|
from libqtile.backend.base import Window
|
||||||
from libqtile.backend.wayland.layer import LayerStatic
|
from libqtile.backend.wayland.window import Window as WaylandWindow, Static as WaylandStatic
|
||||||
from libqtile.backend.wayland.xwindow import XWindow as WaylandXWindow, XStatic as WaylandXStatic
|
|
||||||
from libqtile.backend.x11.window import XWindow as XorgXWindow
|
from libqtile.backend.x11.window import XWindow as XorgXWindow
|
||||||
# Initialize logging
|
# Initialize logging
|
||||||
from libqtile.log_utils import logger
|
from libqtile.log_utils import logger
|
||||||
|
|
@ -30,6 +30,7 @@ logger.warning("Importing kuro utils...")
|
||||||
|
|
||||||
import kuro.utils.widgets
|
import kuro.utils.widgets
|
||||||
from kuro.utils import general as utils
|
from kuro.utils import general as utils
|
||||||
|
from kuro.utils.suntime import Sun
|
||||||
|
|
||||||
logger.warning("Importing variables and other utils...")
|
logger.warning("Importing variables and other utils...")
|
||||||
|
|
||||||
|
|
@ -643,11 +644,9 @@ class Kuro(BaseTheme):
|
||||||
try:
|
try:
|
||||||
w_pid = client.get_pid()
|
w_pid = client.get_pid()
|
||||||
except AttributeError: # Some windows might not have this .get_pid method. Try other ways
|
except AttributeError: # Some windows might not have this .get_pid method. Try other ways
|
||||||
if isinstance(client, WaylandXWindow) or isinstance(client, WaylandXStatic):
|
if isinstance(client, XorgXWindow):
|
||||||
w_pid = client.surface.pid
|
|
||||||
elif isinstance(client, XorgXWindow):
|
|
||||||
w_pid = client.get_net_wm_pid()
|
w_pid = client.get_net_wm_pid()
|
||||||
elif isinstance(client, LayerStatic):
|
elif isinstance(client, WaylandStatic) or isinstance(client, WaylandInternal):
|
||||||
pass # Wayland background layer 'window'
|
pass # Wayland background layer 'window'
|
||||||
else:
|
else:
|
||||||
logger.error(f"Unknown window type {client.__class__.__name__}")
|
logger.error(f"Unknown window type {client.__class__.__name__}")
|
||||||
|
|
@ -714,11 +713,18 @@ class Kuro(BaseTheme):
|
||||||
wallpapers = []
|
wallpapers = []
|
||||||
wallpaper_dir = Config.get("desktop_bg_folder", "")
|
wallpaper_dir = Config.get("desktop_bg_folder", "")
|
||||||
|
|
||||||
# Use a wallpaper from the night folder after 9PM and before 6AM
|
# Get current and sunset/sunrise times using util
|
||||||
|
sun = Sun(Config.get("loc_latitude", 52.357603), Config.get("loc_longitude", 6.663761))
|
||||||
|
tzone = tz.gettz(Config.get("loc_timezone", "Europe/Amsterdam"))
|
||||||
|
cur_time = datetime.datetime.now(tz=tzone)
|
||||||
|
sunset = sun.get_sunset_time(time_zone=tzone)
|
||||||
|
sunrise = sun.get_sunrise_time(time_zone=tzone)
|
||||||
|
logger.warning("Using current time {}, sunset {}, sunrise {} to determine wallpaper.".format(cur_time, sunset, sunrise))
|
||||||
|
|
||||||
|
# Use a wallpaper from the night folder after sunset and before sunrise
|
||||||
wallpaper_night_dir = Config.get("desktop_bg_night_folder", "")
|
wallpaper_night_dir = Config.get("desktop_bg_night_folder", "")
|
||||||
if wallpaper_night_dir and os.path.isdir(wallpaper_night_dir):
|
if wallpaper_night_dir and os.path.isdir(wallpaper_night_dir):
|
||||||
cur_time = datetime.datetime.now()
|
if cur_time > sunset or cur_time < sunrise:
|
||||||
if cur_time.hour > 21 or cur_time.hour < 6:
|
|
||||||
wallpaper_dir = wallpaper_night_dir
|
wallpaper_dir = wallpaper_night_dir
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
141
kuro/utils/suntime.py
Normal file
141
kuro/utils/suntime.py
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
import math
|
||||||
|
import warnings
|
||||||
|
from datetime import datetime, timedelta, time, timezone
|
||||||
|
|
||||||
|
# Copied from: https://github.com/SatAgro/suntime/blob/master/suntime/suntime.py
|
||||||
|
|
||||||
|
# CONSTANT
|
||||||
|
TO_RAD = math.pi/180.0
|
||||||
|
|
||||||
|
|
||||||
|
class SunTimeException(Exception):
|
||||||
|
|
||||||
|
def __init__(self, message):
|
||||||
|
super(SunTimeException, self).__init__(message)
|
||||||
|
|
||||||
|
|
||||||
|
class Sun:
|
||||||
|
"""
|
||||||
|
Approximated calculation of sunrise and sunset datetimes. Adapted from:
|
||||||
|
https://stackoverflow.com/questions/19615350/calculate-sunrise-and-sunset-times-for-a-given-gps-coordinate-within-postgresql
|
||||||
|
"""
|
||||||
|
def __init__(self, lat, lon):
|
||||||
|
self._lat = lat
|
||||||
|
self._lon = lon
|
||||||
|
|
||||||
|
self.lngHour = self._lon / 15
|
||||||
|
|
||||||
|
def get_sunrise_time(self, at_date=datetime.now(), time_zone=timezone.utc):
|
||||||
|
"""
|
||||||
|
:param at_date: Reference date. datetime.now() if not provided.
|
||||||
|
:param time_zone: pytz object with .tzinfo() or None
|
||||||
|
:return: sunrise datetime.
|
||||||
|
:raises: SunTimeException when there is no sunrise and sunset on given location and date.
|
||||||
|
"""
|
||||||
|
time_delta = self.get_sun_timedelta(at_date, time_zone=time_zone, is_rise_time=True)
|
||||||
|
if time_delta is None:
|
||||||
|
raise SunTimeException('The sun never rises on this location (on the specified date)')
|
||||||
|
else:
|
||||||
|
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta
|
||||||
|
|
||||||
|
def get_sunset_time(self, at_date=datetime.now(), time_zone=timezone.utc):
|
||||||
|
"""
|
||||||
|
Calculate the sunset time for given date.
|
||||||
|
:param at_date: Reference date. datetime.now() if not provided.
|
||||||
|
:param time_zone: pytz object with .tzinfo() or None
|
||||||
|
:return: sunset datetime.
|
||||||
|
:raises: SunTimeException when there is no sunrise and sunset on given location and date.
|
||||||
|
"""
|
||||||
|
time_delta = self.get_sun_timedelta(at_date, time_zone=time_zone, is_rise_time=False)
|
||||||
|
if time_delta is None:
|
||||||
|
raise SunTimeException('The sun never rises on this location (on the specified date)')
|
||||||
|
else:
|
||||||
|
return datetime.combine(at_date, time(tzinfo=time_zone)) + time_delta
|
||||||
|
|
||||||
|
def get_sun_timedelta(self, at_date, time_zone, is_rise_time=True, zenith=90.8):
|
||||||
|
"""
|
||||||
|
Calculate sunrise or sunset date.
|
||||||
|
:param at_date: Reference date
|
||||||
|
:param time_zone: pytz object with .tzinfo() or None
|
||||||
|
:param is_rise_time: True if you want to calculate sunrise time.
|
||||||
|
:param zenith: Sun reference zenith
|
||||||
|
:return: timedelta showing hour, minute, and second of sunrise or sunset
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If not set get local timezone from datetime
|
||||||
|
if time_zone is None:
|
||||||
|
time_zone = datetime.now().tzinfo
|
||||||
|
|
||||||
|
# 1. first get the day of the year
|
||||||
|
N = at_date.timetuple().tm_yday
|
||||||
|
|
||||||
|
# 2. convert the longitude to hour value and calculate an approximate time
|
||||||
|
if is_rise_time:
|
||||||
|
t = N + ((6 - self.lngHour) / 24)
|
||||||
|
else: # sunset
|
||||||
|
t = N + ((18 - self.lngHour) / 24)
|
||||||
|
|
||||||
|
# 3a. calculate the Sun's mean anomaly
|
||||||
|
M = (0.9856 * t) - 3.289
|
||||||
|
|
||||||
|
# 3b. calculate the Sun's true longitude
|
||||||
|
L = M + (1.916 * math.sin(TO_RAD*M)) + (0.020 * math.sin(TO_RAD * 2 * M)) + 282.634
|
||||||
|
L = self._force_range(L, 360) # NOTE: L adjusted into the range [0,360)
|
||||||
|
|
||||||
|
# 4a. calculate the Sun's declination
|
||||||
|
sinDec = 0.39782 * math.sin(TO_RAD*L)
|
||||||
|
cosDec = math.cos(math.asin(sinDec))
|
||||||
|
|
||||||
|
# 4b. calculate the Sun's local hour angle
|
||||||
|
cosH = (math.cos(TO_RAD*zenith) - (sinDec * math.sin(TO_RAD*self._lat))) / (cosDec * math.cos(TO_RAD*self._lat))
|
||||||
|
|
||||||
|
if cosH > 1:
|
||||||
|
return None # The sun never rises on this location (on the specified date)
|
||||||
|
if cosH < -1:
|
||||||
|
return None # The sun never sets on this location (on the specified date)
|
||||||
|
|
||||||
|
# 4c. finish calculating H and convert into hours
|
||||||
|
if is_rise_time:
|
||||||
|
H = 360 - (1/TO_RAD) * math.acos(cosH)
|
||||||
|
else: # setting
|
||||||
|
H = (1/TO_RAD) * math.acos(cosH)
|
||||||
|
H = H / 15
|
||||||
|
|
||||||
|
# 5a. calculate the Sun's right ascension
|
||||||
|
RA = (1/TO_RAD) * math.atan(0.91764 * math.tan(TO_RAD*L))
|
||||||
|
RA = self._force_range(RA, 360) # NOTE: RA adjusted into the range [0,360)
|
||||||
|
|
||||||
|
# 5b. right ascension value needs to be in the same quadrant as L
|
||||||
|
Lquadrant = (math.floor(L/90)) * 90
|
||||||
|
RAquadrant = (math.floor(RA/90)) * 90
|
||||||
|
RA = RA + (Lquadrant - RAquadrant)
|
||||||
|
|
||||||
|
# 5c. right ascension value needs to be converted into hours
|
||||||
|
RA = RA / 15
|
||||||
|
|
||||||
|
# 6. calculate local mean time of rising/setting
|
||||||
|
T = H + RA - (0.06571 * t) - 6.622
|
||||||
|
|
||||||
|
# 7a. adjust back to UTC
|
||||||
|
UT = T - self.lngHour
|
||||||
|
|
||||||
|
if time_zone:
|
||||||
|
# 7b. adjust back to local time
|
||||||
|
UT += time_zone.utcoffset(at_date).total_seconds() / 3600
|
||||||
|
|
||||||
|
# 7c. rounding and impose range bounds
|
||||||
|
UT = round(UT, 2)
|
||||||
|
# if is_rise_time:
|
||||||
|
UT = self._force_range(UT, 24)
|
||||||
|
|
||||||
|
# 8. return timedelta
|
||||||
|
return timedelta(hours=UT)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _force_range(v, max):
|
||||||
|
# force v to be >= 0 and < max
|
||||||
|
if v < 0:
|
||||||
|
return v + max
|
||||||
|
elif v >= max:
|
||||||
|
return v - max
|
||||||
|
return v
|
||||||
Loading…
Add table
Add a link
Reference in a new issue