1249 lines
51 KiB
Python
1249 lines
51 KiB
Python
# 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
|
|
import os
|
|
from kivy.config import Config
|
|
from kivy.properties import ObjectProperty
|
|
import time
|
|
from sounds import WakeUpSounds
|
|
|
|
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', '750')
|
|
#Config.set('graphics', 'height', '450')
|
|
|
|
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()
|
|
|
|
backlight = Backlight()
|
|
else:
|
|
Config.set('graphics', 'width', '1200')
|
|
Config.set('graphics', 'height', '720')
|
|
|
|
pixels = None
|
|
backlight = None
|
|
|
|
Config.set('graphics', 'maxfps', '60')
|
|
|
|
from kivy.app import App
|
|
from kivy.uix.floatlayout import FloatLayout
|
|
from kivy.uix.label import Label
|
|
from kivy.uix.slider import Slider
|
|
from kivy.uix.button import Button
|
|
from kivy.uix.gridlayout import GridLayout
|
|
from kivy.uix.checkbox import CheckBox
|
|
from kivy.clock import Clock
|
|
from kivy.lang import Builder
|
|
from kivy.graphics import Color, Line, Rectangle, Ellipse
|
|
from kivy.core.window import Window
|
|
|
|
if is_arm():
|
|
Window.show_cursor = False
|
|
|
|
import pulsectl
|
|
import vlc
|
|
|
|
Builder.load_file('clock.kv')
|
|
|
|
Position = collections.namedtuple('Position', 'x y')
|
|
|
|
class Theme():
|
|
def __init__(self, x="Dark"):
|
|
self.name = x
|
|
if x == "Dark":
|
|
self.color_background = [0, 0, 0]
|
|
self.color_shade = [.1, .1, .1]
|
|
self.color_clock_hands_hours = [.9, .9, .9]
|
|
self.color_clock_hands_minutes = [.8, .8, .8]
|
|
self.color_clock_hands_seconds = [.7, .7, .7]
|
|
self.color_alarm_hands_hours = [.9, .0, .0]
|
|
self.color_alarm_hands_minutes = [.8, .0, .0]
|
|
self.color_alarm_hands_seconds = [.7, .0, .0]
|
|
self.color_font = [1, 1, 1]
|
|
self.color_numbers = [1, 1, 1]
|
|
self.color_button = [.2, .2, .2, 1]
|
|
self.color_funky = [.5, .2, .1, 0.2]
|
|
|
|
self.icon_light_off = 'themes/Dark/light_off.png'
|
|
self.icon_light_reading = 'themes/Dark/light_reading.png'
|
|
self.icon_light_sunrise = 'themes/Dark/light_sunrise.png'
|
|
self.icon_light_on = 'themes/Dark/light_on.png'
|
|
self.icon_media_playing = 'themes/Dark/media_playing.png'
|
|
self.icon_media_stopped = 'themes/Dark/media_stopped.png'
|
|
self.icon_alarm_on = 'themes/Dark/alarm_on.png'
|
|
self.icon_alarm_off = 'themes/Dark/alarm_off.png'
|
|
self.icon_settings_visible = 'themes/Dark/settings_visible.png'
|
|
self.icon_settings_not_visible = 'themes/Dark/settings_not_visible.png'
|
|
elif x == "Light":
|
|
self.color_background = [1, 1, 1]
|
|
self.color_shade = [.9, .9, .9]
|
|
self.color_clock_hands_hours = [.1, .1, .1]
|
|
self.color_clock_hands_minutes = [.2, .2, .2]
|
|
self.color_clock_hands_seconds = [.3, .3, .3]
|
|
self.color_alarm_hands_hours = [.9, .0, .0]
|
|
self.color_alarm_hands_minutes = [.8, .0, .0]
|
|
self.color_alarm_hands_seconds = [.7, .0, .0]
|
|
self.color_font = [0, 0, 0]
|
|
self.color_numbers = [0, 0, 0]
|
|
self.color_button = [.8, .8, .8, 1]
|
|
self.color_funky = [.1, .2, .5, 0.2]
|
|
|
|
self.icon_light_off = 'themes/Light/light_off.png'
|
|
self.icon_light_reading = 'themes/Light/light_reading.png'
|
|
self.icon_light_sunrise = 'themes/Light/light_sunrise.png'
|
|
self.icon_light_on = 'themes/Light/light_on.png'
|
|
self.icon_media_playing = 'themes/Light/media_playing.png'
|
|
self.icon_media_stopped = 'themes/Light/media_stopped.png'
|
|
self.icon_alarm_on = 'themes/Light/alarm_on.png'
|
|
self.icon_alarm_off = 'themes/Light/alarm_off.png'
|
|
self.icon_settings_visible = 'themes/Light/settings_visible.png'
|
|
self.icon_settings_not_visible = 'themes/Light/settings_not_visible.png'
|
|
|
|
class AlarmSettings():
|
|
alarm_time = datetime.datetime(2022, 12, 10, 7, 30, 0, 0)
|
|
alarm_activated = False
|
|
alarm_playing = False
|
|
|
|
alarm_modified = False
|
|
|
|
seconds_to_sunrise = 30 * 60 # 30 minutes
|
|
|
|
volume = 15
|
|
wake_up_brightness = 20
|
|
reading_light_brightness = 1
|
|
display_brightness = 10
|
|
|
|
class Touch():
|
|
def __init__(self, x=None):
|
|
if x is None:
|
|
self.pos = []
|
|
self.spos = []
|
|
self.is_empty = True
|
|
self.angle = 0
|
|
self.corrected = False
|
|
else:
|
|
self.pos = [i for i in x.pos]
|
|
self.spos = [i for i in x.spos]
|
|
self.is_empty = False
|
|
x = self.spos[0] - 0.5
|
|
y = self.spos[1] - 0.5
|
|
self.angle = math.atan2(y, x) / math.pi; # angle is between -1 and 1
|
|
self.corrected = False
|
|
|
|
def __repr__(self):
|
|
return ".is_empty: " + str(self.is_empty) + ", .pos: " + str(self.pos) + ", .spos: " + str(self.spos), ", .corrected: " + str(self.corrected)
|
|
|
|
def copy(self, x):
|
|
self = Touch(x)
|
|
|
|
def clear(self):
|
|
self = Touch()
|
|
|
|
class TouchEvent():
|
|
def __init__(self, x=None):
|
|
self.time = time.time()
|
|
self.touch = copy.copy(x)
|
|
self.processed = False
|
|
|
|
class MyClockWidget(FloatLayout):
|
|
theme_selected = "Dark"
|
|
theme = ObjectProperty(Theme(theme_selected))
|
|
|
|
grabbed = ""
|
|
face_numbers = []
|
|
|
|
# if not grabbed, set_alarm_timeout_counter is incremented at every update call;
|
|
# 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
|
|
|
|
light_state = "off" # "off", "reading", "sunrise" or "on"
|
|
intensity_target = 0
|
|
intensity_prev = 0
|
|
intensity_curr = 0
|
|
intensity_target_prev = None
|
|
rgbw_prev = None
|
|
|
|
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen
|
|
# For each type of touch event, handling of the event is ignored until the last event is more than touch_delay_time seconds old
|
|
touch_delay_time = 0.1
|
|
touch_down_event_prev = None
|
|
touch_move_event_prev = None
|
|
touch_up_event_prev = None
|
|
touch_down_event_curr = None
|
|
touch_move_event_curr = None
|
|
touch_up_event_curr = None
|
|
|
|
# view can be one of the following strings:
|
|
# - "clock"
|
|
# - "set_alarm"
|
|
# - "settings_menu"
|
|
# - "settings_menu_wake_up_sound"
|
|
# - "settings_menu_theme"
|
|
view = "clock"
|
|
view_prev = ""
|
|
view_active_since = time.time()
|
|
|
|
# ugly workaround for issue where input is processed twice (specifically:
|
|
# pressing Ok in wake up sound view switches to settings view but also
|
|
# adjusts display brightness slider)
|
|
time_to_ignore_inputs_after_view_change = 0.5
|
|
|
|
# ugly workaround for issue where graphics are not drawn correctly after view change
|
|
time_to_force_redraws_after_view_change = 0.5
|
|
|
|
# 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
|
|
settings_menu_theme_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 = []
|
|
vlc = vlc.Instance()
|
|
player = vlc.media_player_new()
|
|
|
|
is_arm = is_arm()
|
|
|
|
|
|
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))
|
|
if self.is_arm:
|
|
if backlight.brightness != z:
|
|
backlight.brightness = z
|
|
|
|
def hide_widget(self, widget, hide=True):
|
|
if hasattr(widget, 'saved_attrs'):
|
|
if not hide:
|
|
widget.height, widget.size_hint_y, widget.opacity, widget.disabled = widget.saved_attrs
|
|
del widget.saved_attrs
|
|
elif hide:
|
|
widget.saved_attrs = widget.height, widget.size_hint_y, widget.opacity, widget.disabled
|
|
widget.height, widget.size_hint_y, widget.opacity, widget.disabled = 0, None, 0, True
|
|
|
|
def draw_face(self):
|
|
"""
|
|
Add number labels when added in widget hierarchy
|
|
"""
|
|
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if self.view == "set_alarm":
|
|
t = alarm_settings.alarm_time
|
|
else:
|
|
t = datetime.datetime.now()
|
|
|
|
for i in range(1, 13):
|
|
if t.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,
|
|
color=self.theme.color_numbers,
|
|
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_background(self):
|
|
background = self.ids["background"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", background])
|
|
with background.canvas:
|
|
self.draw_list_curr_frame.append(["Color", background.canvas, self.theme.color_background[0], self.theme.color_background[1], self.theme.color_background[2]])
|
|
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, None])
|
|
|
|
def update_face(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
face_plate = self.ids["face_plate"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", face_plate])
|
|
with face_plate.canvas:
|
|
self.draw_list_curr_frame.append(["Color", face_plate.canvas, self.theme.color_shade[0], self.theme.color_shade[1], self.theme.color_shade[2]])
|
|
self.draw_list_curr_frame.append(["Ellipse", face_plate.canvas, face_plate.size, face_plate.pos])
|
|
|
|
if self.view == "set_alarm":
|
|
t = alarm_settings.alarm_time
|
|
else:
|
|
t = datetime.datetime.now()
|
|
|
|
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)
|
|
|
|
|
|
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(
|
|
center_x + round(length * math.sin(2 * math.pi * fraction)),
|
|
center_y + round(length * math.cos(2 * math.pi * fraction)),
|
|
)
|
|
|
|
def update_light_button(self):
|
|
if (self.light_state == "off"):
|
|
source = self.theme.icon_light_off
|
|
rgb = [1.0, 1.0, 1.0]
|
|
elif (self.light_state == "reading"):
|
|
source = self.theme.icon_light_reading
|
|
rgb = [1.0, 1.0, 1.0]
|
|
elif (self.light_state == "sunrise"):
|
|
source = self.theme.icon_light_sunrise
|
|
rgb = [1.0, 1.0, 1.0]
|
|
elif (self.light_state == "on"):
|
|
source = self.theme.icon_light_on
|
|
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])
|
|
|
|
def update_play_button(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if alarm_settings.alarm_playing:
|
|
source = self.theme.icon_media_playing
|
|
rgb = [1.0, 1.0, 1.0]
|
|
else:
|
|
source = self.theme.icon_media_stopped
|
|
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])
|
|
|
|
def update_set_alarm_button(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if (self.view == "set_alarm") or alarm_settings.alarm_activated:
|
|
source = self.theme.icon_alarm_on
|
|
rgb = [1.0, 1.0, 1.0]
|
|
else:
|
|
source = self.theme.icon_alarm_off
|
|
rgb = [1.0, 1.0, 1.0]
|
|
|
|
set_alarm_button = self.ids["set_alarm_button"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", set_alarm_button])
|
|
with set_alarm_button.canvas:
|
|
self.draw_list_curr_frame.append(["Color", set_alarm_button.canvas, rgb[0], rgb[1], rgb[2]])
|
|
self.draw_list_curr_frame.append(["Rectangle", set_alarm_button.canvas, set_alarm_button.size, set_alarm_button.pos, source])
|
|
|
|
def update_settings_button(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if (self.view.startswith("settings_menu")):
|
|
source = self.theme.icon_settings_visible
|
|
rgb = [1.0, 1.0, 1.0]
|
|
else:
|
|
source = self.theme.icon_settings_not_visible
|
|
rgb = [1.0, 1.0, 1.0]
|
|
|
|
settings_button = self.ids["settings_button"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", settings_button])
|
|
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])
|
|
|
|
def intensity_to_rgbw(self, intensity):
|
|
if intensity < 0:
|
|
intensity = 0
|
|
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
|
|
|
|
def update_backlight(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
# make sure brightness of display is never lower than intensity of leds
|
|
brightness_min = 20 * self.intensity_curr
|
|
if alarm_settings.display_brightness < brightness_min:
|
|
self.set_backlight(brightness_min)
|
|
else:
|
|
self.set_backlight(alarm_settings.display_brightness)
|
|
|
|
def set_leds(self):
|
|
if self.intensity_prev != self.intensity_curr:
|
|
self.intensity_prev = self.intensity_curr
|
|
if self.is_arm:
|
|
led_color = self.intensity_to_rgbw(self.intensity_curr)
|
|
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))
|
|
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)]
|
|
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))
|
|
|
|
def sunrise(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if self.view == "set_alarm":
|
|
# Do not simulate sunrise when adjusting alarm time
|
|
return
|
|
|
|
if self.seconds_to_next_alarm < 0.1:
|
|
intensity_target = (alarm_settings.wake_up_brightness / 20.0)
|
|
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)
|
|
new_state = "sunrise"
|
|
|
|
# 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
|
|
self.light_state = new_state
|
|
|
|
def process_led_state(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if (alarm_settings.alarm_activated) and (self.seconds_to_next_alarm < alarm_settings.seconds_to_sunrise):
|
|
self.sunrise()
|
|
else:
|
|
if (self.light_state == "off"):
|
|
self.intensity_target = 0
|
|
elif (self.light_state == "reading"):
|
|
self.intensity_target = alarm_settings.reading_light_brightness / 20.0
|
|
elif (self.light_state == "on"):
|
|
self.intensity_target = alarm_settings.wake_up_brightness / 20.0
|
|
|
|
weight = 0.05
|
|
intensity_next = weight * self.intensity_target + (1 - weight) * self.intensity_curr
|
|
|
|
step = intensity_next - self.intensity_curr
|
|
|
|
if abs(step) < 0.001:
|
|
step = self.intensity_target - self.intensity_curr
|
|
|
|
self.intensity_curr = self.intensity_curr + step
|
|
|
|
def check_play_sound(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if alarm_settings.alarm_activated == False:
|
|
return
|
|
|
|
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)
|
|
|
|
def calc_seconds_to_next_alarm(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if alarm_settings.alarm_activated == False:
|
|
return
|
|
|
|
# Make sure alarm_time is in the future but not more than 24 h from now
|
|
now = datetime.datetime.now()
|
|
d = alarm_settings.alarm_time - now
|
|
alarm_settings.alarm_time -= datetime.timedelta(days=d.days)
|
|
|
|
# Calculate number of seconds until next alarm
|
|
d = alarm_settings.alarm_time - now
|
|
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()
|
|
self.process_led_state()
|
|
self.set_leds()
|
|
self.update_backlight()
|
|
self.check_play_sound()
|
|
|
|
def update_clock(self):
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face_plate"], False])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face"], False])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["hands"], False])
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if self.view == "set_alarm":
|
|
t = alarm_settings.alarm_time
|
|
else:
|
|
t = datetime.datetime.now()
|
|
|
|
hands = self.ids["hands"]
|
|
seconds_hand = self.position_on_clock(t.second/60, length=0.45*hands.size[0])
|
|
minutes_hand = self.position_on_clock(t.minute/60+t.second/3600, length=0.40*hands.size[0])
|
|
hours_hand = self.position_on_clock(t.hour/12 + t.minute/720, length=0.35*hands.size[0])
|
|
|
|
self.draw_list_curr_frame.append(["canvas.clear()", hands])
|
|
update_rate = App.get_running_app().update_rate
|
|
with hands.canvas:
|
|
if self.view == "set_alarm":
|
|
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, self.theme.color_alarm_hands_hours[0], self.theme.color_alarm_hands_hours[1], self.theme.color_alarm_hands_hours[2]])
|
|
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
|
|
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_alarm_hands_minutes[0], self.theme.color_alarm_hands_minutes[1], self.theme.color_alarm_hands_minutes[2]])
|
|
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
|
|
|
|
if self.grabbed == "":
|
|
self.set_alarm_timeout_counter += 1
|
|
|
|
if self.set_alarm_timeout_counter >= 4.5 * update_rate:
|
|
self.view = "clock"
|
|
self.set_alarm_timeout_counter = 0
|
|
self.view_active_since = time.time()
|
|
|
|
if alarm_settings.alarm_modified:
|
|
alarm_settings.alarm_activated = True
|
|
alarm_settings.alarm_modified = False
|
|
else:
|
|
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_hours[0], self.theme.color_clock_hands_hours[1], self.theme.color_clock_hands_hours[2]])
|
|
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, hours_hand.x, hours_hand.y], 3, "round"])
|
|
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_minutes[0], self.theme.color_clock_hands_minutes[1], self.theme.color_clock_hands_minutes[2]])
|
|
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, minutes_hand.x, minutes_hand.y], 2, "round"])
|
|
self.draw_list_curr_frame.append(["Color", hands.canvas, self.theme.color_clock_hands_seconds[0], self.theme.color_clock_hands_seconds[1], self.theme.color_clock_hands_seconds[2]])
|
|
self.draw_list_curr_frame.append(["Line", hands.canvas, [hands.center_x, hands.center_y, seconds_hand.x, seconds_hand.y], 1, "round"])
|
|
self.update_face()
|
|
|
|
def update_settings_menu(self):
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_background"], False])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], False])
|
|
|
|
background = self.ids["settings_menu_background"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", background])
|
|
with background.canvas:
|
|
rgb = self.theme.color_shade
|
|
self.draw_list_curr_frame.append(["Color", background.canvas, rgb[0], rgb[1], rgb[2]])
|
|
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, ""])
|
|
|
|
for s in ["label_0", "label_1", "label_2", "label_3", "label_4", "label_5", "theme_select_button", "wake_up_sound_select_button"]:
|
|
i = self.ids["settings_menu_" + s]
|
|
i.color = self.theme.color_font
|
|
i = self.ids["settings_menu_theme_select_button"]
|
|
i.background_color = self.theme.color_button
|
|
i = self.ids["settings_menu_wake_up_sound_select_button"]
|
|
i.background_color = self.theme.color_button
|
|
|
|
def update_settings_menu_wake_up_sound(self):
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound_background"], False])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], False])
|
|
|
|
background = self.ids["settings_menu_wake_up_sound_background"]
|
|
self.draw_list_curr_frame.append(["canvas.clear()", background])
|
|
with background.canvas:
|
|
rgb = self.theme.color_shade
|
|
self.draw_list_curr_frame.append(["Color", background.canvas, rgb[0], rgb[1], rgb[2]])
|
|
self.draw_list_curr_frame.append(["Rectangle", background.canvas, background.size, background.pos, ""])
|
|
|
|
for i in self.wake_up_sound_labels:
|
|
i.color = self.theme.color_font
|
|
|
|
self.settings_menu_wake_up_sound_Ok_button.background_color = self.theme.color_button
|
|
|
|
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, ""])
|
|
|
|
for s in ["label_top", "label_0", "label_1", "label_2", "Ok_button"]:
|
|
i = self.ids["settings_menu_theme_" + s]
|
|
i.color = self.theme.color_font
|
|
i = self.ids["settings_menu_theme_Ok_button"]
|
|
i.background_color = self.theme.color_button
|
|
|
|
def update_settings(self):
|
|
if self.view == "settings_menu":
|
|
self.update_settings_menu()
|
|
elif self.view == "settings_menu_wake_up_sound":
|
|
self.update_settings_menu_wake_up_sound()
|
|
elif self.view == "settings_menu_theme":
|
|
self.update_settings_menu_theme()
|
|
|
|
def draw_display(self):
|
|
t = time.time()
|
|
if (self.view != self.view_prev) or (t - self.view_active_since < self.time_to_force_redraws_after_view_change):
|
|
self.draw_list_last_frame = [] # force redraw when view has changed
|
|
self.view_prev = self.view
|
|
|
|
if self.draw_list_curr_frame != self.draw_list_last_frame:
|
|
for i in self.draw_list_curr_frame:
|
|
if i[0] == "self.hide_widget":
|
|
self.hide_widget(i[1], i[2])
|
|
elif i[0] == "canvas.clear()":
|
|
i[1].canvas.clear()
|
|
elif i[0] == "Color":
|
|
with i[1]:
|
|
if len(i) == 5:
|
|
Color(i[2], i[3], i[4])
|
|
else:
|
|
Color(i[2], i[3], i[4], i[5])
|
|
elif i[0] == "Rectangle":
|
|
with i[1]:
|
|
Rectangle(size=i[2], pos=i[3], source=i[4])
|
|
elif i[0] == "Ellipse":
|
|
with i[1]:
|
|
Ellipse(size=i[2], pos=i[3])
|
|
elif i[0] == "Line":
|
|
with i[1]:
|
|
Line(points=i[2], width=i[3], cap=i[4])
|
|
else:
|
|
print("Unknown draw command: " + i[0])
|
|
self.draw_list_last_frame = self.draw_list_curr_frame
|
|
self.draw_list_curr_frame = []
|
|
|
|
def process_touch_events(self):
|
|
t = time.time()
|
|
if (self.touch_down_event_curr is not None) and (self.touch_down_event_curr.processed == False) and \
|
|
(t - self.touch_down_event_curr.time > self.touch_delay_time):
|
|
self.touch_down_function(self.touch_down_event_curr.touch)
|
|
self.touch_down_event_curr.processed = True
|
|
self.touch_down_event_prev = copy.copy(self.touch_down_event_curr)
|
|
self.touch_down_event_curr = None
|
|
|
|
if (self.touch_move_event_curr is not None) and (self.touch_move_event_curr.processed == False) and \
|
|
(t - self.touch_move_event_curr.time > self.touch_delay_time):
|
|
self.touch_move_function(self.touch_move_event_curr.touch)
|
|
self.touch_move_event_curr.processed = True
|
|
self.touch_move_event_prev = copy.copy(self.touch_move_event_curr)
|
|
self.touch_move_event_curr = None
|
|
|
|
if (self.touch_up_event_curr is not None) and (self.touch_up_event_curr.processed == False) and \
|
|
(t - self.touch_up_event_curr.time > self.touch_delay_time):
|
|
self.touch_up_function(self.touch_up_event_curr.touch)
|
|
self.touch_up_event_curr.processed = True
|
|
self.touch_up_event_prev = copy.copy(self.touch_up_event_curr)
|
|
self.touch_up_event_curr = None
|
|
|
|
def update_display(self, *args):
|
|
self.process_touch_events()
|
|
self.check_alarm()
|
|
|
|
# Hide all dynamic widgets; will be enabled when updating respecive view
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face_plate"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["face"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["hands"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_background"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound_background"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_wake_up_sound"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme_background"], True])
|
|
self.draw_list_curr_frame.append(["self.hide_widget", self.ids["settings_menu_theme"], True])
|
|
|
|
self.update_background()
|
|
self.update_light_button()
|
|
self.update_play_button()
|
|
self.update_set_alarm_button()
|
|
self.update_settings_button()
|
|
if self.view == "clock" or self.view == "set_alarm":
|
|
self.update_clock()
|
|
elif self.view.startswith("settings_menu"):
|
|
self.update_settings()
|
|
else:
|
|
print("unknown view: " + self.view)
|
|
|
|
self.draw_display()
|
|
|
|
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
|
|
|
|
for c in self.wake_up_sound_checkboxes:
|
|
c.active = False
|
|
|
|
print("sound selected: " + alarm_settings.sound_selected)
|
|
|
|
n = 0
|
|
for i in self.wake_up_sounds:
|
|
if i == alarm_settings.sound_selected:
|
|
self.wake_up_sound_checkboxes[n].active = True
|
|
n = n + 1
|
|
|
|
self.view = "settings_menu_wake_up_sound"
|
|
self.view_active_since = time.time()
|
|
|
|
def settings_menu_wake_up_sound_Ok_button_cb(self, event):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
self.ids["settings_menu_wake_up_sound_select_button"].text = alarm_settings.sound_selected
|
|
self.view = "settings_menu"
|
|
self.view_active_since = time.time()
|
|
|
|
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
|
|
|
|
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 = self.wake_up_sounds[sound]
|
|
alarm_settings.sound_selected = sound
|
|
|
|
def settings_menu_theme_select_button_cb(self):
|
|
self.settings_menu_wake_up_theme_button_cb_hack = True
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
self.ids["settings_menu_theme_Dark"].active = False
|
|
self.ids["settings_menu_theme_Light"].active = False
|
|
print("theme selected: " + self.theme.name)
|
|
if self.theme.name == "Dark":
|
|
self.ids["settings_menu_theme_Dark"].active = True
|
|
elif self.theme.name == "Light":
|
|
self.ids["settings_menu_theme_Light"].active = True
|
|
|
|
self.view = "settings_menu_theme"
|
|
self.view_active_since = time.time()
|
|
|
|
def settings_menu_theme_Ok_button_cb(self):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
self.ids["settings_menu_theme_select_button"].text = self.theme.name
|
|
self.view = "settings_menu"
|
|
self.view_active_since = time.time()
|
|
|
|
def settings_menu_theme_cb(self, instance, value, theme):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if self.settings_menu_theme_select_button_cb_hack:
|
|
self.settings_menu_theme_select_button_cb_hack = False
|
|
if not (self.theme.name == "" and theme != ""):
|
|
return
|
|
|
|
if value == True:
|
|
print("You selected " + theme)
|
|
else:
|
|
print("You deselected " + theme)
|
|
|
|
self.theme_selected = theme
|
|
if theme == "Automatic":
|
|
self.theme = Theme("Light")
|
|
else:
|
|
self.theme = Theme(theme)
|
|
|
|
def volume_slider_value(self, *args):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
alarm_settings.volume = int(args[1])
|
|
|
|
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
|
|
|
|
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
|
|
|
|
alarm_settings.reading_light_brightness = int(args[1])
|
|
if (self.light_state == "reading"):
|
|
self.intensity_target = alarm_settings.reading_light_brightness / 20.0
|
|
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
|
|
|
|
alarm_settings.display_brightness = int(args[1])
|
|
|
|
def on_light_button_pressed(self):
|
|
print("light button pressed from view " + self.view)
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
if self.light_state == "off":
|
|
self.light_state = "reading"
|
|
self.intensity_target = alarm_settings.reading_light_brightness / 20.0
|
|
elif self.light_state == "reading":
|
|
self.light_state = "off"
|
|
self.intensity_target = 0
|
|
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:
|
|
self.light_state = "reading"
|
|
self.intensity_target = alarm_settings.reading_light_brightness / 20.0
|
|
else:
|
|
self.light_state = "off"
|
|
|
|
elif self.light_state == "on":
|
|
self.light_state = "reading"
|
|
self.intensity_target = 0
|
|
if alarm_settings.alarm_playing:
|
|
self.stop_sound()
|
|
|
|
def on_play_button_pressed(self):
|
|
print("play button pressed from view " + self.view)
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
if alarm_settings.alarm_playing:
|
|
self.stop_sound()
|
|
else:
|
|
self.play_sound(alarm_settings.sound_source)
|
|
|
|
def on_alarm_button_pressed(self):
|
|
print("alarm button pressed from view " + self.view)
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
alarm_settings.alarm_modified = False
|
|
self.set_alarm_timeout_counter = 0
|
|
|
|
if self.view == "set_alarm":
|
|
self.view = "clock"
|
|
self.view_active_since = time.time()
|
|
alarm_settings.alarm_activated = False
|
|
else:
|
|
self.view = "set_alarm"
|
|
self.view_active_since = time.time()
|
|
alarm_settings.alarm_activated = True
|
|
|
|
def on_settings_button_pressed(self):
|
|
print("settings button pressed from view " + self.view)
|
|
if self.view != "settings_menu":
|
|
self.view = "settings_menu"
|
|
self.view_active_since = time.time()
|
|
else:
|
|
self.view = "clock"
|
|
self.view_active_since = time.time()
|
|
print("view updated to " + self.view)
|
|
|
|
def touch_up_function(self, touch):
|
|
self.grabbed = ""
|
|
self.light_button_move_init = []
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
|
|
if (self.view == "set_alarm") and (self.grabbed == "hour" or self.grabbed == "minute"):
|
|
self.set_alarm_timeout_counter = 0
|
|
|
|
super(MyClockWidget, self).on_touch_up(touch)
|
|
|
|
def touch_move_function(self, touch):
|
|
if self.grabbed == "":
|
|
return
|
|
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
|
|
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)
|
|
|
|
if self.grabbed == "minute":
|
|
alarm_settings.alarm_modified = True
|
|
self.set_alarm_timeout_counter = 0
|
|
minute = round(-touch_curr.angle * 30 + 15)
|
|
|
|
while minute < 0:
|
|
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
|
|
|
|
# hour correction
|
|
hour = alarm_settings.alarm_time.hour
|
|
if alarm_settings.alarm_time.minute >= 55 and minute <= 5:
|
|
hour += 1
|
|
elif alarm_settings.alarm_time.minute <= 5 and minute >= 55:
|
|
hour -= 1
|
|
|
|
while hour < 0:
|
|
hour += 24
|
|
while hour >= 24:
|
|
hour -= 24
|
|
|
|
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)
|
|
elif self.grabbed == "hour":
|
|
alarm_settings.alarm_modified = True
|
|
self.set_alarm_timeout_counter = 0
|
|
hour = round(-touch_curr.angle * 6 + 3)
|
|
|
|
while hour < 0:
|
|
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
|
|
|
|
if alarm_settings.alarm_time.hour >= 12:
|
|
hour += 12
|
|
|
|
|
|
# AM / PM correction
|
|
if alarm_settings.alarm_time.hour == 11 and hour == 0:
|
|
hour = 12
|
|
elif alarm_settings.alarm_time.hour == 23 and hour == 12:
|
|
hour = 0
|
|
elif alarm_settings.alarm_time.hour == 0 and hour == 11:
|
|
hour = 23
|
|
elif alarm_settings.alarm_time.hour == 12 and hour == 23:
|
|
hour = 11
|
|
|
|
minute = alarm_settings.alarm_time.minute
|
|
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)
|
|
|
|
elif self.grabbed == "light_button":
|
|
if len(self.light_button_move_init) == 0:
|
|
self.light_button_move_init = touch_curr.spos
|
|
|
|
|
|
d = touch_curr.spos[0] - self.light_button_move_init[0]
|
|
threshold = 0.05
|
|
|
|
# Ugly workaround for issue with Kivy and Raspberry Pi 3 + touch screen: mirror d if position is on other side
|
|
if self.light_button_move_init[0] > 0.5:
|
|
d = -d
|
|
|
|
if d > 0.05:
|
|
# move to the right: set light to wake up level
|
|
self.light_state = "on"
|
|
elif d < -0.05:
|
|
# move to the left: set light off
|
|
self.light_state = "off"
|
|
|
|
super(MyClockWidget, self).on_touch_move(touch)
|
|
|
|
def touch_down_function(self, touch):
|
|
alarm_settings = App.get_running_app().alarm_settings
|
|
t = alarm_settings.alarm_time
|
|
hands = self.ids["hands"]
|
|
minutes_hand = self.position_on_clock(t.minute/60+t.second/3600, length=0.40*hands.size[0])
|
|
hours_hand = self.position_on_clock(t.hour/12 + t.minute/720, length=0.35*hands.size[0])
|
|
|
|
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):
|
|
self.on_play_button_pressed()
|
|
elif (0.85 <= touch.spos[0] <= 0.95) and (0.05 <= touch.spos[1] <= 0.15):
|
|
self.on_alarm_button_pressed()
|
|
elif (0.85 <= touch.spos[0] <= 0.95) and (0.85 <= touch.spos[1] <= 0.95):
|
|
self.on_settings_button_pressed()
|
|
elif self.view == "set_alarm":
|
|
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 = ""
|
|
elif self.view == "settings_menu":
|
|
pass
|
|
elif self.view == "settings_menu_wake_up_sound":
|
|
pass
|
|
elif self.view == "settings_menu_theme_select":
|
|
pass
|
|
elif self.view == "clock":
|
|
self.stop_sound()
|
|
|
|
super(MyClockWidget, self).on_touch_down(touch)
|
|
|
|
def on_touch_down(self, touch, after=False):
|
|
t = time.time()
|
|
|
|
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
|
|
return True
|
|
|
|
"""
|
|
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))
|
|
"""
|
|
|
|
if after:
|
|
self.touch_down_event_curr = TouchEvent(touch)
|
|
return True
|
|
else:
|
|
Clock.schedule_once(lambda dt: self.on_touch_down(touch, True))
|
|
return super(MyClockWidget, self).on_touch_down(touch)
|
|
|
|
def on_touch_move(self, touch, after=False):
|
|
t = time.time()
|
|
|
|
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
|
|
return True
|
|
|
|
"""
|
|
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))
|
|
"""
|
|
|
|
if after:
|
|
# Do not delay processing of move events
|
|
self.touch_move_function(touch)
|
|
return True
|
|
else:
|
|
Clock.schedule_once(lambda dt: self.on_touch_move(touch, True))
|
|
return super(MyClockWidget, self).on_touch_move(touch)
|
|
|
|
def on_touch_up(self, touch, after=False):
|
|
t = time.time()
|
|
|
|
if t - self.view_active_since <= self.time_to_ignore_inputs_after_view_change:
|
|
return True
|
|
|
|
"""
|
|
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))
|
|
"""
|
|
|
|
if after:
|
|
self.touch_up_event_curr = TouchEvent(touch)
|
|
return True
|
|
else:
|
|
Clock.schedule_once(lambda dt: self.on_touch_up(touch, True))
|
|
return super(MyClockWidget, self).on_touch_up(touch)
|
|
|
|
class MyApp(App):
|
|
alarm_settings = AlarmSettings()
|
|
update_rate = 60.0
|
|
|
|
# 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))
|
|
|
|
def build(self):
|
|
clock_widget = MyClockWidget()
|
|
|
|
x = clock_widget.ids["settings_menu_wake_up_sound_boxlayout"]
|
|
gl = GridLayout(
|
|
cols=2,
|
|
)
|
|
|
|
clock_widget.wake_up_sounds = WakeUpSounds
|
|
|
|
self.alarm_settings.sound_selected = next(iter(clock_widget.wake_up_sounds))
|
|
self.alarm_settings.sound_source = clock_widget.wake_up_sounds[self.alarm_settings.sound_selected]
|
|
clock_widget.ids["settings_menu_wake_up_sound_select_button"].text = self.alarm_settings.sound_selected
|
|
|
|
clock_widget.wake_up_sound_checkboxes = []
|
|
clock_widget.wake_up_sound_labels = []
|
|
|
|
i = 0
|
|
for w in clock_widget.wake_up_sounds:
|
|
c = CheckBox(
|
|
group = "settings_menu_wake_up_sound",
|
|
size = [gl.size[0] * 0.1, gl.size[1]],
|
|
)
|
|
c.bind(active=clock_widget.settings_menu_wake_up_sound_cb)
|
|
gl.add_widget(c)
|
|
clock_widget.wake_up_sound_checkboxes.append(c)
|
|
|
|
if i == 0:
|
|
a = True
|
|
else:
|
|
a = False
|
|
|
|
l = Label(
|
|
text = w,
|
|
halign = "left",
|
|
valign = "middle",
|
|
size = [gl.size[0] * 2.5, c.size[1]],
|
|
text_size = Window.size,
|
|
font_size = Window.height*0.05,
|
|
color = clock_widget.theme.color_font,
|
|
active = a
|
|
)
|
|
l.text_size = l.size
|
|
gl.add_widget(l)
|
|
clock_widget.wake_up_sound_labels.append(l)
|
|
i = i + 1
|
|
|
|
x.add_widget(gl)
|
|
|
|
b = Button(
|
|
text = "Ok",
|
|
font_size = clock_widget.height*0.3,
|
|
color = clock_widget.theme.color_font,
|
|
background_normal = '',
|
|
background_color = clock_widget.theme.color_button
|
|
)
|
|
b.bind(on_press = clock_widget.settings_menu_wake_up_sound_Ok_button_cb)
|
|
x.add_widget(b)
|
|
clock_widget.settings_menu_wake_up_sound_Ok_button = b
|
|
|
|
update_rate = App.get_running_app().update_rate
|
|
# update initially, just after construction of the widget is complete
|
|
Clock.schedule_once(clock_widget.update_display, 0)
|
|
# then update at update_rate times per second
|
|
Clock.schedule_interval(clock_widget.update_display, 1.0/update_rate)
|
|
|
|
if is_arm():
|
|
Window.borderless = True
|
|
|
|
return clock_widget
|
|
|
|
def except_hook(type, value, tb):
|
|
if is_arm():
|
|
pixels.fill((0, 0, 0, 0))
|
|
pixels.show()
|
|
backlight.brightness = 50
|
|
return
|
|
|
|
if __name__ == '__main__':
|
|
if is_arm():
|
|
sys.excepthook = except_hook
|
|
MyApp().run()
|