Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added oleds #397

Merged
merged 10 commits into from
May 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions docs/peg_oled_display.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Peg Oled Display
To use this you need to make some changes to your kb.py as well as you main.py I will break it into two sections for you.

### What you can and cant do

#### Can do
* Display images
* Display text
* Set images or text to react to your layer


#### Cant do yet / on the way
* React to battery percentage
* React to WPM

## Required Libs
You need these frozen into your circuitpython or in a lib folder at the root of your drive.
* [Adafruit_CircuitPython_DisplayIO_SSD1306](https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306)
* [Adafruit_CircuitPython_Display_Text](https://github.com/adafruit/Adafruit_CircuitPython_Display_Text)
* [Download .mpy versions from here](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20220415/adafruit-circuitpython-bundle-7.x-mpy-20220415.zip)


## kb.py
Your chosen board may already have these changes done If not you will need to add them.

You need to add SCL and SDA to your keyboard. The pins the oled are connected to on your controller may not be called "SCL"and "SDA" they could be "GP21" and "GP13" for example. The best way to find out what they are is look at the boards pinout.
```python
SCL=board.SCL
SDA=board.SDA
```


## Main.py
These are the changes that need to be made / added to your main.py
### Config
No mater how you are going to use the oled you need this part
```python
from kmk.extensions.peg_oled_Display import Oled,OledDisplayMode,OledReactionType,OledData
keyboard = KMKKeyboard()
# ... Other oled code
keyboard.extensions.append(oled_ext)

```
### Photos
So the config for photos is quite simple. Getting the photos maybe not so much. I will explain.

Oled takes 2-3 arguments

1. OledData
* OledData can take image **or** corner_one, corner_two, corner_three and corner_four
* Every item in OledData has 2 fields
* 0: This is the reaction type right now it can be OledReactionType.LAYER or OledReactionType.STATIC
* 1: An array of the items you want to show for the reaction. In this example 4 images to switch on the 4 layers
2. To display called as "toDisplay=OledDisplayMode.TXT" this takes a OledDisplayMode TXT or IMG.
* This tells the extension to load images or text.
3. Flip called as "flip= Boolean" this will simply flip your display.


```python
oled_ext = Oled(OledData(image={0:OledReactionType.LAYER,1:["1.bmp","2.bmp","1.bmp","2.bmp"]}),toDisplay=OledDisplayMode.IMG,flip=False)
```
In this code example we are saying to react to the layer change and load a image filed named "1.bmp" for layer one and "2.bmp" for layer two and so on.

### Preparing the images
So you need to include all the images in your circuitpython drive in the root along side main.py

Your images need to be 128x32px and should only be black and white. After you have made your image you can save as a "monochrome bmp" this will save you a lot of space.

### Text
Ok now we get into something that looks a lot more complicated but we will get though it.

Almost everything is the same We swap toDisplay to TXT and there are more items in the OledData Class, lets get into that.

1. Top left
2. Top right
3. Bottom left
4. Bottom right

After that is the same as the previous example. Each one has two fields 0:the reaction type. 1:what to display

In this code we will always display the word "layer" in the top left corner of the screen then the other 3 corners will swap depending on the layer.



```python
oled_ext = Oled(
OledData(
corner_one={0:OledReactionType.STATIC,1:["layer"]},
corner_two={0:OledReactionType.LAYER,1:["1","2","3","4"]},
corner_three={0:OledReactionType.LAYER,1:["base","raise","lower","adjust"]},
corner_four={0:OledReactionType.LAYER,1:["qwerty","nums","shifted","leds"]}
),
toDisplay=OledDisplayMode.TXT,flip=False)
```

### Note
Your oled data can be a variable as shown below with images.

```python
oled_display_data=OledData(image={0:OledReactionType.LAYER,1:["1.bmp","2.bmp","1.bmp","2.bmp"]})

oled_ext = Oled(oled_display_data,toDisplay=OledDisplayMode.IMG,flip=False)
```

### Text example


![example](https://boardsource.imgix.net/a4f155e0-bc83-11ec-a4ed-79d542ba3127.gif)

161 changes: 161 additions & 0 deletions kmk/extensions/peg_oled_display.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import busio
import gc

import adafruit_displayio_ssd1306
import displayio
import terminalio
from adafruit_display_text import label

from kmk.extensions import Extension


class OledDisplayMode:
TXT = 0
IMG = 1


class OledReactionType:
STATIC = 0
LAYER = 1


class OledData:
def __init__(
self,
image=None,
corner_one=None,
corner_two=None,
corner_three=None,
corner_four=None,
):
if image:
self.data = [image]
elif corner_one and corner_two and corner_three and corner_four:
self.data = [corner_one, corner_two, corner_three, corner_four]


class Oled(Extension):
def __init__(
self,
views,
toDisplay=OledDisplayMode.TXT,
oWidth=128,
oHeight=32,
flip: bool = False,
):
displayio.release_displays()
self.rotation = 180 if flip else 0
self._views = views.data
self._toDisplay = toDisplay
self._width = oWidth
self._height = oHeight
self._prevLayers = 0
gc.collect()

def returnCurrectRenderText(self, layer, singleView):
# for now we only have static things and react to layers. But when we react to battery % and wpm we can handle the logic here
if singleView[0] == OledReactionType.STATIC:
return singleView[1][0]
if singleView[0] == OledReactionType.LAYER:
return singleView[1][layer]

def renderOledTextLayer(self, layer):
splash = displayio.Group()
self._display.show(splash)
splash.append(
label.Label(
terminalio.FONT,
text=self.returnCurrectRenderText(layer, self._views[0]),
color=0xFFFFFF,
x=0,
y=10,
)
)
splash.append(
label.Label(
terminalio.FONT,
text=self.returnCurrectRenderText(layer, self._views[1]),
color=0xFFFFFF,
x=64,
y=10,
)
)
splash.append(
label.Label(
terminalio.FONT,
text=self.returnCurrectRenderText(layer, self._views[2]),
color=0xFFFFFF,
x=0,
y=25,
)
)
splash.append(
label.Label(
terminalio.FONT,
text=self.returnCurrectRenderText(layer, self._views[3]),
color=0xFFFFFF,
x=64,
y=25,
)
)
gc.collect()

def renderOledImgLayer(self, layer):
splash = displayio.Group()
self._display.show(splash)
odb = displayio.OnDiskBitmap(
'/' + self.returnCurrectRenderText(layer, self._views[0])
)
image = displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
splash.append(image)
gc.collect()

def updateOLED(self, sandbox):
if self._toDisplay == OledDisplayMode.TXT:
self.renderOledTextLayer(sandbox.active_layers[0])
if self._toDisplay == OledDisplayMode.IMG:
self.renderOledImgLayer(sandbox.active_layers[0])
gc.collect()

def on_runtime_enable(self, sandbox):
return

def on_runtime_disable(self, sandbox):
return

def during_bootup(self, board):
displayio.release_displays()
i2c = busio.I2C(board.SCL, board.SDA)
self._display = adafruit_displayio_ssd1306.SSD1306(
displayio.I2CDisplay(i2c, device_address=0x3C),
width=self._width,
height=self._height,
rotation=self.rotation,
)
if self._toDisplay == OledDisplayMode.TXT:
self.renderOledTextLayer(0)
if self._toDisplay == OledDisplayMode.IMG:
self.renderOledImgLayer(0)
return

def before_matrix_scan(self, sandbox):
if sandbox.active_layers[0] != self._prevLayers:
self._prevLayers = sandbox.active_layers[0]
self.updateOLED(sandbox)
return

def after_matrix_scan(self, sandbox):

return

def before_hid_send(self, sandbox):
return

def after_hid_send(self, sandbox):
return

def on_powersave_enable(self, sandbox):
return

def on_powersave_disable(self, sandbox):
return