mirror of
https://github.com/pimoroni/grow-python
synced 2025-10-25 15:19:23 +00:00
Add light detection, fixes and tweaks
This commit is contained in:
@@ -9,6 +9,7 @@ import threading
|
|||||||
|
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
import ST7735
|
import ST7735
|
||||||
|
import ltr559
|
||||||
from fonts.ttf import RobotoMedium as UserFont
|
from fonts.ttf import RobotoMedium as UserFont
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
@@ -47,8 +48,9 @@ def icon(image, icon, position, color):
|
|||||||
|
|
||||||
|
|
||||||
class View:
|
class View:
|
||||||
def __init__(self):
|
def __init__(self, image):
|
||||||
pass
|
self._image = image
|
||||||
|
self._draw = ImageDraw.Draw(image)
|
||||||
|
|
||||||
def button_a(self):
|
def button_a(self):
|
||||||
return False
|
return False
|
||||||
@@ -65,12 +67,11 @@ class View:
|
|||||||
def update(self):
|
def update(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def label(
|
def label(
|
||||||
self,
|
self,
|
||||||
canvas,
|
|
||||||
position="X",
|
position="X",
|
||||||
text="",
|
text="",
|
||||||
bgcolor=(0, 0, 0),
|
bgcolor=(0, 0, 0),
|
||||||
@@ -80,8 +81,7 @@ class View:
|
|||||||
if position not in ["A", "B", "X", "Y"]:
|
if position not in ["A", "B", "X", "Y"]:
|
||||||
raise ValueError(f"Invalid label position {position}")
|
raise ValueError(f"Invalid label position {position}")
|
||||||
|
|
||||||
draw = ImageDraw.Draw(canvas)
|
text_w, text_h = self._draw.textsize(text, font=font)
|
||||||
text_w, text_h = draw.textsize(text, font=font)
|
|
||||||
text_h = 11
|
text_h = 11
|
||||||
text_w += margin * 2
|
text_w += margin * 2
|
||||||
text_h += margin * 2
|
text_h += margin * 2
|
||||||
@@ -97,17 +97,16 @@ class View:
|
|||||||
|
|
||||||
x2, y2 = x + text_w, y + text_h
|
x2, y2 = x + text_w, y + text_h
|
||||||
|
|
||||||
draw.rectangle((x, y, x2, y2), bgcolor)
|
self._draw.rectangle((x, y, x2, y2), bgcolor)
|
||||||
draw.text((x + margin, y + margin - 1), text, font=font, fill=textcolor)
|
self._draw.text((x + margin, y + margin - 1), text, font=font, fill=textcolor)
|
||||||
|
|
||||||
|
|
||||||
class MainView(View):
|
class MainView(View):
|
||||||
def __init__(self, channels=None):
|
def __init__(self, image, channels=None):
|
||||||
self.channels = channels
|
self.channels = channels
|
||||||
View.__init__(self)
|
View.__init__(self, image)
|
||||||
|
|
||||||
def render_channel(self, canvas, channel, font):
|
def render_channel(self, channel, font):
|
||||||
draw = ImageDraw.Draw(image)
|
|
||||||
x = [21, 61, 101][channel.channel - 1]
|
x = [21, 61, 101][channel.channel - 1]
|
||||||
|
|
||||||
# Saturation amounts from each sensor
|
# Saturation amounts from each sensor
|
||||||
@@ -116,65 +115,92 @@ class MainView(View):
|
|||||||
|
|
||||||
if active:
|
if active:
|
||||||
# Draw background bars
|
# Draw background bars
|
||||||
draw.rectangle(
|
self._draw.rectangle(
|
||||||
(x, int((1.0 - saturation) * HEIGHT), x + 37, HEIGHT),
|
(x, int((1.0 - saturation) * DISPLAY_HEIGHT), x + 37, DISPLAY_HEIGHT),
|
||||||
channel.indicator_color(saturation) if active else (229, 229, 229),
|
channel.indicator_color(saturation) if active else (229, 229, 229),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Channel selection icons
|
# Channel selection icons
|
||||||
x += 15
|
x += 15
|
||||||
col = channel.indicator_color(saturation, channel.label_colours)
|
col = channel.indicator_color(saturation, channel.label_colours)
|
||||||
draw.rectangle(
|
if channel.alarm:
|
||||||
(x, 2, x + 15, 17),
|
icon(
|
||||||
col if active else (129, 129, 129),
|
self._image,
|
||||||
)
|
icon_snooze,
|
||||||
|
(x - 2, 0),
|
||||||
|
col if active else (129, 129, 129)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._draw.rectangle(
|
||||||
|
(x, 2, x + 15, 17),
|
||||||
|
col if active else (129, 129, 129),
|
||||||
|
)
|
||||||
|
|
||||||
# TODO: replace number text with graphic
|
# TODO: replace number text with graphic
|
||||||
tw, th = font.getsize("{}".format(channel.channel))
|
tw, th = font.getsize("{}".format(channel.channel))
|
||||||
draw.text(
|
self._draw.text(
|
||||||
(x + int(math.ceil(8 - (tw / 2.0))), 2),
|
(x + int(math.ceil(8 - (tw / 2.0))), 2),
|
||||||
"{}".format(channel.channel),
|
"{}".format(channel.channel),
|
||||||
font=font,
|
font=font,
|
||||||
fill=(255, 255, 255) if active else (200, 200, 200),
|
fill=(255, 255, 255) if active else (200, 200, 200),
|
||||||
)
|
)
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self):
|
||||||
draw = ImageDraw.Draw(canvas)
|
self._draw.rectangle((0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT), (255, 255, 255))
|
||||||
width, height = canvas.size
|
|
||||||
draw.rectangle((0, 0, width, height), (255, 255, 255))
|
|
||||||
|
|
||||||
for channel in self.channels:
|
for channel in self.channels:
|
||||||
self.render_channel(canvas, channel, font)
|
self.render_channel(channel, font)
|
||||||
|
|
||||||
# Icon backdrops
|
# Icon backdrops
|
||||||
draw.rectangle((0, 0, 19, 19), (32, 138, 251))
|
self._draw.rectangle((0, 0, 19, 19), (32, 138, 251))
|
||||||
|
|
||||||
# Icons
|
# Icons
|
||||||
icon(image, icon_rightarrow, (0, 0), (255, 255, 255))
|
icon(self._image, icon_rightarrow, (0, 0), (255, 255, 255))
|
||||||
|
|
||||||
alarm.render(canvas, (0, DISPLAY_HEIGHT - 19))
|
alarm.render((0, DISPLAY_HEIGHT - 19))
|
||||||
|
|
||||||
|
|
||||||
class DetailView(View):
|
class ChannelView(View):
|
||||||
def __init__(self, channel=None):
|
def draw_status(self, subtle=False):
|
||||||
|
self._draw.rectangle((0, 20, DISPLAY_WIDTH, 40), (50, 50, 50))
|
||||||
|
|
||||||
|
self._draw.text(
|
||||||
|
(3, 23),
|
||||||
|
f"{self.channel.sensor.saturation * 100:.2f}% ({self.channel.sensor.moisture:.2f}Hz)",
|
||||||
|
font=font,
|
||||||
|
fill=(150, 150, 150) if subtle else (255, 255, 255),
|
||||||
|
)
|
||||||
|
|
||||||
|
def draw_next_button(self, disabled=False):
|
||||||
|
if disabled:
|
||||||
|
# Draw disabled "Next" button
|
||||||
|
self._draw.rectangle((0, 0, 19, 19), (138, 138, 138))
|
||||||
|
icon(self._image, icon_rightarrow, (0, 0), (150, 150, 150))
|
||||||
|
else:
|
||||||
|
self._draw.rectangle((0, 0, 19, 19), COLOR_BLUE)
|
||||||
|
icon(self._image, icon_rightarrow, (0, 0), COLOR_WHITE)
|
||||||
|
|
||||||
|
|
||||||
|
class DetailView(ChannelView):
|
||||||
|
def __init__(self, image, channel=None):
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
View.__init__(self)
|
View.__init__(self, image)
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self):
|
||||||
draw = ImageDraw.Draw(canvas)
|
width, height = self._image.size
|
||||||
width, height = canvas.size
|
self._draw.rectangle((0, 0, width, height), (255, 255, 255))
|
||||||
draw.rectangle((0, 0, width, height), (255, 255, 255))
|
|
||||||
|
|
||||||
draw.text(
|
self._draw.text(
|
||||||
(23, 3),
|
(23, 3),
|
||||||
"{}".format(self.channel.title),
|
"{}".format(self.channel.title),
|
||||||
font=font,
|
font=font,
|
||||||
fill=(0, 0, 0),
|
fill=(0, 0, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
graph_height = DISPLAY_HEIGHT - 20
|
graph_height = DISPLAY_HEIGHT - 40
|
||||||
|
|
||||||
draw.rectangle((0, 20, DISPLAY_WIDTH, DISPLAY_HEIGHT), (60, 60, 60))
|
self._draw.rectangle((0, 40, DISPLAY_WIDTH, 40 + graph_height), (10, 10, 10))
|
||||||
|
self.draw_status()
|
||||||
|
|
||||||
offset_x = 20
|
offset_x = 20
|
||||||
offset_y = 20
|
offset_y = 20
|
||||||
@@ -182,47 +208,42 @@ class DetailView(View):
|
|||||||
for x, value in enumerate(self.channel.sensor.history[:DISPLAY_WIDTH]):
|
for x, value in enumerate(self.channel.sensor.history[:DISPLAY_WIDTH]):
|
||||||
color = self.channel.indicator_color(value)
|
color = self.channel.indicator_color(value)
|
||||||
h = value * graph_height
|
h = value * graph_height
|
||||||
draw.rectangle((x, DISPLAY_HEIGHT - h, x + 1, DISPLAY_HEIGHT), color)
|
x = DISPLAY_WIDTH - x - 1
|
||||||
|
self._draw.rectangle((x, DISPLAY_HEIGHT - h, x + 1, DISPLAY_HEIGHT), color)
|
||||||
|
|
||||||
alarm_line = self.channel.alarm_level * graph_height
|
alarm_line = int(self.channel.alarm_level * graph_height)
|
||||||
draw.rectangle(
|
r = 255
|
||||||
|
if self.channel.alarm:
|
||||||
|
r = int(((math.sin(time.time() * 3 * math.pi) + 1.0) / 2.0) * 128) + 127
|
||||||
|
self._draw.rectangle(
|
||||||
(
|
(
|
||||||
0,
|
0,
|
||||||
DISPLAY_HEIGHT - alarm_line,
|
DISPLAY_HEIGHT - alarm_line,
|
||||||
|
DISPLAY_WIDTH - 40,
|
||||||
|
DISPLAY_HEIGHT - alarm_line + 1,
|
||||||
|
),
|
||||||
|
(r, 0, 0),
|
||||||
|
)
|
||||||
|
self._draw.rectangle(
|
||||||
|
(
|
||||||
|
DISPLAY_WIDTH - 20,
|
||||||
|
DISPLAY_HEIGHT - alarm_line,
|
||||||
DISPLAY_WIDTH,
|
DISPLAY_WIDTH,
|
||||||
DISPLAY_HEIGHT - alarm_line + 1,
|
DISPLAY_HEIGHT - alarm_line + 1,
|
||||||
),
|
),
|
||||||
(255, 0, 0),
|
(r, 0, 0),
|
||||||
)
|
|
||||||
draw.rectangle(
|
|
||||||
(
|
|
||||||
DISPLAY_WIDTH - 50,
|
|
||||||
DISPLAY_HEIGHT - alarm_line - 16,
|
|
||||||
DISPLAY_WIDTH,
|
|
||||||
DISPLAY_HEIGHT - alarm_line + 1,
|
|
||||||
),
|
|
||||||
(255, 0, 0),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
draw.text(
|
icon(self._image, icon_snooze, (DISPLAY_WIDTH - 40, DISPLAY_HEIGHT - alarm_line - 10), (r, 0, 0))
|
||||||
(DISPLAY_WIDTH - 47, DISPLAY_HEIGHT - alarm_line - 15),
|
|
||||||
"Alarm",
|
|
||||||
font=font,
|
|
||||||
fill=(255, 255, 255),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Icon backdrops
|
self.draw_next_button()
|
||||||
draw.rectangle((0, 0, 19, 19), (32, 138, 251))
|
|
||||||
|
|
||||||
# Icons
|
|
||||||
icon(image, icon_rightarrow, (0, 0), (255, 255, 255))
|
|
||||||
|
|
||||||
# Edit
|
# Edit
|
||||||
self.label(canvas, "X", "Edit", textcolor=(255, 255, 255), bgcolor=COLOR_RED)
|
self.label("X", "Edit", textcolor=(255, 255, 255), bgcolor=COLOR_RED)
|
||||||
|
|
||||||
|
|
||||||
class EditView(View):
|
class EditView(ChannelView):
|
||||||
def __init__(self, channel=None):
|
def __init__(self, image, channel=None):
|
||||||
self._options = [
|
self._options = [
|
||||||
{
|
{
|
||||||
"title": "Alarm Level",
|
"title": "Alarm Level",
|
||||||
@@ -258,21 +279,16 @@ class EditView(View):
|
|||||||
self._current_option = 0
|
self._current_option = 0
|
||||||
self._change_mode = False
|
self._change_mode = False
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
View.__init__(self)
|
View.__init__(self, image)
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self):
|
||||||
draw = ImageDraw.Draw(canvas)
|
graph_height = DISPLAY_HEIGHT - 40
|
||||||
width, height = canvas.size
|
|
||||||
draw.rectangle((0, 0, width, height), (255, 255, 255))
|
|
||||||
|
|
||||||
draw.text((23, 3), "{}".format(self.channel.title), font=font, fill=(0, 0, 0))
|
self._draw.rectangle((0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT), (255, 255, 255))
|
||||||
|
|
||||||
draw.text(
|
self._draw.text((23, 3), "{}".format(self.channel.title), font=font, fill=(0, 0, 0))
|
||||||
(5, 25),
|
|
||||||
f"Now: {self.channel.sensor.saturation * 100:.2f}% {self.channel.sensor.moisture:.2f}Hz",
|
self.draw_status(True)
|
||||||
font=font,
|
|
||||||
fill=(0, 0, 0),
|
|
||||||
)
|
|
||||||
|
|
||||||
option = self._options[self._current_option]
|
option = self._options[self._current_option]
|
||||||
title = option["title"]
|
title = option["title"]
|
||||||
@@ -280,23 +296,18 @@ class EditView(View):
|
|||||||
value = getattr(self.channel, prop)
|
value = getattr(self.channel, prop)
|
||||||
text = option["format"](value)
|
text = option["format"](value)
|
||||||
mode = option.get("mode", "int")
|
mode = option.get("mode", "int")
|
||||||
draw.text((5, 40), f"{title} : {text}", font=font, fill=(0, 0, 0))
|
self._draw.text((3, 43), f"{title} : {text}", font=font, fill=(0, 0, 0))
|
||||||
|
|
||||||
draw.rectangle((0, 0, 19, 19), (138, 138, 138))
|
self.draw_next_button(True)
|
||||||
|
|
||||||
# Icons
|
|
||||||
icon(image, icon_rightarrow, (0, 0), (255, 255, 255))
|
|
||||||
|
|
||||||
if self._change_mode:
|
if self._change_mode:
|
||||||
self.label(canvas, "Y", "Yes" if mode == "bool" else "++", textcolor=COLOR_WHITE, bgcolor=COLOR_YELLOW)
|
self.label("Y", "Yes" if mode == "bool" else "++", textcolor=COLOR_WHITE, bgcolor=COLOR_YELLOW)
|
||||||
self.label(canvas, "B", "No" if mode == "bool" else "--", textcolor=COLOR_WHITE, bgcolor=COLOR_BLUE)
|
self.label("B", "No" if mode == "bool" else "--", textcolor=COLOR_WHITE, bgcolor=COLOR_BLUE)
|
||||||
else:
|
else:
|
||||||
self.label(
|
self.label("Y", "Change", textcolor=COLOR_WHITE, bgcolor=COLOR_YELLOW)
|
||||||
canvas, "Y", "Change", textcolor=COLOR_WHITE, bgcolor=COLOR_YELLOW
|
self.label("B", "Next", textcolor=COLOR_WHITE, bgcolor=COLOR_BLUE)
|
||||||
)
|
|
||||||
self.label(canvas, "B", "Next", textcolor=COLOR_WHITE, bgcolor=COLOR_BLUE)
|
|
||||||
|
|
||||||
self.label(canvas, "X", "Done", textcolor=COLOR_WHITE, bgcolor=COLOR_RED)
|
self.label("X", "Done", textcolor=COLOR_WHITE, bgcolor=COLOR_RED)
|
||||||
|
|
||||||
def button_a(self):
|
def button_a(self):
|
||||||
pass
|
pass
|
||||||
@@ -320,6 +331,7 @@ class EditView(View):
|
|||||||
else:
|
else:
|
||||||
self._current_option += 1
|
self._current_option += 1
|
||||||
self._current_option %= len(self._options)
|
self._current_option %= len(self._options)
|
||||||
|
return True
|
||||||
|
|
||||||
def button_x(self):
|
def button_x(self):
|
||||||
if self._change_mode:
|
if self._change_mode:
|
||||||
@@ -388,17 +400,43 @@ class Channel:
|
|||||||
self.pump_speed = pump_speed
|
self.pump_speed = pump_speed
|
||||||
self.pump_time = pump_time
|
self.pump_time = pump_time
|
||||||
self.watering_delay = watering_delay
|
self.watering_delay = watering_delay
|
||||||
self.wet_point = wet_point
|
self._wet_point = wet_point
|
||||||
self.dry_point = dry_point
|
self._dry_point = dry_point
|
||||||
self.last_dose = time.time()
|
self.last_dose = time.time()
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.enabled = enabled
|
self._enabled = enabled
|
||||||
self.alarm = False
|
self.alarm = False
|
||||||
self.title = f"Channel {display_channel}" if title is None else title
|
self.title = f"Channel {display_channel}" if title is None else title
|
||||||
|
|
||||||
self.sensor.set_wet_point(wet_point)
|
self.sensor.set_wet_point(wet_point)
|
||||||
self.sensor.set_dry_point(dry_point)
|
self.sensor.set_dry_point(dry_point)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@enabled.setter
|
||||||
|
def enabled(self, enabled):
|
||||||
|
self._enabled = enabled
|
||||||
|
|
||||||
|
@property
|
||||||
|
def wet_point(self):
|
||||||
|
return self._wet_point
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dry_point(self):
|
||||||
|
return self._dry_point
|
||||||
|
|
||||||
|
@wet_point.setter
|
||||||
|
def wet_point(self, wet_point):
|
||||||
|
self._wet_point = wet_point
|
||||||
|
self.sensor.set_wet_point(wet_point)
|
||||||
|
|
||||||
|
@dry_point.setter
|
||||||
|
def dry_point(self, dry_point):
|
||||||
|
self._dry_point = dry_point
|
||||||
|
self.sensor.set_dry_point(dry_point)
|
||||||
|
|
||||||
def indicator_color(self, value, r=None):
|
def indicator_color(self, value, r=None):
|
||||||
value = 1.0 - value
|
value = 1.0 - value
|
||||||
|
|
||||||
@@ -444,7 +482,16 @@ Delay: {watering_delay}
|
|||||||
Wet point: {wet_point}
|
Wet point: {wet_point}
|
||||||
Dry point: {dry_point}
|
Dry point: {dry_point}
|
||||||
""".format(
|
""".format(
|
||||||
**self.__dict__
|
channel=self.channel,
|
||||||
|
enabled=self.enabled,
|
||||||
|
alarm_level=self.alarm_level,
|
||||||
|
auto_water=self.auto_water,
|
||||||
|
water_level=self.water_level,
|
||||||
|
pump_speed=self.pump_speed,
|
||||||
|
pump_time=self.pump_time,
|
||||||
|
watering_delay=self.watering_delay,
|
||||||
|
wet_point=self.wet_point,
|
||||||
|
dry_point=self.dry_point
|
||||||
)
|
)
|
||||||
|
|
||||||
def water(self):
|
def water(self):
|
||||||
@@ -470,17 +517,22 @@ Dry point: {dry_point}
|
|||||||
self.channel, self.pump_speed, self.pump_time
|
self.channel, self.pump_speed, self.pump_time
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if sat < self.alarm_level and not self.alarm:
|
if sat < self.alarm_level:
|
||||||
|
if not self.alarm:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Alarm on Channel: {} - saturation is {:.2f}% (warn level {:.2f}%)".format(
|
"Alarm on Channel: {} - saturation is {:.2f}% (warn level {:.2f}%)".format(
|
||||||
self.channel, sat * 100, self.alarm_level * 100
|
self.channel, sat * 100, self.alarm_level * 100
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.alarm = True
|
self.alarm = True
|
||||||
|
else:
|
||||||
|
self.alarm = False
|
||||||
|
|
||||||
|
|
||||||
class Alarm:
|
class Alarm:
|
||||||
def __init__(self, enabled=True, interval=10.0, beep_frequency=440):
|
def __init__(self, image, enabled=True, interval=10.0, beep_frequency=440):
|
||||||
|
self._image = image
|
||||||
|
self._draw = ImageDraw.Draw(image)
|
||||||
self.piezo = Piezo()
|
self.piezo = Piezo()
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
@@ -494,13 +546,14 @@ class Alarm:
|
|||||||
self.enabled = config.get("alarm_enable", self.enabled)
|
self.enabled = config.get("alarm_enable", self.enabled)
|
||||||
self.interval = config.get("alarm_interval", self.interval)
|
self.interval = config.get("alarm_interval", self.interval)
|
||||||
|
|
||||||
def update(self):
|
def update(self, lights_out=False):
|
||||||
if self._sleep_until is not None:
|
if self._sleep_until is not None:
|
||||||
if self._sleep_until > time.time():
|
if self._sleep_until > time.time():
|
||||||
return
|
return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.enabled
|
self.enabled
|
||||||
|
and not lights_out
|
||||||
and self._triggered
|
and self._triggered
|
||||||
and time.time() - self._time_last_beep > self.interval
|
and time.time() - self._time_last_beep > self.interval
|
||||||
):
|
):
|
||||||
@@ -519,19 +572,18 @@ class Alarm:
|
|||||||
).start()
|
).start()
|
||||||
self._time_last_beep = time.time()
|
self._time_last_beep = time.time()
|
||||||
|
|
||||||
def render(self, canvas, position=(0, 0)):
|
def render(self, position=(0, 0)):
|
||||||
draw = ImageDraw.Draw(canvas)
|
|
||||||
x, y = position
|
x, y = position
|
||||||
# Draw the snooze icon- will be pulsing red if the alarm state is True
|
# Draw the snooze icon- will be pulsing red if the alarm state is True
|
||||||
draw.rectangle((x, y, x + 19, y + 19), (255, 255, 255))
|
self._draw.rectangle((x, y, x + 19, y + 19), (255, 255, 255))
|
||||||
r = 129
|
r = 129
|
||||||
if self._triggered:
|
if self._triggered:
|
||||||
r = int(((math.sin(time.time() * 3 * math.pi) + 1.0) / 2.0) * 255)
|
r = int(((math.sin(time.time() * 3 * math.pi) + 1.0) / 2.0) * 128) + 127
|
||||||
icon(image, icon_snooze, (x, y - 1), (r, 129, 129))
|
icon(self._image, icon_snooze, (x, y - 1), (r, 129, 129))
|
||||||
|
|
||||||
if self._sleep_until is not None: # TODO maybe sleeping alarm icon?
|
if self._sleep_until is not None: # TODO maybe sleeping alarm icon?
|
||||||
if self._sleep_until > time.time():
|
if self._sleep_until > time.time():
|
||||||
draw.text((x, y), "zZ", font=font, fill=(255, 255, 255))
|
self._draw.text((x, y), "zZ", font=font, fill=(255, 255, 255))
|
||||||
|
|
||||||
def trigger(self):
|
def trigger(self):
|
||||||
self._triggered = True
|
self._triggered = True
|
||||||
@@ -579,22 +631,24 @@ class ViewController:
|
|||||||
def update(self):
|
def update(self):
|
||||||
self.view.update()
|
self.view.update()
|
||||||
|
|
||||||
def render(self, canvas):
|
def render(self):
|
||||||
self.view.render(canvas)
|
self.view.render()
|
||||||
|
|
||||||
def button_a(self):
|
def button_a(self):
|
||||||
if not self.view.button_a():
|
if not self.view.button_a():
|
||||||
self.next_view()
|
self.next_view()
|
||||||
|
|
||||||
def button_b(self):
|
def button_b(self):
|
||||||
self.view.button_b()
|
return self.view.button_b()
|
||||||
|
|
||||||
def button_x(self):
|
def button_x(self):
|
||||||
if not self.view.button_x():
|
if not self.view.button_x():
|
||||||
self.next_subview()
|
self.next_subview()
|
||||||
|
return True
|
||||||
|
return True
|
||||||
|
|
||||||
def button_y(self):
|
def button_y(self):
|
||||||
self.view.button_y()
|
return self.view.button_y()
|
||||||
|
|
||||||
|
|
||||||
def handle_button(pin):
|
def handle_button(pin):
|
||||||
@@ -620,10 +674,12 @@ display = ST7735.ST7735(
|
|||||||
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=80000000
|
port=0, cs=1, dc=9, backlight=12, rotation=270, spi_speed_hz=80000000
|
||||||
)
|
)
|
||||||
display.begin()
|
display.begin()
|
||||||
WIDTH, HEIGHT = display.width, display.height
|
|
||||||
|
# Set up light sensor
|
||||||
|
light = ltr559.LTR559()
|
||||||
|
|
||||||
# Set up our canvas and prepare for drawing
|
# Set up our canvas and prepare for drawing
|
||||||
image = Image.new("RGBA", (WIDTH, HEIGHT), color=(255, 255, 255))
|
image = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(255, 255, 255))
|
||||||
font = ImageFont.truetype(UserFont, 14)
|
font = ImageFont.truetype(UserFont, 14)
|
||||||
|
|
||||||
|
|
||||||
@@ -636,14 +692,14 @@ channels = [
|
|||||||
|
|
||||||
viewcontroller = ViewController(
|
viewcontroller = ViewController(
|
||||||
[
|
[
|
||||||
MainView(channels=channels),
|
MainView(image, channels=channels),
|
||||||
(DetailView(channel=channels[0]), EditView(channel=channels[0])),
|
(DetailView(image, channel=channels[0]), EditView(image, channel=channels[0])),
|
||||||
(DetailView(channel=channels[1]), EditView(channel=channels[1])),
|
(DetailView(image, channel=channels[1]), EditView(image, channel=channels[1])),
|
||||||
(DetailView(channel=channels[2]), EditView(channel=channels[2])),
|
(DetailView(image, channel=channels[2]), EditView(image, channel=channels[2])),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
alarm = Alarm()
|
alarm = Alarm(image)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -695,10 +751,10 @@ Alarm Interval: {:.2f}s
|
|||||||
if channel.alarm:
|
if channel.alarm:
|
||||||
alarm.trigger()
|
alarm.trigger()
|
||||||
|
|
||||||
alarm.update()
|
alarm.update(light.get_lux() < 4.0)
|
||||||
|
|
||||||
viewcontroller.update()
|
viewcontroller.update()
|
||||||
viewcontroller.render(image)
|
viewcontroller.render()
|
||||||
display.display(image.convert("RGB"))
|
display.display(image.convert("RGB"))
|
||||||
|
|
||||||
# 5 FPS
|
# 5 FPS
|
||||||
|
|||||||
Reference in New Issue
Block a user