Skip to content

Commit bbce3e5

Browse files
authored
Merge pull request #60 from pimoroni/examples/tomato-timer
Examples/tomato timer
2 parents becb35d + 9dbfb4a commit bbce3e5

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

examples/tomato.py

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# ICON [[(-0.01, 10.0), (2.24, 9.81), (3.75, 9.44), (4.75, 9.07), (6.15, 8.34), (7.06, 7.74), (8.39, 6.6), (9.5, 5.36), (10.75, 3.41), (11.53, 1.42), (11.85, -0.05), (11.98, -1.31), (11.96, -2.9), (11.84, -4.02), (11.32, -6.07), (10.89, -7.15), (9.93, -8.8), (8.7, -10.29), (7.47, -11.42), (6.58, -12.08), (4.99, -12.96), (4.04, -13.34), (2.41, -13.78), (0.04, -14.0), (-0.01, -2.0), (-8.51, 6.5), (-7.0, 7.73), (-5.84, 8.47), (-4.65, 9.08), (-3.52, 9.48), (-2.22, 9.79), (-0.06, 10.0)], [(-0.01, 18.0), (-2.77, 17.82), (-5.22, 17.33), (-6.81, 16.84), (-9.0, 15.88), (-10.82, 14.83), (-12.37, 13.73), (-13.38, 12.88), (-14.8, 11.47), (-16.53, 9.28), (-17.71, 7.33), (-18.44, 5.84), (-18.93, 4.56), (-19.44, 2.82), (-19.69, 1.62), (-19.93, -0.24), (-19.98, -3.03), (-19.82, -4.82), (-19.36, -7.14), (-18.78, -8.99), (-18.18, -10.41), (-16.87, -12.77), (-15.61, -14.52), (-14.53, -15.77), (-13.03, -17.19), (-11.75, -18.19), (-9.49, -19.6), (-7.63, -20.48), (-5.31, -21.29), (-2.8, -21.81), (-1.17, -21.97), (0.56, -22.0), (2.17, -21.89), (4.17, -21.57), (5.78, -21.15), (6.98, -20.74), (8.54, -20.07), (10.61, -18.95), (12.5, -17.62), (14.56, -15.73), (15.71, -14.38), (16.82, -12.81), (18.11, -10.45), (18.75, -8.94), (19.3, -7.26), (19.84, -4.56), (19.98, -2.76), (19.98, -1.18), (19.8, 0.82), (19.39, 2.89), (18.67, 5.12), (17.97, 6.73), (16.56, 9.2), (15.45, 10.7), (13.58, 12.69), (11.88, 14.09), (10.45, 15.06), (9.16, 15.79), (6.7, 16.87), (5.01, 17.38), (2.25, 17.88), (0.04, 18.0)], [(-0.01, 14.0), (1.92, 13.89), (4.04, 13.53), (6.12, 12.86), (7.5, 12.21), (8.55, 11.61), (9.86, 10.67), (11.86, 8.81), (13.1, 7.28), (14.15, 5.61), (14.75, 4.36), (15.29, 2.88), (15.79, 0.68), (15.96, -0.91), (15.96, -3.16), (15.72, -5.08), (15.17, -7.27), (14.67, -8.56), (13.98, -9.93), (12.87, -11.61), (11.38, -13.32), (9.85, -14.68), (8.89, -15.38), (7.49, -16.22), (5.15, -17.22), (3.7, -17.61), (1.72, -17.92), (0.3, -18.0), (-1.89, -17.9), (-4.1, -17.52), (-5.31, -17.17), (-7.19, -16.38), (-8.13, -15.88), (-9.61, -14.88), (-10.93, -13.76), (-12.29, -12.34), (-13.3, -11.02), (-14.5, -8.96), (-15.22, -7.16), (-15.61, -5.71), (-15.89, -4.07), (-15.99, -1.35), (-15.76, 0.93), (-15.4, 2.54), (-14.53, 4.89), (-13.63, 6.52), (-12.25, 8.38), (-10.86, 9.82), (-9.67, 10.82), (-8.31, 11.75), (-6.16, 12.84), (-5.16, 13.21), (-2.83, 13.77), (-1.35, 13.95), (-0.06, 14.0)], [(-0.01, -2.0)]]
2+
# NAME Tomato Timer
3+
# DESC A pomodoro timer for your Presto
4+
5+
import time
6+
from picovector import ANTIALIAS_BEST, PicoVector, Polygon, Transform
7+
from presto import Presto, Buzzer
8+
from touch import Button
9+
10+
presto = Presto(ambient_light=True)
11+
display = presto.display
12+
WIDTH, HEIGHT = display.get_bounds()
13+
14+
# Centre points for the display
15+
CX = WIDTH // 2
16+
CY = HEIGHT // 2
17+
18+
# We'll need this for the touch element of the screen
19+
touch = presto.touch
20+
21+
# Pico Vector
22+
vector = PicoVector(display)
23+
vector.set_antialiasing(ANTIALIAS_BEST)
24+
t = Transform()
25+
26+
vector.set_font("Roboto-Medium.af", 96)
27+
vector.set_font_letter_spacing(100)
28+
vector.set_font_word_spacing(100)
29+
vector.set_transform(t)
30+
31+
BLACK = display.create_pen(0, 0, 0)
32+
33+
# Setup the buzzer. The Presto piezo is on pin 43.
34+
buzzer = Buzzer(43)
35+
36+
37+
class Tomato(object):
38+
def __init__(self):
39+
40+
self.hue = 0
41+
self.background = display.create_pen_hsv(self.hue, 0.8, 1.0) # We'll use this one for the background.
42+
self.foreground = display.create_pen_hsv(self.hue, 0.5, 1.0) # Slightly lighter for foreground elements.
43+
self.text_colour = display.create_pen_hsv(self.hue, 0.2, 1.0)
44+
45+
# Time constants.
46+
# Feel free to change these to ones that work better for you.
47+
self.TASK = 25 * 60
48+
self.SHORT = 10 * 60
49+
self.LONG = 30 * 60
50+
51+
# How long the completion alert should be played (seconds)
52+
self.alert_duration = 2
53+
self.alert_start_time = 0
54+
55+
self.is_break_time = False
56+
self.start_time = 0
57+
self.tasks_complete = 0
58+
self.running = False
59+
self.paused = False
60+
self.time_elapsed = 0
61+
self.current_timer = self.TASK
62+
63+
# We'll use a rect with rounded corners for the background.
64+
self.background_rect = Polygon()
65+
self.background_rect.rectangle(0, 0, WIDTH, HEIGHT, (10, 10, 10, 10))
66+
67+
self.foreground_rect = Polygon()
68+
self.foreground_rect.rectangle(10, 10, WIDTH - 20, HEIGHT - 120, (10, 10, 10, 10))
69+
70+
# Touch button
71+
self.start_button = Button(CX - 56, HEIGHT - 75, CX - 2, 50)
72+
x, y, w, h = self.start_button.bounds
73+
self.start = Polygon()
74+
self.start.rectangle(x, y, w, h, (10, 10, 10, 10))
75+
self.start_shadow = Polygon()
76+
self.start_shadow.rectangle(x + 3, y + 3, w, h, (10, 10, 10, 10))
77+
78+
# Update the pens for the background, foreground and text elements based on the given hue.
79+
def update_pens(self, hue):
80+
self.hue = hue
81+
self.background = display.create_pen_hsv(self.hue, 0.8, 1.0)
82+
self.foreground = display.create_pen_hsv(self.hue, 0.5, 1.0)
83+
self.text_colour = display.create_pen_hsv(self.hue, 0.2, 1.0)
84+
85+
def draw(self):
86+
87+
# Clear the screen
88+
display.set_pen(BLACK)
89+
display.clear()
90+
91+
# Draw the background rect with rounded corners
92+
display.set_pen(self.background)
93+
vector.draw(self.background_rect)
94+
95+
# Draw the foreground rect, this is where we will show the time remaining.
96+
display.set_pen(self.foreground)
97+
vector.draw(self.foreground_rect)
98+
99+
# Draw the button with drop shadow
100+
vector.draw(self.start_shadow)
101+
display.set_pen(self.text_colour)
102+
vector.draw(self.start)
103+
104+
# Draw the button text, the text shown here depends on the current timer state
105+
vector.set_font_size(24)
106+
display.set_pen(self.foreground)
107+
108+
if not self.running:
109+
if self.is_break_time:
110+
vector.text("Start Break", self.start_button.bounds[0] + 8, self.start_button.bounds[1] + 33)
111+
else:
112+
vector.text("Start Task", self.start_button.bounds[0] + 12, self.start_button.bounds[1] + 33)
113+
elif self.running and self.paused:
114+
vector.text("Resume", self.start_button.bounds[0] + 22, self.start_button.bounds[1] + 33)
115+
else:
116+
vector.text("Pause", self.start_button.bounds[0] + 32, self.start_button.bounds[1] + 33)
117+
118+
display.set_pen(self.text_colour)
119+
text = self.return_string()
120+
vector.set_font_size(96)
121+
tx = int(CX - (205 // 2))
122+
ty = int(CY - (58 // 2)) + 10
123+
vector.text(text, tx, ty)
124+
125+
def run(self):
126+
self.stop_buzzer()
127+
128+
if self.is_break_time:
129+
if self.tasks_complete < 4:
130+
self.current_timer = self.SHORT
131+
self.update_pens(0.55)
132+
else:
133+
self.current_timer = self.LONG
134+
self.update_pens(0.55)
135+
else:
136+
self.current_timer = self.TASK
137+
self.update_pens(0.0)
138+
139+
if not self.running:
140+
self.reset()
141+
self.running = True
142+
self.start_time = time.time()
143+
elif self.running and not self.paused:
144+
self.paused = True
145+
elif self.running and self.paused:
146+
self.paused = False
147+
self.start_time = time.time() - self.time_elapsed
148+
149+
def reset(self):
150+
self.start_time = 0
151+
self.time_elapsed = 0
152+
153+
def start_buzzer(self):
154+
self.alert_start_time = time.time()
155+
buzzer.set_tone(150)
156+
157+
def stop_buzzer(self):
158+
buzzer.set_tone(-1)
159+
self.alert_start_time = 0
160+
161+
def update(self):
162+
163+
if time.time() - self.alert_start_time >= self.alert_duration:
164+
self.stop_buzzer()
165+
166+
if self.running and not self.paused:
167+
168+
self.time_elapsed = time.time() - self.start_time
169+
170+
if self.time_elapsed >= self.current_timer:
171+
self.running = False
172+
self.start_buzzer()
173+
if not self.is_break_time:
174+
if self.tasks_complete < 4:
175+
self.tasks_complete += 1
176+
else:
177+
self.tasks_complete = 0
178+
self.is_break_time = not self.is_break_time
179+
180+
# Return the remaining time formatted in a string for displaying with vector text.
181+
def return_string(self):
182+
minutes, seconds = divmod(self.current_timer - self.time_elapsed, 60)
183+
return f"{minutes:02d}:{seconds:02d}"
184+
185+
def pressed(self):
186+
return self.start_button.is_pressed()
187+
188+
189+
# Create an instance of our timer object
190+
timer = Tomato()
191+
192+
while True:
193+
194+
if timer.pressed():
195+
while timer.pressed():
196+
touch.poll()
197+
timer.run()
198+
199+
timer.draw()
200+
timer.update()
201+
presto.update()

0 commit comments

Comments
 (0)