Three firmware-side pieces of work, now that building and flashing from the browser works end to end (#230). They are listed together because they touch the same files, but they are independent and can land separately.
1. Wireless upload — the device pulls, nothing pushes
Flashing over USB works and takes about twenty seconds, so this is convenience rather than a blocker. It matters for a Patternflow mounted on a wall, an installation, or anyone with more than one device.
What cannot work, and why — worth writing down, because two of these look plausible until you try them:
- OSC is not a transport. It carries knob and state messages over UDP. It can trigger an update ("there is one waiting"), but it is not how 1.1 MB travels.
- ArduinoOTA — what the firmware has today — is LAN push. The uploader has to reach the device on UDP 3232. A browser cannot send UDP at all, and the build server cannot reach a device behind someone's home NAT.
- Browser straight to the device over the LAN is blocked. An HTTPS page cannot fetch
http://192.168.x.x; mixed content stops it, and the community is HTTPS.
What does work: the device fetches over HTTPS. An outbound connection traverses NAT with nothing to configure, and neither the browser nor the server needs to reach the device.
The hardware makes the pairing pleasant — there is a display and four encoders:
- Long-press into an update screen. The device shows a short code and starts polling.
- On the web, after a build, enter that code.
- The server maps the code to the build; the device's next poll returns a URL, downloads, flashes, reboots.
Device-shows / human-types is the right direction: typing six characters on a keyboard beats turning a knob to dial them in.
What it needs
Note the chicken-and-egg: this capability has to arrive by USB once. It ships in a stock release, and everyone who flashes that gets wireless updates from then on.
2. More than one custom pattern per build
Worth correcting a common assumption: the firmware already has three custom slots (custom1.h…custom3.h, three entries in customPatterns[]), and the build service's assembler already handles up to three. The reason only one arrives is that the web UI sends one — see #233.
So this is mostly a web change. On this side:
3. Rebuild only the pattern that changed
A warm build is 14–16 s on the Pi, nearly all of it recompiling one translation unit. Arduino concatenates the sketch, and every pattern header is textually included into it, so changing one custom slot recompiles all ~34 presets along with it. Extra cores do not help: it is one file.
That is fine today. It stops being fine as the preset library grows, since build time tracks the total amount of pattern code rather than what changed.
A shape worth considering. Splitting every pattern into its own .cpp is the obvious answer, but it is a large refactor and would break the header-only .h format that community patterns are already written and shared in. A smaller change gets most of the win:
- Give the custom slots fixed namespaces (
Custom1, Custom2, Custom3) and have the assembler rename the submitted pattern into its slot. The displayed name comes from the NAME constant, not the namespace, so nothing changes for the author.
- With fixed namespaces,
pattern_registry.h never changes between builds — today it is regenerated every time, which is itself enough to force a full recompile.
- Compile each custom slot as its own translation unit (a generated
customN.cpp that includes the submitted .h), leaving the presets in the main unit where they belong, since they do not change.
Result: a build recompiles one small file and relinks, instead of recompiling the entire pattern library. Rough guess 15 s → 5 s, most of what remains being the link.
Trigger for doing it at all: when a warm build passes ~30 s. There is no reason to touch this while it sits at 15.
Three firmware-side pieces of work, now that building and flashing from the browser works end to end (#230). They are listed together because they touch the same files, but they are independent and can land separately.
1. Wireless upload — the device pulls, nothing pushes
Flashing over USB works and takes about twenty seconds, so this is convenience rather than a blocker. It matters for a Patternflow mounted on a wall, an installation, or anyone with more than one device.
What cannot work, and why — worth writing down, because two of these look plausible until you try them:
http://192.168.x.x; mixed content stops it, and the community is HTTPS.What does work: the device fetches over HTTPS. An outbound connection traverses NAT with nothing to configure, and neither the browser nor the server needs to reach the device.
The hardware makes the pairing pleasant — there is a display and four encoders:
Device-shows / human-types is the right direction: typing six characters on a keyboard beats turning a knob to dial them in.
What it needs
HTTPUpdate(oresp_https_ota) in the firmware, plus the update-mode screen and polling loopsetInsecure()is not acceptable here — a man in the middle could push arbitrary firmware. Pin the root CA and verify the image hash (HTTPUpdatesupports an MD5 check).app0/app1andotadata, but the app must mark itself valid after a successful boot or a bad image can strand a device that is hard to reach.Note the chicken-and-egg: this capability has to arrive by USB once. It ships in a stock release, and everyone who flashes that gets wireless updates from then on.
2. More than one custom pattern per build
Worth correcting a common assumption: the firmware already has three custom slots (
custom1.h…custom3.h, three entries incustomPatterns[]), and the build service's assembler already handles up to three. The reason only one arrives is that the web UI sends one — see #233.So this is mostly a web change. On this side:
3. Rebuild only the pattern that changed
A warm build is 14–16 s on the Pi, nearly all of it recompiling one translation unit. Arduino concatenates the sketch, and every pattern header is textually included into it, so changing one custom slot recompiles all ~34 presets along with it. Extra cores do not help: it is one file.
That is fine today. It stops being fine as the preset library grows, since build time tracks the total amount of pattern code rather than what changed.
A shape worth considering. Splitting every pattern into its own
.cppis the obvious answer, but it is a large refactor and would break the header-only.hformat that community patterns are already written and shared in. A smaller change gets most of the win:Custom1,Custom2,Custom3) and have the assembler rename the submitted pattern into its slot. The displayed name comes from theNAMEconstant, not the namespace, so nothing changes for the author.pattern_registry.hnever changes between builds — today it is regenerated every time, which is itself enough to force a full recompile.customN.cppthat includes the submitted.h), leaving the presets in the main unit where they belong, since they do not change.Result: a build recompiles one small file and relinks, instead of recompiling the entire pattern library. Rough guess 15 s → 5 s, most of what remains being the link.
.hformat; community patterns already in circulation must not need editingTrigger for doing it at all: when a warm build passes ~30 s. There is no reason to touch this while it sits at 15.