GoodMorningSunshine/clock.py

1037 lines
40 KiB
Python
Raw 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-08 21:37:28 +02:00
import os
from kivy.config import Config
2022-12-11 16:08:13 +01:00
def is_arm():
if (os.uname()[4][:3] == 'arm') or (os.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
from hsluv import hsluv_to_rgb
#Config.set('graphics', 'width', '800')
#Config.set('graphics', 'height', '480')
Config.set('graphics', 'width', '667')
Config.set('graphics', 'height', '400')
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()
else:
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '720')
2023-04-09 22:34:59 +02:00
pixels = None
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
2022-12-11 16:08:13 +01:00
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.graphics import Color, Line, Rectangle
2023-01-07 16:09:28 +01:00
import pulsectl
2023-04-08 21:37:28 +02:00
import vlc
2022-12-11 16:08:13 +01:00
Builder.load_string('''
<MyClockWidget>:
2023-01-06 22:39:31 +01:00
on_pos: self.update_display()
on_size: self.update_display()
2022-12-11 16:08:13 +01:00
FloatLayout
id: face
size_hint: None, None
pos_hint: {"center_x":0.5, "center_y":0.5}
size: 0.9*min(root.size), 0.9*min(root.size)
canvas:
Color:
rgb: 0.1, 0.1, 0.1
Ellipse:
size: self.size
pos: self.pos
FloatLayout
id: hands
size_hint: None, None
pos_hint: {"center_x":0.5, "center_y":0.5}
size: 0.9*min(root.size), 0.9*min(root.size)
2023-04-09 15:00:04 +02:00
FloatLayout
id: play_button
size_hint: None, None
pos_hint: {"center_x":0.1, "center_y":0.1}
size: 0.1*min(root.size), 0.1*min(root.size)
2022-12-11 16:08:13 +01:00
FloatLayout
id: set_alarm_button
size_hint: None, None
pos_hint: {"center_x":0.9, "center_y":0.1}
size: 0.1*min(root.size), 0.1*min(root.size)
2023-01-06 22:39:31 +01:00
2023-04-09 15:00:04 +02:00
FloatLayout
id: light_button
size_hint: None, None
2023-04-09 15:56:45 +02:00
pos_hint: {"center_x":0.124, "center_y":0.9}
size: 0.1*125/70*min(root.size), 0.1*min(root.size)
2023-04-09 15:00:04 +02:00
2023-01-06 22:39:31 +01:00
FloatLayout
id: settings_button
size_hint: None, None
pos_hint: {"center_x":0.9, "center_y":0.9}
2023-04-09 15:00:04 +02:00
size: 0.1*min(root.size), 0.1*min(root.size)
2023-01-06 22:39:31 +01:00
FloatLayout
id: settings_menu
size_hint: None, None
pos_hint: {"center_x":0.5, "center_y":0.5}
2023-04-10 01:01:25 +02:00
size: 0.8*min(root.size), 0.7*min(root.size)
2023-01-06 22:39:31 +01:00
canvas:
Color:
rgb: 0.1, 0.1, 0.1
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 8
2023-01-06 22:39:31 +01:00
cols: 2
2023-01-07 21:38:26 +01:00
pos_hint: {"center_x":0.5, "center_y":0.5}
2023-01-06 22:39:31 +01:00
Label:
2023-01-07 16:09:28 +01:00
text: "Volume"
halign: "left"
valign: "middle"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-07 16:09:28 +01:00
text_size: self.size
2023-01-06 22:39:31 +01:00
Slider:
id: volume_slider
min: 0
max: 20
2023-01-07 16:09:28 +01:00
value: 15
2023-01-06 22:39:31 +01:00
on_value: root.volume_slider_value(*args)
2023-01-07 16:09:28 +01:00
value_track: True
value_track_color: [1, 0, 0, 1]
Label:
text:"Wake up sound"
halign: "left"
valign: "middle"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
text_size: self.size
2023-01-08 22:11:18 +01:00
Button:
id: settings_menu_wake_up_sound_select_button
on_press: root.settings_menu_wake_up_sound_select_button_cb()
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-08 22:11:18 +01:00
text: str(app.alarm_settings.sound_selected)
2023-01-06 22:39:31 +01:00
Label:
text:"Wake up brightness"
2023-01-07 16:09:28 +01:00
halign: "left"
valign: "middle"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-07 16:09:28 +01:00
text_size: self.size
2023-01-06 22:39:31 +01:00
Slider:
id: wake_up_bightness_slider
min: 0
max: 20
value: 20
2023-01-07 16:09:28 +01:00
on_value: root.wake_up_brightness_slider_value(*args)
value_track: True
value_track_color: [1, 0, 0, 1]
2023-01-06 22:39:31 +01:00
Label:
text:"Reading light brightness"
2023-01-07 16:09:28 +01:00
halign: "left"
valign: "middle"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-07 16:09:28 +01:00
text_size: self.size
2023-01-06 22:39:31 +01:00
Slider:
id: reading_light_brightness_slider
2023-04-10 15:25:34 +02:00
min: 1
2023-01-06 22:39:31 +01:00
max: 20
value: 1
2023-01-07 16:09:28 +01:00
on_value: root.reading_light_brightness_slider_value(*args)
value_track: True
value_track_color: [1, 0, 0, 1]
Label:
text:"Display brightness"
halign: "left"
valign: "middle"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-07 16:09:28 +01:00
text_size: self.size
Slider:
id: display_brightness_slider
min: 0
max: 20
value: 10
on_value: root.display_brightness_slider_value(*args)
value_track: True
value_track_color: [1, 0, 0, 1]
2023-01-08 22:11:18 +01:00
FloatLayout
id: settings_menu_wake_up_sound
size_hint: None, None
pos_hint: {"center_x":0.5, "center_y":0.5}
2023-04-10 01:01:25 +02:00
size: 0.8*min(root.size), 0.8*min(root.size)
2023-01-08 22:11:18 +01:00
canvas:
Color:
rgb: 0.1, 0.1, 0.1
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
orientation: "vertical"
pos_hint: {"center_x":0.5, "center_y":0.5}
Label:
text: "Select wake up sound"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-08 22:11:18 +01:00
GridLayout:
cols: 2
CheckBox:
group: "settings_menu_wake_up_sound"
on_active: root.settings_menu_wake_up_sound_cb(self, self.active, "Birds")
id: settings_menu_wake_up_sound_Birds
Label:
text: "Birds"
halign: "left"
valign: "middle"
text_size: self.size
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-08 22:11:18 +01:00
active: True
CheckBox:
group: "settings_menu_wake_up_sound"
on_active: root.settings_menu_wake_up_sound_cb(self, self.active, "NPO Radio 1")
id: settings_menu_wake_up_sound_NpoRadio1
Label:
text: "NPO Radio 1"
halign: "left"
valign: "middle"
text_size: self.size
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2023-01-08 22:11:18 +01:00
Button:
id: settings_menu_wake_up_sound_Ok_button
on_press: root.settings_menu_wake_up_sound_Ok_button_cb()
text: "Ok"
2023-04-10 01:01:25 +02:00
font_size: root.height*0.05
2022-12-11 16:08:13 +01:00
''')
Position = collections.namedtuple('Position', 'x y')
2023-01-05 22:02:22 +01:00
class AlarmSettings():
2022-12-11 16:08:13 +01:00
alarm_time = datetime.datetime(2022, 12, 10, 7, 30, 0, 0)
alarm_activated = False
2023-04-08 21:37:28 +02:00
alarm_playing = False
2022-12-11 16:08:13 +01:00
alarm_modified = False
2023-01-08 22:11:18 +01:00
# sound_selected = "NPO Radio 1"
# sound_source = "https://icecast.omroep.nl/radio1-bb-mp3"
2023-01-08 22:11:18 +01:00
sound_selected = "Birds"
sound_source = "Woodpecker Chirps - QuickSounds.com.mp3"
seconds_to_sunrise = 30 * 60 # 30 minutes
2022-12-11 16:08:13 +01:00
2023-01-07 16:09:28 +01:00
volume = 15
2023-01-06 22:39:31 +01:00
wake_up_brightness = 20
reading_light_brightness = 1
2023-01-07 16:09:28 +01:00
display_brightness = 10
2023-01-06 22:39:31 +01: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()
2023-01-05 22:02:22 +01:00
class MyClockWidget(FloatLayout):
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-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-01-06 20:18:22 +01:00
view = "clock"
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
# 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()
if is_arm:
backlight = Backlight()
2023-04-08 21:37:28 +02:00
else:
backlight = None
2023-04-08 21:37:28 +02:00
def play_sound(self, source):
alarm_settings = App.get_running_app().alarm_settings
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)
media = self.vlc.media_new(source)
self.player.set_media(media)
self.player.play()
alarm_settings.alarm_playing = True
def stop_sound(self):
self.player.stop()
alarm_settings = App.get_running_app().alarm_settings
alarm_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))
self.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
2022-12-11 16:08:13 +01:00
def draw_face(self):
"""
Add number labels when added in widget hierarchy
"""
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
2023-01-05 22:02:22 +01:00
time = alarm_settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
time = datetime.datetime.now()
for i in range(1, 13):
if time.hour < 12:
offset = 0
else:
offset = 12
self.face_numbers.append(Label(
text=str(i + offset),
font_size=float(Config.get('graphics', 'height'))*0.05,
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])
def update_face(self):
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
2023-01-05 22:02:22 +01:00
time = alarm_settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
time = datetime.datetime.now()
for i in range(0, 12):
if time.hour < 12:
offset = 0
else:
offset = 12
self.face_numbers[i].text=str(i + 1 + offset)
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"):
source = 'light_off.png'
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "reading"):
source = 'light_reading.png'
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "sunrise"):
source = 'light_sunrise.png'
rgb = [1.0, 1.0, 1.0]
elif (self.light_state == "on"):
source = 'light_on.png'
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):
alarm_settings = App.get_running_app().alarm_settings
if alarm_settings.alarm_playing:
source = 'media_playing.png'
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2023-04-09 15:00:04 +02:00
else:
source = 'media_stopped.png'
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-01-15 11:58:53 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-05 22:02:22 +01:00
2023-01-06 20:18:22 +01:00
if (self.view == "set_alarm") or alarm_settings.alarm_activated:
2022-12-11 16:08:13 +01:00
source = 'alarm_on.png'
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2022-12-11 16:08:13 +01:00
else:
source = 'alarm_off.png'
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]])
# Rectangle(size=set_alarm_button.size, pos=set_alarm_button.pos, source=source)
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-15 11:58:53 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-06 22:39:31 +01:00
2023-01-08 22:11:18 +01:00
if (self.view.startswith("settings_menu")):
2023-01-06 22:39:31 +01:00
source = 'settings_visible.png'
2023-04-10 00:47:04 +02:00
rgb = [1.0, 1.0, 1.0]
2023-01-06 22:39:31 +01:00
else:
source = 'settings_not_visible.png'
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
2023-04-09 22:34:59 +02:00
def intensity_to_rgbw(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
h = max(0, min(75, (75 - 12) * intensity + 12))
s = max(0, min(100, 250 - 250 * intensity))
l = 100 * intensity
rgb = hsluv_to_rgb([h, s, l])
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-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):
alarm_settings = App.get_running_app().alarm_settings
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 = (alarm_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 / alarm_settings.seconds_to_sunrise) * (alarm_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):
alarm_settings = App.get_running_app().alarm_settings
2022-12-11 16:08:13 +01:00
2023-04-09 23:53:37 +02:00
if (alarm_settings.alarm_activated) and (self.seconds_to_next_alarm < alarm_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 = alarm_settings.reading_light_brightness / 20.0
2023-04-09 23:53:37 +02:00
elif (self.light_state == "on"):
self.intensity_target = alarm_settings.wake_up_brightness / 20.0
step = self.intensity_target - self.intensity_curr
stepsize = 0.01
if step > stepsize:
step = stepsize
elif step < -stepsize:
step = -stepsize
#self.intensity_curr = self.intensity_curr + stepsize
self.intensity_curr = self.intensity_target
2022-12-11 16:08:13 +01:00
def check_play_sound(self):
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2022-12-11 16:08:13 +01:00
2023-01-05 22:02:22 +01:00
if alarm_settings.alarm_activated == False:
2022-12-11 16:08:13 +01:00
return
2023-04-08 21:37:28 +02:00
if (self.seconds_to_next_alarm < 0.1) or (alarm_settings.alarm_playing == True):
if alarm_settings.sound_source != "":
self.play_sound(alarm_settings.sound_source)
2022-12-11 16:08:13 +01:00
def calc_seconds_to_next_alarm(self):
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
if alarm_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-01-05 22:02:22 +01:00
d = alarm_settings.alarm_time - now
alarm_settings.alarm_time -= datetime.timedelta(days=d.days)
2022-12-11 16:08:13 +01:00
# Calculate number of seconds until next alarm
2023-01-05 22:02:22 +01:00
d = alarm_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()
2022-12-11 16:08:13 +01:00
self.check_play_sound()
2023-01-06 22:39:31 +01:00
def update_clock(self):
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-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-06 20:18:22 +01:00
if self.view == "set_alarm":
2023-01-05 22:02:22 +01:00
time = alarm_settings.alarm_time
2022-12-11 16:08:13 +01:00
else:
time = datetime.datetime.now()
hands = self.ids["hands"]
seconds_hand = self.position_on_clock(time.second/60, length=0.45*hands.size[0])
minutes_hand = self.position_on_clock(time.minute/60+time.second/3600, length=0.40*hands.size[0])
hours_hand = self.position_on_clock(time.hour/12 + time.minute/720, length=0.35*hands.size[0])
self.update_face()
#hands.canvas.clear()
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 alarm_settings.alarm_modified == False:
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.9, 0.0, 0.0])
# Line(points=[hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], width=3, cap="round")
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.8, 0.0, 0.0])
#Line(points=[hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], width=2, cap="round")
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"
2022-12-11 16:08:13 +01:00
self.set_alarm_timeout_counter = 0
2023-01-05 22:02:22 +01:00
if alarm_settings.alarm_modified:
alarm_settings.alarm_activated = True
alarm_settings.alarm_modified = False
2022-12-11 16:08:13 +01:00
else:
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.9, 0.9, 0.9])
# Line(points=[hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], width=3, cap="round")
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.8, 0.8, 0.8])
# Line(points=[hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], width=2, cap="round")
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
self.draw_list_curr_frame.append(["Color", hands.canvas, 0.7, 0.7, 0.7])
# Line(points=[hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], width=1, cap="round")
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], 1, "round"])
2022-12-11 16:08:13 +01: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-02-17 21:43:24 +01:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], False])
2023-01-08 22:11:18 +01:00
elif self.view == "settings_menu_wake_up_sound":
2023-02-17 21:43:24 +01:00
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], False])
2023-01-06 22:39:31 +01:00
def draw_display(self):
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]:
Color(i[2], i[3], i[4])
elif i[0] == "Rectangle":
with i[1]:
Rectangle(size=i[2], pos=i[3], source=i[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 = []
2023-01-06 22:39:31 +01:00
def update_display(self, *args):
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
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])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], True])
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], True])
2023-01-06 22:39:31 +01: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()
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
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-08 22:11:18 +01:00
self.ids["settings_menu_wake_up_sound_Birds"].active = False
self.ids["settings_menu_wake_up_sound_NpoRadio1"].active = False
print("sound selected: " + alarm_settings.sound_selected)
if alarm_settings.sound_selected == "Birds":
self.ids["settings_menu_wake_up_sound_Birds"].active = True
elif alarm_settings.sound_selected == "NPO Radio 1":
self.ids["settings_menu_wake_up_sound_NpoRadio1"].active = True
self.view = "settings_menu_wake_up_sound"
def settings_menu_wake_up_sound_Ok_button_cb(self):
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-08 22:11:18 +01:00
self.ids["settings_menu_wake_up_sound_select_button"].text = alarm_settings.sound_selected
self.view = "settings_menu"
def settings_menu_wake_up_sound_cb(self, instance, value, sound):
alarm_settings = App.get_running_app().alarm_settings
if self.settings_menu_wake_up_sound_select_button_cb_hack:
self.settings_menu_wake_up_sound_select_button_cb_hack = False
if not (alarm_settings.sound_selected == "" and sound != ""):
return
if value == True:
print("You selected " + sound)
else:
print("You deselected " + sound)
alarm_settings.sound_source = ""
alarm_settings.sound_selected = ""
if self.ids["settings_menu_wake_up_sound_Birds"].active:
alarm_settings.sound_selected = sound
alarm_settings.sound_source = "Woodpecker Chirps - QuickSounds.com.mp3"
elif self.ids["settings_menu_wake_up_sound_NpoRadio1"].active:
alarm_settings.sound_selected = sound
alarm_settings.sound_source = "https://icecast.omroep.nl/radio1-bb-mp3"
2023-01-06 22:39:31 +01:00
def volume_slider_value(self, *args):
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-06 22:39:31 +01:00
alarm_settings.volume = int(args[1])
2023-01-07 16:09:28 +01:00
print("Volume changed to " + str(alarm_settings.volume))
with pulsectl.Pulse('volume-increaser') as pulse:
for sink in pulse.sink_list():
# Volume is usually in 0-1.0 range, with >1.0 being soft-boosted
old_vol = pulse.volume_get_all_chans(sink)
pulse.volume_set_all_chans(sink, alarm_settings.volume / 20.0)
new_vol = pulse.volume_get_all_chans(sink)
print("HW volume changed from " + str(old_vol) + " to " + str(new_vol))
def wake_up_brightness_slider_value(self, *args):
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-07 16:09:28 +01:00
alarm_settings.wake_up_brightness = int(args[1])
print("Wake up brightness changed to " + str(alarm_settings.wake_up_brightness))
def reading_light_brightness_slider_value(self, *args):
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-07 16:09:28 +01:00
alarm_settings.reading_light_brightness = int(args[1])
2023-04-10 15:25:34 +02:00
if (self.light_state == "reading"):
self.intensity_target = alarm_settings.reading_light_brightness / 20.0
2023-01-07 16:09:28 +01:00
print("Reading light brightness changed to " + str(alarm_settings.reading_light_brightness))
def display_brightness_slider_value(self, *args):
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-07 16:09:28 +01:00
alarm_settings.display_brightness = int(args[1])
if self.is_arm:
self.set_backlight(alarm_settings.display_brightness)
2023-01-06 22:39:31 +01:00
def on_light_button_pressed(self):
2023-04-09 22:34:59 +02:00
alarm_settings = App.get_running_app().alarm_settings
2023-04-09 23:53:37 +02:00
if self.light_state == "off":
self.light_state = "reading"
self.intensity_target = alarm_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
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 < alarm_settings.reading_light_brightness / 20.0:
2023-04-09 23:53:37 +02:00
self.light_state = "reading"
self.intensity_target = alarm_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 23:53:37 +02:00
if alarm_settings.alarm_playing:
self.stop_sound()
2023-04-09 15:00:04 +02:00
def on_play_button_pressed(self):
alarm_settings = App.get_running_app().alarm_settings
if alarm_settings.alarm_playing:
self.stop_sound()
else:
self.play_sound(alarm_settings.sound_source)
2022-12-11 16:08:13 +01:00
def on_alarm_button_pressed(self):
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-05 22:02:22 +01:00
alarm_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-01-05 22:02:22 +01:00
alarm_settings.alarm_activated = False
2022-12-11 16:08:13 +01:00
else:
2023-01-06 20:18:22 +01:00
self.view = "set_alarm"
2023-01-05 22:02:22 +01:00
alarm_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-01-06 22:39:31 +01:00
else:
self.view = "clock"
print("view updated to " + self.view)
2022-12-11 16:08:13 +01:00
def on_touch_up(self, touch):
self.grabbed = ""
self.light_button_move_init = []
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
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)
2022-12-11 16:08:13 +01:00
def on_touch_move(self, touch):
if self.grabbed == "":
return
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
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":
2023-01-05 22:02:22 +01:00
alarm_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 - alarm_settings.alarm_time.minute) >= 15) and ((minute - alarm_settings.alarm_time.minute) <= 45)):
minute = minute - 30
elif (((minute - alarm_settings.alarm_time.minute) <= -15) and ((minute - alarm_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
2023-01-05 22:02:22 +01:00
hour = alarm_settings.alarm_time.hour
if alarm_settings.alarm_time.minute >= 55 and minute <= 5:
2022-12-11 16:08:13 +01:00
hour += 1
2023-01-05 22:02:22 +01:00
elif alarm_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
2023-01-05 22:02:22 +01:00
alarm_settings.alarm_time = datetime.datetime(alarm_settings.alarm_time.year, \
alarm_settings.alarm_time.month, alarm_settings.alarm_time.day, \
hour, minute, alarm_settings.alarm_time.second, 0)
2022-12-11 16:08:13 +01:00
elif self.grabbed == "hour":
2023-01-05 22:02:22 +01:00
alarm_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 - alarm_settings.alarm_time.hour) >= 3) and ((hour - alarm_settings.alarm_time.hour) <= 9)):
hour = hour - 6
if (((hour - alarm_settings.alarm_time.hour) <= -3) and ((hour - alarm_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
2023-01-05 22:02:22 +01:00
if alarm_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
2023-01-05 22:02:22 +01:00
if alarm_settings.alarm_time.hour == 11 and hour == 0:
2022-12-11 16:08:13 +01:00
hour = 12
2023-01-05 22:02:22 +01:00
elif alarm_settings.alarm_time.hour == 23 and hour == 12:
2022-12-11 16:08:13 +01:00
hour = 0
2023-01-05 22:02:22 +01:00
elif alarm_settings.alarm_time.hour == 0 and hour == 11:
2022-12-11 16:08:13 +01:00
hour = 23
2023-01-05 22:02:22 +01:00
elif alarm_settings.alarm_time.hour == 12 and hour == 23:
2022-12-11 16:08:13 +01:00
hour = 11
minute = alarm_settings.alarm_time.minute
2023-01-05 22:02:22 +01:00
alarm_settings.alarm_time = datetime.datetime(alarm_settings.alarm_time.year, \
alarm_settings.alarm_time.month, alarm_settings.alarm_time.day, \
hour, alarm_settings.alarm_time.minute, alarm_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
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen: ignore corrected touched
if touch_curr.corrected == False:
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)
2022-12-11 16:08:13 +01:00
def on_touch_down(self, touch):
2023-01-05 22:02:22 +01:00
alarm_settings = App.get_running_app().alarm_settings
2023-01-15 11:58:53 +01:00
2023-01-05 22:02:22 +01:00
time = alarm_settings.alarm_time
2022-12-11 16:08:13 +01:00
hands = self.ids["hands"]
minutes_hand = self.position_on_clock(time.minute/60+time.second/3600, length=0.40*hands.size[0])
hours_hand = self.position_on_clock(time.hour/12 + time.minute/720, length=0.35*hands.size[0])
if (0.05 <= touch.spos[0] <= 0.25) and (0.85 <= touch.spos[1] <= 0.95):
if self.grabbed == "":
self.grabbed = "light_button"
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
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 = ""
print("grabbed: " + 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 == "clock":
2023-04-08 21:37:28 +02:00
self.stop_sound()
2022-12-11 16:08:13 +01:00
2023-01-06 22:39:31 +01:00
super(MyClockWidget, self).on_touch_down(touch)
2022-12-11 16:08:13 +01:00
class MyApp(App):
2023-01-05 22:02:22 +01:00
alarm_settings = AlarmSettings()
2023-01-15 11:58:53 +01:00
update_rate = 60.0
2023-01-05 22:02:22 +01:00
2023-01-07 16:09:28 +01:00
# apply volume setting
with pulsectl.Pulse('volume-increaser') as pulse:
for sink in pulse.sink_list():
# Volume is usually in 0-1.0 range, with >1.0 being soft-boosted
old_vol = pulse.volume_get_all_chans(sink)
pulse.volume_set_all_chans(sink, alarm_settings.volume / 20.0)
new_vol = pulse.volume_get_all_chans(sink)
print("HW volume changed from " + str(old_vol) + " to " + str(new_vol))
2022-12-11 16:08:13 +01:00
def build(self):
clock_widget = MyClockWidget()
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)
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-08 21:37:28 +02:00
return
2022-12-11 16:08:13 +01:00
if __name__ == '__main__':
2023-04-09 22:34:59 +02:00
#sys.excepthook = except_hook
2022-12-11 16:08:13 +01:00
MyApp().run()