fix(web): drop the rows cap and document every display setting accurately

Rows: no upper limit in the form or the API. Still even and at least 8. The
current rgbmatrix library rejects more than 64 per panel, so a larger value
saves but the matrix won't start; the help tip, README, config reference and
troubleshooting section all say so, and nothing here needs changing if the
library lifts the limit.

limit_refresh_rate_hz: the form accepts 0 (the library's "no cap"), a stored
0 no longer renders and re-saves as 120, and the API rejects negatives.

pwm_dither_bits stays 0-2: the library rejects 3 and 4, so the old form's
0-4 only ever let users save a config the display couldn't start with.

Docs and help tips, checked against the pinned library and its README:
- panel_type and rp1_rio get README entries
- show_refresh_rate prints to stdout; it never drew on the panel
- dither bits raise the refresh rate; the tip said they lowered it
- scan_mode is about interlacing at low refresh, not wrong colours
- disable_hardware_pulsing: hardware pulsing needs OE on GPIO 18 and the
  onboard sound driver off; software timing makes rows flash brighter
- gpio_slowdown guidance agrees between the README and the UI
- all 22 multiplexing values listed; every numeric setting states its range
- troubleshooting for a blank panel after a settings change, jumping rows
  and brightness flashes

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-15 17:09:05 -04:00
co-authored by Claude Opus 5
parent b26b31e320
commit 5709036e3c
7 changed files with 145 additions and 98 deletions
+11 -8
View File
@@ -586,17 +586,19 @@ def save_main_config():
# accepts (RGBMatrix::Options::Validate in lib/options-initialize.cc,
# the gpio_slowdown check in lib/led-matrix.cc). Outside those ranges
# the config used to save, then the matrix refused to start and the
# display dropped to fallback mode. cols and chain_length have no
# upper bound in the library, so none here.
# display dropped to fallback mode. cols, chain_length and
# limit_refresh_rate_hz (0 = no cap) have no upper bound in the
# library. rows has none here by choice: the library currently
# rejects more than 64 per panel, and that limit is left to it so a
# library that lifts it needs no change here.
def _hardware_int_error(field, low, high=None, even=False):
"""A 400 response if data[field] is not an allowed integer, else None."""
raw = data[field]
if even:
allowed = f"an even integer from {low} to {high}"
elif high is None:
allowed = f"an integer of at least {low}"
kind = "an even integer" if even else "an integer"
if high is None:
allowed = f"{kind} of at least {low}"
else:
allowed = f"an integer from {low} to {high}"
allowed = f"{kind} from {low} to {high}"
rejection = (jsonify({'status': 'error', 'message': f"Invalid {field} '{raw}'. Must be {allowed}."}), 400)
# int() would quietly turn true into 1 and 48.5 into 48.
if isinstance(raw, bool) or (isinstance(raw, float) and not raw.is_integer()):
@@ -609,11 +611,12 @@ def save_main_config():
return rejection
return None
for field, low, high, even in (('rows', 8, 64, True), ('cols', 16, None, False),
for field, low, high, even in (('rows', 8, None, True), ('cols', 16, None, False),
('chain_length', 1, None, False), ('parallel', 1, 3, False),
('brightness', 1, 100, False), ('scan_mode', 0, 1, False),
('pwm_bits', 1, 11, False), ('pwm_dither_bits', 0, 2, False),
('pwm_lsb_nanoseconds', 50, 3000, False),
('limit_refresh_rate_hz', 0, None, False),
('gpio_slowdown', 0, 10, False)):
if field in data:
error = _hardware_int_error(field, low, high, even)