Files
diy-layout-creator/diylc/docs/plans/maker-peripherals.md
T
Bane Stojkovic a743de4024 Controllers (#1080)
* initial

* more components

* fixes

* Update TreePanel.java

* fix boost converter

* Improve wrapping of component names

* Update ULN2003Driver.java

* Update NRF24L01Transceiver.java

* imp

* updates

* improvements

* more components

* arduino

* uno

* icon

* cleanup

* mega

* mega

* improveent

* nano

* esp boards

* esp

* esp32

* esp32

* Update ESP8266NodeMCU.java

* d1

* Update WemosD1Mini.java

* pi

* consolidate esp32

* pi pico updates

* pi zero

* Update RaspberryPiZero.java

* pi pico

* cleanup

* pi improvements

* consolidate pins

* antenna consolidation

* improve solder pads

* teensy

* headers

* teensy fix, test cleanup

* s3

* Update ESP32DevKit.java

* usb standardization

* pico w

* button standardization

* arduino improvements

* Update AbstractMakerBoard.java

* Update RaspberryPiZero.java

* Update RaspberryPi.java

* pi 3

* pi 5 improvements

* Update RaspberryPiZero.java

* fix tests

* esp pinout fix

* Update ESP32DevKit.java

* pin name improvements

* Create tier-1-modern-boards.md

* new versions

* pinouts

* nano improvements

* sanitize node names

* label improvements

* minima fixes

* arduino uno labels

* nano labels

* Update ArduinoNano.java

* mega

* mega

* comment out future stuff

* release prep

* Update RaspberryPiPico.java

* Refactor abstract class

* labeling improvement

* label offset fixes

* Update Teensy.java

* consolidate tests

* micro variants

* Update RaspberryPi.java

* displays tweaks

* display improvements

* neopix

* displays

* improvements

* led matrix

* strip

* led bar graph

* jewel

* tft

* tft

* Update maker-peripherals.md

* nokia

* led bar

* labels

* tft

* cleanup

* oled

* cleanup

* display enhancement

* displays

* neopixel

* displays

* displays

* new tft

* displays

* icon

* variants

* 2-digit 0.56 inch 7 segment

* Added ability to hide component categories in the component tree and toolbar from the Config menu

* led bar

* Update variants.xml

* color selection for bar graph

* Added 1.8" sd

* tft fixes

* Update WS2812BRing.java

* neopixel improvements

* netlist and node name improvements

* oled tweak

* cleanup

* mockito fix

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 09:38:09 +02:00

16 KiB
Raw Blame History

Maker Peripherals — Displays & Outputs

Status: 13 components shipped, in the as-yet-unreleased 6.7.0 block of diylc-core/src/main/resources/update.xml. Scope: diylc-library, package org.diylc.components.displays. Companion: maker-board-roadmap.md, which covers org.diylc.components.micro.

Nothing in this package has been in a release, so defaults, control-point counts and serialized field names can still be changed freely. That stops the moment 6.7.0 ships.

1. What is in the palette

Class Variants Other properties
CharacterLCD 16x2, 20x4 × I2C backpack, parallel HD44780 Backlight Color, Screen
OLEDDisplay 0.96" SSD1306 128x64, 0.91" SSD1306 128x32, 1.3" SH1106 128x64 × I2C, 7-pin SPI, 6-pin SPI Pixel Color, Screen
TFTDisplay 2.8" / 2.4" ILI9341, 0.96" / 1.8" ST7735, 1.54" ST7789, 1.28" GC9A01 round Screen
Nokia5110LCD single part (PCD8544 84x48) Backlight Color, Screen
SevenSegmentDisplay 1-digit 0.56", 4-digit 0.36", 4-digit 0.56", 4-digit TM1637 module Common, Punctuation, LED / Board / Body colour
LEDMatrix MAX7219 single 8x8, compact 8x8, 4-in-1 32x8, 8-in-1 64x8 Dot Color
LEDBarGraph 8, 10, 12 segments Orientation, body / border colour
WS2812BBreakout single LED —
WS2812BStick 8 LEDs —
WS2812BJewel 7 LEDs —
WS2812BRing 12, 16, 24 LEDs —
WS2812BStrip 30 / 60 / 144 LED·m⁻¹ × 1–144 LEDs —
WS2812BPanel Adafruit 8x8 NeoMatrix —

Twelve extend AbstractMakerBoard. LEDBarGraph is the exception: a DIP-outline part, so it follows DIL_IC on AbstractLabeledComponent with its own transformer and inherits none of the maker helpers. It is still in this category because that is where someone looks for a bar graph.

2. Conventions this package follows

These are the rules worth knowing before touching anything here. Most were learned by getting them wrong once.

Variants. A Version-style enum on the existing class where the footprint family is shared; a new class where it is not. The test is structural, not cosmetic: WS2812BJewel is a separate class from WS2812BRing because it is a disc rather than an annulus, with a centre LED and its own pad arrangement — five variant-specific structures is a different part.

Figures live on the variant. Hardcoded Size constants and String[] arrays in the component class, per-variant wherever a variant changes them. No pin-definition resource, and no pixel literals in draw() — every dimension derives from a Size.

A different silkscreen is not a variant; a different pin count is. The same two pads on an SSD1306 carry the clock and data lines in both interfaces — the module's BS jumpers choose the protocol, not the pins — so SCL/SCK/CLK/D0 are one pin and SDA/MOSI/D1 are another, and boards that print them differently are the same board. Node names pick one spelling and move on. A 6-pin SPI board is the opposite case: its chip select is tied low on the PCB rather than brought out, so it cannot share a bus, and that is a variant because it reaches the netlist.

Say whether a figure is measured or derived. Active areas computed from a nominal diagonal at a panel's aspect ratio are derivations, and are commented as such so nothing is built on them. Where a part's own measurement contradicts a derivation the measurement wins and carries its own field — but check first that it really contradicts it. A supplied figure sitting within half a millimetre of what an existing rule already produces is more likely a reading than a departure, and has twice turned out to be one; query it before it earns a mechanism.

Orientation is sourced per variant, never standardised. Which edge a board's header leaves by is a fact about the part. Control point zero is always the leftmost pin, so with the pin order fixed a top header and a bottom header are mirror images, not the same board turned round. TFTDisplay divides three and three, and every constant states its own edge — the short constructor takes the flag too, so none can inherit a default. Standardising this family onto one orientation was tried and had to be undone: it had moved two boards away from the truth.

Do not let one property stand in for another. isRound() was serving as "the header is at the bottom" and broke the moment a rectangular board had a bottom header; isDualRow() was serving as "this is a bare package". Carry both questions explicitly even while the answers agree.

Pins are drawn and covered, never skipped. drawPinHeader is what registers a conductive area, so a header hidden under a module or a moulding is drawn first and painted over. Leaving the call out looks identical and silently drops those pins from continuity and the netlist.

Silk where it fits, nowhere else. Pin names go through getSilkPinLabel, so a name is written once. A row with no clear strip beside it gets no labels rather than crowded ones — the matrix's covered rows, the LCD's I2C backpack and the TFTs' SD rows all go unlabelled deliberately. A SILK_NAMES array exists only where the node name is actively wrong on the board, not merely long.

The glass prints the part's own spec. Display.VALUE puts the variant string on the lit area, generated from the properties rather than typed, carrying no prose and no language. Display.NONE gives the unpowered part. No invented demo content, ever.

BOM. Every class sets bomPolicy = SHOW_ONLY_TYPE_NAME and returns the variant string from getVariantLabel(), because BomMaker groups rows on type name plus value — without it every variant of a class collapses into one line and the BOM cannot say which part to buy.

Shared arrays are shared by identity. Where two variants have the same pinout they reference one array constant and the test asserts assertSame, so a correction to one reaches both. Two copies that happen to match would pass every name check and drift the day one is corrected.

Nested types at the bottom of the file. Where a variant needs more than a couple of extra figures they go into a nested value class rather than onto the enum constructor — OLEDDisplay.Layout, TFTDisplay.Glass, SevenSegmentDisplay.Module. A constructor past about fifteen arguments is the signal.

3. Figures that are not measurements

Kept visible so no one mistakes them for sourced data and builds on them.

  • SevenSegmentDisplay digit widths — 8.1 mm on both 0.56" packages (unverified) and 5.2 mm on the 0.36" (inferred from the 0.56" ratio, so resting on an unchecked figure). Deliberately left as inferences: they size the drawn glyph and nothing else, and the glyph is already a declared departure from the package at DIGIT_DRAW_SCALE 0.88. An error here is cosmetic and bounded, unlike a wrong pin array.
  • SevenSegmentDisplay.Module hole figures — 1.778 and 1.524 mm, which are the 14 and 12 pixel offsets the class drew before they were figures at all, converted exactly so the drawing did not change.
  • Nokia5110LCD — the 3.5 mm clearance from the bottom edge to the pin row.
  • WS2812BStrip — tape width (10 mm / 12 mm) is a stated norm rather than a measurement, and the end-pad lead-in derives from the pad and package footprints.
  • TFTDisplay — the SD rows' horizontal placement is centred across the board by derivation; only their offset from the edge was given.
  • OLEDDisplay — the 6-pin SPI boards borrow the 7-pin boards' outlines. A 6-pin module is a PCB of its own with one fewer pad, and nothing but its outline would say whether it matches.

4. Testing

Per-class tests in diylc-library/src/test/java/org/diylc/components/displays/, using MakerBoardTestSupport (assertRow, assertRowSpacing, assertBoardSize, assertDrawsCleanly, assertScreenTextIsDrawn, renderPixels).

What these tests are for, beyond the obvious count-and-dimension checks:

  • Assert relationships, not transcriptions. A board is exactly as wide as its modules; a glass clears the mounting holes; no hole is drilled where a pad is; a lit area that is measured really does disagree with the rule it replaced. A test that restates the constant passes while the component is wrong.
  • No duplicate node names, on every variant. The cost is legibility, not connectivity: nodes are identified by component and control point index and the netlist graph is keyed on position, so two pads named GND stay two nodes that merely print the same, and a reader cannot tell which one a connection reached. They are invisible on the canvas too, since getDisplayPinLabel cuts the suffix off and both silk as GND. Teensy is the one board that still repeats a bare name.
  • A drawing smoke test over every variant, state and orientation.
  • When a refactor is meant to change nothing, render before and after and compare pixels. The digitCount work was verified that way, and it caught a sub-pixel hole shift the unit tests missed.

MakerComponentsTest carries the generic discovery and icon coverage. A class ships by moving from unreleasedMakerComponentClasses to releasedMakerComponentClasses and uncommenting its @ComponentDescriptor.

5. Release

The slice is worth shipping on its own: it is archetype-complete, part of it (7-segment, character LCD, bar graph, addressable strips) reaches builds with no microcontroller in them, and the slices after it are large and differently shaped, so batching would mean a much later and far less reviewable release. A release is also the only validation loop that reaches people who own the parts.

5.1 What shipping makes permanent

Only this list needs checking beforehand, because only this list is a contract afterwards:

  • class names, and serialized field names and types
  • control-point counts
  • control-point positions relative to point 0 — these are stored per instance, so moving a pin relative to the body misplaces every wire in an existing file

Everything else is fixable in a later release without breaking a file: bezel placement, colours, silk, hole positions, digit widths. Every figure in §3 falls here, which is why none of them blocks a release.

5.2 Pre-release checklist

  1. Audit the pin layout of all 13 — count, node names, and each pin's position relative to the body. Not the cosmetics; those are §5.1's second list.
  2. Settle TFTDisplay's 2.8" SD row. It is the least verified thing in the package: the row was added on the argument that the "(Touch + SD)" label implied a missing header, and its 3.0 mm offset was read from "the same offset as the bottom row" rather than measured. Four control points that become permanent.
  3. Re-check TFTDisplay generally. It is where the churn concentrated — both ILI9341s went 14 to 18 control points, and the 0.96", 1.8" and 1.54" each had every pin move relative to the body when their orientation was corrected.
  4. Render a contact sheet of all 13 and look at it. Cheap, and it caught several real errors that the unit tests passed straight over.

Regression samples (§6.3) are deliberately not on this list. They protect against future change, which is what a released contract makes dangerous — so they are the first task after shipping, not a blocker on it.

5.3 Release notes

One NEW_FEATURE per palette entry in the 6.7.0 block, part name then variant list. A released block is never edited. A new variant of a component that is new in the same block goes onto that component's existing line rather than being logged as an IMPROVEMENT — there is no earlier release for it to improve on.

6. Next steps

6.1 Parts worth adding, ranked by how often they appear in builds

  1. 1.3" 240x240 ST7789, and the 1.14" and 2.0" ST7789 the Pico ecosystem buys. TFTDisplay now absorbs offset panels, either header edge and second rows, so each is one Controller constant. Needs per board: outline, header offset and edge, pin names in printed order, hole inset and drill, bezel height, and whether the lit area is centred or measured.
  2. MAX7219 8-digit 7-segment module — the clock and counter staple, and this package already models a MAX7219 cascade for the matrix. Unblocked: DisplayType now carries digit count, pin array and module board figures, so this is a constant.
  3. 6-digit TM1637 and 2-digit 0.56" — the rest of the clock and thermometer range. Same.
  4. E-paper, 1.54" / 2.13" / 2.9" SSD1680. Once judged niche; that call is stale, as ESP32 badge builds and the Waveshare and Good Display modules made it ordinary. The flexible-cable mounting is real new drawing work, which is the only reason it is not higher.
  5. WS2812B 16x16 and flexible 8x32 matrices — the one addressable form the package lacks.
  6. The bare WS2812B 5050 LED, as against a breakout. People solder these directly.
  7. 16x4 character LCD. Also the RGB-backlight 1602, which is not the free colour default it looks like: it is an 18-pin part whose three backlight anodes are real pins, so it is an LCDInterface constant with its own array.
  8. Nixie tubes — IN-12, IN-14, B7971. The strongest audience overlap on this list: DIYLC already has a Tubes category, and the people in it build Nixie clocks.
  9. 2.42" SSD1309 OLED, 14- and 16-segment alphanumeric, HT16K33 backpacks. Real, second tier.

Explicitly rejected: a tint property on TFTDisplay. A 240x320 colour panel has no tint to set, and offering one invites a drawing that says something false about the hardware.

6.2 The "& Outputs" half of the name is unfulfilled

Every member of this category emits light. There is no analog panel meter, no VU meter, no speaker or driver, and no magic-eye tube anywhere in the library — misc/Buzzer and electromechanical/PilotLampHolder are the whole non-display output range.

This is a bigger gap than anything in §6.1, and it reaches the audience DIYLC already has: a VU meter and a loudspeaker appear in amp and effect builds containing no microcontroller at all, Dial Scale is already next door in misc, and a moving-coil meter is a simpler drawing than any display here. Whether these belong in this category or in Electro-Mechanical is not an interesting question; that they are absent is the finding.

6.3 Regression coverage — the standing risk

No .diy file among the 1418 in diylc-regression-data references org.diylc.components.micro or org.diylc.components.displays, so 23 components have no rendering or netlist baseline. Unit tests guard the figures we chose; they cannot catch a pin dropping out of the netlist or a component misbehaving in a real project. Samples were declined for this slice; the case is stronger now that orientations, pin arrays and geometry have all moved.

6.4 Later slices

sensors (9 drafts). Ship the four that are the unrivalled answer in their function — HC-SR04, DHT11/22, PIR HC-SR501, MPU6050 — and leave the five commodity KY-style three-pin boards, which carry most of the sourcing cost for the least distinctiveness. Do not collapse the tail into a parameterised "three-pin sensor module": that is the generic configurable board that was already built and reverted, and it fails for the same reason — people search the palette for a product name.

modules (21 drafts). The largest and least homogeneous batch, and the worst geometry drift in the tree (ULN2003Driver has 24 raw pixel offsets, PCA9685ServoDriver 22, L298NMotorDriver 18). Split by function rather than shipping as one category. Settle one overlap first: the drafted ActiveBuzzerModule (KY-012) against the existing misc/Buzzer.

robotics (4 drafts). Blocked on an architectural decision, not on part selection. AbstractMotor is a parallel fork of AbstractMakerBoard, re-implementing rotatePoints, drawPins, getFinalBorderColor and getCachingBounds plus its own PIN_COLOR, PIN_SIZE and silk fonts. Four components do not justify a second hierarchy: either lift the shared behaviour into a common base or take the duplication deliberately.

i18n. Component display names and enum labels are plain strings, absent from diylc-swing/src/main/resources/lang/*.txt, as they are for the shipped boards. No work required here; noted for a future pass.