GoodMorningSunshine/clock.py

1766 lines
69 KiB
Python
Raw Permalink Normal View History

2022-12-11 16:08:13 +01:00
# Many thanks to https://stackoverflow.com/questions/18923321/making-a-clock-in-kivy
import collections
import datetime
import math
import sys
import traceback
import copy
2023-04-23 14:00:45 +02:00
from os import uname, walk
from kivy.config import Config
2023-04-11 22:49:58 +02:00
from kivy.properties import ObjectProperty
import time
from sounds import WakeUpSounds
2023-04-23 18:26:37 +02:00
import json
from hsluv import hsluv_to_rgb, rgb_to_hsluv
import requests
import urllib.parse
2022-12-11 16:08:13 +01:00
2023-05-28 23:15:55 +02:00
from kivy.core.image import Image as CoreImage
from kivy.uix.image import Image as kiImage
from PIL import Image, ImageChops
from io import BytesIO
def is_arm():
2023-04-23 14:00:45 +02:00
if (uname()[4][:3] == 'arm') or (uname()[4][:7] == 'aarch64'):
return True
else:
return False
if is_arm():
# Do not forget to create udev rule:
# echo 'SUBSYSTEM=="backlight",RUN+="/bin/chmod 666 /sys/class/backlight/%k/brightness /sys/class/backlight/%k/bl_power"' | sudo tee -a /etc/udev/rules.d/backlight-permissions.rules
from rpi_backlight import Backlight
from rgbw_colorspace_converter.colors.converters import HSV, RGB
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '480')
#Config.set('graphics', 'width', '750')
#Config.set('graphics', 'height', '450')
2023-04-09 22:34:59 +02:00
import board
import neopixel
pixel_pin = board.D10
2023-08-01 12:10:09 +02:00
num_pixels = 300
2023-04-09 22:34:59 +02:00
ORDER = neopixel.GRBW
pixels = neopixel.NeoPixel(
pixel_pin, num_pixels, brightness=0.2, auto_write=False, pixel_order=ORDER
)
pixels.fill((0, 0, 0, 0))
pixels.show()
2023-04-11 22:49:58 +02:00
backlight = Backlight()
else:
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '720')
2023-04-09 22:34:59 +02:00
pixels = None
2023-04-11 22:49:58 +02:00
backlight = None
2023-04-09 22:34:59 +02:00
Config.set('graphics', 'maxfps', '60')
2022-12-11 16:08:13 +01:00
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
2023-01-06 22:39:31 +01:00
from kivy.uix.slider import Slider
2023-01-08 22:11:18 +01:00
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
2022-12-11 16:08:13 +01:00
from kivy.clock import Clock
from kivy.lang import Builder
2023-04-11 22:49:58 +02:00
from kivy.graphics import Color, Line, Rectangle, Ellipse
from kivy.core.window import Window
if is_arm():
Window.show_cursor = False
2022-12-11 16:08:13 +01:00
import alsaaudio
2023-04-08 21:37:28 +02:00
import vlc
2022-12-11 16:08:13 +01:00
2023-04-14 20:32:05 +02:00
Builder.load_file('clock.kv')
2022-12-11 16:08:13 +01:00
Position = collections.namedtuple('Position', 'x y')
2023-04-11 22:49:58 +02:00
class Theme():
def __init__(self, x="Dark"):
2023-04-23 18:26:37 +02:00
print("reading themes/" + x + "/theme.json")
f = open("themes/" + x + "/theme.json")
j = json.load(f)
f.close()
self.name = x
2023-04-23 18:26:37 +02:00
self.color_background = j["color_background"]
self.color_shade = j["color_shade"]
self.color_clock_hands_hours = j["color_clock_hands_hours"]
self.color_clock_hands_minutes = j["color_clock_hands_minutes"]
self.color_clock_hands_seconds = j["color_clock_hands_seconds"]
self.color_alarm_hands_hours = j["color_alarm_hands_hours"]
self.color_alarm_hands_minutes = j["color_alarm_hands_minutes"]
self.color_alarm_hands_seconds = j["color_alarm_hands_seconds"]
self.color_font = j["color_font"]
self.color_numbers = j["color_numbers"]
self.color_button = j["color_button"]
self.color_funky = j["color_funky"]
self.icon_light_off = "themes/" + x + "/light_off.png"
self.icon_light_reading = "themes/" + x + "/light_reading.png"
self.icon_light_sunrise = "themes/" + x + "/light_sunrise.png"
self.icon_light_on = "themes/" + x + "/light_on.png"
self.icon_media_playing = "themes/" + x + "/media_playing.png"
self.icon_media_stopped = "themes/" + x + "/media_stopped.png"
self.icon_alarm_on = "themes/" + x + "/alarm_on.png"
self.icon_alarm_off = "themes/" + x + "/alarm_off.png"
self.icon_settings_visible = "themes/" + x + "/settings_visible.png"
self.icon_settings_not_visible = "themes/" + x + "/settings_not_visible.png"
2023-04-11 22:49:58 +02:00
class Touch():
def __init__(self, x=None):
if x is None:
self.pos = []
self.spos = []
self.is_empty = True
self.angle = 0
self.corrected = False
else:
self.pos = [i for i in x.pos]
self.spos = [i for i in x.spos]
self.is_empty = False
x = self.spos[0] - 0.5
y = self.spos[1] - 0.5
self.angle = math.atan2(y, x) / math.pi; # angle is between -1 and 1
self.corrected = False
def __repr__(self):
return ".is_empty: " + str(self.is_empty) + ", .pos: " + str(self.pos) + ", .spos: " + str(self.spos), ", .corrected: " + str(self.corrected)
def copy(self, x):
self = Touch(x)
def clear(self):
self = Touch()
class TouchEvent():
def __init__(self, x=None):
self.time = time.time()
self.touch = copy.copy(x)
self.processed = False
class ClockSettings():
def __init__(self):
f = open("settings.json")
j = json.load(f)
f.close()
self.theme_selected = j["theme"]
self.wake_up_volume = j["volume"]
2023-04-23 20:31:28 +02:00
self.sound_selected = j["wake_up_sound"]
self.wake_up_brightness = j["wake_up_brightness"]
self.reading_light_brightness = j["reading_light_brightness"]
self.display_brightness = j["display_brightness"]
2023-04-23 21:23:23 +02:00
self.alarm_activated = j["alarm_activated"]
try:
self.address = j["address"]
except:
pass
2023-04-23 21:23:23 +02:00
hour = j["alarm_time_hour"]
minute = j["alarm_time_minute"]
t = datetime.datetime.now()
self.alarm_time = datetime.datetime(t.year, \
t.month, t.day, hour, minute, 0, 0)
self.alarm_activated = False
self.alarm_playing = False
self.alarm_modified = False
self.seconds_to_sunrise = 30 * 60 # 30 minutes
def read(self):
ClockSettings()
def write(self):
2023-04-23 21:23:23 +02:00
j = {}
j["theme"] = self.theme_selected
j["volume"] = self.wake_up_volume
j["wake_up_sound"] = self.sound_selected
j["wake_up_brightness"] = self.wake_up_brightness
j["reading_light_brightness"] = self.reading_light_brightness
j["display_brightness"] = self.display_brightness
j["alarm_activated"] = self.alarm_activated
j["alarm_time_hour"] = self.alarm_time.hour
j["alarm_time_minute"] = self.alarm_time.minute
if hasattr(self, "address"):
j["address"] = self.address
2023-04-23 21:23:23 +02:00
with open("settings.json", "w") as f:
json.dump(j, f, indent=4)
print("settings saved")
2023-01-05 22:02:22 +01:00
class MyClockWidget(FloatLayout):
settings = ClockSettings()
if settings.theme_selected == "Automatic":
theme_name = "Light"
else:
theme_name = settings.theme_selected
theme = ObjectProperty(Theme(theme_name))
2023-04-11 22:49:58 +02:00
for x in ('', 'PCM'):
try:
mixer = alsaaudio.Mixer()
break
except:
pass
else:
raise OSError('could not open mixer ' + x)
2023-01-05 22:02:22 +01:00
grabbed = ""
face_numbers = []
2023-01-15 11:58:53 +01:00
# if not grabbed, set_alarm_timeout_counter is incremented at every update call;
2023-01-05 22:02:22 +01:00
# this is used to blink the hands at 1 Hz when setting the alarm and releasing the hand
set_alarm_timeout_counter = 0
seconds_to_next_alarm = 0
2023-04-09 22:34:59 +02:00
2023-04-09 23:53:37 +02:00
light_state = "off" # "off", "reading", "sunrise" or "on"
intensity_target = 0
intensity_prev = 0
intensity_curr = 0
intensity_target_prev = None
rgbw_prev = None
2023-01-05 22:02:22 +01:00
2023-04-23 16:06:05 +02:00
volume_target = 0
volume_prev = 0
volume_curr = 0
volume_target_prev = None
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen
# For each type of touch event, handling of the event is ignored until the last event is more than touch_delay_time seconds old
touch_delay_time = 0.1
touch_down_event_prev = None
touch_move_event_prev = None
touch_up_event_prev = None
touch_down_event_curr = None
touch_move_event_curr = None
touch_up_event_curr = None
2023-01-08 22:11:18 +01:00
# view can be one of the following strings:
# - "clock"
# - "set_alarm"
# - "settings_menu"
# - "settings_menu_wake_up_sound"
2023-04-11 22:49:58 +02:00
# - "settings_menu_theme"
2023-01-06 20:18:22 +01:00
view = "clock"
2023-04-13 22:42:58 +02:00
view_prev = ""
view_active_since = time.time()
# ugly workaround for issue where input is processed twice (specifically:
# pressing Ok in wake up sound view switches to settings view but also
# adjusts display brightness slider)
time_to_ignore_inputs_after_view_change = 0.5
# ugly workaround for issue where graphics are not drawn correctly after view change
time_to_force_redraws_after_view_change = 0.5
2023-01-06 20:18:22 +01:00
2023-01-08 22:11:18 +01:00
# we need a dirty hack to sensure that radio button is always in sync with selected setting
settings_menu_wake_up_sound_select_button_cb_hack = False
2023-04-11 22:49:58 +02:00
settings_menu_theme_select_button_cb_hack = False
2023-01-08 22:11:18 +01:00
# defer drawing to improve application speed: if list of draw calls for
# this frame is identical to list of previous frame then nothing needs to
# be drawed
draw_list_last_frame = []
draw_list_curr_frame = []
touch_prev = Touch()
light_button_move_init = []
2023-04-08 21:37:28 +02:00
vlc = vlc.Instance()
player = vlc.media_player_new()
is_arm = is_arm()
aqi_colors = [
2023-05-26 23:12:35 +02:00
[0.0, 0.0, 0.0], # x < 1.0 black (good)
2023-05-29 12:38:26 +02:00
[0.3, 0.3, 255.0/255.0], # 1.0 <= x < 2.0 blue (good)
2023-05-26 23:12:35 +02:00
[0.0, 160.0/255.0, 160.0/255.0], # 2.0 <= x < 3.0 cyan (good)
[1.0, 1.0, 1.0], # 3.0 <= x < 4.0 white (mediocre)
[1.0, 1.0, 150.0/255.0], # 4.0 <= < x 5.0 light yellow (mediocre)
[245.0/255.0, 245.0/255.0, 0.0], # 5.0 <= x < 6.0 yellow (mediocre)
2023-05-26 23:12:35 +02:00
[1.0, 175.0/255.0, 0.0], # 6.0 <= x < 7.0 orange (inadequate)
[1.0, 120.0/255.0, 0.0], # 7.0 <= x < 8.0 red orange (inadequate)
[200.0/255.0, 0.0, 0.0], # 8.0 <= x < 9.0 red (bad)
[200.0/255.0, 0.0, 200.0/255.0], # 9.0 <= x < 10.0 magenta (bad)
2023-05-29 12:38:26 +02:00
[100.0/255.0, 0.0, 200.0/255.0], # 10.0 <= x purple (terrible)
]
2023-05-27 09:58:47 +02:00
precipitation = []
precipitation_thresholds = [0.1, 0.22, 0.47, 1.0, 2.2, 4.7, 10, 22, 47, 100]
pollen = []
pollen_thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
aqi = []
aqi_thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
paqi = []
paqi_thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
uvi = []
uvi_thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
2023-06-03 22:53:25 +02:00
iaqi = []
iaqi_thresholds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
2023-05-27 09:43:20 +02:00
def get_air_quality_metric(self, j, t, metric, periodicity):
x = []
try:
for i in j[metric]:
if i["time"]>= t - periodicity:
x.append(i["value"])
except:
print("Couldn't find metric " + metric)
return x
def get_air_quality(self, *args):
if hasattr(self.settings, "address") == False:
print("No address specified")
return
url = "https://sinoptik.luon.net/forecast?address=" + urllib.parse.quote(self.settings.address, safe="") + "&metrics=precipitation&metrics=UVI&metrics=AQI&metrics=pollen&metrics=PAQI"
response = requests.get(url)
2023-05-27 09:58:47 +02:00
self.precipitation = []
self.pollen = []
self.aqi = []
self.paqi = []
self.uvi = []
2023-06-03 23:02:34 +02:00
self.iaqi = []
2023-05-27 09:43:20 +02:00
if response.status_code == 200:
t = datetime.datetime.now().timestamp()
j = json.loads(response.text)
2023-05-27 09:58:47 +02:00
self.precipitation = self.get_air_quality_metric(j, t, "precipitation", 300)
2023-05-29 12:38:26 +02:00
# self.precipitation = [0, 0.1, 0.22, 0.47, 1, 2.2, 4.7, 10, 22, 47, 100]
2023-05-27 09:43:20 +02:00
self.pollen = self.get_air_quality_metric(j, t, "pollen", 3600)
self.aqi = self.get_air_quality_metric(j, t, "AQI", 3600)
self.paqi = self.get_air_quality_metric(j, t, "PAQI", 3600)
self.uvi = self.get_air_quality_metric(j, t, "UVI", 3600 * 24)
else:
print("Error retrieving air quality; got response " + str(response))
def sync_air_quality(self, *args):
Clock.schedule_interval(self.get_air_quality, 60)
def update_background_automatic_sunrise(self):
background = self.ids["background"]
self.draw_list_curr_frame.append(["canvas.clear()", background])
with background.canvas:
color = self.intensity_to_rgb(self.intensity_curr)
self.draw_list_curr_frame.append(["Color", background.canvas, color[0], color[1], color[2]])
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, None])
def update_background_automatic_no_sunrise(self):
background = self.ids["background"]
self.draw_list_curr_frame.append(["canvas.clear()", background])
with background.canvas:
color = self.theme.color_background
self.draw_list_curr_frame.append(["Color", background.canvas, color[0], color[1], color[2]])
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, None])
def apply_theme(self):
if self.settings.theme_selected == "Automatic":
if (self.light_state != "sunrise") and (self.light_state != "on"):
# switch to light theme after 7:00 AM, to dark theme after 19:00
t = datetime.datetime.now()
h = t.hour + t.minute / 60
if (h >= 7) and (h < 19):
if self.theme.name != "Light":
self.theme = Theme("Light")
else:
if self.theme.name != "Dark":
self.theme = Theme("Dark")
self.update_background_automatic_no_sunrise()
else:
if self.intensity_curr >= 0.5:
if self.theme.name != "Light":
self.theme = Theme("Light")
else:
if self.theme.name != "Dark":
self.theme = Theme("Dark")
self.update_background_automatic_sunrise()
else:
if self.theme.name != self.settings.theme_selected:
self.theme = Theme(self.settings.theme_selected)
self.update_background_automatic_no_sunrise()
self.ids["settings_menu_wake_up_sound_label_top"].color = self.theme.color_font
self.settings_menu_wake_up_sound_Ok_button.color = self.theme.color_font
self.ids["settings_menu_theme_label_top"].color = self.theme.color_font
self.settings_menu_theme_Ok_button.color = self.theme.color_font
2023-04-23 14:00:45 +02:00
def find_themes(self):
themes = next(walk('themes/'))[1]
if ('Dark' in themes) and ('Light' in themes):
themes.append('Automatic')
print('Found the following themes: ' + str(themes))
return themes
2023-04-16 22:14:10 +02:00
def add_themes(self):
2023-04-23 14:00:45 +02:00
self.themes = self.find_themes()
2023-04-16 22:14:10 +02:00
x = self.ids["settings_menu_theme_boxlayout"]
gl = GridLayout(
cols=2,
)
self.ids["settings_menu_theme_select_button"].text = self.settings.theme_selected
2023-04-16 22:14:10 +02:00
self.theme_checkboxes = []
self.theme_labels = []
i = 0
for w in self.themes:
c = CheckBox(
group = "settings_menu_theme",
size = [gl.size[0] * 0.1, gl.size[1]],
)
c.bind(active=self.settings_menu_theme_cb)
gl.add_widget(c)
self.theme_checkboxes.append(c)
if i == 0:
a = True
else:
a = False
l = Label(
text = w,
halign = "left",
valign = "middle",
size = [Window.size[0] * 0.3, Window.size[1]],
text_size = Window.size,
font_size = Window.height*0.05,
color = self.theme.color_font,
)
l.text_size = l.size
gl.add_widget(l)
self.theme_labels.append(l)
i = i + 1
x.add_widget(gl)
b = Button(
text = "Ok",
font_size = self.height*0.3,
color = self.theme.color_font,
background_normal = '',
background_color = self.theme.color_button
)
b.bind(on_press = self.settings_menu_theme_Ok_button_cb)
x.add_widget(b)
self.settings_menu_theme_Ok_button = b
self.apply_theme()
2023-04-16 22:14:10 +02:00
2023-04-23 20:31:28 +02:00
def apply_settings(self):
self.ids["volume_slider"].value = self.settings.wake_up_volume
self.ids["settings_menu_wake_up_sound_select_button"].text = self.settings.sound_selected
self.ids["wake_up_brightness_slider"].value = self.settings.wake_up_brightness
self.ids["reading_light_brightness_slider"].value = self.settings.reading_light_brightness
self.ids["display_brightness_slider"].value = self.settings.display_brightness
2023-04-16 22:14:10 +02:00
def add_wake_up_sounds(self):
2023-04-16 20:28:40 +02:00
x = self.ids["settings_menu_wake_up_sound_boxlayout"]
gl = GridLayout(
cols=2,
)
self.wake_up_sounds = WakeUpSounds
self.settings.sound_source = self.wake_up_sounds[self.settings.sound_selected]
2023-04-16 20:28:40 +02:00
self.wake_up_sound_checkboxes = []
self.wake_up_sound_labels = []
i = 0
for w in self.wake_up_sounds:
c = CheckBox(
group = "settings_menu_wake_up_sound",
size = [gl.size[0] * 0.1, gl.size[1]],
)
c.bind(active=self.settings_menu_wake_up_sound_cb)
gl.add_widget(c)
self.wake_up_sound_checkboxes.append(c)
if i == 0:
a = True
else:
a = False
l = Label(
text = w,
halign = "left",
valign = "middle",
size = [Window.size[0] * 0.3, Window.size[1]],
text_size = Window.size,
font_size = Window.height*0.05,
color = self.theme.color_font,
)
l.text_size = l.size
gl.add_widget(l)
self.wake_up_sound_labels.append(l)
i = i + 1
x.add_widget(gl)
b = Button(
text = "Ok",
font_size = self.height*0.3,
color = self.theme.color_font,
background_normal = '',
background_color = self.theme.color_button
)
b.bind(on_press = self.settings_menu_wake_up_sound_Ok_button_cb)
x.add_widget(b)
self.settings_menu_wake_up_sound_Ok_button = b
2023-04-23 16:06:05 +02:00
def set_volume(self, x):
self.mixer.setvolume(int(x * 100))
self.volume_prev = self.volume_curr
self.volume_curr = x
2023-04-08 21:37:28 +02:00
def play_sound(self, source):
if (self.player.get_state() == vlc.State.NothingSpecial) or \
(self.player.get_state() == vlc.State.Paused) or \
(self.player.get_state() == vlc.State.Stopped) or \
(self.player.get_state() == vlc.State.Ended) or \
(self.player.get_state() == vlc.State.Error):
print("beep beep! " + source)
self.volume_target = self.settings.wake_up_volume / 20.0
2023-04-08 21:37:28 +02:00
media = self.vlc.media_new(source)
self.player.set_media(media)
self.player.play()
self.settings.alarm_playing = True
2023-04-08 21:37:28 +02:00
2023-04-08 21:37:28 +02:00
def stop_sound(self):
self.player.stop()
self.settings.alarm_playing = False
def set_backlight(self, x):
offset = 3
# 20 steps to from 1 to 100 - offset
c = (100 - offset)**(1/20)
y = c**x + offset
z = max(1, round(y))
if self.is_arm:
2023-04-11 22:49:58 +02:00
if backlight.brightness != z:
backlight.brightness = z
2023-01-06 22:39:31 +01:00
def hide_widget(self, widget, hide=True):
if hasattr(widget, 'saved_attrs'):
if not hide:
widget.height, widget.size_hint_y, widget.opacity, widget.disabled = widget.saved_attrs
del widget.saved_attrs
elif hide:
widget.saved_attrs = widget.height, widget.size_hint_y, widget.opacity, widget.disabled
widget.height, widget.size_hint_y, widget.opacity, widget.disabled = 0, None, 0, True
def is_widget_hidden(self, widget):
return hasattr(widget, 'saved_attrs')
def draw_numbers(self):
2022-12-11 16:08:13 +01:00
"""
Add number labels when added in widget hierarchy
"""
2023-01-05 22:02:22 +01:00
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
t = self.settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
t = datetime.datetime.now()
2022-12-11 16:08:13 +01:00
for i in range(1, 13):
if t.hour < 12:
2022-12-11 16:08:13 +01:00
offset = 0
else:
offset = 12
self.face_numbers.append(Label(
text=str(i + offset),
font_size=float(Config.get('graphics', 'height'))*0.05,
2023-04-11 22:49:58 +02:00
color=self.theme.color_numbers,
2022-12-11 16:08:13 +01:00
pos_hint={
# pos_hint is a fraction in range (0, 1)
"center_x": 0.5 + 0.45*math.sin(2 * math.pi * i/12),
"center_y": 0.5 + 0.45*math.cos(2 * math.pi * i/12),
}
))
self.ids["face"].add_widget(self.face_numbers[i - 1])
2023-05-27 09:43:20 +02:00
def draw_colored_circle(self, reference, x, y, r, color):
if color != [0.0, 0.0, 0.0]:
if color == [1, 1, 1]:
# Draw black circle
p = [x - r, y - r]
self.draw_list_curr_frame.append(["Color", reference.canvas, 0, 0, 0])
self.draw_list_curr_frame.append(["Ellipse", reference.canvas, [2 * r, 2 * r], p])
# Draw slightly smaller white circle
p = [x - r * 0.95, y - r * 0.95]
self.draw_list_curr_frame.append(["Color", reference.canvas, color[0], color[1], color[2]])
self.draw_list_curr_frame.append(["Ellipse", reference.canvas, [2 * r * 0.95, 2 * r * 0.95], p])
else:
# Draw slightly smaller colored circle
p = [x - r, y - r]
self.draw_list_curr_frame.append(["Color", reference.canvas, color[0], color[1], color[2]])
self.draw_list_curr_frame.append(["Ellipse", reference.canvas, [2 * r, 2 * r], p])
2023-05-28 23:15:55 +02:00
def calculate_colors(self, x, x_thresholds):
colors = []
for i in range(0, len(x)):
idx = 0
for l in x_thresholds:
if l > x[i]:
break
idx = idx + 1
if idx >= len(self.aqi_colors):
idx = len(self.aqi_colors) - 1
colors.append(self.aqi_colors[idx])
return colors
def draw_precipitation_paqi_expectation(self, x, x_thresholds, location):
2023-05-26 23:12:35 +02:00
if len(x) == 0:
return
face_plate = self.ids["face_plate"]
with face_plate.canvas:
N = min(12, len(x))
colors = self.calculate_colors(x[:N], x_thresholds)
2023-05-27 09:43:20 +02:00
for i in range(0, N):
2023-05-28 23:15:55 +02:00
color = colors[i]
2023-05-27 09:43:20 +02:00
R = face_plate.size[0] / 2
r = R / 10
tmp_x = 0.5 + location*math.sin(2 * math.pi * i/12)
tmp_y = 0.5 + location*math.cos(2 * math.pi * i/12)
coord_x = face_plate.pos[0] + 2 * R * tmp_x
coord_y = face_plate.pos[1] + 2 * R * tmp_y
self.draw_colored_circle(face_plate, coord_x, coord_y, r, color)
2023-05-27 09:58:47 +02:00
def draw_precipitation_expectation(self):
2023-05-28 23:15:55 +02:00
self.draw_precipitation_paqi_expectation(self.precipitation, self.precipitation_thresholds, 0.45)
def draw_paqi_expectation(self):
self.draw_precipitation_paqi_expectation(self.paqi, self.paqi_thresholds, 0.32)
def paint_icon(self, color, img_source, label):
2023-05-28 23:15:55 +02:00
c = (int(256 * color[0]), int(256 * color[1]), int(256 * color[2]), int(256))
tmp = Image.new('RGBA', img_source.size, color = c)
img_modified = ImageChops.multiply(tmp, img_source)
data = BytesIO()
img_modified.save(data, format='png')
data.seek(0)
im = CoreImage(BytesIO(data.read()), ext='png')
icon = self.ids[label]
icon.texture = im.texture
def draw_icon_helper(self, x, x_thresholds, x_label, L, color_prev, img):
N = min(L, len(x))
colors = self.calculate_colors(x[:N], x_thresholds)
color = colors[x.index(max(x[:N]))]
if color_prev != color:
# Color has changed
if color == [1, 1, 1]:
img = Image.open("icons/" + x_label + "_outline.png")
else:
if color_prev == [1, 1, 1]:
img = Image.open("icons/" + x_label + ".png")
2023-08-01 12:10:09 +02:00
if self.is_arm:
img = img.resize((int(img.width * 0.67), int(img.height * 0.67)))
self.paint_icon(color, img, "icon_" + x_label)
return color
2023-06-03 22:53:25 +02:00
def draw_icon_iaqi(self):
if hasattr(self, 'image_iaqi') == False:
self.image_iaqi = Image.open("icons/iaqi.png")
if len(self.iaqi) == 0:
if self.is_widget_hidden(self.ids["icon_iaqi"]) == False:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_iaqi"], True])
return
if self.is_widget_hidden(self.ids["icon_iaqi"]):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_iaqi"], False])
if hasattr(self, 'iaqi_color_prev') == False:
self.iaqi_color_prev = []
if hasattr(self, 'iaqi_color') == False:
self.iaqi_color = []
color = self.draw_icon_helper(self.iaqi, self.iaqi_thresholds, "iaqi", 1, self.iaqi_color_prev, self.image_iaqi)
self.iaqi_color_prev = self.iaqi_color
self.iaqi_color = color
2023-05-28 23:15:55 +02:00
def draw_icon_uvi(self):
if hasattr(self, 'image_uvi') == False:
self.image_uvi = Image.open("icons/uvi.png")
if len(self.uvi) == 0:
if self.is_widget_hidden(self.ids["icon_uvi"]) == False:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_uvi"], True])
return
if self.is_widget_hidden(self.ids["icon_uvi"]):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_uvi"], False])
if hasattr(self, 'uvi_color_prev') == False:
self.uvi_color_prev = []
2023-05-28 23:15:55 +02:00
if hasattr(self, 'uvi_color') == False:
self.uvi_color = []
color = self.draw_icon_helper(self.uvi, self.uvi_thresholds, "uvi", 1, self.uvi_color_prev, self.image_uvi)
self.uvi_color_prev = self.uvi_color
self.uvi_color = color
2023-05-28 23:15:55 +02:00
def draw_icon_pollen(self):
if hasattr(self, 'image_pollen') == False:
self.image_pollen = Image.open("icons/pollen.png")
if len(self.pollen) == 0:
if self.is_widget_hidden(self.ids["icon_pollen"]) == False:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_pollen"], True])
return
2023-05-28 23:15:55 +02:00
if self.is_widget_hidden(self.ids["icon_pollen"]):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_pollen"], False])
if hasattr(self, 'pollen_color_prev') == False:
self.pollen_color_prev = []
if hasattr(self, 'pollen_color') == False:
self.pollen_color = []
color = self.draw_icon_helper(self.pollen, self.pollen_thresholds, "pollen", 12, self.pollen_color_prev, self.image_pollen)
self.pollen_color_prev = self.pollen_color
self.pollen_color = color
2023-05-28 23:15:55 +02:00
def draw_icon_aqi(self):
if hasattr(self, 'image_aqi') == False:
self.image_aqi = Image.open("icons/aqi.png")
if len(self.aqi) == 0:
if self.is_widget_hidden(self.ids["icon_aqi"]) == False:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_aqi"], True])
return
if self.is_widget_hidden(self.ids["icon_aqi"]):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_aqi"], False])
if hasattr(self, 'aqi_color_prev') == False:
self.aqi_color_prev = []
2023-05-28 23:15:55 +02:00
if hasattr(self, 'aqi_color') == False:
self.aqi_color = []
color = self.draw_icon_helper(self.aqi, self.aqi_thresholds, "aqi", 12, self.aqi_color_prev, self.image_aqi)
self.aqi_color_prev = self.aqi_color
self.aqi_color = color
2023-05-28 23:15:55 +02:00
def draw_icons(self):
self.draw_icon_uvi()
self.draw_icon_pollen()
self.draw_icon_aqi()
2023-06-03 22:53:25 +02:00
self.draw_icon_iaqi()
def draw_face(self):
self.draw_numbers()
def update_theme(self):
if self.settings.theme_selected == "Automatic":
self.apply_theme()
2023-04-11 22:49:58 +02:00
2022-12-11 16:08:13 +01:00
def update_face(self):
2023-04-11 22:49:58 +02:00
face_plate = self.ids["face_plate"]
self.draw_list_curr_frame.append(["canvas.clear()", face_plate])
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
t = self.settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
t = datetime.datetime.now()
2022-12-11 16:08:13 +01:00
2023-05-27 09:58:47 +02:00
if (self.view == "clock") and (self.precipitation != []) and (self.paqi != []):
for i in range(0, 12):
self.face_numbers[i].text = ""
2022-12-11 16:08:13 +01:00
2023-05-27 09:58:47 +02:00
self.draw_precipitation_expectation()
2023-05-28 23:15:55 +02:00
self.draw_paqi_expectation()
self.draw_icons()
else:
2023-05-27 09:43:20 +02:00
with face_plate.canvas:
color = self.theme.color_numbers
self.draw_list_curr_frame.append(["Color", face_plate.canvas, color[0], color[1], color[2]])
r = face_plate.size[0] / 2
p = [face_plate.pos[0] + r, face_plate.pos[1] + r]
self.draw_list_curr_frame.append(["Circle", face_plate.canvas, p, r])
for i in range(0, 12):
if t.hour < 12:
offset = 0
else:
offset = 12
self.face_numbers[i].color = self.theme.color_numbers
self.face_numbers[i].text = str(i + 1 + offset)
2022-12-11 16:08:13 +01:00
def on_parent(self, myclock, parent):
self.draw_face()
def position_on_clock(self, fraction, length):
"""
Calculate position in the clock using trygonometric functions
"""
center_x = self.size[0]/2
center_y = self.size[1]/2
return Position(
2023-02-17 21:43:24 +01:00
center_x + round(length * math.sin(2 * math.pi * fraction)),
center_y + round(length * math.cos(2 * math.pi * fraction)),
2022-12-11 16:08:13 +01:00
)
def update_light_button(self):
2023-04-10 00:47:04 +02:00
if (self.light_state == "off"):
2023-04-11 22:49:58 +02:00
source = self.theme.icon_light_off
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "reading"):
2023-04-11 22:49:58 +02:00
source = self.theme.icon_light_reading
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "sunrise"):
2023-04-11 22:49:58 +02:00
source = self.theme.icon_light_sunrise
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "on"):
2023-04-11 22:49:58 +02:00
source = self.theme.icon_light_on
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
light_button = self.ids["light_button"]
self.draw_list_curr_frame.append(["canvas.clear()", light_button])
with light_button.canvas:
self.draw_list_curr_frame.append(["Color", light_button.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", light_button.canvas, light_button.size, light_button.pos, source])
2023-04-09 15:00:04 +02:00
def update_play_button(self):
if self.settings.alarm_playing:
2023-04-11 22:49:58 +02:00
source = self.theme.icon_media_playing
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2023-04-09 15:00:04 +02:00
else:
2023-04-11 22:49:58 +02:00
source = self.theme.icon_media_stopped
2023-04-09 15:00:04 +02:00
rgb = [1.0, 1.0, 1.0]
play_button = self.ids["play_button"]
self.draw_list_curr_frame.append(["canvas.clear()", play_button])
with play_button.canvas:
self.draw_list_curr_frame.append(["Color", play_button.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", play_button.canvas, play_button.size, play_button.pos, source])
2022-12-11 16:08:13 +01:00
def update_set_alarm_button(self):
if (self.view == "set_alarm") or self.settings.alarm_activated:
2023-04-11 22:49:58 +02:00
source = self.theme.icon_alarm_on
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2022-12-11 16:08:13 +01:00
else:
2023-04-11 22:49:58 +02:00
source = self.theme.icon_alarm_off
2022-12-17 20:50:47 +01:00
rgb = [1.0, 1.0, 1.0]
2022-12-11 16:08:13 +01:00
set_alarm_button = self.ids["set_alarm_button"]
self.draw_list_curr_frame.append(["canvas.clear()", set_alarm_button])
2022-12-11 16:08:13 +01:00
with set_alarm_button.canvas:
self.draw_list_curr_frame.append(["Color", set_alarm_button.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", set_alarm_button.canvas, set_alarm_button.size, set_alarm_button.pos, source])
2022-12-11 16:08:13 +01:00
2023-01-06 22:39:31 +01:00
def update_settings_button(self):
2023-01-08 22:11:18 +01:00
if (self.view.startswith("settings_menu")):
2023-04-11 22:49:58 +02:00
source = self.theme.icon_settings_visible
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2023-01-06 22:39:31 +01:00
else:
2023-04-11 22:49:58 +02:00
source = self.theme.icon_settings_not_visible
2023-01-06 22:39:31 +01:00
rgb = [1.0, 1.0, 1.0]
settings_button = self.ids["settings_button"]
self.draw_list_curr_frame.append(["canvas.clear()", settings_button])
2023-01-06 22:39:31 +01:00
with settings_button.canvas:
self.draw_list_curr_frame.append(["Color", settings_button.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", settings_button.canvas, settings_button.size, settings_button.pos, source])
2023-01-06 22:39:31 +01:00
def intensity_to_rgb(self, intensity):
2022-12-17 20:50:47 +01:00
if intensity < 0:
intensity = 0
2023-04-09 22:34:59 +02:00
elif intensity > 1:
intensity = 1
# sunlight intensity and color temperature vary with sine function
intensity = math.sin(2 * math.pi * intensity / 4)
2023-04-09 22:34:59 +02:00
# from https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html
# usable between 1000 and 40000 K
# we only want color temperatures between 2000 and 6500 K
CCT = 2000 + (6500 - 2000) * intensity
if CCT < 1000:
CCT = 1000
if CCT > 40000:
CCT = 40000
Temperature = CCT / 100
if Temperature <= 66:
Red = 255
else:
Red = Temperature - 60
Red = 329.698727446 * pow(Red, -0.1332047592)
if Red < 0:
Red = 0
if Red > 255:
Red = 255
if Temperature <= 66:
Green = Temperature
Green = 99.4708025861 * math.log(Green) - 161.1195681661
if Green < 0:
Green = 0
if Green > 255:
Green = 255
else:
Green = Temperature - 60
Green = 288.1221695283 * pow(Green, -0.0755148492)
if Green < 0:
Green = 0
if Green > 255:
Green = 255
if Temperature >= 66:
Blue = 255
else:
if Temperature <= 19:
Blue = 0
else:
Blue = Temperature - 10
Blue = 138.5177312231 * math.log(Blue) - 305.0447927307
if Blue < 0:
Blue = 0
if Blue > 255:
Blue = 255
rgb_cct = [Red / 255, Green / 255, Blue / 255]
# adjust intensity
[h, s, l]= rgb_to_hsluv(rgb_cct)
l = l * intensity
2023-04-09 22:34:59 +02:00
rgb = hsluv_to_rgb([h, s, l])
return rgb
def intensity_to_rgbw(self, intensity):
rgb = self.intensity_to_rgb(intensity)
2023-04-09 22:34:59 +02:00
led_color = RGB(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255)
return led_color
2022-12-17 20:50:47 +01:00
def update_backlight(self):
# make sure brightness of display is never lower than intensity of leds
brightness_min = 20 * self.intensity_curr
if self.settings.display_brightness < brightness_min:
self.set_backlight(brightness_min)
else:
self.set_backlight(self.settings.display_brightness)
2023-04-09 23:53:37 +02:00
def set_leds(self):
if self.intensity_prev != self.intensity_curr:
self.intensity_prev = self.intensity_curr
2023-04-09 23:53:37 +02:00
if self.is_arm:
led_color = self.intensity_to_rgbw(self.intensity_curr)
2023-04-10 15:25:34 +02:00
if self.rgbw_prev != led_color.rgbw:
self.rgbw_prev = led_color.rgbw
# print(self.light_state + ", t: " + str(self.seconds_to_next_alarm) + ", i: " + str(self.intensity_curr) + ", rgbw: " + str(led_color.rgbw))
2023-04-10 15:25:34 +02:00
pixels.fill(led_color.rgbw)
pixels.show()
else:
# On non-arm rgbw_colorspace_converter and hsluv are not available; fake rgbw by setting w component to scaled value of intensity_curr
rgbw = [0, 0, 0, round(self.intensity_curr * 255)]
2023-04-10 15:25:34 +02:00
if self.rgbw_prev != rgbw:
self.rgbw_prev = rgbw
# print(self.light_state + ", t: " + str(self.seconds_to_next_alarm) + ", i: " + str(self.intensity_curr) + ", rgbw: " + str(rgbw))
2023-04-10 15:25:34 +02:00
2023-04-09 22:34:59 +02:00
def sunrise(self):
2023-04-09 23:53:37 +02:00
if self.view == "set_alarm":
2023-04-10 00:47:04 +02:00
# Do not simulate sunrise when adjusting alarm time
return
2023-04-09 23:53:37 +02:00
if self.seconds_to_next_alarm < 0.1:
intensity_target = (self.settings.wake_up_brightness / 20.0)
2023-04-10 15:25:34 +02:00
new_state = "on"
else:
intensity_target = (1.0 - self.seconds_to_next_alarm / self.settings.seconds_to_sunrise) * (self.settings.wake_up_brightness / 20.0)
2023-04-10 15:25:34 +02:00
new_state = "sunrise"
2022-12-11 16:08:13 +01:00
# only adjust intensity_target if new intensity_target is higher than current intesity, to avoid dimming light when reading mode is on
if self.intensity_target < intensity_target:
self.intensity_target = intensity_target
2023-04-10 15:25:34 +02:00
self.light_state = new_state
2023-01-05 22:02:22 +01:00
2023-04-09 23:53:37 +02:00
def process_led_state(self):
if (self.settings.alarm_activated) and (self.seconds_to_next_alarm < self.settings.seconds_to_sunrise):
2023-04-09 22:34:59 +02:00
self.sunrise()
else:
2023-04-09 23:53:37 +02:00
if (self.light_state == "off"):
self.intensity_target = 0
2023-04-09 23:53:37 +02:00
elif (self.light_state == "reading"):
self.intensity_target = self.settings.reading_light_brightness / 20.0
2023-04-09 23:53:37 +02:00
elif (self.light_state == "on"):
self.intensity_target = self.settings.wake_up_brightness / 20.0
weight = 0.05
intensity_next = weight * self.intensity_target + (1 - weight) * self.intensity_curr
step = intensity_next - self.intensity_curr
if abs(step) < 0.001:
step = self.intensity_target - self.intensity_curr
self.intensity_curr = self.intensity_curr + step
2022-12-11 16:08:13 +01:00
2023-04-23 16:06:05 +02:00
def process_volume_state(self):
if (self.settings.alarm_playing) and (self.player.get_state() == vlc.State.Playing):
2023-04-23 16:06:05 +02:00
step = 0.005
if (self.volume_curr <= self.volume_target):
if (self.volume_curr + step > self.volume_target):
step = self.volume_target - self.volume_curr
else:
step = -step
if (self.volume_curr + step < self.volume_target):
step = self.volume_target - self.volume_curr
if step != 0:
volume_next = self.volume_curr + step
self.set_volume(volume_next)
if volume_next == 0:
self.stop_sound()
2022-12-11 16:08:13 +01:00
def check_play_sound(self):
if self.settings.alarm_activated == False:
2022-12-11 16:08:13 +01:00
return
if (self.seconds_to_next_alarm < 0.1) or (self.settings.alarm_playing == True):
if self.settings.sound_source != "":
self.play_sound(self.settings.sound_source)
2022-12-11 16:08:13 +01:00
def calc_seconds_to_next_alarm(self):
if self.settings.alarm_activated == False:
2022-12-11 16:08:13 +01:00
return
# Make sure alarm_time is in the future but not more than 24 h from now
now = datetime.datetime.now()
d = self.settings.alarm_time - now
self.settings.alarm_time -= datetime.timedelta(days=d.days)
2022-12-11 16:08:13 +01:00
# Calculate number of seconds until next alarm
d = self.settings.alarm_time - now
2022-12-11 16:08:13 +01:00
self.seconds_to_next_alarm = d.days * 24 * 3600 + d.seconds + d.microseconds / 1000000.0
def check_alarm(self):
self.calc_seconds_to_next_alarm()
2023-04-09 23:53:37 +02:00
self.process_led_state()
self.set_leds()
self.update_backlight()
2022-12-11 16:08:13 +01:00
self.check_play_sound()
2023-04-23 16:06:05 +02:00
self.process_volume_state()
2022-12-11 16:08:13 +01:00
2023-01-06 22:39:31 +01:00
def update_clock(self):
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face_plate"], False])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face"], False])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["hands"], False])
2023-05-28 23:22:05 +02:00
if self.view == "clock":
if len(self.uvi) > 0:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_uvi"], False])
if len(self.pollen) > 0:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_pollen"], False])
if len(self.aqi) > 0:
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_aqi"], False])
2023-01-15 11:58:53 +01:00
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
t = self.settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
t = datetime.datetime.now()
2022-12-11 16:08:13 +01:00
hands = self.ids["hands"]
seconds_hand = self.position_on_clock(t.second/60, length=0.45*hands.size[0])
minutes_hand = self.position_on_clock(t.minute/60+t.second/3600, length=0.38*hands.size[0])
hours_hand = self.position_on_clock(t.hour/12 + t.minute/720, length=0.32*hands.size[0])
2022-12-11 16:08:13 +01:00
self.draw_list_curr_frame.append(["canvas.clear()", hands])
2023-01-15 11:58:53 +01:00
update_rate = App.get_running_app().update_rate
2022-12-11 16:08:13 +01:00
with hands.canvas:
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
2023-01-15 11:58:53 +01:00
if self.grabbed != "" or self.set_alarm_timeout_counter < 1 * update_rate or \
self.set_alarm_timeout_counter % update_rate <= update_rate / 2 or self.settings.alarm_modified == False:
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_alarm_hands_hours[0], self.theme.color_alarm_hands_hours[1], self.theme.color_alarm_hands_hours[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_alarm_hands_minutes[0], self.theme.color_alarm_hands_minutes[1], self.theme.color_alarm_hands_minutes[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
2022-12-11 16:08:13 +01:00
if self.grabbed == "":
self.set_alarm_timeout_counter += 1
2023-01-15 11:58:53 +01:00
if self.set_alarm_timeout_counter >= 4.5 * update_rate:
2023-01-06 20:18:22 +01:00
self.view = "clock"
2023-04-23 21:23:23 +02:00
self.settings.write()
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
self.view_active_since = time.time()
2022-12-11 16:08:13 +01:00
if self.settings.alarm_modified:
self.settings.alarm_activated = True
self.settings.alarm_modified = False
2022-12-11 16:08:13 +01:00
else:
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_hours[0], self.theme.color_clock_hands_hours[1], self.theme.color_clock_hands_hours[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_minutes[0], self.theme.color_clock_hands_minutes[1], self.theme.color_clock_hands_minutes[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_seconds[0], self.theme.color_clock_hands_seconds[1], self.theme.color_clock_hands_seconds[2]])
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], 1, "round"])
2023-04-11 22:49:58 +02:00
self.update_face()
2022-12-11 16:08:13 +01:00
2023-04-13 22:42:58 +02:00
def update_settings_menu(self):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_background"], False])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], False])
background = self.ids["settings_menu_background"]
self.draw_list_curr_frame.append(["canvas.clear()", background])
with background.canvas:
rgb = self.theme.color_shade
self.draw_list_curr_frame.append(["Color", background.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, ""])
for s in ["label_0", "label_1", "label_2", "label_3", "label_4", "label_5", "theme_select_button", "wake_up_sound_select_button"]:
i = self.ids["settings_menu_" + s]
i.color = self.theme.color_font
i = self.ids["settings_menu_theme_select_button"]
i.background_color = self.theme.color_button
i = self.ids["settings_menu_wake_up_sound_select_button"]
i.background_color = self.theme.color_button
def update_settings_menu_wake_up_sound(self):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound_background"], False])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], False])
background = self.ids["settings_menu_wake_up_sound_background"]
self.draw_list_curr_frame.append(["canvas.clear()", background])
with background.canvas:
rgb = self.theme.color_shade
self.draw_list_curr_frame.append(["Color", background.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, ""])
for i in self.wake_up_sound_labels:
2023-04-13 22:42:58 +02:00
i.color = self.theme.color_font
self.settings_menu_wake_up_sound_Ok_button.background_color = self.theme.color_button
2023-04-13 22:42:58 +02:00
def update_settings_menu_theme(self):
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme_background"], False])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme"], False])
background = self.ids["settings_menu_theme_background"]
self.draw_list_curr_frame.append(["canvas.clear()", background])
with background.canvas:
rgb = self.theme.color_shade
self.draw_list_curr_frame.append(["Color", background.canvas, rgb[0], rgb[1], rgb[2]])
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, ""])
2023-04-16 22:14:10 +02:00
for i in self.theme_labels:
2023-04-13 22:42:58 +02:00
i.color = self.theme.color_font
2023-04-16 22:14:10 +02:00
self.settings_menu_theme_Ok_button.background_color = self.theme.color_button
2023-04-13 22:42:58 +02:00
2023-01-06 22:39:31 +01:00
def update_settings(self):
2023-01-08 22:11:18 +01:00
if self.view == "settings_menu":
2023-04-13 22:42:58 +02:00
self.update_settings_menu()
2023-01-08 22:11:18 +01:00
elif self.view == "settings_menu_wake_up_sound":
2023-04-13 22:42:58 +02:00
self.update_settings_menu_wake_up_sound()
2023-04-11 22:49:58 +02:00
elif self.view == "settings_menu_theme":
2023-04-13 22:42:58 +02:00
self.update_settings_menu_theme()
2023-01-06 22:39:31 +01:00
def draw_display(self):
2023-04-13 22:42:58 +02:00
t = time.time()
if (self.view != self.view_prev) or (t - self.view_active_since < self.time_to_force_redraws_after_view_change):
2023-04-13 22:42:58 +02:00
self.draw_list_last_frame = [] # force redraw when view has changed
self.view_prev = self.view
if self.draw_list_curr_frame != self.draw_list_last_frame:
for i in self.draw_list_curr_frame:
if i[0] == "self.hide_widget":
self.hide_widget(i[1], i[2])
elif i[0] == "canvas.clear()":
i[1].canvas.clear()
elif i[0] == "Color":
with i[1]:
2023-04-13 22:42:58 +02:00
if len(i) == 5:
Color(i[2], i[3], i[4])
else:
Color(i[2], i[3], i[4], i[5])
elif i[0] == "Rectangle":
with i[1]:
Rectangle(size=i[2], pos=i[3], source=i[4])
2023-04-11 22:49:58 +02:00
elif i[0] == "Ellipse":
with i[1]:
Ellipse(size=i[2], pos=i[3])
elif i[0] == "Circle":
with i[1]:
Line(circle=(i[2][0], i[2][1], i[3]), width=4)
elif i[0] == "Line":
with i[1]:
Line(points=i[2], width=i[3], cap=i[4])
else:
print("Unknown draw command: " + i[0])
self.draw_list_last_frame = self.draw_list_curr_frame
self.draw_list_curr_frame = []
def process_touch_events(self):
t = time.time()
if (self.touch_down_event_curr is not None) and (self.touch_down_event_curr.processed == False) and \
(t - self.touch_down_event_curr.time > self.touch_delay_time):
self.touch_down_function(self.touch_down_event_curr.touch)
self.touch_down_event_curr.processed = True
self.touch_down_event_prev = copy.copy(self.touch_down_event_curr)
self.touch_down_event_curr = None
if (self.touch_move_event_curr is not None) and (self.touch_move_event_curr.processed == False) and \
(t - self.touch_move_event_curr.time > self.touch_delay_time):
self.touch_move_function(self.touch_move_event_curr.touch)
self.touch_move_event_curr.processed = True
self.touch_move_event_prev = copy.copy(self.touch_move_event_curr)
self.touch_move_event_curr = None
if (self.touch_up_event_curr is not None) and (self.touch_up_event_curr.processed == False) and \
(t - self.touch_up_event_curr.time > self.touch_delay_time):
self.touch_up_function(self.touch_up_event_curr.touch)
self.touch_up_event_curr.processed = True
self.touch_up_event_prev = copy.copy(self.touch_up_event_curr)
self.touch_up_event_curr = None
2023-01-06 22:39:31 +01:00
def update_display(self, *args):
self.process_touch_events()
2023-01-07 16:45:47 +01:00
self.check_alarm()
2023-01-06 22:39:31 +01:00
# Hide all dynamic widgets; will be enabled when updating respecive view
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face_plate"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["hands"], True])
2023-04-13 22:42:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_background"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], True])
2023-04-13 22:42:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound_background"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], True])
2023-04-13 22:42:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme_background"], True])
2023-04-11 22:49:58 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme"], True])
2023-05-28 23:22:05 +02:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_uvi"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_pollen"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["icon_aqi"], True])
2023-01-06 22:39:31 +01:00
self.update_theme()
self.update_light_button()
2023-04-09 15:00:04 +02:00
self.update_play_button()
2023-01-06 22:39:31 +01:00
self.update_set_alarm_button()
self.update_settings_button()
if self.view == "clock" or self.view == "set_alarm":
self.update_clock()
2023-01-08 22:11:18 +01:00
elif self.view.startswith("settings_menu"):
2023-01-06 22:39:31 +01:00
self.update_settings()
else:
print("unknown view: " + self.view)
self.draw_display()
2023-01-06 22:39:31 +01:00
2023-01-08 22:11:18 +01:00
def settings_menu_wake_up_sound_select_button_cb(self):
self.settings_menu_wake_up_sound_select_button_cb_hack = True
2023-01-15 11:58:53 +01:00
for c in self.wake_up_sound_checkboxes:
c.active = False
print("sound selected: " + self.settings.sound_selected)
n = 0
for i in self.wake_up_sounds:
if i == self.settings.sound_selected:
self.wake_up_sound_checkboxes[n].active = True
n = n + 1
2023-01-08 22:11:18 +01:00
self.view = "settings_menu_wake_up_sound"
self.view_active_since = time.time()
2023-01-08 22:11:18 +01:00
def settings_menu_wake_up_sound_Ok_button_cb(self, event):
self.ids["settings_menu_wake_up_sound_select_button"].text = self.settings.sound_selected
2023-01-08 22:11:18 +01:00
self.view = "settings_menu"
self.view_active_since = time.time()
2023-01-08 22:11:18 +01:00
def settings_menu_wake_up_sound_cb(self, instance, value):
n = 0
for c in self.wake_up_sound_checkboxes:
if c == instance:
break
n = n + 1
k = 0
for sound in self.wake_up_sounds:
if k == n:
break
k = k + 1
2023-01-08 22:11:18 +01:00
if self.settings_menu_wake_up_sound_select_button_cb_hack:
self.settings_menu_wake_up_sound_select_button_cb_hack = False
if not (self.settings.sound_selected == "" and sound != ""):
2023-01-08 22:11:18 +01:00
return
if value == True:
print("You selected " + sound)
else:
print("You deselected " + sound)
self.settings.sound_source = self.wake_up_sounds[sound]
self.settings.sound_selected = sound
2023-01-08 22:11:18 +01:00
2023-04-16 22:14:10 +02:00
2023-04-11 22:49:58 +02:00
def settings_menu_theme_select_button_cb(self):
2023-04-16 22:14:10 +02:00
self.settings_menu_theme_select_button_cb_hack = True
for c in self.theme_checkboxes:
c.active = False
print("theme selected: " + self.settings.theme_selected)
2023-04-16 22:14:10 +02:00
n = 0
print("self.themes: " + str(self.themes))
for i in self.themes:
if i == self.settings.theme_selected:
2023-04-16 22:14:10 +02:00
self.theme_checkboxes[n].active = True
n = n + 1
2023-04-11 22:49:58 +02:00
self.view = "settings_menu_theme"
self.view_active_since = time.time()
2023-04-16 22:14:10 +02:00
def settings_menu_theme_Ok_button_cb(self, event):
self.ids["settings_menu_theme_select_button"].text = self.settings.theme_selected
2023-04-11 22:49:58 +02:00
self.view = "settings_menu"
self.view_active_since = time.time()
2023-04-16 22:14:10 +02:00
def settings_menu_theme_cb(self, instance, value):
n = 0
for c in self.theme_checkboxes:
if c == instance:
break
n = n + 1
k = 0
for theme in self.themes:
if k == n:
break
k = k + 1
2023-04-11 22:49:58 +02:00
if self.settings_menu_theme_select_button_cb_hack:
self.settings_menu_theme_select_button_cb_hack = False
if not (self.settings.theme_selected == "" and theme != ""):
2023-04-11 22:49:58 +02:00
return
if value == True:
print("You selected " + theme)
else:
print("You deselected " + theme)
self.settings.theme_selected = theme
self.apply_theme()
self.settings.write()
2023-04-11 22:49:58 +02:00
2023-01-06 22:39:31 +01:00
def volume_slider_value(self, *args):
self.settings.wake_up_volume = int(args[1])
2023-01-07 16:09:28 +01:00
old_vol = self.mixer.getvolume()
if (self.settings.alarm_playing) and (self.player.get_state() == vlc.State.Playing):
# immediately set volume when audio is playing
self.volume_target = self.settings.wake_up_volume / 20.0
self.set_volume(self.volume_target)
new_vol = self.mixer.getvolume()
2023-01-07 16:09:28 +01:00
def wake_up_brightness_slider_value(self, *args):
self.settings.wake_up_brightness = int(args[1])
print("Wake up brightness changed to " + str(self.settings.wake_up_brightness))
2023-01-07 16:09:28 +01:00
def reading_light_brightness_slider_value(self, *args):
self.settings.reading_light_brightness = int(args[1])
2023-04-10 15:25:34 +02:00
if (self.light_state == "reading"):
self.intensity_target = self.settings.reading_light_brightness / 20.0
print("Reading light brightness changed to " + str(self.settings.reading_light_brightness))
2023-01-07 16:09:28 +01:00
def display_brightness_slider_value(self, *args):
self.settings.display_brightness = int(args[1])
2023-01-06 22:39:31 +01:00
def on_light_button_pressed(self):
print("light button pressed from view " + self.view)
2023-04-09 22:34:59 +02:00
2023-04-09 23:53:37 +02:00
if self.light_state == "off":
self.light_state = "reading"
self.intensity_target = self.settings.reading_light_brightness / 20.0
2023-04-09 23:53:37 +02:00
elif self.light_state == "reading":
self.light_state = "off"
self.intensity_target = 0
if self.settings.alarm_playing:
2023-04-23 16:06:05 +02:00
self.volume_target = 0
2023-04-09 23:53:37 +02:00
elif self.light_state == "sunrise":
# allow enabling reading mode when sunrise has not yet reached that level
if self.intensity_target < self.settings.reading_light_brightness / 20.0:
2023-04-09 23:53:37 +02:00
self.light_state = "reading"
self.intensity_target = self.settings.reading_light_brightness / 20.0
2023-04-09 23:53:37 +02:00
else:
self.light_state = "off"
elif self.light_state == "on":
self.light_state = "reading"
self.intensity_target = 0
2023-04-09 15:00:04 +02:00
def on_play_button_pressed(self):
print("play button pressed from view " + self.view)
if self.settings.alarm_playing:
2023-04-23 16:06:05 +02:00
self.volume_target = 0
2023-04-09 15:00:04 +02:00
else:
self.play_sound(self.settings.sound_source)
2023-04-09 15:00:04 +02:00
2022-12-11 16:08:13 +01:00
def on_alarm_button_pressed(self):
print("alarm button pressed from view " + self.view)
2023-01-15 11:58:53 +01:00
self.settings.alarm_modified = False
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
self.view = "clock"
self.view_active_since = time.time()
self.settings.alarm_activated = False
2023-04-23 21:23:23 +02:00
self.settings.write()
2022-12-11 16:08:13 +01:00
else:
2023-04-23 21:23:23 +02:00
if (self.view.startswith("settings_menu")):
self.settings.write()
2023-01-06 20:18:22 +01:00
self.view = "set_alarm"
self.view_active_since = time.time()
self.settings.alarm_activated = True
2022-12-11 16:08:13 +01:00
2023-01-06 22:39:31 +01:00
def on_settings_button_pressed(self):
print("settings button pressed from view " + self.view)
2023-01-08 22:11:18 +01:00
if self.view != "settings_menu":
self.view = "settings_menu"
self.view_active_since = time.time()
2023-01-06 22:39:31 +01:00
else:
self.view = "clock"
self.view_active_since = time.time()
2023-04-23 21:23:23 +02:00
self.settings.write()
2023-01-06 22:39:31 +01:00
print("view updated to " + self.view)
def touch_up_function(self, touch):
2022-12-11 16:08:13 +01:00
self.grabbed = ""
self.light_button_move_init = []
2023-01-05 22:02:22 +01:00
2023-01-15 11:58:53 +01:00
2023-01-06 20:18:22 +01:00
if (self.view == "set_alarm") and (self.grabbed == "hour" or self.grabbed == "minute"):
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
2023-01-06 22:39:31 +01:00
super(MyClockWidget, self).on_touch_up(touch)
def touch_move_function(self, touch):
if self.grabbed == "":
return
2022-12-11 16:08:13 +01:00
self.alarm_set_timeout = 0
touch_curr = Touch(touch)
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen
tol = 0.5 # 0.5 is equal to 90 degrees
inc = 1 # 1 is equal to 180 degrees
if (self.touch_prev.is_empty == False) and (touch_curr.angle - self.touch_prev.angle >= tol):
touch_curr.spos[0] = 1 - touch_curr.spos[0]
touch_curr.spos[1] = 1 - touch_curr.spos[1]
touch_curr.corrected = True
while touch_curr.angle - self.touch_prev.angle >= tol:
touch_curr.angle -= inc
elif (self.touch_prev.is_empty == False) and (touch_curr.angle - self.touch_prev.angle <= -tol):
touch_curr.spos[0] = 1 - touch_curr.spos[0]
touch_curr.spos[1] = 1 - touch_curr.spos[1]
touch_curr.corrected = True
while touch_curr.angle - self.touch_prev.angle <= -tol:
touch_curr.angle += inc
self.touch_prev = copy.deepcopy(touch_curr)
2022-12-11 16:08:13 +01:00
if self.grabbed == "minute":
self.settings.alarm_modified = True
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
minute = round(-touch_curr.angle * 30 + 15)
while minute < 0:
2022-12-11 16:08:13 +01:00
minute += 60
while minute >= 60:
minute -= 60
# Sometimes the hand is 30 minutes ahead / behind the place where the user touches the screen --> correct for this behavior
if (((minute - self.settings.alarm_time.minute) >= 15) and ((minute - self.settings.alarm_time.minute) <= 45)):
minute = minute - 30
elif (((minute - self.settings.alarm_time.minute) <= -15) and ((minute - self.settings.alarm_time.minute) >= -45)):
minute = minute + 30
while minute < 0:
minute += 60
while minute >= 60:
minute -= 60
2022-12-11 16:08:13 +01:00
# hour correction
hour = self.settings.alarm_time.hour
if self.settings.alarm_time.minute >= 55 and minute <= 5:
2022-12-11 16:08:13 +01:00
hour += 1
elif self.settings.alarm_time.minute <= 5 and minute >= 55:
2022-12-11 16:08:13 +01:00
hour -= 1
while hour < 0:
hour += 24
while hour >= 24:
hour -= 24
2022-12-11 16:08:13 +01:00
self.settings.alarm_time = datetime.datetime(self.settings.alarm_time.year, \
self.settings.alarm_time.month, self.settings.alarm_time.day, \
hour, minute, self.settings.alarm_time.second, 0)
2022-12-11 16:08:13 +01:00
elif self.grabbed == "hour":
self.settings.alarm_modified = True
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
hour = round(-touch_curr.angle * 6 + 3)
while hour < 0:
2022-12-11 16:08:13 +01:00
hour += 12
while hour >= 12:
hour -= 12
# Sometimes the hand is 6 hours ahead / behind the place where the user touches the screen --> correct for this behavior
if (((hour - self.settings.alarm_time.hour) >= 3) and ((hour - self.settings.alarm_time.hour) <= 9)):
hour = hour - 6
if (((hour - self.settings.alarm_time.hour) <= -3) and ((hour - self.settings.alarm_time.hour) >= -9)):
hour = hour + 6
while hour < 0:
hour += 12
while hour >= 12:
hour -= 12
2022-12-11 16:08:13 +01:00
if self.settings.alarm_time.hour >= 12:
2022-12-11 16:08:13 +01:00
hour += 12
2022-12-11 16:08:13 +01:00
# AM / PM correction
if self.settings.alarm_time.hour == 11 and hour == 0:
2022-12-11 16:08:13 +01:00
hour = 12
elif self.settings.alarm_time.hour == 23 and hour == 12:
2022-12-11 16:08:13 +01:00
hour = 0
elif self.settings.alarm_time.hour == 0 and hour == 11:
2022-12-11 16:08:13 +01:00
hour = 23
elif self.settings.alarm_time.hour == 12 and hour == 23:
2022-12-11 16:08:13 +01:00
hour = 11
minute = self.settings.alarm_time.minute
self.settings.alarm_time = datetime.datetime(self.settings.alarm_time.year, \
self.settings.alarm_time.month, self.settings.alarm_time.day, \
hour, self.settings.alarm_time.minute, self.settings.alarm_time.second, 0)
2022-12-11 16:08:13 +01:00
elif self.grabbed == "light_button":
if len(self.light_button_move_init) == 0:
self.light_button_move_init = touch_curr.spos
d = touch_curr.spos[0] - self.light_button_move_init[0]
threshold = 0.05
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen: mirror d if position is on other side
if self.light_button_move_init[0] > 0.5:
d = -d
if d > 0.05:
# move to the right: set light to wake up level
self.light_state = "on"
elif d < -0.05:
# move to the left: set light off
self.light_state = "off"
2023-01-06 22:39:31 +01:00
super(MyClockWidget, self).on_touch_move(touch)
def touch_down_function(self, touch):
t = self.settings.alarm_time
2022-12-11 16:08:13 +01:00
hands = self.ids["hands"]
minutes_hand = self.position_on_clock(t.minute/60+t.second/3600, length=0.40*hands.size[0])
hours_hand = self.position_on_clock(t.hour/12 + t.minute/720, length=0.35*hands.size[0])
2022-12-11 16:08:13 +01:00
2023-08-01 12:10:09 +02:00
if (0.02 <= touch.spos[0] <= 0.28) and (0.82 <= touch.spos[1] <= 0.98):
if self.grabbed == "":
self.grabbed = "light_button"
self.on_light_button_pressed()
2023-08-01 12:10:09 +02:00
elif (0.02 <= touch.spos[0] <= 0.18) and (0.02 <= touch.spos[1] <= 0.18):
2023-04-09 15:00:04 +02:00
self.on_play_button_pressed()
2023-08-01 12:10:09 +02:00
elif (0.82 <= touch.spos[0] <= 0.98) and (0.02 <= touch.spos[1] <= 0.18):
2022-12-11 16:08:13 +01:00
self.on_alarm_button_pressed()
2023-08-01 12:10:09 +02:00
elif (0.82 <= touch.spos[0] <= 0.98) and (0.82 <= touch.spos[1] <= 0.98):
2023-01-06 22:39:31 +01:00
self.on_settings_button_pressed()
2023-01-06 20:18:22 +01:00
elif self.view == "set_alarm":
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
if self.grabbed == "":
if (minutes_hand.x - 0.1 * self.size[0] <= touch.pos[0] <= minutes_hand.x + 0.1 * self.size[0]) and \
(minutes_hand.y - 0.1 * self.size[1] <= touch.pos[1] <= minutes_hand.y + 0.1 * self.size[1]):
self.grabbed = "minute"
self.touch_prev.clear()
elif (hours_hand.x - 0.1 * self.size[0] <= touch.pos[0] <= hours_hand.x + 0.1 * self.size[0]) and \
(hours_hand.y - 0.1 * self.size[1] <= touch.pos[1] <= hours_hand.y + 0.1 * self.size[1]):
self.grabbed = "hour"
self.touch_prev.clear()
else:
self.grabbed = ""
2023-01-08 22:11:18 +01:00
elif self.view == "settings_menu":
2023-01-07 16:09:28 +01:00
pass
elif self.view == "settings_menu_wake_up_sound":
pass
2023-04-11 22:49:58 +02:00
elif self.view == "settings_menu_theme_select":
pass
2023-01-07 16:09:28 +01:00
elif self.view == "clock":
2023-04-23 16:06:05 +02:00
self.volume_target = 0
2022-12-11 16:08:13 +01:00
2023-01-06 22:39:31 +01:00
super(MyClockWidget, self).on_touch_down(touch)
def on_touch_down(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
2023-04-11 22:49:58 +02:00
"""
if self.touch_down_event_prev is None:
print("touch down at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch down at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_down_event_prev.time) + " on " + str(self.touch_down_event_prev.touch.spos))
2023-04-11 22:49:58 +02:00
"""
if after:
self.touch_down_event_curr = TouchEvent(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))
return super(MyClockWidget, self).on_touch_down(touch)
def on_touch_move(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
2023-04-11 22:49:58 +02:00
"""
if self.touch_move_event_prev is None:
print("touch move at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch move at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_move_event_prev.time) + " on " + str(self.touch_move_event_prev.touch.spos))
2023-04-11 22:49:58 +02:00
"""
if after:
# Do not delay processing of move events
self.touch_move_function(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_move(touch, True))
return super(MyClockWidget, self).on_touch_move(touch)
def on_touch_up(self, touch, after=False):
t = time.time()
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
return True
2023-04-11 22:49:58 +02:00
"""
if self.touch_up_event_prev is None:
print("touch up at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event: None")
else:
print("touch up at " + str(t) + " on " + str(touch.spos) + ", after: " + str(after) + ", prev event at " + str(self.touch_up_event_prev.time) + " on " + str(self.touch_up_event_prev.touch.spos))
2023-04-11 22:49:58 +02:00
"""
if after:
self.touch_up_event_curr = TouchEvent(touch)
return True
else:
Clock.schedule_once(lambda dt: self.on_touch_up(touch, True))
return super(MyClockWidget, self).on_touch_up(touch)
2023-01-06 22:39:31 +01:00
2022-12-11 16:08:13 +01:00
class MyApp(App):
2023-01-15 11:58:53 +01:00
update_rate = 60.0
2023-01-05 22:02:22 +01:00
2022-12-11 16:08:13 +01:00
def build(self):
clock_widget = MyClockWidget()
2023-04-16 22:14:10 +02:00
clock_widget.add_wake_up_sounds()
clock_widget.add_themes()
2023-01-15 11:58:53 +01:00
update_rate = App.get_running_app().update_rate
2022-12-11 16:08:13 +01:00
# update initially, just after construction of the widget is complete
2023-01-06 22:39:31 +01:00
Clock.schedule_once(clock_widget.update_display, 0)
2023-01-15 11:58:53 +01:00
# then update at update_rate times per second
Clock.schedule_interval(clock_widget.update_display, 1.0/update_rate)
Clock.schedule_once(clock_widget.get_air_quality, 0)
t = datetime.datetime.now()
delay = 58 - (t.second + t.microsecond / 1000000)
if delay < 0:
delay = delay + 60
Clock.schedule_once(clock_widget.sync_air_quality, delay)
if is_arm():
Window.borderless = True
2023-04-23 16:06:05 +02:00
# Volume is in 0-1.0 range
old_vol = clock_widget.mixer.getvolume()
clock_widget.volume_target = clock_widget.settings.wake_up_volume / 20.0
new_vol = clock_widget.mixer.getvolume()
print("HW volume changed from " + str(old_vol) + " to " + str(new_vol))
2023-04-23 20:31:28 +02:00
clock_widget.apply_settings()
2022-12-11 16:08:13 +01:00
return clock_widget
def except_hook(type, value, tb):
2023-04-09 22:34:59 +02:00
if is_arm():
pixels.fill((0, 0, 0, 0))
pixels.show()
2023-04-11 22:49:58 +02:00
backlight.brightness = 50
2023-04-08 21:37:28 +02:00
return
2022-12-11 16:08:13 +01:00
if __name__ == '__main__':
2023-04-11 22:49:58 +02:00
if is_arm():
sys.excepthook = except_hook
2022-12-11 16:08:13 +01:00
MyApp().run()