MOAR README
This commit is contained in:
parent
f799a7ef31
commit
11f502dce6
7 changed files with 267 additions and 67 deletions
242
README.md
242
README.md
|
@ -23,9 +23,9 @@ Unplug your Keybow 2040's USB-C cable, press and hold the button on the top edge
|
|||
of Keybow 2040 while plugging the USB-C cable back into your computer to mount
|
||||
it as a drive (it should show up as `RPI-RP2` or something similar).
|
||||
|
||||
Drag and drop the `xxxxxxxx.uf2` file that you downloaded onto the drive and it
|
||||
should reboot and load the CircuitPython firmware. The drive should now show up
|
||||
as `CIRCUITPY`.
|
||||
Drag and drop the `adafruit-circuitpython-pimoroni_keybow2040-en_US-XXXXX.uf2`
|
||||
file that you downloaded onto the drive and it should reboot and load the
|
||||
CircuitPython firmware. The drive should now show up as `CIRCUITPY`.
|
||||
|
||||
The Adafruit IS31FL3731 LED driver library for CircuitPython is a prequisite for
|
||||
this Keybow 2040 library, so you'll need to download it from GitHub at the link
|
||||
|
@ -41,4 +41,238 @@ Pick one of the [examples](examples) (I'd suggest the
|
|||
[reactive.press.py](examples/reactive-press.py) example to begin), copy the
|
||||
code, and save it in the `code.py` file on your `CIRCUITPY` drive using your
|
||||
favourite text editor. As soon as you save the `code.py` file, or make any other
|
||||
changes, then it should load up and run the code!
|
||||
changes, then it should load up and run the code!
|
||||
|
||||
## Basics
|
||||
|
||||
## Imports and setup
|
||||
|
||||
All of your programs will need to start with the following:
|
||||
|
||||
```
|
||||
import board
|
||||
from keybow2040 import Keybow2040
|
||||
|
||||
i2c = board.I2C()
|
||||
keybow = Keybow2040(i2c)
|
||||
```
|
||||
|
||||
First, this imports the `board` module which contains all of the pin objects for
|
||||
the Keybow 2040 board, including `board.I2C`, a quick way to set up the I2C bus,
|
||||
which is needed for the IS31FL3731 LED driver library used in this Keybow 2040
|
||||
library.
|
||||
|
||||
The `Keybow2040()` class, imported from the `keybow2040` module, is instantiated
|
||||
and passed the i2c bus object. Instantiating this sets up all of the pins, keys,
|
||||
and LEDs, and provides access to all of the attributes and methods associated
|
||||
with it.
|
||||
|
||||
## The Keybow class
|
||||
|
||||
The Keybow class exposes a number of handy attributes and methods. The main one
|
||||
you'll be interested in is the `.keys` attribute, which is a list of `Key`
|
||||
class instances, one for each key.
|
||||
|
||||
```
|
||||
keys = keybow.keys
|
||||
```
|
||||
|
||||
The indices of the keys in that list correspond to their position on the keypad,
|
||||
staring from the bottom left corner (when the USB connector is at the top),
|
||||
which is key 0, going upwards in columns, and ending at the top right corner,
|
||||
which is key 15.
|
||||
|
||||
More about the `Key` class later...
|
||||
|
||||
A **super** important method of the `Keybow` class is `.update()` method. It
|
||||
updates all of the keys, key states, and other attributes like the time of the
|
||||
last key press, and sleep state of the LEDs.
|
||||
|
||||
**You need to call this method on your `Keybow` class at the very start of each
|
||||
iteration of your program's main loop, as follows:**
|
||||
|
||||
```
|
||||
while True:
|
||||
keybow.update()
|
||||
```
|
||||
|
||||
## An interlude on timing!
|
||||
|
||||
Another **super** important thing is **not to include any `time.sleep()`s in
|
||||
your main loop!** Doing so will ruin the latency and mean that you'll miss key
|
||||
press events. Just don't do it.
|
||||
|
||||
If you need introduce timed events, then you have to go about it in a slightly
|
||||
(!!) roundabout fashion, by using `time.monotonic()` a constantly incremented
|
||||
count of seconds elapsed, and use it to check the time elapsed since your last
|
||||
event, for example:
|
||||
|
||||
```
|
||||
time_interval = 10
|
||||
|
||||
# An event just happened!
|
||||
|
||||
time_last_fired = time.monotonic()
|
||||
time_elapsed = 0
|
||||
|
||||
# ... some iterations later
|
||||
|
||||
time_elapsed = time.monotonic() - time_last_fired
|
||||
|
||||
if time_elapsed > time_interval:
|
||||
# Fire your event again!
|
||||
```
|
||||
|
||||
There's a handy `keybow.time_of_last_press` attribute that allows you to quickly
|
||||
check if a certain amount of time has elapsed since any key press, and that
|
||||
attribute gets updated every time `keybow.update()` is called.
|
||||
|
||||
## Key presses
|
||||
|
||||
There are a few ways that you can go about detecting key presses, some
|
||||
global methods on the `Keybow` class instance, and some on the `Key` class
|
||||
instances themselves.
|
||||
|
||||
### Keybow class methods for detecting presses and key states
|
||||
|
||||
`keybow.get_states()` will return a list of the state of all of the keys, in
|
||||
order, with a state of `0` being not pressed, and `1` being pressed. You can
|
||||
then loop through that list to do whatever you like.
|
||||
|
||||
`keybow.get_pressed()` will return a list of the key numbers (indices in the
|
||||
list of keys) that are currently pressed. If you only care about key presses,
|
||||
then this is an efficient way to do things, especially since you have all the
|
||||
key numbers in a list.
|
||||
|
||||
`keybow.any_pressed()` returns a Boolean (`True`/`False`) that tells you whether
|
||||
any keys are currently being pressed. Handy if you want to attach a behaviour to
|
||||
all of the keys, which this is effectively a proxy for.
|
||||
|
||||
`keybow.none_pressed()` is similar to `.any_pressed()`, in that it returns a
|
||||
Boolean also, but... you guessed it, it returns `True` if no keys are being
|
||||
pressed, and `False` if any keys are pressed.
|
||||
|
||||
### Key class methods for detecting key presses
|
||||
|
||||
If we want to check whether key 0 is pressed, we can do so as follows:
|
||||
|
||||
```
|
||||
keys = keybow.keys()
|
||||
|
||||
if keys[0].pressed:
|
||||
# Do something!
|
||||
```
|
||||
|
||||
The `.pressed` attribute returns a Boolean that is `True` if the key is pressed
|
||||
and `False` if it is not pressed.
|
||||
|
||||
`key.state` is another way to check the state of a key. It will equal `1` if the
|
||||
key is pressed and `0` if it is not pressed.
|
||||
|
||||
If you want to attach an additional behaviour to your key, you can use
|
||||
`key.held` to check if a key is being key rather than being pressed and released
|
||||
quickly. It returns `True` if the key is held and `False` if it is not.
|
||||
|
||||
The default hold time (after which `key.held` is `True`) for all of the keys is
|
||||
0.75 seconds, but you can change `key.hold_time` to adjust this to your liking,
|
||||
on a per key basis.
|
||||
|
||||
This means that we could extend the example above to be:
|
||||
|
||||
```
|
||||
keys = keybow.keys()
|
||||
|
||||
if keys[0].pressed:
|
||||
# Do something!
|
||||
|
||||
if keys[0].held:
|
||||
# Do something else!
|
||||
```
|
||||
|
||||
## LEDs!
|
||||
|
||||
LEDs can be set either globally for all keys, using the `Keybow` class instance,
|
||||
or on a per-key basis, either through the `Keybow` class, or using a `Key` class
|
||||
instance.
|
||||
|
||||
To set all of the keys to the same colour, you can use the `.set_all()` method
|
||||
of the `Keybow` class, to which you pass three 0-255 integers for red, green,
|
||||
and blue. For example, to set all of the keys to magenta:
|
||||
|
||||
```
|
||||
keybow.set_all(255, 0, 255)
|
||||
```
|
||||
|
||||
To set an individal key through your `Keybow` class instance, you can do as
|
||||
follows, to set key 0 to white:
|
||||
|
||||
```
|
||||
keybow.set_led(0, 255, 255, 255)
|
||||
```
|
||||
|
||||
To set the colour on the key itself, you could do as follows, again to set key
|
||||
0 to white:
|
||||
|
||||
```
|
||||
keybow.keys[0].set_led(255, 255, 255)
|
||||
```
|
||||
|
||||
A key retains its RGB value, even if it is turned off, so once a key has its
|
||||
colour set with `key.rgb = (255, 0, 0)` for example, you can turn it off using
|
||||
`key.led_off()` or even `key.set_led(0, 0, 0)` and then when you turn it back on
|
||||
with `key.led_on()`, then it will still be red when it comes back on.
|
||||
|
||||
As a convenience, and to avoid having to check `key.lit`, there is a
|
||||
`key.toggle_led()` method that will toggle the current state of the key's LED
|
||||
(on to off, and _vice versa_).
|
||||
|
||||
There's a handy `hsv_to_rgb()` function that can be imported from the
|
||||
`keybow2040` module to convert an HSV colour (a tuple of floats from 0.0 to 1.0)
|
||||
to an RGB colour (a tuple of integers from 0 to 255), as follows:
|
||||
|
||||
```
|
||||
from keybow2040 import hsv_to_rgb
|
||||
|
||||
h = 0.5 # Hue
|
||||
s = 1.0 # Saturation
|
||||
v = 1.0 # Value
|
||||
|
||||
r, g, b = hsv_to_rgb(h, s, v)
|
||||
```
|
||||
|
||||
## Attaching functions to keys with decorators
|
||||
|
||||
There are three decorators that can be attached to functions to link that
|
||||
function to, i) a key press, ii) a key release, or iii) a key hold.
|
||||
|
||||
Here's an example of how you could attach a decorator to a function that lights
|
||||
up that key yellow when it is pressed, turns all of the LEDs on when held, and
|
||||
turns them all off when released:
|
||||
|
||||
```
|
||||
import board
|
||||
from keybow2040 import Keybow2040
|
||||
|
||||
i2c = board.I2C()
|
||||
keybow = Keybow2040(i2c)
|
||||
keys = keybow.keys
|
||||
|
||||
key = keys[0]
|
||||
rgb = (255, 255, 0)
|
||||
key.rgb = rgb
|
||||
|
||||
@keybow.on_press(key)
|
||||
def press_handler(key):
|
||||
key.led_on()
|
||||
|
||||
@keybow.on_release(key)
|
||||
def release_handler(key):
|
||||
keybow.set_all(0, 0, 0)
|
||||
|
||||
@keybow.on_hold(key)
|
||||
def hold_handler(key):
|
||||
keybow.set_all(*rgb)
|
||||
|
||||
while True:
|
||||
keybow.update()
|
||||
```
|
|
@ -7,39 +7,11 @@
|
|||
|
||||
# Drop the keybow2040.py file into your `lib` folder on your `CIRCUITPY` drive.
|
||||
|
||||
import time
|
||||
import board
|
||||
import random
|
||||
from keybow2040 import Keybow2040, number_to_xy
|
||||
from keybow2040 import Keybow2040, number_to_xy, hsv_to_rgb
|
||||
|
||||
MODIFIER_KEY = 0
|
||||
|
||||
def hsv_to_rgb(h, s, v):
|
||||
# Convert an HSV (0.0-1.0) colour to RGB (0-255)
|
||||
if s == 0.0:
|
||||
rgb = [v, v, v]
|
||||
|
||||
i = int(h * 6.0)
|
||||
|
||||
f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
|
||||
|
||||
if i == 0:
|
||||
rgb = [v, t, p]
|
||||
if i == 1:
|
||||
rgb = [q, v, p]
|
||||
if i == 2:
|
||||
rgb = [p, v, t]
|
||||
if i == 3:
|
||||
rgb = [p, q, v]
|
||||
if i == 4:
|
||||
rgb = [t, p, v]
|
||||
if i == 5:
|
||||
rgb = [v, p, q]
|
||||
|
||||
rgb = [int(c * 255) for c in rgb]
|
||||
|
||||
return rgb
|
||||
|
||||
# Set up Keybow
|
||||
i2c = board.I2C()
|
||||
keybow = Keybow2040(i2c)
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
# Drop the keybow2040.py file into your `lib` folder on your `CIRCUITPY` drive.
|
||||
|
||||
import time
|
||||
import board
|
||||
import random
|
||||
from keybow2040 import Keybow2040
|
||||
|
||||
# Set up Keybow
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
import time
|
||||
import board
|
||||
import random
|
||||
from keybow2040 import Keybow2040
|
||||
|
||||
import usb_midi
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
import time
|
||||
import board
|
||||
import random
|
||||
from keybow2040 import Keybow2040
|
||||
|
||||
import usb_midi
|
||||
|
|
|
@ -6,37 +6,9 @@
|
|||
|
||||
# Drop the keybow2040.py file into your `lib` folder on your `CIRCUITPY` drive.
|
||||
|
||||
import time
|
||||
import math
|
||||
import board
|
||||
from keybow2040 import Keybow2040, number_to_xy
|
||||
|
||||
|
||||
def hsv_to_rgb(h, s, v):
|
||||
# Convert an HSV (0.0-1.0) colour to RGB (0-255)
|
||||
if s == 0.0:
|
||||
rgb = [v, v, v]
|
||||
|
||||
i = int(h * 6.0)
|
||||
|
||||
f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
|
||||
|
||||
if i == 0:
|
||||
rgb = [v, t, p]
|
||||
if i == 1:
|
||||
rgb = [q, v, p]
|
||||
if i == 2:
|
||||
rgb = [p, v, t]
|
||||
if i == 3:
|
||||
rgb = [p, q, v]
|
||||
if i == 4:
|
||||
rgb = [t, p, v]
|
||||
if i == 5:
|
||||
rgb = [v, p, q]
|
||||
|
||||
rgb = (int(c * 255) for c in rgb)
|
||||
|
||||
return rgb
|
||||
from keybow2040 import Keybow2040, number_to_xy, hsv_to_rgb
|
||||
|
||||
# Set up Keybow
|
||||
i2c = board.I2C()
|
||||
|
|
|
@ -420,4 +420,30 @@ def number_to_xy(number):
|
|||
x = number % 4
|
||||
y = number // 4
|
||||
|
||||
return (x, y)
|
||||
return (x, y)
|
||||
|
||||
def hsv_to_rgb(h, s, v):
|
||||
# Convert an HSV (0.0-1.0) colour to RGB (0-255)
|
||||
if s == 0.0:
|
||||
rgb = [v, v, v]
|
||||
|
||||
i = int(h * 6.0)
|
||||
|
||||
f = (h*6.)-i; p,q,t = v*(1.-s), v*(1.-s*f), v*(1.-s*(1.-f)); i%=6
|
||||
|
||||
if i == 0:
|
||||
rgb = [v, t, p]
|
||||
if i == 1:
|
||||
rgb = [q, v, p]
|
||||
if i == 2:
|
||||
rgb = [p, v, t]
|
||||
if i == 3:
|
||||
rgb = [p, q, v]
|
||||
if i == 4:
|
||||
rgb = [t, p, v]
|
||||
if i == 5:
|
||||
rgb = [v, p, q]
|
||||
|
||||
rgb = (int(c * 255) for c in rgb)
|
||||
|
||||
return rgb
|
Loading…
Reference in a new issue