Skip to content

Commit

Permalink
Add continuous integration (#11)
Browse files Browse the repository at this point in the history
* Standardize code style

* Add continuous integration workflow
  • Loading branch information
TillFleisch authored Jan 30, 2024
1 parent 1675d24 commit b088bbd
Show file tree
Hide file tree
Showing 15 changed files with 797 additions and 502 deletions.
10 changes: 10 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
UseTab: Never
IndentWidth: 4
NamespaceIndentation: All
AccessModifierOffset: -4
BreakBeforeBraces: Allman
AllowShortIfStatementsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
IndentCaseLabels: false
SortIncludes: false
ColumnLimit: 0
129 changes: 129 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: CI

# yamllint disable-line rule:truthy
on:
workflow_dispatch:
inputs:
esphome_version:
description: "ESPHome PyPi Package version to use"
required: false
type: string
push:
branches: [main, dev]

pull_request:
merge_group:

permissions:
contents: read

concurrency:
# yamllint disable-line rule:line-length
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
ci:
name: ${{ matrix.name }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
include:
- id: test
file: tests/full.yaml
name: Test tests/full.yaml
pio_cache_key: full
- id: test
file: tests/base.yaml
name: Test tests/base.yaml
pio_cache_key: base
- id: clang-format
name: Run clang-format
- id: yamllint
name: Run yamllint
- id: black-format
name: Run black-format
- id: isort
name: Run isort

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
id: python
with:
python-version: "3.9"

- name: Cache virtualenv
uses: actions/cache@v3
with:
path: .venv
# yamllint disable-line rule:line-length
key: venv-${{ steps.python.outputs.python-version }}
restore-keys: |
venv-${{ steps.python.outputs.python-version }}
- name: Set up virtualenv
# yamllint disable rule:line-length
run: |
python -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt
if [ ${{ github.event.inputs.esphome_version != '' }} == true ]; then pip install ESPHome==${{ github.event.inputs.esphome_version }}; else pip install -U ESPHome; fi
echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH
echo "VIRTUAL_ENV=$GITHUB_WORKSPACE/.venv" >> $GITHUB_ENV
# yamllint enable rule:line-length

# Use per check platformio cache because checks use different parts
- name: Cache platformio
uses: actions/cache@v3
with:
path: ~/.platformio
# yamllint disable-line rule:line-length
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
if: matrix.id == 'test'

- run: esphome compile ${{ matrix.file }}
if: matrix.id == 'test'
env:
# Also cache libdeps, store them in a ~/.platformio subfolder
PLATFORMIO_LIBDEPS_DIR: ~/.platformio/libdeps

- name: Run clang-format
uses: jidicula/[email protected]
with:
clang-format-version: "13"
check-path: "components"
if: matrix.id == 'clang-format'

- name: Run yamllint
if: matrix.id == 'yamllint'
uses: frenck/[email protected]

- name: Run black-format
if: matrix.id == 'black-format'
uses: psf/black@stable
with:
options: "--check --verbose"
version: "~= 24.1"

- name: Run isort
if: matrix.id == 'isort'
uses: isort/isort-action@master
with:
requirementsFiles: "requirements.txt"

ci-status:
name: CI Status
runs-on: ubuntu-latest
needs: [ci]
if: always()
steps:
- name: Successful deploy
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing deploy
if: ${{ contains(needs.*.result, 'failure') }}
run: exit 1
17 changes: 17 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.1.0
hooks:
- id: black
language_version: python3.11

- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
name: isort (python)

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v17.0.6
hooks:
- id: clang-format
2 changes: 2 additions & 0 deletions .yamllint
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore: |
venv/
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# ESP32-HUB75-MatrixPanel-I2S-DMA ESPHome wrapper
# ESP32-HUB75-MatrixPanel-I2S-DMA ESPHome wrapper [![CI](https://github.com/TillFleisch/ESPHome-HUB75-MatrixDisplayWrapper/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/TillFleisch/ESPHome-HUB75-MatrixDisplayWrapper/actions/workflows/ci.yaml)

This custom component is a [ESPHome](https://esphome.io/) wrapper for the [ESP32-HUB75-MatrixPanel-DMA](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA#master) library. For more details regarding wiring, choosing the correct parameters and more complex configurations please refer to the above linked documentation.
This ESPHome component wraps the library into an ESPHome [display component](https://esphome.io/components/display/index.html) which can be used to show text, sensor values and images.
Expand All @@ -7,9 +7,10 @@ This wrapper currently only supports horizontally chained panels.
[Vertically aligned panels and VirtualDisplays](https://github.com/mrfaptastic/ESP32-HUB75-MatrixPanel-DMA/tree/master/examples/ChainedPanels) are currently not supported.

### My Pixel Art display
- 32x64 Pixel P5 Panel
- [CAD Files and more print info](https://www.printables.com/model/600039-pixel-art-matrix-display)
- retrofit ambient light sensor for adaptive brightness control

- 32x64 Pixel P5 Panel
- [CAD Files and more print info](https://www.printables.com/model/600039-pixel-art-matrix-display)
- retrofit ambient light sensor for adaptive brightness control

![Pixel Matrix Display](images/pixel_matrix_display_front.gif)
Backside|Raw panel
Expand Down
163 changes: 86 additions & 77 deletions components/matrix_display/display.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import display
from esphome import pins
from esphome.const import (CONF_ID, CONF_LAMBDA, CONF_HEIGHT,
CONF_WIDTH, CONF_UPDATE_INTERVAL)

AUTO_LOAD = ['switch', 'matrix_display_switch',
'number', 'matrix_display_brightness']
MATRIX_ID = 'matrix_id'
CHAIN_LENGTH = 'chain_length'
BRIGHTNESS = 'brightness'

R1_PIN = 'R1_pin'
G1_PIN = 'G1_pin'
B1_PIN = 'B1_pin'
R2_PIN = 'R2_pin'
G2_PIN = 'G2_pin'
B2_PIN = 'B2_pin'

A_PIN = 'A_pin'
B_PIN = 'B_pin'
C_PIN = 'C_pin'
D_PIN = 'D_pin'
E_PIN = 'E_pin'

LAT_PIN = 'LAT_pin'
OE_PIN = 'OE_pin'
CLK_PIN = 'CLK_pin'

DRIVER = 'driver'
I2SSPEED = 'i2sspeed'
LATCH_BLANKING = 'latch_blanking'
CLOCK_PHASE = 'clock_phase'
from esphome.components import display
from esphome.const import (
CONF_HEIGHT,
CONF_ID,
CONF_LAMBDA,
CONF_UPDATE_INTERVAL,
CONF_WIDTH,
)

AUTO_LOAD = ["switch", "matrix_display_switch", "number", "matrix_display_brightness"]
MATRIX_ID = "matrix_id"
CHAIN_LENGTH = "chain_length"
BRIGHTNESS = "brightness"

R1_PIN = "R1_pin"
G1_PIN = "G1_pin"
B1_PIN = "B1_pin"
R2_PIN = "R2_pin"
G2_PIN = "G2_pin"
B2_PIN = "B2_pin"

A_PIN = "A_pin"
B_PIN = "B_pin"
C_PIN = "C_pin"
D_PIN = "D_pin"
E_PIN = "E_pin"

LAT_PIN = "LAT_pin"
OE_PIN = "OE_pin"
CLK_PIN = "CLK_pin"

DRIVER = "driver"
I2SSPEED = "i2sspeed"
LATCH_BLANKING = "latch_blanking"
CLOCK_PHASE = "clock_phase"

matrix_display_ns = cg.esphome_ns.namespace("matrix_display")
MatrixDisplay = matrix_display_ns.class_(
"MatrixDisplay", cg.PollingComponent, display.DisplayBuffer)
"MatrixDisplay", cg.PollingComponent, display.DisplayBuffer
)

shift_driver = cg.global_ns.namespace("HUB75_I2S_CFG").enum("shift_driver")
DRIVERS = {
Expand All @@ -44,58 +49,46 @@
"FM6126A": shift_driver.FM6126A,
"ICN2038S": shift_driver.ICN2038S,
"MBI5124": shift_driver.MBI5124,
"SM5266": shift_driver.SM5266P
"SM5266": shift_driver.SM5266P,
}

clk_speed = cg.global_ns.namespace("HUB75_I2S_CFG").enum("clk_speed")
CLOCK_SPEEDS = {
"HZ_8M": clk_speed.HZ_8M,
"HZ_10M": clk_speed.HZ_10M,
"HZ_15M": clk_speed.HZ_15M,
"HZ_20M": clk_speed.HZ_20M
"HZ_20M": clk_speed.HZ_20M,
}

CONFIG_SCHEMA = (
display.FULL_DISPLAY_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(MatrixDisplay),
cv.Required(CONF_WIDTH): cv.positive_int,
cv.Required(CONF_HEIGHT): cv.positive_int,
cv.Optional(CHAIN_LENGTH, default=1): cv.positive_int,
cv.Optional(BRIGHTNESS, default=128): cv.int_range(min=0, max=255),
cv.Optional(
CONF_UPDATE_INTERVAL, default="16ms"
): cv.positive_time_period_milliseconds,

cv.Optional(R1_PIN, default=25): pins.gpio_output_pin_schema,
cv.Optional(G1_PIN, default=26): pins.gpio_output_pin_schema,
cv.Optional(B1_PIN, default=27): pins.gpio_output_pin_schema,
cv.Optional(R2_PIN, default=14): pins.gpio_output_pin_schema,
cv.Optional(G2_PIN, default=12): pins.gpio_output_pin_schema,
cv.Optional(B2_PIN, default=13): pins.gpio_output_pin_schema,

cv.Optional(A_PIN, default=23): pins.gpio_output_pin_schema,
cv.Optional(B_PIN, default=19): pins.gpio_output_pin_schema,
cv.Optional(C_PIN, default=5): pins.gpio_output_pin_schema,
cv.Optional(D_PIN, default=17): pins.gpio_output_pin_schema,
cv.Optional(E_PIN): pins.gpio_output_pin_schema,

cv.Optional(LAT_PIN, default=4): pins.gpio_output_pin_schema,
cv.Optional(OE_PIN, default=15): pins.gpio_output_pin_schema,
cv.Optional(CLK_PIN, default=16): pins.gpio_output_pin_schema,

cv.Optional(DRIVER): cv.enum(
DRIVERS, upper=True, space="_"
),

cv.Optional(I2SSPEED): cv.enum(
CLOCK_SPEEDS, upper=True, space="_"
),

cv.Optional(LATCH_BLANKING): cv.positive_int,
cv.Optional(CLOCK_PHASE): cv.boolean,
}
)
CONFIG_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(MatrixDisplay),
cv.Required(CONF_WIDTH): cv.positive_int,
cv.Required(CONF_HEIGHT): cv.positive_int,
cv.Optional(CHAIN_LENGTH, default=1): cv.positive_int,
cv.Optional(BRIGHTNESS, default=128): cv.int_range(min=0, max=255),
cv.Optional(
CONF_UPDATE_INTERVAL, default="16ms"
): cv.positive_time_period_milliseconds,
cv.Optional(R1_PIN, default=25): pins.gpio_output_pin_schema,
cv.Optional(G1_PIN, default=26): pins.gpio_output_pin_schema,
cv.Optional(B1_PIN, default=27): pins.gpio_output_pin_schema,
cv.Optional(R2_PIN, default=14): pins.gpio_output_pin_schema,
cv.Optional(G2_PIN, default=12): pins.gpio_output_pin_schema,
cv.Optional(B2_PIN, default=13): pins.gpio_output_pin_schema,
cv.Optional(A_PIN, default=23): pins.gpio_output_pin_schema,
cv.Optional(B_PIN, default=19): pins.gpio_output_pin_schema,
cv.Optional(C_PIN, default=5): pins.gpio_output_pin_schema,
cv.Optional(D_PIN, default=17): pins.gpio_output_pin_schema,
cv.Optional(E_PIN): pins.gpio_output_pin_schema,
cv.Optional(LAT_PIN, default=4): pins.gpio_output_pin_schema,
cv.Optional(OE_PIN, default=15): pins.gpio_output_pin_schema,
cv.Optional(CLK_PIN, default=16): pins.gpio_output_pin_schema,
cv.Optional(DRIVER): cv.enum(DRIVERS, upper=True, space="_"),
cv.Optional(I2SSPEED): cv.enum(CLOCK_SPEEDS, upper=True, space="_"),
cv.Optional(LATCH_BLANKING): cv.positive_int,
cv.Optional(CLOCK_PHASE): cv.boolean,
}
)


Expand Down Expand Up @@ -127,8 +120,24 @@ async def to_code(config):
else:
E_pin = 0

cg.add(var.set_pins(R1_pin, G1_pin, B1_pin, R2_pin, G2_pin, B2_pin,
A_pin, B_pin, C_pin, D_pin, E_pin, LAT_pin, OE_pin, CLK_pin))
cg.add(
var.set_pins(
R1_pin,
G1_pin,
B1_pin,
R2_pin,
G2_pin,
B2_pin,
A_pin,
B_pin,
C_pin,
D_pin,
E_pin,
LAT_pin,
OE_pin,
CLK_pin,
)
)

if DRIVER in config:
cg.add(var.set_driver(config[DRIVER]))
Expand Down
Loading

0 comments on commit b088bbd

Please sign in to comment.