rm-hull / luma.examples

Companion repo for running examples against the luma.oled, luma.lcd, luma.led_matrix and luma.emulator display drivers.
MIT License
367 stars 140 forks source link

Menu, point and shoot help #133

Open chuckv2014 opened 3 years ago

chuckv2014 commented 3 years ago

I have a 128x128 SPI to a RPi Zero W under Raspbian with 5 button navigation (Left, Right, Up, Down, Enter functions). My screens look great (love LUMA.OLED) I want to create a Menu system that utilizes the NAV buttons to create a "point and shoot" menu...

Ideally, I'd like to only update a small region (the inverse video selected by the NAV buttons) but only know how to update the entire display.... is there a way to update only a portion of the display?

Currently, my Menu works too slow a clunky, when updating the entire display when the NAV button scrolls to the selection (in which I reverse the video).

Any help is appreciated.

Thank you, Chuck

rm-hull commented 3 years ago

Hi chuck, you dont say which device you have, but most implementations have a framebuffer which selectively picks only the changes since the last render, so as long as you just keep drawing the full image each time, the device will manage only sending the diffs to device.

As it happens, there is a new version of that diff algorithm coming out soon which should improve performance significantly. For some of the luma.examples demo's we have seen the frames/sec increase from about 10FPS before to about 85FPS afterwards.

chuckv2014 commented 3 years ago

Hi Richard!

Thank you for taking the time to respond to my inquiry! Every email I’ve sent (total of 2) have bounced back, so figured you were not available.

My goal is a “point and shoot” menu system using 128x128 SPI Display (RPi Zero W and Raspbian).

This speed improvement sounds great, but even so, I was hoping (still) not to have to refresh the entire display... each button press should move the selection forward/back... and that should be done (IMO) as only that portion of the screen for best performance. The “selection” is simply reverse video of the text that is displayed.

***If I could simply grab a rectangle of the display and invert it in/out it would be golden... however, don’t have the ability to code this myself without some guidance... was hoping for the help (for pay, not for free) to create a simple function.

I know you must stay busy, so, if you are unavailable, maybe a colleague who is familiar with LUMA.OLED could do this... I’m sure the display image is in video memory somewhere, so with a mapping from LUMA to simply toggle the area is all I need... this would be the core of the Menu System that I could build, etc.

Let me know if this is feasible and if there is anyone who could knock this out for me.

LUMA is very popular, and it is very easy to use. Five stars!

Best, Chuck

On Oct 30, 2020, at 7:06 PM, Richard Hull notifications@github.com wrote:

Hi chuck, you dont say which device you have, but most implementations have a framebuffer which selectively picks only the changes since the last render, so as long as you just keep drawing the full image each time, the device will manage only sending the diffs to device.

As it happens, there is a new version of that diff algorithm coming out soon which should improve performance significantly. For some of the luma.examples demo's we have seen the frames/sec increase from about 10FPS before to about 85FPS afterwards.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

chuckv2014 commented 3 years ago

Device: https://shop.pimoroni.com/products/1-12-oled-breakout?variant=12628508704851 Uses the SH1107 chip 128 x 128 pixels monochrome

Chuck

On Oct 30, 2020, at 7:06 PM, Richard Hull notifications@github.com wrote:

Hi chuck, you dont say which device you have, but most implementations have a framebuffer which selectively picks only the changes since the last render, so as long as you just keep drawing the full image each time, the device will manage only sending the diffs to device.

As it happens, there is a new version of that diff algorithm coming out soon which should improve performance significantly. For some of the luma.examples demo's we have seen the frames/sec increase from about 10FPS before to about 85FPS afterwards.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

chuckv2014 commented 3 years ago

Richard,

Does the sh1106 OLED def display(self, image) function in .../oled/device/init.py support “RGB” Mode?

I’m doing... white = (255,255,255) .. self.im = Image.new(“RGB”, (128,128), white) .. .. device.display(self.im)

And am getting an error on this line... assert(image.mode == self.mode)

Comments in def display... make mention of “1-bit”

*** what version supports RGB?

I’m using 3.7.0

If a newer version is available, can you provide exact instructions to update my Raspbian, Python 3.8.6 ? (Newbie to Raspbian, but 30+ years in Windows development).

Thank you, Chuck

On Nov 5, 2020, at 12:42 PM, Chuck Van Dien chuck@vandien.com wrote:

Richard, I have updated LUMA.OLED and have to remark my code for the new library.

I have an SPI display that was working under the older LUMA.OLED but no longer works... I have made the following changes...

from luma.core.nterface.serial import spi from luma.core.renderer import canvas from luma.device import sh1106

display_serial = spi(device=1, port=0) device = sh1106(display_serial, rotate=1)

However, I get an error “SPI device not found”

I have cycled through all device/ports... never finds it...

Here is the command line that worked under the older version flawlessly...

python3 TEST_MENU.py -d sh1106 —height 128 -rotate 1 —interface spi —gpio-data-command 9 —spi-device 1

Chuck

On Oct 30, 2020, at 7:06 PM, Richard Hull notifications@github.com wrote:

Hi chuck, you dont say which device you have, but most implementations have a framebuffer which selectively picks only the changes since the last render, so as long as you just keep drawing the full image each time, the device will manage only sending the diffs to device.

As it happens, there is a new version of that diff algorithm coming out soon which should improve performance significantly. For some of the luma.examples demo's we have seen the frames/sec increase from about 10FPS before to about 85FPS afterwards.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

rm-hull commented 3 years ago

Since SH1106 is a monochrome device, then the image you supply when you call display() directly must be the same dimensions and colour depth, so you should either create an image with mode "1" (rather than "RGB"), or you can call im.convert(mode="1") (see https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.convert)

rm-hull commented 3 years ago

In regard to your earlier question about not to have to refresh the entire display:

The luma.device.* classes are really just a wrapper around being able to send Pillow images to the display along with a bunch of helper classes to make it simple to draw text and primitives onto a canvas (which is really just a Pillow ImageDraw object).

You will find it easier to manage state in your application if it just does full renders every time. You shouldn't worry too much about performance - for such small screens there are not really too many pixels to update, and it is possible to get high frame rates rendering complex screens. For some of the higher resolution screens there are some mechanisms we use to only do partial/intelligent screen updates which hugely improve frame render time. This implies the time taken to send bytes to the device takes more time than it does for you to draw them onto an image canvas.

If you are wanting to have a menu system where you toggle things on and off and want to revert back to a previous display without having to redraw, possibly have a look at using the history class and an example of its usage: https://github.com/rm-hull/luma.examples/blob/master/examples/savepoint.py

chuckv2014 commented 3 years ago

Awesome! Thanks for replying Richard! (Image sources are RGB, so the convert is the way to go). Chuck

On Nov 5, 2020, at 5:25 PM, Richard Hull notifications@github.com wrote:

In regard to your earlier question about not to have to refresh the entire display:

The luma.device.* classes are really just a wrapper around being able to send Pillow images to the display along with a bunch of helper classes to make it simple to draw text and primitives onto a canvas (which is really just a Pillow ImageDraw object).

You will find it easier to manage state in your application if it just does full renders every time. You shouldn't worry too much about performance - for such small screens there are not really too many pixels to update, and it is possible to get high frame rates rendering complex screens. For some of the higher resolution screens there are some mechanisms we use to only do partial/intelligent screen updates which hugely improve frame render time. This implies the time taken to send bytes to the device takes more time than it does for you to draw them onto an image canvas.

If you are wanting to have a menu system where you toggle things on and off and want to revert back to a previous display without having to redraw, possibly have a look at using the history class and an example of its usage: https://github.com/rm-hull/luma.examples/blob/master/examples/savepoint.py

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

chuckv2014 commented 3 years ago

Richard, got my menu working and am now trying to set “test_menu.py” as auto-starting ... using “python3 /home/pi/code/test_menu.py” or “sudo python3 /home/pi/code/test_menu.py” works at the console command line prompt... however, when I added this to the profile... I get an error: No Module named ‘luma’

This is probably every rudimentary, but I am a newbie (seasoned in Windows desktop) can you help me get going with this?

Chuck

On Nov 5, 2020, at 5:25 PM, Richard Hull notifications@github.com wrote:

In regard to your earlier question about not to have to refresh the entire display:

The luma.device.* classes are really just a wrapper around being able to send Pillow images to the display along with a bunch of helper classes to make it simple to draw text and primitives onto a canvas (which is really just a Pillow ImageDraw object).

You will find it easier to manage state in your application if it just does full renders every time. You shouldn't worry too much about performance - for such small screens there are not really too many pixels to update, and it is possible to get high frame rates rendering complex screens. For some of the higher resolution screens there are some mechanisms we use to only do partial/intelligent screen updates which hugely improve frame render time. This implies the time taken to send bytes to the device takes more time than it does for you to draw them onto an image canvas.

If you are wanting to have a menu system where you toggle things on and off and want to revert back to a previous display without having to redraw, possibly have a look at using the history class and an example of its usage: https://github.com/rm-hull/luma.examples/blob/master/examples/savepoint.py

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

thijstriemstra commented 3 years ago

this is more of a stackoverflow question, search for systemd + python

rm-hull commented 3 years ago

@chuckv2014 when you said:

however, when I added this to the profile... I get an error: No Module named ‘luma’

Can you explain exactly what you did?

chuckv2014 commented 3 years ago

Thank you Richard, As mentioned, I can execute everything fine from my pi@raspberrypi command prompt... both of these execute fine... python3 ~/CODE/TEST_MENU.py sudo python3 ~/CODE/TEST_MENU.py

Likewise, if I change to the CODE folder... this works fine... python3 TEST_MENU.py

However, when I edit the profile and add this line at the end, it returns the error about LUMA...

sudo nano /etc/profile

I have also tried the following as the last lines in the profile... cd CODE sudo python3 TEST_MENU.py

... and have tried... cd CODE sudo python3 ~/CODE/TEST_MENU.py

... and have tried... without changing to the CODE subfolder sudo python3 ~/CODE/TEST_MENY.py

***In every case, I get the following: ... from luma.core.interface.serial import spi ImportError: No module named ‘luma’

Thanks for the help!

Chuck

On Nov 15, 2020, at 5:07 AM, Richard Hull notifications@github.com wrote:

@chuckv2014 when you said:

however, when I added this to the profile... I get an error: No Module named ‘luma’

Can you explain exactly what you did?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

rm-hull commented 3 years ago

Chuck - I would recommend adding your script to /etc/rc.local instead (be sure to use the & at the end of your command) or as Thijs mentioned, have a read around systemd.

These documents should be a good place to start:

/etc/profile is usually used to set PATH variable, user limits, and other settings: it may be that you are trying to start the python script before all the paths are correctly set up.

chuckv2014 commented 3 years ago

Thank you Richard, it was very nice of you to take your time and reply.

Just coming up on this platform, and I have tons of reading still to do... I Google for fixes - and was steered in the direction I mentioned above... I was definitely stuck... will try your suggestion right away.

I greatly appreciate the help, THANK YOU!

Chuck

On Nov 16, 2020, at 5:57 PM, Richard Hull notifications@github.com wrote:

Chuck - I would recommend adding your script to /etc/rc.local instead (be sure to use the & at the end of your command) or as Thijs mentioned, have a read around systemd.

These documents should be a good place to start:

https://www.raspberrypi.org/documentation/linux/usage/rc-local.md https://www.raspberrypi.org/documentation/linux/usage/systemd.md /etc/profile is usually used to set PATH variable, user limits, and other settings: it may be that you are trying to start the python script before all the paths are correctly set up.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

chuckv2014 commented 3 years ago

Richard, have another issue that may be a bug, else maybe you can direct me I’m still a newb.

Using LUMA.OLED on a monochrome OLED display.... everything works great, except...

I have a status line designed that changes Glyphs based on value, so these Glyphs simply get over-written with the new Glyph that corresponds to the value... in theory works for WiFi Strength, Remaining Battery, etc.

black = (0, 0, 0, 0) white = (255,255,255,0) self.draw.text((x,y), text=glyph1, font=font, fill=black) #wifi glyph 5 bars device.display(self.im.convert(device.mode)) sleep(3) self.draw.text((x,y), text=glyph2, font=font, fill=black) #wifi glyph 0 bars device.display(self.im.convert(device.mode))

I think my issue is with opacity, but can’t figure it out... basically, glyph1 and glyph2 are identical except in the number of WiFi bars filled.... 5 filled (all white bars) vs. 0 filled (all bars filled with black)

The 5 white bars display first... then after 3 seconds (to simulate WiFi Strength changing) then I display the 0 bars... what should happen is this location should change to unfilled bars... instead they stay filled (using other Glyphs in the same scenario, turns out both glyphs stay displayed (like a BIT OR of the two, rather than a BIT AND).

This indicates to me, that glyph1 is not being completely over-written by glyph2 on the second call (shown above). The black areas of glyph2 are treated as “transparent” rather than “opaque” so, the full bars of glyph1 always show through... which is undesired.

I’ve tried every combination of Alpha channel settings... nothing resolves this to the way desired.

As mentioned, this is a mono color OLED display.

**how do I get the black pixels to over-write the white pixels without* clearing the screen/location (because then the Glyphs looks like it has flashed).

With your knowledge of your library... what’s the fix for this?

I appreciate your help and your time.

Thank you, Chuck

On Nov 16, 2020, at 5:57 PM, Richard Hull notifications@github.com wrote:

Chuck - I would recommend adding your script to /etc/rc.local instead (be sure to use the & at the end of your command) or as Thijs mentioned, have a read around systemd.

These documents should be a good place to start:

https://www.raspberrypi.org/documentation/linux/usage/rc-local.md https://www.raspberrypi.org/documentation/linux/usage/systemd.md /etc/profile is usually used to set PATH variable, user limits, and other settings: it may be that you are trying to start the python script before all the paths are correctly set up.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

rm-hull commented 3 years ago

In the example you gave, did you mean to do fill=black ?

If you want to do incremental updates like that, the only thing i can think is if you cleared out the rectangle before redrawing, e.g.

black = (0, 0, 0, 0)
white = (255,255,255,0)
self.draw.text((x,y), text=glyph1, font=font, fill=black) #wifi glyph 5 bars
device.display(self.im.convert(device.mode))
sleep(3)
w, h = self.draw.textsize(text=glyph1, font=font)
self.draw.rectangle((x, y, x+w, y+h), fill=background_color)
self.draw.text((x,y), text=glyph2, font=font, fill=black) #wifi glyph 0 bars
device.display(self.im.convert(device.mode))

However, I would really just recommend doing full screen updates every time using the canvas helper, as documented here: https://luma-oled.readthedocs.io/en/latest/python-usage.html#python-usage - look in the examples

chuckv2014 commented 3 years ago

Hi Richard, thank you for taking the time to reply.

As mentioned, clearing the area makes the glyph flash (on-off-on) and that is undesirable (un-natural looking).

Early on, I, in no way, wanted to refresh the entire screen simply to update a 10 pixel square... it too will look un-natural and take too much time.

The only real route, for the single glyph update (which Pillow seems to not allow or even identify with...) is that draw.text should BIT AND the new value (pixel by pixel AND or maybe it is an XOR of what is in the current memory buffer and what draw.text() is writing... it’s rather foolish (IMO) and non-sense that successive draw.text() will combine and co-mingle with what is already in memory for that location...

Doing it this way, there is no “flash” due to clearing it (nor the expense of time to do so...) and it just simply over-writes what is there... perfect.

Anyway... great products over-all... disappointed that this “finer” polish is not part of them. “One size fits all” approaches seldom work successfully in a broad deployment.

I admire you taking your time on this issue, the beers are on me if ever in south Florida!

Chuck

On Nov 18, 2020, at 7:05 PM, Richard Hull notifications@github.com wrote:

In the example you gave, did you mean to do fill=black ?

If you want to do incremental updates like that, the only thing i can think is if you cleared out the rectangle before redrawing, e.g.

black = (0, 0, 0, 0) white = (255,255,255,0) self.draw.text((x,y), text=glyph1, font=font, fill=black) #wifi glyph 5 bars device.display(self.im.convert(device.mode)) sleep(3) w, h = self.draw.textsize(text=glyph1, font=font) self.draw.rectangle((x, y, x+w, y+h), fill=background_color) self.draw.text((x,y), text=glyph2, font=font, fill=black) #wifi glyph 0 bars device.display(self.im.convert(device.mode)) However, I would really just recommend doing full screen updates every time using the canvas helper, as documented here: https://luma-oled.readthedocs.io/en/latest/python-usage.html#python-usage - look in the examples

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.