plugowski / umenu

Menu generator for MicroPython
20 stars 6 forks source link

Just a question about switches. #2

Closed johnr1245 closed 2 years ago

johnr1245 commented 2 years ago

Hi there so I have been having success so far getting basic menus made with this code but have been trying to add some tactile switches as navigation buttons but have been having some issues. I took this code below from the rotary encoder example so am not sure if it is not for the tactile switches themselves or just a click function on the rotary encoder?

sw = Pin(17, Pin.IN, Pin.PULL_UP) def menu_click(pin): time.sleep_ms(50) if pin.value() == 0: menu.click() sw.irq(menu_click, Pin.IRQ_FALLING)

I have tried adjusting this to my correct gpio pin for the switch on the board, however Im not sure if in your video you have both leads of the switch connected to gpio or one to gpio and one to ground. I am wondering if I need pull up resistors as I didnt think I saw any in your video and was just wondering how you went about wiring this up and how you wired the up, down, and select buttons for the menu. I had tried changing the menu.click to menu.down(-1) and it still wasnt working and tried changing the pull up to down, and none without much success. If you could just give some pointers on the wiring and coding that would be very much appreciated!!!! Thank you!

side note: also curious before I go deeper into this gui if I would be able to have a menu open to a submenu which reads the names of text files on the card and make them selectable and then could open that text file into a scrollable string so the text can fill the screen and it could be read. Sorry if that was poorly explained haha, can try to clarify more. Would that be possible with this gui library before I keep going? Thank you very much for all your work!

johnr1245 commented 2 years ago

Hi there I solved the issue with the switch! Just still wondering about the question in bold. Thanks!

plugowski commented 2 years ago

Hi @johnr1245 please see that simple implementation of file listing with preview. Please also keep in mind that it just print what can fit in the screen, the rest should be implemented by you :) Just add some pointer and move it back and forward when up and down will be triggered :)

Live demo

class FileList(CustomItem):

    def __init__(self, name):
        super().__init__(name)
        self._menu = None

    def prepare_list(self):
        # here should be listing files from SD card, for now I just list main dir from flash
        import os
        files = os.listdir()
        self._menu = Menu(self.display, 5, 10)
        builder = MenuScreen('Files', self.parent)
        for file in files:
            builder.add(FilePreview(file))
        self._menu.set_screen(builder)

    def up(self):
        self._menu.move(-1)

    def down(self):
        self._menu.move()

    def select(self):
        self._menu.click()
        return self

    def draw(self):
        if self._menu is None:
            self.prepare_list()
        self._menu.draw()

class FilePreview(CustomItem):

    def __init__(self,  file):
        super().__init__(file)
        self._file = file

    def select(self):
        return self.parent

    def draw(self):
        f = open(self._file)
        d = f.read()
        self.display.fill(0)
        # this should be adjusted to print few lines only and be sure it match to screen
        # here can be implemented up / down methods to scroll up and down text
        max_l = int(self.display.width / 8)  # standard font width is 8
        chunks = [d[i:i + max_l] for i in range(0, len(d), max_l)]
        y = 0
        for _ in chunks:
            self.display.text(_, 0, y, 1)
            y += 9
        self.display.show()
johnr1245 commented 2 years ago

Thank you so much for this!!!!!! That demo video looks very promising! This is super helpful but since Im still very much a beginner I still need some clarification. Does this code only work for viewing files on the flash memory of the MCU, therefore only reading the .py files mounted on the board? I am looking to only read text from an sd card.

As well I am having some issue integrating this code into what I currently have. When I simply paste what you posted at the bottom of my code it does run but nothing is different, no files are read. Currently this is my code for main.py :

from machine import Pin, I2C
import ssd1306
import time
from umenu import *

i2c = I2C(1, scl=Pin(22), sda=Pin(21))

oled_width = 128
oled_height = 64
display = ssd1306.SSD1306_I2C(oled_width, oled_height
, i2c)

menu = Menu(display, 4, 12)
menu.set_screen(MenuScreen('Welcome')
            .add(SubMenuItem('Library'))
            .add(SubMenuItem('Clock'))
            )
menu.draw()

sw = Pin(15, Pin.IN, Pin.PULL_UP)

def menu_move(pin):
    time.sleep_ms(50)
    if pin.value() == 0:
        menu.move(-1)

sw.irq(menu_move, Pin.IRQ_FALLING)

sw = Pin(27, Pin.IN, Pin.PULL_UP)

def menu_click(pin):
    time.sleep_ms(50)
    if pin.value() == 0:
        menu.click()

sw.irq(menu_click, Pin.IRQ_FALLING)

sw = Pin(14, Pin.IN, Pin.PULL_UP)

def menu_move(pin):
    time.sleep_ms(50)
    if pin.value() == 0:
        menu.move()

sw.irq(menu_move, Pin.IRQ_FALLING)

I am looking to have the Library menu be the menu which reads the content of the SD card. Should I add this code as a submenu underneath .add(SubMenuItem('Library')) or to the end of the code? As well which values should be adjusted to make it address the correct menu? Also, do thing likeimport sdcard and other pin definitions have to be done first as mentioned here: https://docs.micropython.org/en/latest/library/machine.SDCard.html ? It seems like there are a few different things you have to declare at the start of the code so I am just curious which ones are necessary for your library. Sorry for all the quetions but I am still very new lol, Would love if you could post the code from the demo you linked on your youtube short linke din your reply to go through just to get an idea about how the menus are nested and what goes where but i could still use some guidance on reading from the sd card. So far have build everything above just from your example code and another resources but since I am not too fluent in it Im limited in how much I can add to it.

Thank you so much for the help!!!! This is already helped me make huge progress on my project compared to similar libraries! Much appreciated!

Also this is unrelated to this issue but I am also curious if this library would be compatible with an eink display?

plugowski commented 2 years ago

You can either add this under Submenu like:

MenuScreen('Welcome').add(Submenu('Name of Submenu')
    .add(FileList("Name of List"))
)

or just

MenuScreen('Welcome').add(FileList("Name of List"))

Depends if you want have it nested under another submenu or not.

As it extends CustomItem it's just Item on menu, so the name will be always clickable position which let you go into. And as you can see in my comments in example code there are places which you have to implement by yourself to meet your requirements, that's your homework :P What I'm doing in that code I just list files and folders from main dir under ESP32 and show them on screen, you can implement reading from any dir you need and any method you want to implement.

It can be compatible with eink display if only it will be compatible with framebuf - mentioned in README. You can always create your own wrapper on eink driver, you need to provide such methods like show, fill, text, hline, fill_rect, width. If all that methods will be implemented, that menu should works as well ;)

Would love if you could post the code from the demo you linked on your youtube

That code you have exactly as my answer for your question... I wrote it specially for you! I also pushed full example in examples folder: File Listing

johnr1245 commented 2 years ago

Oh wow was wondering about that! Thank you so much for writing that up, has been super handy, much appreciated :) And thanks for the clarifications about the menu structure, will be sure to keep that in mind! And good to know about the eink, seems like creating the wrapper might be a bit above my level now but will look more into it!

And sorry if you saw my messy comment yesterday. I have since figured out how to access the sd card but am now having some errors from umenu.py regarding the draw function I think? I have been able to use the movement buttons on the main menu and to click to access the sd card, but once I access the sd card I am unable to use the movement buttons anymore and am given this error message in the REPL:

Traceback (most recent call last):
  File "<stdin>", line 100, in menu_move
  File "umenu.py", line 355, in move
  File "<stdin>", line 33, in down
AttributeError: 'FileList' object has no attribute 'menu_move'

I was only able to get the buttons working on the main menu by changing sw.irq(menu.move, Pin.IRQ_FALLING) to sw.irq(menu_move, Pin.IRQ_FALLING) so it would match to def prepare_list(self) declared earlier.

I tried on the homework but am still getting confused haha, please let me know if there is something Im missing or should be changing in umenu since I adjusted stuff for the switches. Could also be that I have my menus nested incorrectly so it is looking to the wrong menu? As well I think it is getting confused between the def up in the CustomItem class and the move_menu command generally? Any idea what the cause could be?

Here is my main.py file currently which was throwing the error message above: https://pastebin.com/hCS1xVPz

Thank you very much for the help! Please let me know if you have tip jar or donate link I could send to :)

plugowski commented 2 years ago

@johnr1245 of course object FileList doesn't have method (attribute) menu_move. You shouldn't override self._menu[move|click], here. I wrote FileList class which inside creates another menu, and it "redirects" up, down and select to that internal menu (select i called when you click menu select button - menu.click(). So just leave it as it was in my example. Only place you have to touch is prepare_list() method.

johnr1245 commented 2 years ago

Oh alright I see. I'll try that but the issue I was having prior with the default code was that it wouldn't register any button presses without declaring the pins for the switches and I wasn't clear on how to do that with the code you provided, should I retain the code for the switches but just keep the original def menu. move code at the bottom as it attaches the pin to thst movement and then the self._menu reads that? I think it was trying that before but was still getting errors I was mentioning before. Sorry about this I was just trying to trouble shoot what was making me unable to use the buttons for movement.

johnr1245 commented 2 years ago

Have gone back to your original code with sd initialized in prepare.list() I think correctly as it is reading the contents. Have not made any adjustments yet to FilePreview yet and slightly confused on how to change it for the sd card. I am currently getting this error with the code you gave with the sd card initialized and my code taken from your rotary encoder example.

Sorry for my confusion with some of this stuff, im pretty much completely new to programming and especially for anything python lol


  File "<stdin>", line 92, in menu_click
  File "umenu.py", line 359, in click
  File "<stdin>", line 36, in select
  File "umenu.py", line 361, in click
  File "umenu.py", line 371, in draw
  File "<stdin>", line 55, in draw
OSError: [Errno 2] ENOENT
plugowski commented 2 years ago

Sorry, but any context I have no idea what you have in line 55 in your code...

johnr1245 commented 2 years ago

Sorry forgot to add: https://pastebin.com/hwEg9vBm

plugowski commented 2 years ago

Okay, so as you can see problem is with: f = open(self._file) - so please make sure that you're reading file in proper way. That's the basic debugging skill :P I think you should do open('/sd/' + self._file) but not sure, I never work with SD reader with ESP.

johnr1245 commented 2 years ago

lol gotcha! was wondering if that was causing the issue but wasnt finding what f meant from docs about sd cards like from here: https://www.instructables.com/ESP32-Micro-SD-Card-Interface/

is there any command i need to add for the file that opens to be the one that is highlighted in the menu?

Will try some stuff out!

plugowski commented 2 years ago

is there any command i need to add for the file that opens to be the one that is highlighted in the menu?

No just fix the problem with opening file in FilePreview.draw() and that's it.