Inventor 2040 user button

Looking for guidance on if/how the user button on the Inventor 2040 could be set as a HID USB keyboard key, such that when pressed it activates a macro on the host Mac. There a lots of examples that use usb_hid but they are all using a separate keyboard.

Thanks

Micro Python or Circuit Python?
I ask because, last time I checked, Micro Python didn’t have USB HID support.

Circuit Python.

I’ve been thinking about alternatives to USB comms, for example, setting up a socket connection and sending say a get request from the Pi to the Mac which would run the Python macro script.

Ok, my only experience of this type, is with Pimoroni’s RGB Keypad and Adafruit’s PMK library. And even then that’s on a Windows PC sending keypresses.
pimoroni/pmk-circuitpython (github.com)

EDIT: I’m tagging along to see what you come up with. I have a spare RGB Keypad I’d like to use with my Pi 400.

Thank you for the info. I am doubtful I am going to come up with any reasonable solution as I’m a sloppy hack. Lots to learn from trying though!

I don’t have the inventor 2040, but I do have the Keybow 2040… which also has a user key that I use for loading page swaps, but there’s no reason it couldn’t be used for hid macros.

a bare minimum setup might look like…

import machine
my_button = machine.Pin( ??, Machine.Pin.IN, machine.Pin.PULL_DOWN )

and test in a loop with…
if my_button.value() == 1:

or a bit more fancy

import board
from digitalio import DigitalInOut

class UserButton:
	def __init__( self, pin ):
		self.__switch = DigitalInOut( pin ) # defaults to pull up
		
	@property
	def pressed( self ):
		self._state = int( not self.__switch.value ) # reverse the value since it's pull up
		return self._state
my_button = UserButton( board.USER_SW )

and test in a loop with…
if my_button.pressed:

if you look at the example code files for the Keybow 2040, or RGB Keybase they’ll have all the examples of using the adafruit HID library, which amount to send commands that go inside your if statement

ETA:
you probably want to cobble together some sort of debounce check, there’s code in those examples for that too
ETA 2:
forgot to mention, the question marks in the first code snippet should be replaced with the pin number of the user switch (should be listed on the device spec sheet), and board.USER_SW in the fancy snippet may actually be something different. This will you you a list of the names of the pins (which should match the names printed on the board)

import board
print( dir( board ) )

Very helpful Nox. I’ll consider this if I hit a dead end on my current path which is to:

  • capture the keypress on the pico
  • initiate a get request to a URL on my mac (which of course has to have a web server running)
  • hitting the URL kicks off a simple Python script that uses os.open(“/Applications/Whatever.app”

I’m sure I’m missing some issues with this approach but doesn’t hurt to try. My simple logic is that the pico/micropython supports get requests, I can turn up a web server on my Mac and kick off a script when a URL is hit that uses os.open(). I’ve tested that os.open() will bring an already open app to the foreground.

If it’s an app that can be assigned a control sequence to open (eg: ctrl+opt+j), your pico can send that sequence directly with the HID commands when the user switch is detected to be pressed. That would save you needing anything extra running on the mac side. The downside is that you have to assign a control sequence in advance, so it’s not universal to every mac you connect it to.

my familiarity with macs is limited, so I don’t remember if there is a universal key sequence for opening a terminal window, but if there is, than doing that would work as a more general solution

Hi, I did this (something similar) recently. It’s possible with circuit python and you can use all the mac system keys. I didn’t need to use macros in my case, but you could. Good luck!

So, after considerable effort I was able to turn the Pimoroni RGB keypad into a wireless macro keypad using MicroPython. I didn’t want to use CircuitPython because it is my understanding that only it supports usb_hid and I wasn’t sure if you could do usb_hid over wifi. It took considerable effort because my Python skills would best be described as beginner level, so, my “solution” is really just a crude proof-of-concept which has many holes and lots of room for improvement, for example, using a simple web server rather than Flask. I can’t even remember why I ended up using Flask. With all that said, this little hack works really well.

I’ve included the code below and here is a summary of my hack solution:

Two scripts - one on the Pico and one on the Mac

The Pico script establishes the WLAN connection, creates the keypad then sets a trigger on each of the keys associated with the “macro” which is actually not a macro, rather, an os.system call on the Mac which launches and/or brings the target app to the foreground. The communication between the Pico and the Mac is done via urequests.get.

On the Mac, I used Flask to receive and process the path value which is the string representing the name of the app to be launched and/or brought to foreground and returns a success or fail in the response to the Pico. I turned up the Flask server with: flask run -h 0.0.0.0 -p 8000

The script on the Pico:

from rgbkeypad import RGBKeypad
from random import randint, uniform
from time import sleep
from machine import Pin
import network
import urequests
import secrets

#create onboard LED
led = Pin("LED")

#establish WLAN connection
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(secrets.SSID, secrets.PASSWORD)

max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
            break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)
    
# Manage connection errors
if wlan.status() != 3:
    raise RuntimeError('Network Connection has failed')
else:
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')   
    led.off()
    led.on()


#create the keypad object and set default brightness
keypad = RGBKeypad()
keypad.brightness = .5

#just a little startup lightshow
def lightshow():
    for x in range(4):
        for y in range(4):
            key = keypad[x,y]
            key.brightness = uniform(.1,1)
            key.color = (randint(0,255), randint(0,255), randint(0,255))
            sleep(.1)      
    keypad.clear()    

lightshow()

#create, light and associate keys with specific apps on Mac
key1 = keypad[0,0]
key1.color = (0,255,0)
key1.app = 'TraderWorkstation'

key2 = keypad[3,3]
key2.color = (255,0,0)
key2.app = 'Telegram.app'

key3 = keypad[0,3]
key3.color = (0,0,255)
key3.app = 'GoogleChrome.app'

key4 = keypad[3,0]
key4.color = (0,0,100)
key4.app = 'Thonny.app'

#create the infinite loop and trigger for each key/app
while True:
    if key1.is_pressed():
        r = urequests.get('http://192.168.4.57:8000/'+ key1.app)
        print(r.content)
        r.close()
    if key2.is_pressed():
        r = urequests.get('http://192.168.4.57:8000/' + key2.app)
        print(r.content)
        r.close()
    if key3.is_pressed():
        r = urequests.get('http://192.168.4.57:8000/' + key3.app)
        print(r.content)
        r.close()
    if key4.is_pressed():
        r = urequests.get('http://192.168.4.57:8000/' + key4.app)
        print(r.content)
        r.close()

The script on the Mac:

from flask import Flask, request
import os

app = Flask(__name__)


@app.route("/", defaults={'path': ''})
@app.route("/<path:path>")
def (path):
    app = path
    r = os.system("open /Applications/" + app)
    if r == 0:
        return "<p>Success with code: %s</p>" % r
    else:
        return "<p>Fail with code: %s</p>" % r


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000, debug=True)

Sorry about the improper post of the code. Next time…

Sorry about the improper post of the code. Next time…

Fixed it for you :) It’s triple backticks: ``` for code blocks.

Good stuff, and thanks for the code. AFAIK you are correct that there isn’t a readily available wlan library that’s compatible with the hid library (and BLE support for the pico w in circuitPy isn’t available yet), so going direct through flask is much simpler.

RPF did recently release an SDK for the pico w for BLE, no library yet in circuitPy, but once it does pop up, that would be an option (the af HID library already works over BLE on some of their other boards, so plenty of tutorials)