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

Improvements to OLED and RGB support #548

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

janlindblom
Copy link
Contributor

This pull requests adds a new OLED module that is not constrained by the Peg client which only supports four corners and does not play well with displays any other size than 128x32 at the moment.
The PR also contains some performance improvements to the peg_oled_display and peg_rgb_matrix extensions, primarily by supporting variable brightness for RGB LEDs and for the OLED screens.
This code has been tested on a Kyria v1.4 running Adafruit KB2040 controllers and "standard Kyria" 128x64 OLEDs.

@janlindblom janlindblom force-pushed the janlindblom_rgb_and_underglow_improvements branch from 85c5114 to 5331d2c Compare August 3, 2022 23:08
@kdb424 kdb424 requested a review from daysgobye August 4, 2022 04:04
@daysgobye
Copy link
Collaborator

I gave it a quick look over so far super nice improvements! And thank you so much. I am going to test it on a corne and microdox. I also want to give a good read over your oled code and see if we can merge them. I think it would be awesome to have one oled module thats super awesome. But I understand that it may be too much to ask.

side note:

  • I didnt run the test but I think the formatting is messed up did you run make fix-isort fix-formatting?
  • I am in no place to talk but if we are going to have 2 oled modules then we should have docs. Of course if we can find a way to combine them then nbd we just update the peg oled docs.
  • if you want to talk to me about combining them we can move this to chats in discord I am very easy to find. Cole|boardsouce.xyz

@janlindblom
Copy link
Contributor Author

Thanks @daysgobye ! I'll hop on discord and we can chat further, I'm also rarely in a good spot to have a "linear chat" since I've got a chronic health issue and sometimes dissappears into hospital for a couple of days but I'm more than happy to have a discussion on merging the OLED extensions.

This one came from the fact that I wanted to run Peg with a Kyria and 128x64 px displays, something that was tricky with the corner approach in Peg. I like that approach, don't get me wrong, It's probably pretty easy to wrap your head around without getting into the docs. But I wanted to reach all the pixels on the display so I started tinkering with a somewhat different approach as you can see from my code.

I'd love to see the (small) performance fixes I did reviewed and maybe merged, they're there to reduce flickering and flashing so make the whole experience feel smoother basically - should I make a separate PR with just these and we can park this PR and have a discussion about the oled code separately?

In retrospect, I should have made these changes into separate PR's from the start.

@janlindblom
Copy link
Contributor Author

Alright, @daysgobye I'm cleaning this up a bit - will make one PR with the performance improvements for the Peg oled extension and another for the rgb extension and leaving the "new" oled extension in this PR until we've had a chance to chat about it!

@janlindblom janlindblom marked this pull request as draft August 5, 2022 11:02
Copy link
Collaborator

@daysgobye daysgobye left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey sorry for my super delay in this. I want to get bigger oleds into peg asap I have just been busy with other things sadly.

I have looked over your changes to the peg code and I like what I see all things that should have been there.

looking over your oled extention I like it, it follows the peg extension. If it was up to me we merge it so that people can use it then remove it when we get the two oled extensions merged. I think it is better for the project to have one way we do oleds and it's awesome and covers every use case. I see that there is an argument that it should be " oled " and not "peg_oled". But that's just my 0.02$

@larryare
Copy link

This also works with SH1106:

import busio
import gc

from kmk.handlers.stock import passthrough as handler_passthrough
from kmk.keys import make_key
import adafruit_displayio_sh1106
import displayio
import terminalio
from adafruit_display_text import label
from kmk.extensions import Extension

DISPLAY_OFFSET = 4


class OledEntryType:
    TXT = 0
    IMG = 1


class OledData:
    def __init__(
        self,
        entries=None,
    ):
        if entries != None:
            self.data = entries

    @staticmethod
    def oled_text_entry(x=0, y=0, text="", layer=None):
        return {
            0: text,
            1: x,
            2: y,
            3: layer,
            4: OledEntryType.TXT,
        }

    @staticmethod
    def oled_image_entry(x=0, y=0, image="", layer=None):
        odb = displayio.OnDiskBitmap(image)
        return {
            0: odb,
            1: x,
            2: y,
            3: layer,
            4: OledEntryType.IMG,
        }

class Oled(Extension):
    def __init__(
        self,
        views,
        width=132,
        height=64,
        flip: bool = False,
        device_address=0x3C,
        brightness=0.8,
        brightness_step=0.1,
    ):
        displayio.release_displays()
        self.rotation = 180 if flip else 0
        self._views = views.data
        self._width = width
        self._height = height
        self._prevLayers = 0
        self._device_address = device_address
        self._brightness = brightness
        self._brightness_step = brightness_step
        gc.collect()

        make_key(
            names=("OLED_BRI",), on_press=self._oled_bri, on_release=handler_passthrough
        )
        make_key(
            names=("OLED_BRD",), on_press=self._oled_brd, on_release=handler_passthrough
        )

    def render_oled(self, layer):
        splash = displayio.Group()

        for view in self._views:
            if view[3] == layer or view[3] == None:
                if view[4] == OledEntryType.TXT:
                    splash.append(
                        label.Label(
                            terminalio.FONT,
                            text=view[0],
                            color=0xFFFFFF,
                            x=view[1] + DISPLAY_OFFSET,
                            y=view[2] + DISPLAY_OFFSET,
                        )
                    )
                elif view[4] == OledEntryType.IMG:
                    splash.append(
                        displayio.TileGrid(
                            view[0],
                            pixel_shader=view[0].pixel_shader,
                            x=view[1],
                            y=view[2] + DISPLAY_OFFSET,
                        )
                    )
        gc.collect()
        self._display.show(splash)

    def updateOLED(self, sandbox):
        self.render_oled(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_sh1106.SH1106(
            displayio.I2CDisplay(i2c, device_address=self._device_address),
            width=self._width,
            height=self._height,
            rotation=self.rotation,
            brightness=self._brightness,
        )
        self.render_oled(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):
        self._display.brightness = (
            self._display.brightness / 2 if self._display.brightness > 0.5 else 0.2
        )
        return

    def on_powersave_disable(self, sandbox):
        self._display.brightness = (
            self._brightness
        )  # Restore brightness to default or previous value
        return

    def _oled_bri(self, *args, **kwargs):
        self._display.brightness = (
            self._display.brightness + self._brightness_step
            if self._display.brightness + self._brightness_step <= 1.0
            else 1.0
        )
        self._brightness = self._display.brightness  # Save current brightness

    def _oled_brd(self, *args, **kwargs):
        self._display.brightness = (
            self._display.brightness - self._brightness_step
            if self._display.brightness - self._brightness_step >= 0.1
            else 0.1
        )
        self._brightness = self._display.brightness  # Save current brightness

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants