mirror of
https://github.com/esphome/esphome.git
synced 2026-01-10 12:10:48 -07:00
[hub75] Bump esp-hub75 version to 0.2.2 (#12674)
This commit is contained in:
@@ -15,6 +15,7 @@ from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_OE_PIN,
|
||||
CONF_ROTATION,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
from esphome.core import ID
|
||||
@@ -134,6 +135,14 @@ CLOCK_SPEEDS = {
|
||||
"20MHZ": Hub75ClockSpeed.HZ_20M,
|
||||
}
|
||||
|
||||
Hub75Rotation = cg.global_ns.enum("Hub75Rotation", is_class=True)
|
||||
ROTATIONS = {
|
||||
0: Hub75Rotation.ROTATE_0,
|
||||
90: Hub75Rotation.ROTATE_90,
|
||||
180: Hub75Rotation.ROTATE_180,
|
||||
270: Hub75Rotation.ROTATE_270,
|
||||
}
|
||||
|
||||
HUB75Display = hub75_ns.class_("HUB75Display", cg.PollingComponent, display.Display)
|
||||
Hub75Config = cg.global_ns.struct("Hub75Config")
|
||||
Hub75Pins = cg.global_ns.struct("Hub75Pins")
|
||||
@@ -361,6 +370,8 @@ CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(HUB75Display),
|
||||
# Override rotation - store Hub75Rotation directly (driver handles rotation)
|
||||
cv.Optional(CONF_ROTATION): cv.enum(ROTATIONS, int=True),
|
||||
# Board preset (optional - provides default pin mappings)
|
||||
cv.Optional(CONF_BOARD): cv.one_of(*BOARDS.keys(), lower=True),
|
||||
# Panel dimensions
|
||||
@@ -378,7 +389,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
# Display configuration
|
||||
cv.Optional(CONF_DOUBLE_BUFFER): cv.boolean,
|
||||
cv.Optional(CONF_BRIGHTNESS): cv.int_range(min=0, max=255),
|
||||
cv.Optional(CONF_BIT_DEPTH): cv.int_range(min=6, max=12),
|
||||
cv.Optional(CONF_BIT_DEPTH): cv.int_range(min=4, max=12),
|
||||
cv.Optional(CONF_GAMMA_CORRECT): cv.enum(
|
||||
{"LINEAR": 0, "CIE1931": 1, "GAMMA_2_2": 2}, upper=True
|
||||
),
|
||||
@@ -490,10 +501,11 @@ def _build_config_struct(
|
||||
Fields must be added in declaration order (see hub75_types.h) to satisfy
|
||||
C++ designated initializer requirements. The order is:
|
||||
1. fields_before_pins (panel_width through layout)
|
||||
2. pins
|
||||
3. output_clock_speed
|
||||
4. min_refresh_rate
|
||||
5. fields_after_min_refresh (latch_blanking through brightness)
|
||||
2. rotation
|
||||
3. pins
|
||||
4. output_clock_speed
|
||||
5. min_refresh_rate
|
||||
6. fields_after_min_refresh (latch_blanking through brightness)
|
||||
"""
|
||||
fields_before_pins = [
|
||||
(CONF_PANEL_WIDTH, "panel_width"),
|
||||
@@ -516,6 +528,10 @@ def _build_config_struct(
|
||||
|
||||
_append_config_fields(config, fields_before_pins, config_fields)
|
||||
|
||||
# Rotation - config already contains Hub75Rotation enum from cv.enum
|
||||
if CONF_ROTATION in config:
|
||||
config_fields.append(("rotation", config[CONF_ROTATION]))
|
||||
|
||||
config_fields.append(("pins", pins_struct))
|
||||
|
||||
if CONF_CLOCK_SPEED in config:
|
||||
@@ -531,7 +547,7 @@ def _build_config_struct(
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
add_idf_component(
|
||||
name="esphome/esp-hub75",
|
||||
ref="0.1.7",
|
||||
ref="0.2.2",
|
||||
)
|
||||
|
||||
# Set compile-time configuration via defines
|
||||
@@ -570,6 +586,11 @@ async def to_code(config: ConfigType) -> None:
|
||||
pins_struct = _build_pins_struct(pin_expressions, e_pin_num)
|
||||
hub75_config = _build_config_struct(config, pins_struct, min_refresh)
|
||||
|
||||
# Rotation is handled by the hub75 driver (config_.rotation already set above).
|
||||
# Force rotation to 0 for ESPHome's Display base class to avoid double-rotation.
|
||||
if CONF_ROTATION in config:
|
||||
config[CONF_ROTATION] = 0
|
||||
|
||||
# Create display and register
|
||||
var = cg.new_Pvariable(config[CONF_ID], hub75_config)
|
||||
await display.register_display(var, config)
|
||||
|
||||
@@ -92,14 +92,25 @@ void HUB75Display::fill(Color color) {
|
||||
if (!this->enabled_) [[unlikely]]
|
||||
return;
|
||||
|
||||
// Special case: black (off) - use fast hardware clear
|
||||
if (!color.is_on()) {
|
||||
// Start with full display rect
|
||||
display::Rect fill_rect(0, 0, this->get_width_internal(), this->get_height_internal());
|
||||
|
||||
// Apply clipping using Rect::shrink() to intersect
|
||||
display::Rect clip = this->get_clipping();
|
||||
if (clip.is_set()) {
|
||||
fill_rect.shrink(clip);
|
||||
if (!fill_rect.is_set())
|
||||
return; // Completely clipped
|
||||
}
|
||||
|
||||
// Fast path: black filling entire display
|
||||
if (!color.is_on() && fill_rect.x == 0 && fill_rect.y == 0 && fill_rect.w == this->get_width_internal() &&
|
||||
fill_rect.h == this->get_height_internal()) {
|
||||
driver_->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// For non-black colors, fall back to base class (pixel-by-pixel)
|
||||
Display::fill(color);
|
||||
driver_->fill(fill_rect.x, fill_rect.y, fill_rect.w, fill_rect.h, color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
void HOT HUB75Display::draw_pixel_at(int x, int y, Color color) {
|
||||
|
||||
@@ -39,8 +39,8 @@ class HUB75Display : public display::Display {
|
||||
|
||||
protected:
|
||||
// Display internal methods
|
||||
int get_width_internal() override { return config_.panel_width * config_.layout_cols; }
|
||||
int get_height_internal() override { return config_.panel_height * config_.layout_rows; }
|
||||
int get_width_internal() override { return this->driver_ != nullptr ? this->driver_->get_width() : 0; }
|
||||
int get_height_internal() override { return this->driver_ != nullptr ? this->driver_->get_height() : 0; }
|
||||
|
||||
// Member variables
|
||||
Hub75Driver *driver_{nullptr};
|
||||
|
||||
@@ -28,6 +28,6 @@ dependencies:
|
||||
rules:
|
||||
- if: "target in [esp32s2, esp32s3, esp32p4]"
|
||||
esphome/esp-hub75:
|
||||
version: 0.1.7
|
||||
version: 0.2.2
|
||||
rules:
|
||||
- if: "target in [esp32, esp32s2, esp32s3, esp32p4]"
|
||||
|
||||
39
tests/components/hub75/test.esp32-s3-idf-rotate.yaml
Normal file
39
tests/components/hub75/test.esp32-s3-idf-rotate.yaml
Normal file
@@ -0,0 +1,39 @@
|
||||
display:
|
||||
- platform: hub75
|
||||
id: my_hub75
|
||||
board: apollo-automation-rev6
|
||||
panel_width: 64
|
||||
panel_height: 64
|
||||
layout_rows: 1
|
||||
layout_cols: 2
|
||||
rotation: 90
|
||||
bit_depth: 4
|
||||
double_buffer: true
|
||||
auto_clear_enabled: true
|
||||
update_interval: 16ms
|
||||
latch_blanking: 1
|
||||
clock_speed: 20MHz
|
||||
lambda: |-
|
||||
// Test clipping: 8 columns x 4 rows of 16x16 colored squares
|
||||
Color colors[32] = {
|
||||
Color(255, 0, 0), Color(0, 255, 0), Color(0, 0, 255), Color(255, 255, 0),
|
||||
Color(255, 0, 255), Color(0, 255, 255), Color(255, 128, 0), Color(128, 0, 255),
|
||||
Color(0, 128, 255), Color(255, 0, 128), Color(128, 255, 0), Color(0, 255, 128),
|
||||
Color(255, 128, 128), Color(128, 255, 128), Color(128, 128, 255), Color(255, 255, 128),
|
||||
Color(255, 128, 255), Color(128, 255, 255), Color(192, 64, 0), Color(64, 192, 0),
|
||||
Color(0, 64, 192), Color(192, 0, 64), Color(64, 0, 192), Color(0, 192, 64),
|
||||
Color(128, 64, 64), Color(64, 128, 64), Color(64, 64, 128), Color(128, 128, 64),
|
||||
Color(128, 64, 128), Color(64, 128, 128), Color(255, 255, 255), Color(128, 128, 128)
|
||||
};
|
||||
int idx = 0;
|
||||
for (int row = 0; row < 4; row++) {
|
||||
for (int col = 0; col < 8; col++) {
|
||||
// Clipping mode: clip to square bounds, then fill "entire screen"
|
||||
it.start_clipping(col * 16, row * 16, (col + 1) * 16, (row + 1) * 16);
|
||||
it.fill(colors[idx]);
|
||||
it.end_clipping();
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
<<: !include common.yaml
|
||||
Reference in New Issue
Block a user