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
2023-04-08 17:10:44 +02:00
import copy
2023-04-23 14:00:45 +02:00
from os import uname , walk
2023-04-09 15:52:52 +02:00
from kivy . config import Config
2023-04-11 22:49:58 +02:00
from kivy . properties import ObjectProperty
2023-04-10 22:11:21 +02:00
import time
2023-04-16 17:32:26 +02:00
from sounds import WakeUpSounds
2023-04-23 18:26:37 +02:00
import json
2023-05-05 22:44:13 +02:00
from hsluv import hsluv_to_rgb , rgb_to_hsluv
2023-05-26 22:54:30 +02:00
import requests
2023-05-27 09:57:38 +02:00
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
2023-04-08 23:07:59 +02:00
def is_arm ( ) :
2023-04-23 14:00:45 +02:00
if ( uname ( ) [ 4 ] [ : 3 ] == ' arm ' ) or ( uname ( ) [ 4 ] [ : 7 ] == ' aarch64 ' ) :
2023-04-08 23:07:59 +02:00
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
2023-04-09 22:40:52 +02:00
from rgbw_colorspace_converter . colors . converters import HSV , RGB
2023-04-09 15:52:52 +02:00
2023-04-10 23:12:31 +02:00
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
num_pixels = 144
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 ( )
2023-04-09 15:52:52 +02:00
else :
Config . set ( ' graphics ' , ' width ' , ' 1200 ' )
Config . set ( ' graphics ' , ' height ' , ' 720 ' )
2023-04-08 23:07:59 +02:00
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
2023-02-17 21:27:33 +01: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
2023-04-16 17:00:21 +02:00
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
2023-04-10 22:11:21 +02:00
from kivy . core . window import Window
if is_arm ( ) :
Window . show_cursor = False
2022-12-11 16:08:13 +01:00
2023-04-23 13:24:02 +02: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 ( )
2023-04-26 11:00:23 +02:00
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
2023-04-08 17:10:44 +02:00
class Touch ( ) :
def __init__ ( self , x = None ) :
if x is None :
self . pos = [ ]
self . spos = [ ]
self . is_empty = True
self . angle = 0
2023-04-10 15:59:15 +02:00
self . corrected = False
2023-04-08 17:10:44 +02:00
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
2023-04-10 15:59:15 +02:00
self . corrected = False
2023-04-08 17:10:44 +02:00
def __repr__ ( self ) :
2023-04-10 15:59:15 +02:00
return " .is_empty: " + str ( self . is_empty ) + " , .pos: " + str ( self . pos ) + " , .spos: " + str ( self . spos ) , " , .corrected: " + str ( self . corrected )
2023-04-08 17:10:44 +02:00
def copy ( self , x ) :
self = Touch ( x )
def clear ( self ) :
self = Touch ( )
2023-04-10 22:11:21 +02:00
class TouchEvent ( ) :
def __init__ ( self , x = None ) :
self . time = time . time ( )
2023-04-10 23:12:31 +02:00
self . touch = copy . copy ( x )
2023-04-11 17:39:41 +02:00
self . processed = False
2023-04-10 22:11:21 +02:00
2023-04-23 19:34:03 +02:00
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 " ]
2023-05-27 09:57:38 +02:00
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 )
2023-04-23 19:34:03 +02:00
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
2023-05-27 10:12:48 +02:00
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-04-23 19:34:03 +02:00
2023-01-05 22:02:22 +01:00
class MyClockWidget ( FloatLayout ) :
2023-04-23 19:34:03 +02:00
settings = ClockSettings ( )
2023-04-25 11:20:41 +02:00
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
2023-04-23 13:24:02 +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"
2023-04-10 16:52:40 +02:00
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
2023-04-10 22:11:21 +02:00
# 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
2023-04-11 17:39:41 +02:00
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-04-10 22:11:21 +02:00
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 = " "
2023-04-11 17:39:41 +02:00
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)
2023-04-14 20:28:00 +02:00
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
2023-02-17 21:27:33 +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 = [ ]
2023-04-08 17:10:44 +02:00
touch_prev = Touch ( )
2023-04-10 15:59:15 +02:00
light_button_move_init = [ ]
2023-04-08 21:37:28 +02:00
vlc = vlc . Instance ( )
player = vlc . media_player_new ( )
2023-04-08 23:07:59 +02:00
is_arm = is_arm ( )
2023-05-26 22:54:30 +02:00
aqi_colors = [
2023-05-26 23:12:35 +02:00
[ 0.0 , 0.0 , 0.0 ] , # x < 1.0 black (good)
[ 0.0 , 0.0 , 255.0 / 255.0 ] , # 1.0 <= x < 2.0 blue (good)
[ 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)
[ 200.0 / 255.0 , 200.0 / 255.0 , 0.0 ] , # 5.0 <= x < 6.0 yellow (mediocre)
[ 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)
[ 70.0 / 255.0 , 0.0 , 255.0 / 255.0 ] , # 10.0 <= x purple (terrible)
2023-05-26 22:54:30 +02:00
]
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 ]
2023-05-26 22:54:30 +02:00
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-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
2023-05-26 22:54:30 +02:00
def get_air_quality ( self , * args ) :
2023-05-27 09:57:38 +02:00
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-26 22:54:30 +02:00
2023-05-27 09:58:47 +02:00
self . precipitation = [ ]
2023-05-26 22:54:30 +02:00
self . pollen = [ ]
self . aqi = [ ]
self . paqi = [ ]
self . uvi = [ ]
2023-05-27 09:43:20 +02:00
2023-05-26 22:54:30 +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-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 )
2023-05-26 22:54:30 +02:00
else :
print ( " Error retrieving air quality; got response " + str ( response ) )
2023-05-28 16:33:34 +02:00
def sync_air_quality ( self , * args ) :
Clock . schedule_interval ( self . get_air_quality , 60 )
2023-04-26 11:00:23 +02:00
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 ] )
2023-04-17 22:04:00 +02:00
def apply_theme ( self ) :
2023-04-23 19:34:03 +02:00
if self . settings . theme_selected == " Automatic " :
2023-04-26 11:00:23 +02:00
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 :
2023-05-29 09:01:52 +02:00
if self . theme . name != " Light " :
self . theme = Theme ( " Light " )
2023-04-26 11:00:23 +02:00
else :
2023-05-29 09:01:52 +02:00
if self . theme . name != " Dark " :
self . theme = Theme ( " Dark " )
2023-04-26 11:00:23 +02:00
self . update_background_automatic_sunrise ( )
2023-04-17 22:04:00 +02:00
else :
2023-04-26 11:00:23 +02:00
if self . theme . name != self . settings . theme_selected :
self . theme = Theme ( self . settings . theme_selected )
self . update_background_automatic_no_sunrise ( )
2023-04-17 22:04:00 +02:00
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 ,
)
2023-04-23 19:34:03 +02:00
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
2023-04-17 22:04:00 +02:00
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
2023-04-23 19:34:03 +02:00
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-16 17:00:21 +02:00
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 )
2023-04-23 19:34:03 +02:00
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 ( )
2023-04-23 19:34:03 +02:00
self . settings . alarm_playing = True
2023-04-08 21:37:28 +02:00
2023-04-11 17:39:41 +02:00
2023-04-08 21:37:28 +02:00
def stop_sound ( self ) :
self . player . stop ( )
2023-04-23 19:34:03 +02:00
self . settings . alarm_playing = False
2023-04-08 17:10:44 +02:00
2023-04-08 23:07:59 +02:00
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 ) )
2023-04-10 23:12:31 +02:00
if self . is_arm :
2023-04-11 22:49:58 +02:00
if backlight . brightness != z :
backlight . brightness = z
2023-04-08 23:07:59 +02:00
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
2023-05-29 10:46:45 +02:00
def is_widget_hidden ( self , widget ) :
return hasattr ( widget , ' saved_attrs ' )
2023-05-26 22:54:30 +02:00
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 " :
2023-04-23 19:34:03 +02:00
t = self . settings . alarm_time
2022-12-11 16:08:13 +01:00
else :
2023-04-10 22:11:21 +02:00
t = datetime . datetime . now ( )
2022-12-11 16:08:13 +01:00
for i in range ( 1 , 13 ) :
2023-04-10 22:11:21 +02:00
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 ) ,
2023-04-09 15:52:52 +02:00
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 :
2023-05-26 22:54:30 +02:00
return
face_plate = self . ids [ " face_plate " ]
with face_plate . canvas :
2023-05-28 23:15:55 +02:00
colors = self . calculate_colors ( x [ : 12 ] , x_thresholds )
2023-05-27 09:43:20 +02:00
2023-05-28 23:15:55 +02:00
for i in range ( 0 , 12 ) :
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 )
2023-05-29 10:46:45 +02:00
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
2023-05-29 10:46:45 +02:00
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 " )
self . pollen_color_prev = color
self . paint_icon ( color , img , " icon_ " + x_label )
return 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 " )
2023-05-29 10:46:45 +02:00
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
2023-05-29 10:46:45 +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 " )
2023-05-29 10:46:45 +02:00
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
2023-05-29 10:46:45 +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 " )
2023-05-29 10:46:45 +02:00
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
2023-05-29 10:46:45 +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-26 22:54:30 +02:00
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-05-26 22:54:30 +02:00
def draw_face ( self ) :
self . draw_numbers ( )
2023-04-25 11:20:41 +02:00
def update_theme ( self ) :
if self . settings . theme_selected == " Automatic " :
2023-04-26 11:00:23 +02:00
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 " :
2023-04-23 19:34:03 +02:00
t = self . settings . alarm_time
2022-12-11 16:08:13 +01:00
else :
2023-04-10 22:11:21 +02:00
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 != [ ] ) :
2023-05-26 22:54:30 +02:00
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 ( )
2023-05-26 22:54:30 +02:00
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 ] )
2023-05-26 22:54:30 +02:00
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
)
2023-04-09 15:32:11 +02: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 ]
2023-04-09 15:32:11 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
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 " ]
2023-02-17 21:27:33 +01:00
self . draw_list_curr_frame . append ( [ " canvas.clear() " , set_alarm_button ] )
2022-12-11 16:08:13 +01:00
with set_alarm_button . canvas :
2023-02-17 21:27:33 +01:00
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 " ]
2023-02-17 21:27:33 +01:00
self . draw_list_curr_frame . append ( [ " canvas.clear() " , settings_button ] )
2023-01-06 22:39:31 +01:00
with settings_button . canvas :
2023-02-17 21:27:33 +01:00
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
2023-04-25 11:20:41 +02: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
2023-05-05 22:44:13 +02:00
# 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
2023-05-05 22:44:13 +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 ] )
2023-04-25 11:20:41 +02:00
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
2023-04-10 23:12:31 +02:00
def update_backlight ( self ) :
# make sure brightness of display is never lower than intensity of leds
brightness_min = 20 * self . intensity_curr
2023-04-23 19:34:03 +02:00
if self . settings . display_brightness < brightness_min :
2023-04-10 23:12:31 +02:00
self . set_backlight ( brightness_min )
else :
2023-04-23 19:34:03 +02:00
self . set_backlight ( self . settings . display_brightness )
2023-04-10 23:12:31 +02:00
2023-04-09 23:53:37 +02:00
def set_leds ( self ) :
2023-04-10 16:52:40 +02:00
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 :
2023-04-10 16:52:40 +02:00
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
2023-04-10 22:11:21 +02:00
# 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 :
2023-04-10 16:52:40 +02:00
# 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
2023-04-10 22:11:21 +02:00
# 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
2023-04-09 22:40:52 +02:00
return
2023-04-09 23:53:37 +02:00
if self . seconds_to_next_alarm < 0.1 :
2023-04-23 19:34:03 +02:00
intensity_target = ( self . settings . wake_up_brightness / 20.0 )
2023-04-10 15:25:34 +02:00
new_state = " on "
else :
2023-04-23 19:34:03 +02:00
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
2023-04-10 16:52:40 +02: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 ) :
2023-04-23 19:34:03 +02:00
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 " ) :
2023-04-10 16:52:40 +02:00
self . intensity_target = 0
2023-04-09 23:53:37 +02:00
elif ( self . light_state == " reading " ) :
2023-04-23 19:34:03 +02:00
self . intensity_target = self . settings . reading_light_brightness / 20.0
2023-04-09 23:53:37 +02:00
elif ( self . light_state == " on " ) :
2023-04-23 19:34:03 +02:00
self . intensity_target = self . settings . wake_up_brightness / 20.0
2023-04-10 16:52:40 +02:00
2023-04-10 22:11:21 +02:00
weight = 0.05
intensity_next = weight * self . intensity_target + ( 1 - weight ) * self . intensity_curr
step = intensity_next - self . intensity_curr
2023-04-10 16:52:40 +02:00
2023-04-10 22:11:21 +02:00
if abs ( step ) < 0.001 :
step = self . intensity_target - self . intensity_curr
2023-04-10 16:52:40 +02:00
2023-04-10 22:11:21 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
if self . settings . alarm_activated == False :
2022-12-11 16:08:13 +01:00
return
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
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 ( )
2023-04-23 19:34:03 +02:00
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
2023-04-23 19:34:03 +02:00
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 ( )
2023-04-10 23:12:31 +02:00
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 ] )
2023-02-17 21:27:33 +01:00
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-29 10:46:45 +02:00
2023-05-28 23:22:05 +02:00
if self . view == " clock " :
2023-05-29 10:46:45 +02:00
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 " :
2023-04-23 19:34:03 +02:00
t = self . settings . alarm_time
2022-12-11 16:08:13 +01:00
else :
2023-04-10 22:11:21 +02:00
t = datetime . datetime . now ( )
2022-12-11 16:08:13 +01:00
hands = self . ids [ " hands " ]
2023-04-10 22:11:21 +02:00
seconds_hand = self . position_on_clock ( t . second / 60 , length = 0.45 * hands . size [ 0 ] )
2023-05-27 10:12:48 +02:00
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
2023-02-17 21:27:33 +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 \
2023-04-23 19:34:03 +02:00
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 ] ] )
2023-02-17 21:27:33 +01:00
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 ] ] )
2023-02-17 21:27:33 +01:00
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
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2022-12-11 16:08:13 +01:00
2023-04-23 19:34:03 +02: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 ] ] )
2023-02-17 21:27:33 +01:00
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 ] ] )
2023-02-17 21:27:33 +01:00
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 ] ] )
2023-02-17 21:27:33 +01:00
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 , " " ] )
2023-04-16 17:00:21 +02:00
for i in self . wake_up_sound_labels :
2023-04-13 22:42:58 +02:00
i . color = self . theme . color_font
2023-04-16 17:00:21 +02:00
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
2023-02-17 21:27:33 +01:00
def draw_display ( self ) :
2023-04-13 22:42:58 +02:00
t = time . time ( )
2023-04-14 20:28:00 +02:00
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
2023-02-17 21:27:33 +01:00
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 ] )
2023-02-17 21:27:33 +01:00
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 ] )
2023-04-25 11:20:41 +02:00
elif i [ 0 ] == " Circle " :
with i [ 1 ] :
Line ( circle = ( i [ 2 ] [ 0 ] , i [ 2 ] [ 1 ] , i [ 3 ] ) , width = 4 )
2023-02-17 21:27:33 +01:00
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 = [ ]
2023-04-10 22:11:21 +02:00
def process_touch_events ( self ) :
t = time . time ( )
2023-04-11 17:39:41 +02:00
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-02-17 21:27:33 +01:00
2023-01-06 22:39:31 +01:00
def update_display ( self , * args ) :
2023-04-10 22:11:21 +02:00
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 ] )
2023-02-17 21:27:33 +01:00
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 ] )
2023-02-17 21:27:33 +01:00
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 ] )
2023-02-17 21:27:33 +01:00
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
2023-04-25 11:20:41 +02:00
self . update_theme ( )
2023-04-09 15:32:11 +02:00
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 ( )
2023-02-17 21:27:33 +01:00
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
2023-04-16 17:00:21 +02:00
for c in self . wake_up_sound_checkboxes :
c . active = False
2023-04-23 19:34:03 +02:00
print ( " sound selected: " + self . settings . sound_selected )
2023-04-16 17:00:21 +02:00
n = 0
for i in self . wake_up_sounds :
2023-04-23 19:34:03 +02:00
if i == self . settings . sound_selected :
2023-04-16 17:00:21 +02:00
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 "
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2023-01-08 22:11:18 +01:00
2023-04-16 17:00:21 +02:00
def settings_menu_wake_up_sound_Ok_button_cb ( self , event ) :
2023-04-23 19:34:03 +02:00
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 "
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2023-01-08 22:11:18 +01:00
2023-04-16 17:00:21 +02: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
2023-04-23 19:34:03 +02:00
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 )
2023-04-23 19:34:03 +02:00
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
2023-04-23 19:34:03 +02:00
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 :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
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
2023-04-23 19:34:03 +02:00
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 )
2023-04-23 19:34:03 +02:00
self . settings . theme_selected = theme
2023-04-17 22:04:00 +02:00
self . apply_theme ( )
2023-04-26 11:00:23 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
self . settings . wake_up_volume = int ( args [ 1 ] )
2023-01-07 16:09:28 +01:00
2023-04-23 13:24:02 +02:00
old_vol = self . mixer . getvolume ( )
2023-04-23 16:32:05 +02:00
2023-04-23 19:34:03 +02:00
if ( self . settings . alarm_playing ) and ( self . player . get_state ( ) == vlc . State . Playing ) :
2023-04-23 16:32:05 +02:00
# immediately set volume when audio is playing
2023-04-23 19:34:03 +02:00
self . volume_target = self . settings . wake_up_volume / 20.0
2023-04-23 16:32:05 +02:00
self . set_volume ( self . volume_target )
2023-04-23 13:24:02 +02:00
new_vol = self . mixer . getvolume ( )
2023-01-07 16:09:28 +01:00
def wake_up_brightness_slider_value ( self , * args ) :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
self . settings . reading_light_brightness = int ( args [ 1 ] )
2023-04-10 15:25:34 +02:00
if ( self . light_state == " reading " ) :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-23 19:34:03 +02:00
self . settings . display_brightness = int ( args [ 1 ] )
2023-01-06 22:39:31 +01:00
2023-04-09 15:32:11 +02:00
def on_light_button_pressed ( self ) :
2023-04-10 22:11:21 +02:00
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 "
2023-04-23 19:34:03 +02:00
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 "
2023-04-10 16:52:40 +02:00
self . intensity_target = 0
2023-04-23 19:34:03 +02:00
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
2023-04-23 19:34:03 +02:00
if self . intensity_target < self . settings . reading_light_brightness / 20.0 :
2023-04-09 23:53:37 +02:00
self . light_state = " reading "
2023-04-23 19:34:03 +02:00
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 " :
2023-04-10 15:59:15 +02:00
self . light_state = " reading "
2023-04-10 16:52:40 +02:00
self . intensity_target = 0
2023-04-09 15:32:11 +02:00
2023-04-09 15:00:04 +02:00
def on_play_button_pressed ( self ) :
2023-04-10 22:11:21 +02:00
print ( " play button pressed from view " + self . view )
2023-04-23 19:34:03 +02:00
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 :
2023-04-23 19:34:03 +02:00
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 ) :
2023-04-10 22:11:21 +02:00
print ( " alarm button pressed from view " + self . view )
2023-01-15 11:58:53 +01:00
2023-04-23 19:34:03 +02: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 "
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2023-04-23 19:34:03 +02:00
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 "
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2023-04-23 19:34:03 +02:00
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 "
2023-04-11 17:39:41 +02:00
self . view_active_since = time . time ( )
2023-01-06 22:39:31 +01:00
else :
self . view = " clock "
2023-04-11 17:39:41 +02:00
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 )
2023-04-10 22:11:21 +02:00
def touch_up_function ( self , touch ) :
2022-12-11 16:08:13 +01:00
self . grabbed = " "
2023-04-10 15:59:15 +02:00
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 )
2023-04-10 22:11:21 +02:00
def touch_move_function ( self , touch ) :
2023-04-08 17:10:44 +02:00
if self . grabbed == " " :
return
2022-12-11 16:08:13 +01:00
self . alarm_set_timeout = 0
2023-04-08 17:10:44 +02:00
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 ) :
2023-04-10 15:59:15 +02:00
touch_curr . spos [ 0 ] = 1 - touch_curr . spos [ 0 ]
touch_curr . spos [ 1 ] = 1 - touch_curr . spos [ 1 ]
touch_curr . corrected = True
2023-04-08 17:10:44 +02:00
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 ) :
2023-04-10 15:59:15 +02:00
touch_curr . spos [ 0 ] = 1 - touch_curr . spos [ 0 ]
touch_curr . spos [ 1 ] = 1 - touch_curr . spos [ 1 ]
touch_curr . corrected = True
2023-04-08 17:10:44 +02:00
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 " :
2023-04-23 19:34:03 +02:00
self . settings . alarm_modified = True
2022-12-11 16:08:13 +01:00
self . set_alarm_timeout_counter = 0
2023-04-08 17:10:44 +02:00
minute = round ( - touch_curr . angle * 30 + 15 )
while minute < 0 :
2022-12-11 16:08:13 +01:00
minute + = 60
2023-04-08 17:10:44 +02:00
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
2023-04-23 19:34:03 +02:00
if ( ( ( minute - self . settings . alarm_time . minute ) > = 15 ) and ( ( minute - self . settings . alarm_time . minute ) < = 45 ) ) :
2023-04-08 17:10:44 +02:00
minute = minute - 30
2023-04-23 19:34:03 +02:00
elif ( ( ( minute - self . settings . alarm_time . minute ) < = - 15 ) and ( ( minute - self . settings . alarm_time . minute ) > = - 45 ) ) :
2023-04-08 17:10:44 +02:00
minute = minute + 30
while minute < 0 :
minute + = 60
while minute > = 60 :
minute - = 60
2022-12-11 16:08:13 +01:00
# hour correction
2023-04-23 19:34:03 +02:00
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
2023-04-23 19:34:03 +02:00
elif self . settings . alarm_time . minute < = 5 and minute > = 55 :
2022-12-11 16:08:13 +01:00
hour - = 1
2023-04-08 17:10:44 +02:00
while hour < 0 :
hour + = 24
while hour > = 24 :
hour - = 24
2022-12-11 16:08:13 +01:00
2023-04-23 19:34:03 +02: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 " :
2023-04-23 19:34:03 +02:00
self . settings . alarm_modified = True
2022-12-11 16:08:13 +01:00
self . set_alarm_timeout_counter = 0
2023-04-08 17:10:44 +02:00
hour = round ( - touch_curr . angle * 6 + 3 )
while hour < 0 :
2022-12-11 16:08:13 +01:00
hour + = 12
2023-04-08 17:10:44 +02:00
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
2023-04-23 19:34:03 +02:00
if ( ( ( hour - self . settings . alarm_time . hour ) > = 3 ) and ( ( hour - self . settings . alarm_time . hour ) < = 9 ) ) :
2023-04-08 17:10:44 +02:00
hour = hour - 6
2023-04-23 19:34:03 +02:00
if ( ( ( hour - self . settings . alarm_time . hour ) < = - 3 ) and ( ( hour - self . settings . alarm_time . hour ) > = - 9 ) ) :
2023-04-08 17:10:44 +02:00
hour = hour + 6
while hour < 0 :
hour + = 12
while hour > = 12 :
hour - = 12
2022-12-11 16:08:13 +01:00
2023-04-23 19:34:03 +02:00
if self . settings . alarm_time . hour > = 12 :
2022-12-11 16:08:13 +01:00
hour + = 12
2023-04-08 17:10:44 +02:00
2022-12-11 16:08:13 +01:00
# AM / PM correction
2023-04-23 19:34:03 +02:00
if self . settings . alarm_time . hour == 11 and hour == 0 :
2022-12-11 16:08:13 +01:00
hour = 12
2023-04-23 19:34:03 +02:00
elif self . settings . alarm_time . hour == 23 and hour == 12 :
2022-12-11 16:08:13 +01:00
hour = 0
2023-04-23 19:34:03 +02:00
elif self . settings . alarm_time . hour == 0 and hour == 11 :
2022-12-11 16:08:13 +01:00
hour = 23
2023-04-23 19:34:03 +02:00
elif self . settings . alarm_time . hour == 12 and hour == 23 :
2022-12-11 16:08:13 +01:00
hour = 11
2023-04-23 19:34:03 +02:00
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
2023-04-10 15:59:15 +02:00
elif self . grabbed == " light_button " :
if len ( self . light_button_move_init ) == 0 :
self . light_button_move_init = touch_curr . spos
2023-04-14 20:28:00 +02:00
2023-04-10 22:23:04 +02:00
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-04-10 15:59:15 +02:00
2023-01-06 22:39:31 +01:00
super ( MyClockWidget , self ) . on_touch_move ( touch )
2023-04-10 22:11:21 +02:00
def touch_down_function ( self , touch ) :
2023-04-23 19:34:03 +02:00
t = self . settings . alarm_time
2022-12-11 16:08:13 +01:00
hands = self . ids [ " hands " ]
2023-04-10 22:11:21 +02:00
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-04-10 15:59:15 +02:00
if ( 0.05 < = touch . spos [ 0 ] < = 0.25 ) and ( 0.85 < = touch . spos [ 1 ] < = 0.95 ) :
if self . grabbed == " " :
self . grabbed = " light_button "
2023-04-09 15:32:11 +02:00
self . on_light_button_pressed ( )
elif ( 0.05 < = touch . spos [ 0 ] < = 0.15 ) and ( 0.05 < = touch . spos [ 1 ] < = 0.15 ) :
2023-04-09 15:00:04 +02:00
self . on_play_button_pressed ( )
elif ( 0.85 < = touch . spos [ 0 ] < = 0.95 ) and ( 0.05 < = touch . spos [ 1 ] < = 0.15 ) :
2022-12-11 16:08:13 +01:00
self . on_alarm_button_pressed ( )
2023-01-06 22:39:31 +01:00
elif ( 0.85 < = touch . spos [ 0 ] < = 0.95 ) and ( 0.85 < = touch . spos [ 1 ] < = 0.95 ) :
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
2023-04-08 17:10:44 +02:00
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
2023-04-11 17:39:41 +02:00
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 )
2023-04-10 22:11:21 +02:00
def on_touch_down ( self , touch , after = False ) :
2023-04-11 17:39:41 +02:00
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
"""
2023-04-11 17:39:41 +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
"""
2023-04-11 17:39:41 +02:00
2023-04-10 22:11:21 +02:00
if after :
2023-04-11 17:39:41 +02:00
self . touch_down_event_curr = TouchEvent ( touch )
return True
2023-04-10 22:11:21 +02:00
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 ) :
2023-04-11 17:39:41 +02:00
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
"""
2023-04-11 17:39:41 +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
"""
2023-04-11 17:39:41 +02:00
2023-04-10 22:11:21 +02:00
if after :
# Do not delay processing of move events
self . touch_move_function ( touch )
2023-04-11 17:39:41 +02:00
return True
2023-04-10 22:11:21 +02:00
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 ) :
2023-04-11 17:39:41 +02:00
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
"""
2023-04-11 17:39:41 +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
"""
2023-04-11 17:39:41 +02:00
2023-04-10 22:11:21 +02:00
if after :
2023-04-11 17:39:41 +02:00
self . touch_up_event_curr = TouchEvent ( touch )
return True
2023-04-10 22:11:21 +02:00
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 17:00:21 +02:00
2023-04-16 22:14:10 +02:00
clock_widget . add_wake_up_sounds ( )
clock_widget . add_themes ( )
2023-04-16 17:00:21 +02:00
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 )
2023-04-10 23:12:31 +02:00
2023-05-26 22:54:30 +02:00
Clock . schedule_once ( clock_widget . get_air_quality , 0 )
2023-05-28 16:33:34 +02:00
t = datetime . datetime . now ( )
2023-05-29 09:01:52 +02:00
delay = 58 - ( t . second + t . microsecond / 1000000 )
2023-05-28 16:33:34 +02:00
if delay < 0 :
delay = delay + 60
Clock . schedule_once ( clock_widget . sync_air_quality , delay )
2023-05-26 22:54:30 +02:00
2023-04-10 23:12:31 +02:00
if is_arm ( ) :
Window . borderless = True
2023-04-23 16:06:05 +02:00
# Volume is in 0-1.0 range
2023-04-23 13:24:02 +02:00
old_vol = clock_widget . mixer . getvolume ( )
2023-04-23 19:34:03 +02:00
clock_widget . volume_target = clock_widget . settings . wake_up_volume / 20.0
2023-04-23 13:24:02 +02:00
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 ( )