adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.05k stars 1.2k forks source link

Add option to suppress terminal output on display (if present) #2791

Closed k3wals closed 1 year ago

k3wals commented 4 years ago

I was able to suppress the terminal output to a display by commenting the following lines:

//supervisor_start_terminal(width, height);

within:

It would be convenient to disable the terminal display output in boot.py perhaps.

Blinka icon is still present though momentarily.

@dhalbert suggested I open an issue after discussing on Discord.

tannewt commented 4 years ago

@k3wals What is your reason for this?

k3wals commented 4 years ago

The make the device a bit more product like for demo use. Don't need the verbose info to non-technical user.

I think I'm going to replace the _bitmapdata with a static image with text such as "Contact XYZ and cycle power". Perhaps show a more intelligent error code if possible.

hierophect commented 4 years ago

I can see the appeal of this when used in a product. Is it feasible this could be added as a build flag?

ladyada commented 4 years ago

perhaps it would make more sense if it was handled in boot.py somehow?

tannewt commented 4 years ago

I can see the appeal of this when used in a product. Is it feasible this could be added as a build flag?

Note that CircuitPython is not intended for use in a product and we provide no warranty. It's up to a product creator to understand CircuitPython enough to supply a warranty to their customers.

If they ship with a custom build of CircuitPython they should call it CircuitPython-compatible and not vanilla CircuitPython. CircuitPython has more meaning than just the code base.

hierophect commented 4 years ago

@tannewt I don't mean a literal commercial product necessarily, and I don't mean to imply anything by that statement regarding warranty or legality. I think the point here is that removing the automatic terminal display just adds a bit of polish when a project is demonstrated to non-technical users. Even just from an aesthetic standpoint I think this request is valid - if an artist was using DisplayIO for something and doesn't want a bunch of technical output on reboot, is that so unreasonable?

k0d commented 4 years ago

I'm adding a debug_console (VCP on stm32) at the moment, that will be enabled via a build flag, we could add one for the display_console at the same time?

tannewt commented 4 years ago

I don't think it should be a build flag because then building would be required to change.

I think adding something to boot.py is ok.

However, I don't think it's really necessary. One can show an empty group on the display both in boot.py and code.py very early to minimize when the terminal appears. I don't like the idea of a hard disable because it's helpful to have it appear on crashes.

@k0d I think the debug console is fine at build time because I assume folks are already building their own in that case.

k0d commented 4 years ago

@tannewt I agree 100%

ricardoquesada commented 3 years ago

Another use case: interactive experience, good for teaching

right now, whenever I type something on REPL, I see it on the display as well, and the pixels get "erased".

ricardoquesada commented 3 years ago

nevermind, found a solution that works for me. Compiling it with make CIRCUITPY_TERMINALIO=0 does what I needed.

tannewt commented 3 years ago

@ricardoquesada If you are using displayio, the terminal shouldn't override your displayio Group. How are you setting a pixel?

ricardoquesada commented 3 years ago

Thanks, I'm setting the pixels like the following:

# Enter this from REPL
import board
import busio
import displayio
from adafruit_matrixportal.matrix import Matrix

matrix = Matrix(bit_depth=2)
display = matrix.display
bitmap = displayio.Bitmap(64,32,2)
palette = displayio.Palette(2)
palette[0] = (0,0,0)
palette[1] = (255,0,0)

grid = displayio.TileGrid(bitmap, pixel_shader=palette)
group = displayio.Group()
group.append(grid)

display.show(group)
bitmap[1,1] = 1

I'm using a matrix LED + matrixportal_m4. And I was typing everything from REPL.

tannewt commented 3 years ago

Hrm. I don't use REPL regularly but it sounds like a bug. Why are you using the REPL for this?

ricardoquesada commented 3 years ago

mostly for prototyping and doing quick tests. Also, I'm building a "computer for my kids" using CircuitPython for the API, and I want them to try things using REPL. Things like:

>>> set_pixel([0,1], RED)
>>> play_music("CDEFGAB")
>>> move_sprite(sprite, (x,y))

...and that will give them immediate feedback of what's happening.

tannewt commented 3 years ago

@jerryneedell Do you know if the REPL will overwrite the display while it's in use?

bitboy85 commented 3 years ago

I would go further and think this should be disabled by default. This behaviour is unexpected and a small display like the 128x32 shows only two and a half lines. Of course with no useful information. If someone really needs this output it should be explicitly enabled. Maybe like this: display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT, rotation=180, console=True)

tannewt commented 3 years ago

I would go further and think this should be disabled by default. This behaviour is unexpected and a small display like the 128x32 shows only two and a half lines. Of course with no useful information. If someone really needs this output it should be explicitly enabled. Maybe like this: display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT, rotation=180, console=True)

I strongly disagree. It's useful to know things are running and for most boards the display showing errors is extremely helpful. Getting a serial connection to see errors is a big hurdle for some folks.

aivarannamaa commented 3 years ago

It looks like the need to update display makes using REPL slower. It may not be relevant for manual usage, but Thonny, for example, uses REPL for management tasks (eg. for querying variables and available modules) and also for running code from the active editor. Because of this, using TrinketM0 in Thonny is much smoother experience compared to CLUE (which contains faster processor, if I'm not mistaken).

What about turning off output mirroring when CircuitPython enters REPL? I assume the REPL can only be entered via working serial connection (or, at least this is the main way for using it). In this case I find it unlikely that anybody prefers to look the output on a tiny (or smallish) screen instead of her terminal program.

bitboy85 commented 3 years ago

I strongly disagree. It's useful to know things are running and for most boards the display showing errors is extremely helpful. Getting a serial connection to see errors is a big hurdle for some folks.

I agree that it might be useful for debugging purpose, but for this reason i also think it should be disabled by default because most software has disabled debug output unless you really want it. Instead of using an additional function parameter there might be other solutions like a global debug variable in boot.py.

tannewt commented 3 years ago

What about turning off output mirroring when CircuitPython enters REPL? I assume the REPL can only be entered via working serial connection (or, at least this is the main way for using it). In this case I find it unlikely that anybody prefers to look the output on a tiny (or smallish) screen instead of her terminal program.

I like that it shows on the REPL. You could have thonny do displayio.release_displays() to turn it off completely. You would need to know how to reinitialize a display then though.

I agree that it might be useful for debugging purpose, but for this reason i also think it should be disabled by default because most software has disabled debug output unless you really want it.

I strongly disagree that it should be off by default. Seeing the serial error output is one of the trickiest parts of the usb workflow and having the display show errors by default greatly simplifies it.

adrian-the-git commented 3 years ago

I think CircuitPython is and should be a "debug features ON by default" environment, but it would be great to have the ability to disable the REPL without rebuilding (I'll save my comments on why it's undesirable to do so for an appropriate thread).

So anyhow, on a 64x32 matrix panel, the onscreen REPL doesn't really fit, so the output line which I'm interested in reading is not visible, with Blinka looking more like a flamingo than a snake, and it just looks like a graphical glitch—it's not a nice boot screen for a creative project. So I'm agreeing with @hierophect who made this point about artists wanting to control the aesthetics.

Now asking for confirmation @tannewt that we should not expect a hard switch to disable terminalio, but instead should display an empty group in boot.py? So sayeth the developer on this enhancement-labeled issue?

tannewt commented 3 years ago

I think CircuitPython is and should be a "debug features ON by default" environment, but it would be great to have the ability to disable the REPL without rebuilding (I'll save my comments on why it's undesirable to do so for an appropriate thread).

Why doesn't displayio.release_displays() work? That would allow you to control when the display is initialized.

domdfcoding commented 2 years ago

I tried using displayio.release_displays() in boot.py, but I still get a flash of the blinka logo when the device boots up and when reloading the script.

I found that the initialization of a FramebufferDisplay (in my case via a Matrix object from adafruit_matrixportal.matrix) displays the terminal (and blinka) in the brief time until something else is shown on the display. I managed to stop this by setting auto_refresh=False when creating the FramebufferDisplay, and setting it back to True after .show()ing something on the display. Not super elegant, so it would be great for a proper solution.

zestyping commented 2 years ago

@tannewt I agree that it's useful to have easily accessible error messages when a program crashes, and that setting up a serial connection to see errors is hard.

The problem is that, when I look at the current implementation:

What if we considered an implementation like the following?

Would that meet the needs you're expressing, in addition to those expressed by @k3wals, @hierophect, and @bitboy85 in this discussion?

xgpt commented 2 years ago

Displaying a flash of the logo and console on startup has nothing to do with showing errors on a program crash; the first is not necessary for the second.

Echoing what @zestyping is saying, it's pretty annoying and looks a little...beta-ish? don't understand why we have to see blinka by default.

zestyping commented 2 years ago

@tannewt This is what the terminal output gives us on a typical 64x32 display panel after an uncaught exception is thrown.

20220213_104220

Can you guess what the exception is?

Do we have common ground in this discussion that this is not what anyone wants to see?

tannewt commented 2 years ago

@zestyping I agree that's not ideal.

It takes time to change things and this isn't a priority for me.

I'm happy to give pointers on how to change it and then review the change if anyone does have the time and motivation.

bitboy85 commented 2 years ago

Is currently someone working on this? There are edits to remove blinka and, i guess, the terminal output. https://github.com/adafruit/circuitpython/blob/main/supervisor/shared/display.c

tannewt commented 2 years ago

I don't think there is work to disable it completely. deshipu only added a flag to remove the Blinka logo: https://github.com/adafruit/circuitpython/pull/5298

justinesmithies commented 2 years ago

I too would love to be able to disable the logo and the terminal output from my ssd1306. At the moment I'm having to use the adafruit_ssd1306 driver instead of the adafruit_displayio_ssd1306 because of the issue when my code that displays a splash in the boot.py and it finishes in the gap between code.py starting I see the logo and the words "code.py running" which is not what I want to see. Using the other driver it just seamlessly changes from one image to the next image that is ran from code.py no interruptions in between. Hope that made sense as it did in my head lol ??

tannewt commented 2 years ago

@justinesmithies Would it be ok for you to have the splash setup in code.py? That way you won't have a gap where CircuitPython has control of the display.

justinesmithies commented 2 years ago

@justinesmithies Would it be ok for you to have the splash setup in code.py? That way you won't have a gap where CircuitPython has control of the display.

Yeah minutes after submitting my comment that exact thought popped into my head. But it would be good and I'm sure that I'm not alone to have some kind of option in displayio to disable the terminal output / logo.

bitboy85 commented 2 years ago

I've seen another flag called CIRCUITPY_TERMINALIO so i guessed its for disabling the terminal output...

kmatch98 commented 2 years ago

Not sure your exact need is, but if you are ok with disabling the terminal in the python-side, you can make use of this recently-added feature and move the root_group outside of the visible display. Keep in mind the terminal will still be present in memory and will reappear whenever you fall back into the REPL.

If you want to prevent an image from flashing on the screen, you can set auto_refresh to false while you make the change you need, and then re-enable it. On second thought, I'm uncertain what happens between boot.py and code.py, maybe that will automatically update the auto_refresh.

bablokb commented 2 years ago

I have an additional use-case: I use an OLED to display some info and then go to deep-sleep (exit_and_deep_sleep_until_alarms). As soon as this is executed, the REPL takes over and replaces my content with that very important information that the program is running :-(

Releasing the display before going to deep-sleep is a workaround, but this is clumsy. And I'm not sure if this works with every kind of display. Also, "simulated deep-sleep" does not seem to release the display and bails out after restart.

jeffThompson commented 2 years ago

100% for this, at least at boot. Flashing some random stuff before the actual content doesn't help anyone debug and makes projects, like the ones outlined above, look crappy. (And we want to use CircuitPython for products! We all understand the open source license provides no warranty... doesn't mean we don't add features when it helps the community.)

If nothing else, adding info in the docs and/or the Learn section of the Adafruit site on how to do this in boot.py would be super helpful. I read this thread a few times and can't figure out how to even start.

paulmand3l commented 1 year ago

I strongly support the ability to suppress Blinka (why is this shown at all?) and terminal debugging for a few reasons:

@jeffThompson here's what worked for me to suppress the flash of Blinka and terminal (but not the "Code has been stopped by..." message):

import displayio
from adafruit_displayio_ssd1306 import SSD1306

displayio.release_displays()

i2c = busio.I2C(board.SCL, board.SDA, frequency=1000000)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3c)
display = SSD1306(display_bus, width=128, height=64, rotation=180, auto_refresh=False)

screen = displayio.Group()
display.show(screen)
display.auto_refresh = True

# Draw stuff in the screen group

Here's how I wish it worked:

Rillian-Grant commented 1 year ago

Using a build directly from git including the pull request mentioned above I was able to solve this issue by adding the following to boot.py:

import displayio
displayio.release_displays()
matwho commented 1 year ago

Hi I too have a project with an LED Matrix that is ruined with the console appearing at startup. displayio.release_displays() in boot.py did not work for me.

Rillian-Grant commented 1 year ago

Hi I too have a project with an LED Matrix that is ruined with the console appearing at startup. displayio.release_displays() in boot.py did not work for me.

Did you build circuit python from the git repo? This change is more recent than the latest release.

Breazile commented 1 year ago

This issue also seems to block any deep sleep efforts which is my main concern.

I have a design for a small display that Mandalorian cosplayers use in their gauntlets. I am trying to add a feature where you can put the system into deep sleep and wake it up with a button press later.

The problem that I am having is that once I make the alarm call to put the system to sleep (and I turn off the backlight) the system shows the console and more importantly it turns on the backlight to 100% which drains power. To me it does not matter if the console or the snake logo is shown because the backlight is off.

Is there any way to keep the backlight off? Maybe a deep sleep option that does not exit to the console?

This is what it looks like when it goes to sleep Link to Video

tannewt commented 1 year ago

Is there any way to keep the backlight off? Maybe a deep sleep option that does not exit to the console?

The latest beta versions of CircuitPython have a way to preserve pins when going into deep sleep. https://docs.circuitpython.org/en/latest/shared-bindings/alarm/index.html#alarm.exit_and_deep_sleep_until_alarms

Breazile commented 1 year ago

Thank you for the tip. Will this be available on the Feather? I'm using the Feather M4 Express as well as the ESP32S3. Unfortunately, it looks like preserving the I/O on those boards is not yet available, but I'll put the code in anyway and see what happens.

Limitations: preserve_dios is currently only available on Espressif according to the docs

Breazile commented 1 year ago

I went ahead and added the code and hit another issue. I passed in the I/O pin to the display manager and let it control the backlight level:

ST7789(display_bus, rotation=270, width=240, height=135, rowstart=40, colstart=53, auto_refresh=False, backlight_pin=board.D10, brightness=0)

When I try to put the system into deep sleep I get and error that the I/O pin is in use:

alarm.exit_and_deep_sleep_until_alarms(time_alarm, preserve_dios=[digitalio.DigitalInOut(board.D10)])

Traceback (most recent call last): File "code.py", line 287, in ValueError: D10 in use

tannewt commented 1 year ago

Thank you for the tip. Will this be available on the Feather? I'm using the Feather M4 Express as well as the ESP32S3. Unfortunately, it looks like preserving the I/O on those boards is not yet available, but I'll put the code in anyway and see what happens.

Limitations: preserve_dios is currently only available on Espressif according to the docs

I don't know of anyone adding preserve pin support to the SAMD51 (aka M4). Generally its deep sleep support is less refined.

tannewt commented 1 year ago

When I try to put the system into deep sleep I get and error that the I/O pin is in use:

Deinit the display and then try.

Breazile commented 1 year ago

I set the backlight to 0, and then called displayio.release_displays(), and the result was the backlight was left on.

After the displayio.release_displays() call I setup I/O pin D10 and set it low (driving the backlight), but I received the same error that the GPIO was in use when exit_and_deep_sleep_until_alarms() was called:

backlight = digitalio.DigitalInOut(board.D10)
backlight.direction = digitalio.Direction.OUTPUT
backlight.value = False

Traceback (most recent call last): File "code.py", line 313, in ValueError: D10 in use

So it looks like I am not able to sleep with the backlight off unless you have another suggestion to try.

aricooperdavis commented 1 year ago

... if you are ok with disabling the terminal in the python-side, you can make use of this recently-added feature and move the root_group outside of the visible display. Keep in mind the terminal will still be present in memory and will reappear whenever you fall back into the REPL.

Thank you - this is the easy fix that I was looking for. Just add

display.root_group.hidden = True

after defining your display. e.g.:

import board
display = board.DISPLAY
display.root_group.hidden = True
kmatch98 commented 1 year ago

Closing due to added features with root_group.