10 Commits
v0.6 ... v0.7

5 changed files with 318 additions and 77 deletions

View File

@@ -5,15 +5,15 @@ A collection of programs run on a Raspberry Pi Pico to control a uv exposure uni
## Hardware ## Hardware
This program is strongly customized to my needs, and my DIY exposure unit has **two buttons** and **one switch** to interact with the software (and a power switch FWIW). Also, a **16x2 display** (maybe 20x4 or others do also work, but these are not tested) can show information to the user. This software is strongly customized to my needs, and my DIY exposure unit has **two buttons** and **one switch** to interact with the software (and a power switch FWIW). Also, a **16x2 display** (maybe 20x4 or others do also work, but these are not tested) can show information to the user.
A **relais** is used for switching all the LEDs. A **relais** is used for switching all the LEDs.
| Device Pin | Pi Pico Pin | | Device Pin | Pi Pico Pin |
| ------------------ | ----------- | | ------------------ | ----------- |
| BTN_1 Pin 1 | 3.3V | | BTN\_1 Pin 1 | 3.3V |
| BTN_1 Pin 2 | GPIO15 | | BTN\_1 Pin 2 | GPIO15 |
| BTN_2 Pin 1 | 3.3V | | BTN\_2 Pin 1 | 3.3V |
| BTN_2 Pin 2 | GPIO14 | | BTN\_2 Pin | GPIO14 |
| SWITCH Pin 1 | 3.3V | | SWITCH Pin 1 | 3.3V |
| SWITCH Pin 2 | GPIO13 | | SWITCH Pin 2 | GPIO13 |
| LCD SDA | GPIO8 | | LCD SDA | GPIO8 |
@@ -23,12 +23,12 @@ A **relais** is used for switching all the LEDs.
| Relais control pin | GPIO21 | | Relais control pin | GPIO21 |
## Installation ## Software installation
To install this software on your Pi Pico, first clone the repository with `git clone --recurse-submodules` to populate the submodules also (some libraries are included as submodules). Then use [Thonny](https://thonny.org/), open all the files present in this repository and then save them onto a [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) (or [Pico 2](https://www.raspberrypi.com/products/raspberry-pi-pico-2/), but it's not tested on this platform yet) running [MicroPython](https://micropython.org/). Then, given you followed above wiring, it should just be running! Then you can jump over the configuration section. To install this software on your Pi Pico, first clone the repository with `git clone --recurse-submodules` to populate the submodules also (some libraries are included as submodules). Then use [Thonny](https://thonny.org/), open all the files present in this repository and then save them onto a [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) (or [Pico 2](https://www.raspberrypi.com/products/raspberry-pi-pico-2/), but it's not tested on this platform yet) running [MicroPython](https://micropython.org/). Then, given you followed above wiring, it should just be running! Then you can jump over the configuration section.
## Configuration ## First configuration
All the configuration can be done in the [config.json](config.json) file in JSON format just have a look around there. Some hints for editing this file: All the configuration can be done in the [config.json](config.json) file in JSON format just have a look around there. Some hints for editing this file:
@@ -40,12 +40,14 @@ All the configuration can be done in the [config.json](config.json) file in JSON
- If your display doesn't work properly - the first issue might be a wrong i2c address. To find the address of your display, just follow some of the tutorials on the internet on scanning for i2c devices (e.g. [here](https://randomnerdtutorials.com/raspberry-pi-pico-i2c-scanner-micropython/)). - If your display doesn't work properly - the first issue might be a wrong i2c address. To find the address of your display, just follow some of the tutorials on the internet on scanning for i2c devices (e.g. [here](https://randomnerdtutorials.com/raspberry-pi-pico-i2c-scanner-micropython/)).
- The most basic configuration changes can be made directly from the device, without the need of connecting it to a PC, essentially making it a kind-of standalone device once flashed!
### Attribute table ### Attribute table
| Attribute name (on top level in config.json) | Type | Description | Default | | Attribute name (on top level in config.json) | Type | Description | Default |
| -------------------------------------------- | ---- | ----------- | ------- | | -------------------------------------------- | ---- | ----------- | ------- |
| `"LOG_LEVEL"` | int | defines up to which log level to show log messages in the serial console: warn (0), info (1), debug (2) | `2` | | `"LOG_LEVEL"` | int | defines up to which log level to show log messages in the serial console: warn (0), info (1), debug (2) | `1` |
| `"STARTUP_WELCOME_SHOW"` | bool | show the startup screen? | `true` | | `"STARTUP_WELCOME_SHOW"` | bool | show the startup screen? | `true` |
| `"STARTUP_PROJECT_NAME"` | str | the name shown at the welcome/startup screen | `" UV-Belichter "` | | `"STARTUP_PROJECT_NAME"` | str | the name shown at the welcome/startup screen | `" UV-Belichter "` |
| `"STARTUP_MESSAGE_STARTING"` | str | the message shown at startup when starting | `"Starting..."` | | `"STARTUP_MESSAGE_STARTING"` | str | the message shown at startup when starting | `"Starting..."` |
@@ -59,8 +61,8 @@ All the configuration can be done in the [config.json](config.json) file in JSON
| `"PIN_SCL"` | int | the pin number of the scl wire connected to the lcd | `9` | | `"PIN_SCL"` | int | the pin number of the scl wire connected to the lcd | `9` |
| `"LCD_I2C_CH"` | int | the channel of the i2c bus used | `0` | | `"LCD_I2C_CH"` | int | the channel of the i2c bus used | `0` |
| `"LCD_I2C_ADDR"` | int | the i2c address of the lcd; make sure to convert hexadecimal to decimal numbers | `38` | | `"LCD_I2C_ADDR"` | int | the i2c address of the lcd; make sure to convert hexadecimal to decimal numbers | `38` |
| `"LCD_I2C_NUM\_ROWS"` | int | how many rows for character display has the display? | `2` | | `"LCD_I2C_NUM_ROWS"` | int | how many rows for character display has the display? | `2` |
| `"LCD_I2C_NUM\_COLS"` | int | and how many characters can it display per row? | `16` | | `"LCD_I2C_NUM_COLS"` | int | and how many characters can it display per row? | `16` |
| `"TIMER_1_DURATION"` | int | the timer duration of the first timer; IN SECONDS | `60` (1min) | | `"TIMER_1_DURATION"` | int | the timer duration of the first timer; IN SECONDS | `60` (1min) |
| `"TIMER_2_DURATION"` | int | as above, but of the seconds timer; IN SECONDS | `2400` (40min) | | `"TIMER_2_DURATION"` | int | as above, but of the seconds timer; IN SECONDS | `2400` (40min) |
| `"TIMER_3_DURATION"` | int | as above, but of the third timer; IN SECONDS | `2700` (45min) | | `"TIMER_3_DURATION"` | int | as above, but of the third timer; IN SECONDS | `2700` (45min) |

View File

@@ -1,5 +1,5 @@
{ {
"LOG_LEVEL": 2, "LOG_LEVEL": 1,
"STARTUP_WELCOME_SHOW": true, "STARTUP_WELCOME_SHOW": true,
"STARTUP_PROJECT_NAME":" UV-Belichter ", "STARTUP_PROJECT_NAME":" UV-Belichter ",
"STARTUP_MESSAGE_STARTING": "Starting...", "STARTUP_MESSAGE_STARTING": "Starting...",

62
lcd_driver_demo.py Normal file
View File

@@ -0,0 +1,62 @@
"""
An example "program" which can be used with the lcdMenu library on a 2x16 display (with some tweaks also on 4x20 displays)
Copyright (C) 2024 Benjamin Burkhardt <bluefox@privacynerd.de>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
"""
@ Feature: Demonstrates the lcd driver's functionality
"""
from time import sleep
from utils import log
# lcd is an object of the I2C_LCD class (https://git.privacynerd.de/BlueFox/micropython-libraries/src/branch/main/PCF8574T)
def run(lcd):
# Show off basic functionality of the lcd driver
log(2, "Running the lcd driver demo")
lcd.putstr("Driver demo".center(16))
sleep(1)
lcd.clear()
lcd.putstr("Lorem ipsum dolor sit amet")
sleep(1)
lcd.show_cursor()
sleep(1)
lcd.hide_cursor()
sleep(1)
lcd.blink_cursor_on()
sleep(1)
lcd.blink_cursor_off()
sleep(1)
lcd.backlight_off()
sleep(1)
lcd.backlight_on()
sleep(1)
lcd.display_off()
sleep(1)
lcd.display_on()
sleep(1)
lcd.clear()
sleep(1)
s = ""
for x in range(32, 127):
s += chr(x)
while len(s) > 0:
lcd.clear()
lcd.move_to(0,0)
lcd.putstr(s[:32])
s = s[32:]
sleep(1)
lcd.clear()
return True
if __name__ == "__main__":
import utils
run(utils.Config().LCD)

307
main.py
View File

@@ -33,20 +33,23 @@ def manual():
return True # exit on press of these buttons; True to disable the Quitting message from lcdMenu return True # exit on press of these buttons; True to disable the Quitting message from lcdMenu
def timer(): def timer():
timer_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="TIMERS") timer_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="TIMERS")
timer_values = [config.TIMER_1_DURATION, config.TIMER_2_DURATION, config.TIMER_3_DURATION] timer_values_original = [config.TIMER_1_DURATION, config.TIMER_2_DURATION, config.TIMER_3_DURATION]
timer_values = timer_values_original.copy() # here, the current timers time is stored when interrupting via the interrupt_pin (see below)
timer_splits = [lambda: divmod(round(timer_values[0]), 60), lambda: divmod(round(timer_values[1]), 60), lambda: divmod(round(timer_values[2]), 60)] timer_splits = [lambda: divmod(round(timer_values[0]), 60), lambda: divmod(round(timer_values[1]), 60), lambda: divmod(round(timer_values[2]), 60)]
interrupt_pin = config.PIN_IN_BTN_1 # the interrupt btn stops the timer, saves the current time and goes back to the menu
reset_pin = config.PIN_IN_BTN_2 # the reset btn restores the default value
start_stop_pin = config.PIN_IN_SWITCH # the start_stop switch starts/stops the timer
# timer_number is the number of the timer that will be run, starting at 1
# the _timer variable is needed because otherwise python will throw crazy errors regarding "variable accessed before assignment"...
# ...just see it as a copy of the timer_number-1'th elemnt of the timer_values list (see above)
def run_timer(timer_number: int, _timer: int): def run_timer(timer_number: int, _timer: int):
interrupt_pin = config.PIN_IN_BTN_1
reset_pin = config.PIN_IN_BTN_2
start_stop_pin = config.PIN_IN_SWITCH
original = _timer
config.LCD.clear() config.LCD.clear()
config.LCD.putstr(f"Timer {timer_number}".center(16)) config.LCD.putstr(f"Timer {timer_number}".center(16))
last_start_stop_value = start_stop_pin.value() last_start_stop_value = start_stop_pin.value()
config.PIN_OUT_RELAIS.value(last_start_stop_value) config.PIN_OUT_RELAIS.value(last_start_stop_value)
last_time_ns = time_ns() last_time_ns = time_ns()
while True: while True: # now run the timer (if the switch is high)
config.LCD.move_to(0,1) config.LCD.move_to(0,1)
_timer_div = divmod(round(_timer), 60) _timer_div = divmod(round(_timer), 60)
config.LCD.putstr(f"{_timer_div[0]:02d}:{_timer_div[1]:02d}".center(16)) config.LCD.putstr(f"{_timer_div[0]:02d}:{_timer_div[1]:02d}".center(16))
@@ -56,7 +59,7 @@ def timer():
config.PIN_OUT_RELAIS.value(last_start_stop_value) config.PIN_OUT_RELAIS.value(last_start_stop_value)
return None return None
if reset_pin.value() == 1: if reset_pin.value() == 1:
_timer = original # reset the timers _timer = timer_values_original[timer_number-1] # reset the timers
if _timer <= 0: if _timer <= 0:
config.PIN_OUT_RELAIS.off() config.PIN_OUT_RELAIS.off()
return True return True
@@ -69,84 +72,241 @@ def timer():
_timer -= (time_ns() - last_time_ns) / 1000**3 _timer -= (time_ns() - last_time_ns) / 1000**3
last_time_ns = time_ns() last_time_ns = time_ns()
timer_programs = [(f"{timer_splits[0]()[0]:02d}:{timer_splits[0]()[1]:02d}", lambda: run_timer(1, timer_values[0])), timer_programs = [(f"T1 - {timer_splits[0]()[0]:02d}:{timer_splits[0]()[1]:02d}", lambda: run_timer(1, timer_values[0])),
(f"{timer_splits[1]()[0]:02d}:{timer_splits[1]()[1]:02d}", lambda: run_timer(2, timer_values[1])), (f"T2 - {timer_splits[1]()[0]:02d}:{timer_splits[1]()[1]:02d}", lambda: run_timer(2, timer_values[1])),
(f"{timer_splits[2]()[0]:02d}:{timer_splits[2]()[1]:02d}", lambda: run_timer(3, timer_values[2])), (f"T3 - {timer_splits[2]()[0]:02d}:{timer_splits[2]()[1]:02d}", lambda: run_timer(3, timer_values[2])),
("Exit", timer_menu.stop)] ("Exit", timer_menu.stop)]
timer_menu.setup(timer_programs) # give it the callback list timer_menu.setup(timer_programs) # give it the callback list
timer_menu.run() timer_menu.run()
del timer_menu, timer_programs del timer_menu, timer_programs
collect() collect()
return True # disable the "Quitting" message from lcdMenu return True # disable the "Quitting" message from lcdMenu
def uv_on():
config.PIN_OUT_RELAIS.value(1)
config.LCD.clear()
config.LCD.putstr("------ UV ------ turned on ")
sleep(1)
return True # disable the "Quitting" message from lcdMenu
def uv_off():
config.PIN_OUT_RELAIS.value(0)
config.LCD.clear()
config.LCD.putstr("------ UV ------ turned off ")
sleep(1)
return True # disable the "Quitting" message from lcdMenu
def lcd_big_hello():
import lcd_big_hello as lbh
lbh.run(config.LCD)
del lbh
collect()
return True
def input_tests():
import input_tests as input_tests
input_tests.run(serial_output=False)
collect()
return True
def settings(): def settings():
settings_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="SETTINGS") settings_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="SETTINGS")
def swap_welcome(): def toggle_show_welcome():
config.STARTUP_WELCOME_SHOW = not config.STARTUP_WELCOME_SHOW current_value = config.STARTUP_WELCOME_SHOW
config.LCD.clear() config.LCD.clear()
config.LCD.putstr(f" Welcome Screen ") config.LCD.putstr(f"Currently {'on' if current_value else 'off'}".center(16))
if config.STARTUP_WELCOME_SHOW: config.LCD.putstr("< keep change >")
config.LCD.putstr("--- Enabled! ---") keep_btn = config.PIN_IN_BTN_1
else: change_btn = config.PIN_IN_BTN_2
config.LCD.putstr("--- Disabled ---") while True:
sleep(1) if keep_btn.value() == 1:
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Stay {'on' if current_value else 'off'}!".center(16))
sleep(0.5)
return True
if change_btn.value() == 1:
config.STARTUP_WELCOME_SHOW = not current_value
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Turned {'on' if not current_value else 'off'}!".center(16))
sleep(0.5)
return True
def welcome_cycles(): def welcome_cycles():
config.LCD.clear() config.LCD.clear()
current_cycles = config.STARTUP_WELCOME_CYCLES current_cycles = config.STARTUP_WELCOME_CYCLES
option_down = [" ", "v"][current_cycles>1] option_down = [" ", "v"][current_cycles>1]
config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^") config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^")
btn_left = config.PIN_IN_BTN_1
btn_right = config.PIN_IN_BTN_2
while True: while True:
if config.PIN_IN_BTN_1.value() == 1: if btn_left.value() == 1:
time_ns_when_pressed = time_ns() sleep(0.1) # this value is a good compromise between being able to press both buttons and a fast up/down speed
while config.PIN_IN_BTN_1.value() == 1: if btn_right.value() == 1:
if (time_ns() - time_ns_when_pressed) > 1000000000: # if the time passed is longer than a second config.STARTUP_WELCOME_CYCLES = current_cycles
while config.PIN_IN_BTN_1.value() == 1: config.LCD.move_to(0,1) # move to the second row
pass # wait till release config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
config.STARTUP_WELCOME_CYCLES = current_cycles sleep(0.5)
return True while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
sleep(0.05) pass
return True
current_cycles -= 1 current_cycles -= 1
if current_cycles < 1: current_cycles = 1 if current_cycles < 1: current_cycles = 1
option_down = [" ", "v"][current_cycles>1] option_down = [" ", "v"][current_cycles>1]
config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^") config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^")
if config.PIN_IN_BTN_2.value() == 1: if btn_right.value() == 1:
time_ns_when_pressed = time_ns() sleep(0.1)
while config.PIN_IN_BTN_2.value() == 1: if btn_left.value() == 1:
if (time_ns() - time_ns_when_pressed) > 1000000000: # if the time passed is longer than a second config.STARTUP_WELCOME_CYCLES = current_cycles
while config.PIN_IN_BTN_2.value() == 1: config.LCD.move_to(0,1) # move to the second row
pass # wait till release config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
config.STARTUP_WELCOME_CYCLES = current_cycles sleep(0.5)
return True while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
sleep(0.05) pass
return True
current_cycles += 1 current_cycles += 1
option_down = [" ", "v"][current_cycles>1] option_down = [" ", "v"][current_cycles>1]
config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^") config.LCD.putstr(f" Cycles \n{option_down} {str(current_cycles).center(12)} ^")
settings_programs = [("Show welcome", swap_welcome), # with n being the number of the timer (starting at 0)
def set_n_timer(n: int):
# a small helper function to save the value of the n'th timer...
# as you can't programatically access TIMER_n_DURATION
def set_timer_helper(n, value):
if n == 0:
config.TIMER_1_DURATION = value
elif n == 1:
config.TIMER_2_DURATION = value
elif n == 2:
config.TIMER_3_DURATION = value
else:
utils.log(0, "There are only 3 timers at all. Trying to set the timer number {n} failed.")
config.LCD.clear()
timer_values = [config.TIMER_1_DURATION, config.TIMER_2_DURATION, config.TIMER_3_DURATION]
current_timer = timer_values[n] # get the n'th timer
current_timer_div = lambda: divmod(current_timer, 60)
config.LCD.putstr(f"Timer {n+1}".center(16))
config.LCD.putstr(f"{'v' if current_timer > 1 else ' '} " + f"{current_timer_div()[0]:02d}:{current_timer_div()[1]:02d}".center(12) + " ^")
btn_left = config.PIN_IN_BTN_1
btn_right = config.PIN_IN_BTN_2
left_was_released = True
right_was_released = True
while True:
if btn_left.value() == 1:
if left_was_released:
time_press_start = time_ns()
left_was_released = False
sleep(0.1) # this value is a good compromise between being able to press both buttons and a fast up/down speed
if btn_right.value() == 1: # exit if both btns are pressed
set_timer_helper(n, current_timer)
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
sleep(0.5)
while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
pass
return True
# define the step width
time_now = time_ns()
if (time_now - time_press_start) <= 1*(10**9): # max. 1 seconds pressed
current_timer -= 1
elif (time_now - time_press_start) <= 2*(10**9): # max. 2 seconds pressed
current_timer -= 5
elif (time_now - time_press_start) <= 3*(10**9): # max. 3 seconds pressed
current_timer -= 10
elif (time_now - time_press_start) <= 4*(10**9): # max. 4 seconds pressed
current_timer -= 30
elif (time_now - time_press_start) <= 5*(10**9): # max. 5 seconds pressed
current_timer -= 60
else: # longer than 5s pressed
current_timer -= 300
if current_timer < 1: current_timer = 5999
config.LCD.move_to(0,1)
config.LCD.putstr("v " + f"{current_timer_div()[0]:02d}:{current_timer_div()[1]:02d}".center(12) + " ^")
else:
left_was_released = True
if btn_right.value() == 1:
if right_was_released:
time_press_start = time_ns()
right_was_released = False
sleep(0.1)
if btn_left.value() == 1: # exit if both btns are pressed
set_timer_helper(n, current_timer)
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
sleep(0.5)
while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
pass
return True
# define the step width
time_now = time_ns()
if (time_now - time_press_start) <= 1*(10**9): # max. 1 seconds pressed
current_timer += 1
elif (time_now - time_press_start) <= 2*(10**9): # max. 2 seconds pressed
current_timer += 5
elif (time_now - time_press_start) <= 3*(10**9): # max. 3 seconds pressed
current_timer += 10
elif (time_now - time_press_start) <= 4*(10**9): # max. 4 seconds pressed
current_timer += 30
elif (time_now - time_press_start) <= 5*(10**9): # max. 5 seconds pressed
current_timer += 60
else: # longer than 5s pressed
current_timer += 300
if current_timer > 5999: current_timer = 1
config.LCD.move_to(0,1)
config.LCD.putstr("v " + f"{current_timer_div()[0]:02d}:{current_timer_div()[1]:02d}".center(12) + " ^")
else:
right_was_released = True
def set_log_level():
config.LCD.clear()
current_level = config.LOG_LEVEL
log_levels = ["WARN", "INFO", "DEBUG"]
config.LCD.putstr(f"Log level".center(16))
config.LCD.putstr("v " + f"{log_levels[current_level]} ({current_level})".center(12) + " ^") # show the log level and it's name in the second row
btn_left = config.PIN_IN_BTN_1
btn_right = config.PIN_IN_BTN_2
while True:
if btn_left.value() == 1:
sleep(0.1) # this value is a good compromise between being able to press both buttons and a fast up/down speed
if btn_right.value() == 1:
config.LOG_LEVEL = current_level
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
sleep(0.5)
while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
pass
return True
current_level -= 1
if current_level < 0: current_level = 2
config.LCD.move_to(0,0)
config.LCD.putstr(f"Log level".center(16))
config.LCD.putstr("v " + f"{log_levels[current_level]} ({current_level})".center(12) + " ^") # show the log level and it's name in the second row
if btn_right.value() == 1:
sleep(0.1)
if btn_left.value() == 1:
config.LOG_LEVEL = current_level
config.LCD.move_to(0,1) # move to the second row
config.LCD.putstr(f"Saved!".center(16)) # show a little info that it is now set
sleep(0.5)
while btn_right.value() == 1 or btn_left.value() == 1: # wait till both btns are released
pass
return True
current_level += 1
if current_level > 2: current_level = 0
config.LCD.move_to(0,0)
config.LCD.putstr(f"Log level".center(16))
config.LCD.putstr("v " + f"{log_levels[current_level]} ({current_level})".center(12) + " ^") # show the log level and it's name in the second row
def reset(): # reset all user-settable configuration to the default values
config.LCD.clear()
config.LCD.putstr("Sure about that?")
config.LCD.putstr("< no yes >")
no_btn = config.PIN_IN_BTN_1
yes_btn = config.PIN_IN_BTN_2
while True:
if no_btn.value() == 1:
return None
if yes_btn.value() == 1:
config.LCD.putstr("Resetting...".center(16))
config.LCD.putstr("Welcome Screen".center(16))
config.STARTUP_WELCOME_SHOW = True
config.STARTUP_WELCOME_CYCLES = 1
sleep(0.5)
config.LCD.move_to(0,1)
config.LCD.putstr("Timers".center(16))
config.TIMER_1_DURATION = 60
config.TIMER_2_DURATION = 2400
config.TIMER_3_DURATION = 2700
sleep(0.5)
config.LCD.move_to(0,1)
config.LCD.putstr("Logging".center(16))
config.LOG_LEVEL = 1
sleep(0.5)
return True
settings_programs = [("Show welcome", toggle_show_welcome),
("Welcome cycles", welcome_cycles), ("Welcome cycles", welcome_cycles),
("Timer 1", lambda: set_n_timer(0)),
("Timer 2", lambda: set_n_timer(1)),
("Timer 3", lambda: set_n_timer(2)),
("Log level", set_log_level),
("Reset", reset),
("Exit", settings_menu.stop)] ("Exit", settings_menu.stop)]
settings_menu.setup(settings_programs) # give it the callback list settings_menu.setup(settings_programs) # give it the callback list
settings_menu.run() # run the menu until it's closed settings_menu.run() # run the menu until it's closed
@@ -154,15 +314,34 @@ def settings():
collect() collect()
return True return True
def run_demo_menu(): def run_demo_menu():
def lcd_driver_demo():
import lcd_driver_demo as ldd
ldd.run(config.LCD)
del ldd
collect()
return True
def lcd_big_hello():
import lcd_big_hello as lbh
lbh.run(config.LCD)
del lbh
collect()
return True
def input_tests():
import input_tests as input_tests
input_tests.run(serial_output=False)
del input_tests
collect()
return True
demo_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="DEMOS") demo_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="DEMOS")
demo_programs = [("LCD Demo", lcd_big_hello), demo_programs = [("LCD Demo", lcd_driver_demo),
("Hello world", lcd_big_hello),
("Input tests", input_tests), ("Input tests", input_tests),
("Exit", demo_menu.stop)] ("Exit", demo_menu.stop)]
demo_menu.setup(demo_programs) # give it the callback list demo_menu.setup(demo_programs) # give it the callback list
ret = demo_menu.run() demo_menu.run()
del demo_menu, demo_programs del demo_menu, demo_programs
collect() collect()
return ret return True
if config.STARTUP_WELCOME_SHOW: if config.STARTUP_WELCOME_SHOW:
ws = WelcomeScreen(config.LCD, ws = WelcomeScreen(config.LCD,
@@ -179,8 +358,6 @@ if config.STARTUP_WELCOME_SHOW:
main_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="PROGRAMS") main_menu = lcdMenu(config.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="PROGRAMS")
main_programs = [("Timer", timer), main_programs = [("Timer", timer),
("Manual", manual), ("Manual", manual),
("UV off", uv_off),
("UV on", uv_on),
("Demos", run_demo_menu), ("Demos", run_demo_menu),
("Settings", settings)] ("Settings", settings)]
main_menu.setup(main_programs) # give it the callback list main_menu.setup(main_programs) # give it the callback list

View File

@@ -131,5 +131,5 @@ def log(log_level: int, message: str):
if log_level not in [0, 1, 2]: if log_level not in [0, 1, 2]:
print(f"[LOGGER] Got a message of unknown log level ({log_level}). Original message is printed below.") print(f"[LOGGER] Got a message of unknown log level ({log_level}). Original message is printed below.")
print(f"{message}") print(f"{message}")
elif cfg.LOG_LEVEL >= log_level: # if log level is valid elif Config().LOG_LEVEL >= log_level: # if log level is valid
print(f"[{log_mapping[log_level]}] {message}") print(f"[{log_mapping[log_level]}] {message}")