diff --git a/config.py b/config.py
index 378bbcf..e1a870e 100644
--- a/config.py
+++ b/config.py
@@ -62,4 +62,4 @@ LCD_I2C_NUM_COLS = 16 # and how many characters can it display per row?
LCD = I2C_LCD(I2C(0, sda=LCD_SDA, scl=LCD_SCL, freq=400000),
LCD_I2C_ADDR,
LCD_I2C_NUM_ROWS,
- LCD_I2C_NUM_COLS)
+ LCD_I2C_NUM_COLS)
\ No newline at end of file
diff --git a/input-tests.py b/input_tests.py
similarity index 54%
rename from input-tests.py
rename to input_tests.py
index c332781..1450fad 100644
--- a/input-tests.py
+++ b/input_tests.py
@@ -9,11 +9,24 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
You should have received a copy of the GNU General Public License along with this program. If not, see .
"""
-
import config as cfg
from time import sleep
+
+def run(endless_loop: bool = True, serial_output: bool = True):
+ while endless_loop:
+ if cfg.BTN_1.value() and cfg.BTN_2.value() and cfg.SWITCH.value():
+ cfg.LCD.move_to(0,0)
+ cfg.LCD.putstr("In: Y1 | G1 | S1 Exiting! ")
+ if serial_output:
+ print("All configured inputs pressed! Exiting...")
+ sleep(0.2)
+ break
+ cfg.LCD.move_to(0,0)
+ cfg.LCD.putstr(f"In: Y{cfg.BTN_1.value()} | G{cfg.BTN_2.value()} | S{cfg.SWITCH.value()}Push all to exit")
+ if serial_output:
+ print(f"Y_BTN: {cfg.BTN_1.value()}; G_BTN: {cfg.BTN_2.value()}; Lever: {cfg.SWITCH.value()}")
+ sleep(0.05)
+
if __name__ == "__main__":
- while True:
- print(f"Y_BTN: {cfg.BTN_1.value()}; G_BTN: {cfg.BTN_2.value()}; Lever: {cfg.SWITCH.value()}")
- sleep(0.1)
+ run() # run the program
\ No newline at end of file
diff --git a/lcd_big_hello.py b/lcd_big_hello.py
index 262dc40..eac1c99 100644
--- a/lcd_big_hello.py
+++ b/lcd_big_hello.py
@@ -1,5 +1,5 @@
"""
-An example "program" which can be used with the ProgramChooser library, see also main.py
+An example "program" which can be used with the lcdMenu library, see also main.py
Copyright (C) 2024 Benjamin Burkhardt
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.
diff --git a/lib/PCF8574T.py b/lib/PCF8574T/__init__.py
similarity index 100%
rename from lib/PCF8574T.py
rename to lib/PCF8574T/__init__.py
diff --git a/lib/ProgramChooserAdapted.py b/lib/ProgramChooserAdapted.py
deleted file mode 100644
index 5f1eea1..0000000
--- a/lib/ProgramChooserAdapted.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""
-ProgramChooser - a program launcher for microPython (adapted to the UV Belichter needs)
-Copyright (C) 2024 Benjamin Burkhardt
-
-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 .
-"""
-
-
-import utils, config
-from PCF8574T import I2C_LCD
-import time
-
-class ProgramChooser:
- def __init__(self, programs, debug=False, run_directly=False):
- self.lcd = config.LCD
- self.ok_btn = config.BTN_1
- self.next_btn = config.BTN_2
-
- self.lcd.move_to(0,0)
- self.lcd.putstr("[ PROGRAMS ]< >")
-
- self.current_selection = None # no selection
- self.programs = programs # a dictionary of programs and it's callbacks e.g. {"lora_test": some_callback}
-
- self.show_selection()
-
- if run_directly: self.run()
-
- def log(self, msg, is_debug=False):
- if is_debug:
- utils.log(2, f"[ProgramChooser] {msg}")
- else:
- utils.log(1, f"[ProgramChooser] {msg}")
-
-
- def show_selection(self):
- self.lcd.move_to(1,1)
-
- if len(self.programs) == 0:
- self.lcd.putstr(" No programs!")
- return True
- if self.current_selection == None: # set it initially
- self.current_selection = 0
-
- # the actual displaying process
- to_show = list(self.programs.keys())[self.current_selection]
- if len(to_show) > 14:
- to_show = to_show[:13] + chr(0)
- else:
- to_show = to_show[:14]
- to_show = to_show.center(14)
- self.lcd.putstr(to_show)
- return True
-
-
- def run(self):
- while True:
- if self.next_btn.value() == 1:
- former_program_name = list(self.programs.keys())[self.current_selection]
- self.current_selection = (self.current_selection+1)%len(list(self.programs.keys()))
- self.show_selection()
- now_program_name = list(self.programs.keys())[self.current_selection]
- self.log(f"Selected next program (\"{former_program_name}\" -> \"{now_program_name}\")")
- while self.next_btn.value() == 1: time.sleep(0.01) # wait till release
- if self.ok_btn.value() == 1:
- program_name = list(self.programs.keys())[self.current_selection]
- self.log(f"Running selected program! (\"{program_name}\")")
- # shorten the name for displaying (if too long)
- if len(program_name) > 14:
- program_name = program_name[:13] + chr(0)
- else:
- program_name = program_name[:14]
- program_name = program_name.center(14)
- self.lcd.move_to(0,0)
- self.lcd.putstr(f" {program_name} Executing... ")
- self.execute_selection()
- while self.ok_btn.value() == 1: time.sleep(0.01) # wait till release (e.g. if the "program" is a simple send action)
- self.lcd.putstr(f" {program_name} Closing... ")
- time.sleep(1)
- self.lcd.move_to(0,0)
- self.lcd.putstr("[ PROGRAMS ]< >")
- self.show_selection()
-
- time.sleep(0.01)
-
-
- def execute_selection(self): # execute the current selected program's callback
- self.programs[list(self.programs.keys())[self.current_selection]]()
-
diff --git a/lib/WelcomeScreen.py b/lib/WelcomeScreen/__init__.py
similarity index 100%
rename from lib/WelcomeScreen.py
rename to lib/WelcomeScreen/__init__.py
diff --git a/lib/lcdMenu/__init__.py b/lib/lcdMenu/__init__.py
new file mode 100644
index 0000000..f03b045
--- /dev/null
+++ b/lib/lcdMenu/__init__.py
@@ -0,0 +1,241 @@
+"""
+lcdMenu - A micropython library, which supports vertical and horizontal scrolling through menu items on both 2x16 and 4x20 LCDs
+Copyright (C) 2024 Benjamin Burkhardt
+
+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 .
+"""
+
+from time import sleep
+
+
+class lcdMenu:
+ # lcd: I2C_LCD - an object of the I2C_LCD class (https://git.privacynerd.de/BlueFox/micropython-libraries/src/branch/main/PCF8574T)
+ # buttons: dict - a dictionary with machine.Pin objects as items with following keys
+ # - "prev_btn" - OPTIONAL - when pressed, select the previous menu item
+ # - "next_btn" - REQUIRED - when pressed, select the next menu item
+ # - "ok_btn" - REQUIRED - when pressed, call the callback function of the menu item
+ # menu_items: list - a list (-> maintains order!) containing tuples with the following format: (,)
+ # scroll_direction: bool - if true, the scrolling direction is horizontal, if false, vertical
+ # cycle: bool - if true, start again with the first menu entry after the last one (and show the last before the first)
+ # hide_menu_name: bool - OPTIONAL - if true, hide the menu's name (won't work in combination with a vertical scrolling direction)
+ # name: str - OPTIONAL - a string with the name of the menu (can be hidden under certain circumstances)
+ # debounce_time: float - OPTIONAL - the debounce time used by the library to debounce button presses
+ def __init__(self, lcd, buttons: dict, scroll_direction: bool, cycle: bool, hide_menu_name: bool = False, name: str = "CHOOSE", debounce_time: float = 0.15):
+ # save the argument variables
+ self.lcd = lcd
+ if "prev_btn" in buttons.keys():
+ self.prev_btn = buttons["prev_btn"]
+ else:
+ self.prev_btn = None
+ self.next_btn = buttons["next_btn"]
+ self.ok_btn = buttons["ok_btn"]
+ self.scroll_direction = scroll_direction
+ self.cycle = cycle
+ self.hide_menu_name = hide_menu_name
+ self.name = name
+ self.debounce_time = debounce_time
+
+ self.current_selection = 0 # set a standard value (can/most of the time will be changed directly after __init__ by a call to self.setup())
+ self.menu_items = [] # set a standard empty (can/most of the time will be changed directly after __init__ by a call to self.setup())
+
+ # variables that are very unlikely the user want's to set them (but can be set via ., of course)
+ self.start_execution_msg = "Selected..." # the string displayed when an menu item is selected
+ self.end_execution_msg = "Closing..." # the string displayed when the callback function of a selected menu item returns self.end_execution_wait = 1 # the time (in seconds) to wait after the callback function of a selected menu item returns
+ self.start_execution_wait = 0.5 # the time (in seconds) to wait before the callback function of a selected menu item is called
+ self.end_execution_wait = 1 # the time (in seconds) to wait after the callback function of a selected menu item returns
+ self.fill_char = '-' # the character used to fill up space (used only on 4x20 displays); MUST BE 1 character long
+
+
+ # menu_items: list - a list (-> maintains order!) containing tuples with the following format: (,)
+ # start_selection: int - OPTIONAL - the index of the item selected by default (starting with 0) - DON'T USE NEGATIVE INDEXES
+ def setup(self, menu_items: list, start_selection: int = 0):
+ self.menu_items = menu_items
+ self.current_selection = start_selection
+
+
+ def show_selection(self):
+ # some checks:
+ # 1. if you scrolling vertically, I found no elegant way to hide the name (there just need's to be something up there!)
+ if self.scroll_direction and self.hide_menu_name:
+ raise TypeError("Hiding the menu name whilst having the scroll direction set to horizontal is impossible!")
+ # 2. if there are no menu items to display...
+ if len(self.menu_items) == 0:
+ raise TypeError("Can't show empty menus! Maybe you forgot calling self.setup() after initializing me?")
+
+ # get some often used values into local variables
+ selection_name = self.menu_items[self.current_selection][0]
+ lw = self.lcd.num_columns
+
+ # fill the custom character fields in the displays memory
+ self.lcd.custom_char(0, bytearray([0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00])) # arrow up
+ self.lcd.custom_char(1, bytearray([0x00,0x00,0x00,0x00,0x00,0x11,0x0A,0x04])) # arrow down
+ self.lcd.custom_char(2, bytearray([0x04,0x0A,0x11,0x00,0x00,0x11,0x0A,0x04])) # arrow up and down
+ self.lcd.custom_char(3, bytearray([0x11,0x0A,0x04,0x00,0x00,0x04,0x0A,0x11])) # no options
+ self.lcd.custom_char(4, bytearray([0x08,0x08,0x08,0x0F,0x08,0x08,0x08,0x08])) # line with a fork (to show the current selection - v scrolling)
+ self.lcd.custom_char(5, bytearray([0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08])) # line without a fork (to show unselected items - v scrolling)
+ self.lcd.custom_char(6, bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x00])) # three dots in a row
+
+ # now show it off!
+ # Horizontal scrolling:
+ if self.scroll_direction:
+ self.lcd.move_to(0,0)
+ if self.lcd.num_lines == 4:
+ self.lcd.putstr(f"{self.fill_char*lw}{' '*lw*2}{self.fill_char*lw}") # fill the first and last line with 'fill_char's
+ self.lcd.move_to(0,1) # move to the second line for the starting message below (takes two lines)
+ self.lcd.putstr(f"[{self.name[0:lw-2].center(lw-2)}]") # the menu name (cannot be hidden in this mode)
+ self.lcd.putstr(f"<{selection_name[0:lw-2].center(lw-2)}>") # the current selected menu item's name
+ # Vertical scrolling:
+ else:
+ lines_for_display = self.lcd.num_lines
+ items_before_selection = self.current_selection # e.g. if current selection is the second -> 1; one item is before this
+ items_after_selection = len(self.menu_items) - self.current_selection - 1
+ self.lcd.move_to(0,0)
+ if not self.hide_menu_name:
+ self.lcd.putstr(f"[{self.name[0:lw-2].center(lw-2)}]") # print the menu name surrounded by sqare brackets []
+ lines_for_display -= 1 # decrease the amount of lines available for displaying menu items by 1 (as it's used for the menu name)
+
+ # now we want to display the selections
+ # where the currently selected item should be the uppermost if possible
+ # only at the end of the item list, the current item has to be in a lower line...
+ # ... to avoid emtpy lines at the end as this would seem unprofessional/unclean to me
+ # but it adds an noticeable amount of extra work / a complex algorithm
+ if items_after_selection < (lines_for_display - 1): # if there aren't enough items to fill the display after the current selection
+ # maybe the following could be done with a crazy math formula - but I want to keep it simpler!
+ # as there aren't enough menu items after the current selection to fill the display, we have to...
+ # ... calculate where to place the current selection, how many items there are before it and how many after it
+ menu_items_cut = self.menu_items[::-1][:lines_for_display][::-1] # cut the menu_items list to the relevant last n ones maintaining order (n = number of lines for display)
+ current_pos_in_cut = -len(self.menu_items) + self.current_selection + lines_for_display # calculate the current index of the selection in the new cut
+ # draw all the lines
+ for i in range(lines_for_display):
+ if i == current_pos_in_cut: # if drawing the currently selected item
+ self.lcd.putstr(f"{chr(4)} {menu_items_cut[i][0][0:lw-4]}")
+ self.lcd.putstr(" " * ((lw-4)-len(menu_items_cut[i][0][0:lw-4]))) # fit the line
+ else:
+ self.lcd.putstr(f"{chr(5)} {menu_items_cut[i][0][0:lw-4]}")
+ self.lcd.putstr(" " * ((lw-4)-len(menu_items_cut[i][0][0:lw-4]))) # fit the line
+ # now the arrow
+ if i == 0: # if the first element is drawn, think about printing or not printing the up arrow
+ if self.current_selection == 0 and not self.cycle: # first item selected and no cycling
+ self.lcd.putstr(" ") # leave the line with spaces
+ else:
+ self.lcd.putstr(" " + chr(0))
+ elif i == lines_for_display-1: # if the last element is drawn, print a down arrow?
+ if self.current_selection == (len(self.menu_items)-1) and not self.cycle: # first item selected and no cycling
+ self.lcd.putstr(" ") # leave the line with spaces
+ else:
+ self.lcd.putstr(" " + chr(1)) # arrow down
+
+ else: # there are enough items to fill the display after the current selection
+ # the first line
+ self.lcd.putstr(f"{chr(4)} {selection_name[0:lw-4]}")
+ self.lcd.putstr(" " * ((lw-4)-len(selection_name[0:lw-4]))) # fill the line with spaces up to 2 before the end of the line
+
+ if len(self.menu_items) <= 1:
+ self.lcd.putstr(" " + chr(3)) # no options icon (as there's only one menu item!)
+ elif lines_for_display == 1: # if there is exactly one line to display the menu entries...
+ if self.current_selection == 0 and not self.cycle: # ...and the first element is selected and cycling is disabled so you can't go back
+ self.lcd.putstr(" "+chr(1))
+ elif self.current_selection == (len(self.menu_items)-1) and not self.cycle: # ...as before but with the last element -> you can't go further
+ self.lcd.putstr(" "+chr(0))
+ else: # ...or anything else (cycling or in the middle -> you can go in both directions
+ self.lcd.putstr(" "+chr(2))
+ elif self.current_selection == 0 and not self.cycle: # first item selected and no cycling
+ self.lcd.putstr(" ") # leave the line with spaces
+ else:
+ self.lcd.putstr(" " + chr(0))
+
+ # the other lines... (if existing!)
+ for i in range(lines_for_display-1):
+ self.lcd.putstr(f"{chr(5)} {self.menu_items[self.current_selection+i+1][0][0:lw-4]}")
+ self.lcd.putstr(" " * ((lw-4)-len(self.menu_items[self.current_selection+i+1][0][0:lw-4]))) # fit the line
+ # check if it's the last line being drawn...
+ if (i+1) == (lines_for_display-1):
+ if self.current_selection == (len(self.menu_items)-1) and not self.cycle: # last item selected and no cycling
+ self.lcd.putstr(" ")
+ else:
+ self.lcd.putstr(" " + chr(1))
+ else: # else: if it's not the last line, leave the last two columns of the line empty
+ self.lcd.putstr(" ")
+
+
+
+ def previous_selection(self):
+ self.current_selection -= 1
+ if self.current_selection < 0: # after the last element:
+ if self.cycle: # if cycling is enabled, set it to the index of the last element
+ self.current_selection = len(self.menu_items)-1
+ else: # else, go to first element
+ self.current_selection = 0
+
+
+ def next_selection(self):
+ self.current_selection += 1
+ if self.current_selection >= len(self.menu_items): # after the last element:
+ if self.cycle: # if cycling is enabled, go to first element
+ self.current_selection = 0
+ else: # else, set it to the index of the last element
+ self.current_selection = len(self.menu_items)-1
+
+
+ def execute_selection(self):
+ selection = self.menu_items[self.current_selection]
+ lw = self.lcd.num_columns
+
+ # if the program executed had no display (so the user notices something happens!)
+ self.lcd.move_to(0,0)
+ if self.lcd.num_lines == 4:
+ self.lcd.putstr(f"{self.fill_char*lw}{' '*lw*2}{self.fill_char*lw}") # fill the first and last line with 'fill_char's
+ self.lcd.move_to(0,1) # move to the second line for the starting message below (takes two lines)
+ self.lcd.putstr(f"[{selection[0][0:lw-2].center(lw-2)}]{self.start_execution_msg[0:lw].center(lw)}")
+ sleep(self.start_execution_wait) # wait some time before execution (so that the text can be read)
+
+ # run the program
+ return_value = selection[1]()
+
+ # show a exit when there's no specific return value
+ if not return_value: # if the return value is None / nothing was returned -> show a closing message
+ while self.ok_btn.value() == 1: time.sleep(self.debounce_time) # wait till ok_btn release (e.g. if the "program" is a simple send action)
+ self.lcd.move_to(0,0)
+ if self.lcd.num_lines == 4:
+ self.lcd.putstr(f"{self.fill_char*lw}{' '*lw*2}{self.fill_char*lw}") # fill the first and last line with 'fill_char's
+ self.lcd.move_to(0,1) # move to the second line for the starting message below (takes two lines)
+ self.lcd.putstr(f"[{selection[0][0:lw].center(lw-2)}]{self.end_execution_msg[0:lw].center(lw)}")
+ sleep(self.end_execution_wait)
+ self.show_selection()
+ else: # -> show no message and quit directly back into the lcdMenu
+ self.show_selection()
+
+
+ # listen for button presses (this method should be called in an endless loop, see method run)
+ def loop(self):
+ if self.prev_btn:
+ if self.prev_btn.value() == 1:
+ self.previous_selection()
+ self.show_selection()
+ while self.prev_btn.value() == 1: sleep(self.debounce_time) # wait till release
+ if self.next_btn.value() == 1:
+ self.next_selection()
+ self.show_selection()
+ while self.next_btn.value() == 1: sleep(self.debounce_time) # wait till release
+ if self.ok_btn.value() == 1:
+ while self.ok_btn.value() == 1: sleep(self.debounce_time) # wait till release
+ self.execute_selection()
+
+ def stop(self): # here to act as a callback for a menu entry (if the user wants to ofc!)
+ self.running = False
+ return True
+
+ def run(self):
+ # show the selection first
+ self.show_selection()
+ self.running = True
+
+ # then listen on button presses in a loop...
+ while self.running:
+ self.loop()
+
+ return True # to prevent a "Closing menu ..." in submenu-situations
diff --git a/main.py b/main.py
index 7f78a35..e6d5d51 100644
--- a/main.py
+++ b/main.py
@@ -10,69 +10,89 @@ You should have received a copy of the GNU General Public License along with thi
"""
-import config, utils
-from lib.ProgramChooserAdapted import ProgramChooser
-from lib.WelcomeScreen import WelcomeScreen
+import utils
+from lcdMenu import lcdMenu
+from WelcomeScreen import WelcomeScreen
from time import sleep
import gc # garbage collector for better memory performance
# extra functions to access the garbage collector
def manual():
- config.LCD.clear()
- set_value = config.RELAIS.value()
- config.LCD.putstr(f"---- MANUAL ---- State: {set_value} ")
+ utils.cfg.LCD.clear()
+ set_value = utils.cfg.RELAIS.value()
+ utils.cfg.LCD.putstr(f"---- MANUAL ---- State: {set_value} ")
while True:
- if set_value != config.SWITCH.value():
- config.RELAIS.value(config.SWITCH.value())
- set_value = config.RELAIS.value()
- config.LCD.putstr(f"---- MANUAL ---- State: {set_value} ")
- if config.BTN_1.value() == 1 or config.BTN_2.value() == 1:
- return # exit on press of these buttons
+ if set_value != utils.cfg.SWITCH.value():
+ utils.cfg.RELAIS.value(utils.cfg.SWITCH.value())
+ set_value = utils.cfg.RELAIS.value()
+ utils.cfg.LCD.putstr(f"---- MANUAL ---- State: {set_value} ")
+ if utils.cfg.BTN_1.value() == 1 or utils.cfg.BTN_2.value() == 1:
+ return True # exit on press of these buttons
def timer():
# display WIP
- config.LCD.clear()
- config.LCD.putstr(" Still work-in-progress")
+ utils.cfg.LCD.clear()
+ utils.cfg.LCD.putstr(" Still work-in-progress")
sleep(3)
+ return True # disable the "Quitting" message from lcdMenu
def uv_on():
- config.RELAIS.value(1)
- config.LCD.clear()
- config.LCD.putstr(" UV turned on ")
+ utils.cfg.RELAIS.value(1)
+ utils.cfg.LCD.clear()
+ utils.cfg.LCD.putstr("------ UV ------ turned on ")
sleep(1)
+ return True # disable the "Quitting" message from lcdMenu
def uv_off():
- config.RELAIS.value(0)
- config.LCD.clear()
- config.LCD.putstr("------ UV ------ turned off ")
+ utils.cfg.RELAIS.value(0)
+ utils.cfg.LCD.clear()
+ utils.cfg.LCD.putstr("------ UV ------ turned off ")
sleep(1)
+ return True # disable the "Quitting" message from lcdMenu
def lcd_big_hello():
import lcd_big_hello
lcd_big_hello.run()
gc.collect()
+ return True
+def input_tests():
+ import input_tests as input_tests
+ input_tests.run(serial_output=False)
+ gc.collect()
+ return True
def settings():
# display WIP
- config.LCD.clear()
- config.LCD.putstr(" Still work-in-progress")
+ utils.cfg.LCD.clear()
+ utils.cfg.LCD.putstr(" Still work-in-progress")
sleep(3)
+ return True
-# create a programs dict, where the items are callables (functions)
-programs = {
- "Settings": settings,
- "LCD Demo": lcd_big_hello,
- "UV off": uv_off,
- "UV on": uv_on,
- "Timer": timer,
- "Manual": manual,
-}
-if config.STARTUP_WELCOME_SHOW:
- ws = WelcomeScreen(config.LCD,
- interrupt_pins=[config.BTN_1, config.BTN_2, config.SWITCH],
- subtitle=config.STARTUP_PROJECT_NAME,
- starting_msg=config.STARTUP_MESSAGE_STARTING,
- started_msg=config.STARTUP_MESSAGE_FINISHED)
- ws.show(cycles=config.STARTUP_WELCOME_CYCLES)
+if utils.cfg.STARTUP_WELCOME_SHOW:
+ ws = WelcomeScreen(utils.cfg.LCD,
+ interrupt_pins=[utils.cfg.BTN_1, utils.cfg.BTN_2, utils.cfg.SWITCH],
+ subtitle=utils.cfg.STARTUP_PROJECT_NAME,
+ starting_msg=utils.cfg.STARTUP_MESSAGE_STARTING,
+ started_msg=utils.cfg.STARTUP_MESSAGE_FINISHED)
+ ws.show(cycles=utils.cfg.STARTUP_WELCOME_CYCLES)
del ws
gc.collect()
-pc = ProgramChooser(programs) # initialize the ProgramChooser
-pc.run() # and run it (will be an endless loop)
+
+# create the menus
+btn_mapping = {"ok_btn": utils.cfg.BTN_1, "next_btn": utils.cfg.BTN_2} # the btn mapping for all menus
+
+demo_menu = lcdMenu(utils.cfg.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="DEMOS")
+demo_programs = [("LCD Demo", lcd_big_hello),
+ ("Input tests", input_tests),
+ ("Exit", demo_menu.stop)]
+demo_menu.setup(demo_programs) # give it the callback list
+
+main_menu = lcdMenu(utils.cfg.LCD, btn_mapping, scroll_direction=True, cycle=True, hide_menu_name=False, name="PROGRAMS")
+main_programs = [("Timer", timer),
+ ("Manual", manual),
+ ("UV off", uv_off),
+ ("UV on", uv_on),
+ ("Demos", demo_menu.run),
+ ("Settings", settings)]
+main_menu.setup(main_programs) # give it the callback list
+
+# and run the main menu (will be an endless loop)
+main_menu.run()