CircuitPython - Read user input from USB serial non-blocking

In CircuitPython, we can get user input using input(). But it's a blocking function, that means it will not return until user input something. It's useful tricks to read user input non-blocking, circuitpython-tricks.

Here are my modified exercises running on ESP32-S3-DevKitC-1 flashed CircuitPython 8.0.5. In my exercises, onboard RGB neopixel change color to show it's non-blocking. Library neopixel.mpy is needed in my exercises, read ESP32-S3-DevKitC-1/CircuitPython to drive NeoPixel.


non-blocking_mostly.py Read user input from USB Serial, non-blocking (mostly)
In my test, supervisor.runtime.serial_bytes_available will not be cleared once user input; become blocking.
"""
Read user input from USB Serial, non-blocking (mostly)
https://github.com/todbot/circuitpython-tricks#read-user-input-from-usb-serial-non-blocking-mostly
"""
import time
import supervisor
import board
import neopixel

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.GRB)
pixel[0] = (0, 0, 0)
neo = [0, 0, 150]
def rotNeopixel():
    pixel[0] = (neo[0], neo[1], neo[2])
    neo.insert(0, neo.pop())

print("Type something when you're ready")
last_time = time.monotonic()
while True:
    if supervisor.runtime.serial_bytes_available:
        my_str = input()
        print("You entered:", my_str)
    if time.monotonic() - last_time > 1:  # every second
        last_time = time.monotonic()
        rotNeopixel()

non-blocking.py Read user input from USB serial, non-blocking
"""
Read user input from USB serial, non-blocking
https://github.com/todbot/circuitpython-tricks#read-user-input-from-usb-serial-non-blocking
"""
import time
import board
import neopixel

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.GRB)
pixel[0] = (0, 0, 0)
neo = [0, 0, 150]
def rotNeopixel():
    pixel[0] = (neo[0], neo[1], neo[2])
    neo.insert(0, neo.pop())

class USBSerialReader:
    """ Read a line from USB Serial (up to end_char), non-blocking, with optional echo """
    def __init__(self):
        self.s = ''
    def read(self,end_char='\n', echo=True):
        import sys, supervisor
        n = supervisor.runtime.serial_bytes_available
        if n > 0:                    # we got bytes!
            s = sys.stdin.read(n)    # actually read it in
            if echo: sys.stdout.write(s)  # echo back to human
            self.s = self.s + s      # keep building the string up
            if s.endswith(end_char): # got our end_char!
                rstr = self.s        # save for return
                self.s = ''          # reset str to beginning
                return rstr
        return None                  # no end_char yet

usb_reader = USBSerialReader()
print("type something and press the end_char")
last_time = time.monotonic()
while True:
    mystr = usb_reader.read()  # read until newline, echo back chars
    #mystr = usb_reader.read(end_char='\t', echo=False) # trigger on tab, no echo
    if mystr:
        print("got:",mystr)
    if time.monotonic() - last_time > 1:  # every second
        last_time = time.monotonic()
        rotNeopixel()
    

read_key.py Read keys from USB Serial
"""
Read keys from USB Serial
https://github.com/todbot/circuitpython-tricks#read-keys-from-usb-serial
"""
import time, sys, supervisor
import board
import neopixel

# Create the NeoPixel object
pixel = neopixel.NeoPixel(board.NEOPIXEL,
                          1,
                          pixel_order=neopixel.GRB)
pixel[0] = (0, 0, 0)
neo = [0, 0, 150]
def rotNeopixel():
    pixel[0] = (neo[0], neo[1], neo[2])
    neo.insert(0, neo.pop())

print("type charactcers")
last_time = time.monotonic()
while True:
    n = supervisor.runtime.serial_bytes_available
    if n > 0:  # we read something!
        s = sys.stdin.read(n)  # actually read it in
        # print both text & hex version of recv'd chars (see control chars!)
        print("got:", " ".join("{:s} {:02x}".format(c,ord(c)) for c in s))
    if time.monotonic() - last_time > 1:  # every second
        last_time = time.monotonic()
        rotNeopixel()


Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module