@alphanumeric The same for me, I had my keypad running Circuit Python HID code but when I wanted to change the code I had a go at getting mp HID to work as its my preferred environment.
You may be interested in a slightly more advanced example. I had a Pimoroni example code for the keypad (rgbkeypad.py) that creates a key object for each of the keys and puts them in a list of keys for manipulation. (I think it was a Pimoroni example, but I cant see it on their examples when I just looked). Anyway I amended this example to include the storing an assigned key value and renamed the file to bg_rgbkeypad.py. I show this file below and also an example that makes use of it.
The sending of bunch of HID keys values as a long ‘macro’ list will not work as it trips up when sending more than 3 keycode values, so the example hidkey() function in the example sends any list of keycodes greater than 3 values as individual keycodes. (if you see what I mean). The example shows this for the keypad[3] which sends ‘ls -a’ to list the files in a directory (on my mac)
As before comment out the code line ‘usb.device.get().init(kb, builtin_driver=True)’ to enable the example code to be tested in Thonny with print statements, but restore the line to run it as a HID program outside of Thonny.
bg_rgbkeypad.py:
import machine
PIN_SDA = 4
PIN_SCL = 5
PIN_CS = 17
PIN_SCK = 18
PIN_MOSI = 19
class RGBKeypad():
KEYPAD_ADDRESS = 32
# ------------------------------------------------------------------
class MPDevice():
def __init__(self):
"""
Internal class used to communicate with the keypad device when
using MicroPython.
"""
# setup i2c
self._i2c = machine.I2C(
0,
scl=machine.Pin(PIN_SCL),
sda=machine.Pin(PIN_SDA),
freq=400000
)
# setup spi
self._spi = machine.SPI(
0,
baudrate=4*1024*1024,
sck=machine.Pin(PIN_SCK),
mosi=machine.Pin(PIN_MOSI)
)
# setup cs
self._cs = machine.Pin(
PIN_CS,
machine.Pin.OUT
)
self._cs.high()
def read_keys(self):
self._i2c.writeto(RGBKeypad.KEYPAD_ADDRESS, bytearray(1), True)
data = self._i2c.readfrom(RGBKeypad.KEYPAD_ADDRESS, 2, False)
return data
def write_leds(self, led_data):
self._cs.low()
self._spi.write(led_data)
self._cs.high()
# ------------------------------------------------------------------
class RGBKey():
def __init__(self, keypad, x, y, red, green, blue, brightness,assigned_key=None):
"""
Represents a single key of the RGB Keypad.
Returned when using RGBKeypad[x,y] or RGBKeypad.get_key(x,y)::
keypad = RGBKeypad()
key = keypad[0, 0]
"""
self._keypad = keypad
self._x = x
self._y = y
self._red = red
self._green = green
self._blue = blue
self._brightness = brightness
self._assigned_key = assigned_key
@property
def x(self):
"""
Returns the x position of the key.
"""
return self._x
@property
def y(self):
"""
Returns the y position of the key.
"""
return self._y
@property
def brightness(self):
"""
Sets or returns the brightness of the key.
A value between 0 and 1 where 0 is off and 1 is full brightness.
"""
return self._brightness
@brightness.setter
def brightness(self, value):
value = max(min(1, value), 0)
self._brightness = value
self._update()
@property
def assigned_key(self):
return self._assigned_key
@assigned_key.setter
def assigned_key(self,value):
self._assigned_key = value
@property
def red(self):
"""
Sets or returns the red color of the key.
A value between 0 and 255.
"""
return self._red
@red.setter
def red(self, value):
value = max(min(255, value), 0)
self._red = value
self._update()
@property
def green(self):
"""
Sets or returns the green color of the key.
A value between 0 and 255.
"""
return self._green
@green.setter
def green(self, value):
value = max(min(255, value), 0)
self._green = value
self._update()
@property
def blue(self):
"""
Sets or returns the blue color of the key.
A value between 0 and 255.
"""
return self._blue
@blue.setter
def blue(self, value):
value = max(min(255, value), 0)
self._blue = value
self._update()
@property
def color(self):
"""
Sets or returns the color of the key.
A tuple of (red, green, blue) values between 0 and 255.
"""
return (self.red, self.green, self.blue)
@color.setter
def color(self, value):
auto_update_value = self._keypad.auto_update
self.red = value[0]
self.green = value[1]
self.blue = value[2]
self.auto_update = self._keypad.auto_update
self._update()
def is_pressed(self):
"""
Returns True if the key is pressed when called.
"""
return self._keypad.get_keys_pressed()[
(4 * self._y) + (self._x % 4)
]
def clear(self):
"""
Clears the key color.
Clear is the same as setting the color to black (0, 0, 0).
"""
self.color = (0, 0, 0)
def _update(self):
if self._keypad.auto_update:
self._keypad.update()
# ------------------------------------------------------------------
def __init__(self, color=(0,0,0), brightness=0.5, auto_update=True):
"""
Represents a pimoroni RGB Keypad device connected to a Raspberry Pi
pico running either MicroPython or CircuitPython.
::
rgbkeypad = RGBKeyPad()
A single key can be obtained using its x, y coordinate ::
key = rgbkeypad[0, 0]
:param tuple color:
The initial color for all the keys.
A tuple of (red, green, blue) values between 0 and 255.
The default is (0, 0, 0), black or off.
:param int brightness:
The initial brightness of the keys.
A value between 0 and 1 where 0 is off and 1 is full brightness.
The default is 0.5.
:param bool auto_update:
When True, the key pad will be automatically updated
when the color or brightness of a key is changed.
If False, the update() method will need to be called
before any changes are reflected on the keypad.
The default is True
"""
# create the device
self._device = RGBKeypad.MPDevice()
# setup all the keys before setting aut o update
self.auto_update = False
# setup keys
self._keys = []
for y in range(4):
for x in range(4):
self._keys.append(
RGBKeypad.RGBKey(self, x, y, color[0], color[1], color[2], brightness)
)
self.update()
self.auto_update = auto_update
self._color = color
self._brightness = brightness
def clear(self):
"""
Clears all the keys color.
Clear is the same as setting the color to black (0, 0, 0).
"""
self.color = (0, 0, 0)
@property
def color(self):
"""
Sets the color of all the keys as a tuple of (red, green, blue) values
between 0 and 255.
Note - color will return the "default" or "initial" color of the keys.
If an individual key's color has been change this wont be represented.
"""
return self._color
@color.setter
def color(self, value):
auto_update_value = self.auto_update
self.auto_update = False
for key in self._keys:
key.color = (value[0], value[1], value[2])
self.update()
self.auto_update = auto_update_value
@property
def brightness(self):
"""
Sets the brightness of all the keys as a value between 0 and 1 where
0 is off and 1 is full brightness.
Note - brightness will return the "default" or "initial" brightness
of the keys. If an individual key's brightness has been change this
wont be represented.
"""
return self._brightness
@brightness.setter
def brightness(self, value):
auto_update_value = self.auto_update
self.auto_update = False
for key in self._keys:
key.brightness = value
self.update()
self.auto_update = auto_update_value
@property
def keys(self):
"""
Returns a list of all the keys as RGBKey objects.
"""
return self._keys
def get_keys_pressed(self):
"""
Returns a list of 16 booleans represent the current pressed
state of all the keys.
"""
data = self._device.read_keys()
button_data = int.from_bytes(data, "little")
# button states
button_states = []
for button in range(16):
button_states.append(0 == (button_data & (1<<button)))
return button_states
def get_key(self, x, y):
"""
Returns a key as an RGBKey object.
get_key(x, y) is the equivalent of RGBKeypad[x, y].
:param int x:
The x position of the key.
:param int y:
The y position of the key.
"""
return self._keys[(4 * y) + (x % 4)]
def update(self):
"""
Updates the RGB Keypad with the current color and brightness.
Is only required to be called when auto_update = False.
"""
led_data = bytearray((16*4) + 8)
data_pos = 4
for key in self._keys:
led_data[data_pos] = int(255 - 31 + (31 * key.brightness))
led_data[data_pos + 1] = key.blue
led_data[data_pos + 2] = key.green
led_data[data_pos + 3] = key.red
data_pos += 4
self._device.write_leds(led_data)
def __getitem__(self, index):
return self.get_key(index[0], index[1])
test.py
from bg_rgbkeypad import RGBKeypad
import usb.device
from usb.device.keyboard import KeyboardInterface, KeyCode, LEDCode
import time
kb = KeyboardInterface()
usb.device.get().init(kb, builtin_driver=True)
keypad = RGBKeypad()
def sendkey(key):
if key:
if key[0] == 'msg':
print('mqtt message to publish:',key[1], key[2])
else:
hidkey(key)
def hidkey(key):
if len(key) < 4:
print(key)
kb.send_keys(key)
kb.send_keys([])
else:
for num in range(0, len(key),1):
print(key[num])
kb.send_keys([key[num]])
kb.send_keys([])
def key_colour_end(key):
key.color=(0,0,0)
# -------------------------------------------
# assign keycodes to keypad keys
# keycode (for mac) to list all files, including hidden, in the current dir.
keypad.keys[3].assigned_key = [KeyCode.L, KeyCode.S, KeyCode.SPACE, KeyCode.MINUS, KeyCode.A, KeyCode.ENTER]
keypad.keys[3].color = (0,0,200)
# keypad key 7 to send an mqtt message
keypad.keys[7].assigned_key = ['msg', 'request/wf/today', '']
keypad.keys[7].color = (100,200,100)
# keypad keys set to send HID keycodes
keypad.keys[12].assigned_key = [KeyCode.A]
keypad.keys[12].color = (0,100,0)
keypad.keys[13].assigned_key = [KeyCode.LEFT_SHIFT, KeyCode.A]
keypad.keys[13].color = (0,100,0)
keypad.keys[14].assigned_key = [KeyCode.LEFT_ALT, KeyCode.N3]
keypad.keys[14].color = (0,100,0)
keypad.keys[15].assigned_key = [-0x04,32]
keypad.keys[15].color = (0,100,0)
# continually loop to check what keypad key is pressed
try:
while True:
for key in keypad.keys:
if key.is_pressed():
assigned_color=key.color
key.color=(225,0,0)
print("key", key.x, key.y, "pressed / value:", key.assigned_key)
sendkey(key.assigned_key)
time.sleep(0.25)
key.color=assigned_color
time.sleep(0.01)
except KeyboardInterrupt:
print('Ctl C')
keypad = RGBKeypad() # to put all key colours back to default (off)
So just a simple example. I’ve been looking in my electronic bits boxes for a nice little i2c screen (no luck) to hook up and to print a 3d case for the keyboard and small screen. I will eventually get around to producing async code so that this keypad arrangement can both send and receive mqtt messages, display info on a small screen, and act as a HID keyboard. Good luck with testing out your mp HID.