Help me made this code less verbose please :)

Hello everibody,

I have recently approached Python thanks to Raspberry Pi Pico. I am not a coder in real life and, even if I have some experience programming C, I need your help to figure how to make my code nicer in a reasonable amount of time.
Here is my code. It is intended to be used with raspberry pi pico in order to emulate a keyboard. The following code has only two buttons, but the final code will see approx 20 buttons.

import time
import board
import digitalio
import usb_hid

from adafruit_hid.keyboard import Keyboard, Keycode
from adafruit_debouncer import Debouncer

kbd = Keyboard(usb_hid.devices)

#BUTTONS INIT
btn0 = digitalio.DigitalInOut(board.GP0)
btn0.direction = digitalio.Direction.INPUT
btn0.pull = digitalio.Pull.UP

btn1 = digitalio.DigitalInOut(board.GP1)
btn1.direction = digitalio.Direction.INPUT
btn1.pull = digitalio.Pull.UP

def BUTTON0():
        if btn0.value == 0:
            kbd.press(Keycode.a)
        else:
            kbd.release(Keycode.a)
   
def BUTTON1():
        if btn1.value == 0:
            kbd.press(Keycode.b)
        else:
            kbd.release(Keycode.b)
 
#main loop
while True:
    BUTTON0()
    BUTTON1()

This code works flawlessy, but it’s verbose as hell (figure how it will turn with 20+ switches). How could I make this more concise?

Any help would be much apprecited. Thanks in advance :slight_smile:

You could (maybe) have one function:

def BUTTONS():
    switch0.update()
        if btn0.value == 0:
            kbd.press(Keycode.a)
        else:
            kbd.release(Keycode.a)
    
    switch1.update()
        if btn1.value == 0:
            kbd.press(Keycode.b)
        else:
            kbd.release(Keycode.b)


#main loop
while True:
    BUTTONS()

… rather than a function for each instance, but I don’t know if you could have something like this pseudo code:

def action(number):
    switch_number.update()
        if btn_number.value == 0:
            kbd.press(Keycode.a)
        else:
            kbd.release(Keycode.a)

action(1)

… where number in the function, is passed by the action() call.

If you could, then the number in the action() could be looped:

for number in range(21): # produce a integer value between 0 and 20
    action(number)

I would use a class and put the buttons in a list:

import time
import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard, Keycode
from adafruit_debouncer import Debouncer

class Button:
    def __init__(self, pin, key):
        self.btn = digitalio.DigitalInOut(pin)
        self.btn.direction = digitalio.Direction.INPUT
        self.btn.pull = digitalio.Pull.UP
        self.key = key

    def check(self):
        if self.btn.value == 0:
            kbd.press(self.key)
        else:
            kbd.release(self.key)

kbd = Keyboard(usb_hid.devices)

buttons = [
    Button(board.GP0, Keycode.a),
    Button(board.GP1, Keycode.b),
]

# main loop
while True:
    for button in buttons:
        button.check()

Map your buttons to your key codes, then iterate over them.

button_keys = {
    btn0: Keycode.a,
    btn1: Keycode.b,
}

while True:
    for btn, keycode in button_keys.items():
        if btn.value == 0:
            kbd.press(keycode)
        else:
            kbd.release(keycode)

BTW, you may want a sleep in there, unless the code truly needs to busywait like this.

Thank you very much for the help: I definitely have some solution to test and understand now:)
Chris, what do you mean with busywait? Where should I place the sleep and why?
(Thanks for the kind help so far guys!)

A “busywait” is when you spin, constantly checking for something. In this case, your loop basically says “hey, is that button down? hey, is that button down? hey, is that button down?” constantly. That means the CPU is constantly busy, checking for it.

Having a sleep in the loop (most likely at the very top or bottom of the while loop) gives a tradeoff: the longer the sleep, the less CPU load, but on average, it’ll take half a sleep before you notice a button press. So you wouldn’t want to have it sleep for an entire second (that would mean you’ll wait anywhere from not long to an entire second - on average, half a second), but sleeping for a few milliseconds would be fine.

As a general rule, having a computer respond to a button or key press in a tenth of a second will usually make it feel “snappy”. That figure changes depending on what you’re doing (a professional FPS player will want a response a lot quicker than that), but if you stay well below that, people will hardly even notice. For instance, ten milliseconds (a hundredth of a second) between checks will still feel incredibly fast, but that’ll save the computer a lot of hassle.

I don’t know enough about microcontrollers to know whether this is all still relevant, so it’s up to you to take this as a starting point and have a play around with it :slight_smile: Try time.sleep(0.01) and see if everything still works; then try time.sleep(2) and get an idea of what it’s like when your poll rate is too low. Have fun experimenting!

2 Likes