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

259 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.