From 5a057558d4a1b4270a351c80e53fead09e27b82a Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 15:43:23 +0100 Subject: [PATCH 01/16] add a startup view --- examples/monitor.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index 64bb0b4..b43e702 100644 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -366,6 +366,22 @@ def button_y(self): return True +class StartupView(View): + """Grow Monitor.""" + + def __init__(self, image): + EditView.__init__(self, image) + + def render(self): + self.clear() + self._draw.text( + (28, 5), + "Grow Monitor starting...", + font=self.font, + fill=COLOR_WHITE, + ) + View.render(self) + class SettingsView(EditView): """Main settings.""" @@ -1035,6 +1051,13 @@ def handle_button(pin): # Setup blank image for darkness image_blank = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) + # Setup blank image for darkness + image_starting = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) + startup_view = StartupView(image) + + startup_view.render() + startup_view = None + # Pick a random selection of plant icons to display on screen channels = [ @@ -1133,12 +1156,12 @@ def handle_button(pin): alarm.update(light_level_low) viewcontroller.update() - viewcontroller.render() if light_level_low and config.get_general().get("black_screen_when_light_low"): display.display(image_blank.convert("RGB")) else: + viewcontroller.render() display.display(image.convert("RGB")) config.set_general( From 8bd8923397830a74f5dff1cdb9e8c28d3b118e48 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 15:49:23 +0100 Subject: [PATCH 02/16] fixes for the startup view --- examples/monitor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index b43e702..0660d17 100644 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -370,7 +370,7 @@ class StartupView(View): """Grow Monitor.""" def __init__(self, image): - EditView.__init__(self, image) + View.__init__(self, image) def render(self): self.clear() @@ -1051,8 +1051,7 @@ def handle_button(pin): # Setup blank image for darkness image_blank = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) - # Setup blank image for darkness - image_starting = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) + # startup screen startup_view = StartupView(image) startup_view.render() From 2c4da1d1aab6b0ba2243d15f6c3c1e1c5576f707 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:06:14 +0100 Subject: [PATCH 03/16] use schedule to prevent config saving and rendering being locked together --- examples/monitor.py | 34 +++++++++++++++++++++------------- library/setup.cfg | 2 ++ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index 0660d17..f1a9d45 100644 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -18,6 +18,7 @@ from grow.moisture import Moisture from grow.pump import Pump +import schedule FPS = 10 @@ -1055,7 +1056,6 @@ def handle_button(pin): startup_view = StartupView(image) startup_view.render() - startup_view = None # Pick a random selection of plant icons to display on screen @@ -1143,19 +1143,9 @@ def handle_button(pin): ] ) - while True: - for channel in channels: - config.set_channel(channel.channel, channel) - channel.update() - if channel.alarm: - alarm.trigger() - + def display_loop( light, config, display, viewcontroller, image, image_blank ): light_level_low = light.get_lux() < config.get_general().get("light_level_low") - alarm.update(light_level_low) - - viewcontroller.update() - if light_level_low and config.get_general().get("black_screen_when_light_low"): display.display(image_blank.convert("RGB")) @@ -1163,15 +1153,33 @@ def handle_button(pin): viewcontroller.render() display.display(image.convert("RGB")) + def update_config(config, alarm): config.set_general( { "alarm_enable": alarm.enabled, "alarm_interval": alarm.interval, } ) - config.save() + schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) + schedule.every(3).seconds.do(update_config, config=config, alarm=alarm ) + + while True: + for channel in channels: + config.set_channel(channel.channel, channel) + channel.update() + if channel.alarm: + alarm.trigger() + + light_level_low = light.get_lux() < config.get_general().get("light_level_low") + + alarm.update(light_level_low) + + viewcontroller.update() + + schedule.run_pending() + time.sleep(1.0 / FPS) diff --git a/library/setup.cfg b/library/setup.cfg index ef65b6d..234a786 100644 --- a/library/setup.cfg +++ b/library/setup.cfg @@ -55,6 +55,7 @@ py2deps = python-spidev python-numpy python-rpi.gpio + python-schedule py3deps = python3-pip python3-yaml @@ -63,6 +64,7 @@ py3deps = python3-spidev python3-numpy python3-rpi.gpio + python-schedule commands = printf "Setting up i2c and SPI..\n" raspi-config nonint do_spi 0 From 3b4ddf199db12477dbab7d4048cdafd239753a65 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:06:40 +0100 Subject: [PATCH 04/16] make monitor.py executable --- examples/monitor.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 examples/monitor.py diff --git a/examples/monitor.py b/examples/monitor.py old mode 100644 new mode 100755 From d36b32be5707e1b16a5a301c2cb7d8815ca547ad Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:13:55 +0100 Subject: [PATCH 05/16] move the update loop to every 3 seconds via schedule and avoid unnecessary blank image conversion --- examples/monitor.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index f1a9d45..8bc217f 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1051,6 +1051,7 @@ def handle_button(pin): # Setup blank image for darkness image_blank = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) + image_blank = image_blank.convert("RGB") # startup screen startup_view = StartupView(image) @@ -1147,7 +1148,7 @@ def display_loop( light, config, display, viewcontroller, image, image_blank ): light_level_low = light.get_lux() < config.get_general().get("light_level_low") if light_level_low and config.get_general().get("black_screen_when_light_low"): - display.display(image_blank.convert("RGB")) + display.display(image_blank) else: viewcontroller.render() @@ -1162,10 +1163,8 @@ def update_config(config, alarm): ) config.save() - schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) - schedule.every(3).seconds.do(update_config, config=config, alarm=alarm ) - while True: + def update_loop(channels, alarm, light, config, viewcontroller): for channel in channels: config.set_channel(channel.channel, channel) channel.update() @@ -1178,6 +1177,12 @@ def update_config(config, alarm): viewcontroller.update() + schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) + schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) + schedule.every(3).seconds.do(update_config, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) + + while True: + schedule.run_pending() time.sleep(1.0 / FPS) From 5930e9a5326e186b19b7831775de4cf96622ee43 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:15:07 +0100 Subject: [PATCH 06/16] call the correct callback on scheduling updates --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index 8bc217f..7badfec 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1179,7 +1179,7 @@ def update_loop(channels, alarm, light, config, viewcontroller): schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) - schedule.every(3).seconds.do(update_config, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) + schedule.every(3).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: From 60a7fe5e0bd4dd45285468a85e6fa23368740563 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:24:37 +0100 Subject: [PATCH 07/16] better sleeping with schedule --- examples/monitor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index 7badfec..1b1ae47 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1182,10 +1182,8 @@ def update_loop(channels, alarm, light, config, viewcontroller): schedule.every(3).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: - schedule.run_pending() - - time.sleep(1.0 / FPS) + time.sleep( schedule.idle_seconds() ) if __name__ == "__main__": From fd665a46d07d2172eca3fcb2c6370c0751cca56b Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:26:34 +0100 Subject: [PATCH 08/16] only sleep if idle seconds is a positive value --- examples/monitor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index 1b1ae47..e19bc28 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1182,8 +1182,10 @@ def update_loop(channels, alarm, light, config, viewcontroller): schedule.every(3).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: + n = schedule.idle_seconds() + if n > 0: + time.sleep(n) schedule.run_pending() - time.sleep( schedule.idle_seconds() ) if __name__ == "__main__": From c0370c43c88f6e81da8f06a4b746afe88f43089b Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:28:08 +0100 Subject: [PATCH 09/16] move nested functions out of main --- examples/monitor.py | 65 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index e19bc28..4730b25 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1013,6 +1013,38 @@ def get_general(self): def set_general(self, settings): self.set("general", settings) +def display_loop( light, config, display, viewcontroller, image, image_blank ): + light_level_low = light.get_lux() < config.get_general().get("light_level_low") + + if light_level_low and config.get_general().get("black_screen_when_light_low"): + display.display(image_blank) + + else: + viewcontroller.render() + display.display(image.convert("RGB")) + +def update_config(config, alarm): + config.set_general( + { + "alarm_enable": alarm.enabled, + "alarm_interval": alarm.interval, + } + ) + config.save() + + +def update_loop(channels, alarm, light, config, viewcontroller): + for channel in channels: + config.set_channel(channel.channel, channel) + channel.update() + if channel.alarm: + alarm.trigger() + + light_level_low = light.get_lux() < config.get_general().get("light_level_low") + + alarm.update(light_level_low) + + viewcontroller.update() def main(): def handle_button(pin): @@ -1144,39 +1176,6 @@ def handle_button(pin): ] ) - def display_loop( light, config, display, viewcontroller, image, image_blank ): - light_level_low = light.get_lux() < config.get_general().get("light_level_low") - - if light_level_low and config.get_general().get("black_screen_when_light_low"): - display.display(image_blank) - - else: - viewcontroller.render() - display.display(image.convert("RGB")) - - def update_config(config, alarm): - config.set_general( - { - "alarm_enable": alarm.enabled, - "alarm_interval": alarm.interval, - } - ) - config.save() - - - def update_loop(channels, alarm, light, config, viewcontroller): - for channel in channels: - config.set_channel(channel.channel, channel) - channel.update() - if channel.alarm: - alarm.trigger() - - light_level_low = light.get_lux() < config.get_general().get("light_level_low") - - alarm.update(light_level_low) - - viewcontroller.update() - schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) schedule.every(3).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) From 578b294fa17b8bb1a506277a71c9216de4a3ac4e Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:29:49 +0100 Subject: [PATCH 10/16] reduce FPS to 5 --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index 4730b25..33af9cd 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -20,7 +20,7 @@ import schedule -FPS = 10 +FPS = 5 BUTTONS = [5, 6, 16, 24] LABELS = ["A", "B", "X", "Y"] From cc8d14f8528eb14466743d21f10011b67eda684b Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:38:21 +0100 Subject: [PATCH 11/16] remove the startup view and use RGB directly for the blank screen --- examples/monitor.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/examples/monitor.py b/examples/monitor.py index 33af9cd..cc0692a 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -367,22 +367,6 @@ def button_y(self): return True -class StartupView(View): - """Grow Monitor.""" - - def __init__(self, image): - View.__init__(self, image) - - def render(self): - self.clear() - self._draw.text( - (28, 5), - "Grow Monitor starting...", - font=self.font, - fill=COLOR_WHITE, - ) - View.render(self) - class SettingsView(EditView): """Main settings.""" @@ -1082,14 +1066,7 @@ def handle_button(pin): image = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(255, 255, 255)) # Setup blank image for darkness - image_blank = Image.new("RGBA", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) - image_blank = image_blank.convert("RGB") - - # startup screen - startup_view = StartupView(image) - - startup_view.render() - + image_blank = Image.new("RGB", (DISPLAY_WIDTH, DISPLAY_HEIGHT), color=(0, 0, 0)) # Pick a random selection of plant icons to display on screen channels = [ From 1986619ecc63690b27463fabf9f9a588802b1617 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:42:23 +0100 Subject: [PATCH 12/16] update sensors once a second --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index cc0692a..9222e04 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1155,7 +1155,7 @@ def handle_button(pin): schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) - schedule.every(3).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) + schedule.every(1).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: n = schedule.idle_seconds() From 8c59c2894d844391d3b3c887d566b81f7c84e4f0 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:48:00 +0100 Subject: [PATCH 13/16] double update loop speed --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index 9222e04..ba7454e 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1155,7 +1155,7 @@ def handle_button(pin): schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) - schedule.every(1).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) + schedule.every(0.5).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: n = schedule.idle_seconds() From 522c4276e45c5b440fbb2793c967adf8010fd491 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:49:34 +0100 Subject: [PATCH 14/16] restore 10FPS --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index ba7454e..b345dbd 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -20,7 +20,7 @@ import schedule -FPS = 5 +FPS = 10 BUTTONS = [5, 6, 16, 24] LABELS = ["A", "B", "X", "Y"] From 33764cb876ddad3ea56c252bf85566770ecbc903 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 16:56:49 +0100 Subject: [PATCH 15/16] double update loop --- examples/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/monitor.py b/examples/monitor.py index b345dbd..7d9bbbc 100755 --- a/examples/monitor.py +++ b/examples/monitor.py @@ -1155,7 +1155,7 @@ def handle_button(pin): schedule.every(1.0 / FPS).seconds.do(display_loop, light=light, config=config, display=display, viewcontroller=viewcontroller, image=image, image_blank=image_blank ) schedule.every(5).seconds.do(update_config, config=config, alarm=alarm ) - schedule.every(0.5).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) + schedule.every(0.25).seconds.do(update_loop, channels=channels, alarm=alarm, light=light, config=config, viewcontroller=viewcontroller ) while True: n = schedule.idle_seconds() From 3879874b28fdcec4f306c56c7843c1de2a701c27 Mon Sep 17 00:00:00 2001 From: Tom J Nowell Date: Sat, 22 Jul 2023 18:22:22 +0100 Subject: [PATCH 16/16] fix python 3 schedule dependency --- library/setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/setup.cfg b/library/setup.cfg index 234a786..3b74c66 100644 --- a/library/setup.cfg +++ b/library/setup.cfg @@ -64,7 +64,7 @@ py3deps = python3-spidev python3-numpy python3-rpi.gpio - python-schedule + python3-schedule commands = printf "Setting up i2c and SPI..\n" raspi-config nonint do_spi 0