Start
What Arcus is
A musical fountain: pumps push water through nozzles and LEDs light it, choreographed to music — automatically, from an AI that writes the show.
A pool is a chain of end units (each one jet: a motor driving its pump, and/or an RGB light) hanging off buffers that hang off one Main controller. The Main owns time and the schedule; a Raspberry Pi gateway gives it internet, audio and remote control. In the cloud, the website and phone app talk to a backend that stores shows, runs the AI composer, and holds ownership.
Sold example: a 150-unit fountain = 75 motor (Driver) units + 75 LED (RGB) units, on ~10 buffers of 15 units each.
Hardware
Layout & wiring
One Main controller, up to 30 buffers, and up to 30 end units per buffer — all daisy-chained on a single shared wire.
Every unit is identified by its position in the chain: which buffer it sits on, and its number within that buffer. That position is assigned during a scan, never typed in by hand — so inserting a new unit shifts the numbering of everything below it, and the system re-discovers the order rather than guessing it.
The boxes
Five board types. Each is a PIC microcontroller with I²C FRAM for its settings and a shared RS485 transceiver.
A Main
The brain — song catalog, playlists, 10 schedulers + 100 triggers + a forever list, the pool clock and pump ceiling. Broadcasts prepare/play/time. May carry BLE.
S Buffer
Repeats the bus down to its ≤30 units and back, gates addressed traffic, relays OTA. Mostly transparent.
M Driver
Drives one pump via a VFD (INVT GD10/GD20/CHF100, Modbus). Owns nozzle, max height, accel/decel, pump limits, reverse. 75 in the sold pool.
C RGB
Drives one jet’s RGB light; animates so colour staggers across jets like the water. 75 in the sold pool.
V Valve
Curtain/valve unit, keyed by a curtain id. Not in the 150-unit pool.
Add-ons
Pi gateway, RN4871 BLE on the Main’s UART5, and the ordered ATECC608B secure element.
Cabling & connections
The whole pool is ONE daisy-chained RS485 bus. It leaves the Main, threads through every buffer, and each buffer fans out to its end units — one continuous line, not a star.
- Chain, don’t star — each box has a bus IN and a bus OUT; run OUT → IN down the line. RS485 wants a clean daisy-chain; loose stubs and star splits hurt the signal.
- Keep the pair consistent — RS485 is two data lines (A / B) plus a common reference. Keep A→A, B→B the whole way; one swapped pair silences everything past it.
- Order IS the address — because SlaveIDs are positional, the physical order you chain the units in becomes their numbering. Chain them in the order you want them numbered, then run a search to assign the IDs.
- Power + data together — each box needs its supply and the data pair; the pump motors are driven by their VFD on its own feed. Watch the total run length and volt-drop on long chains.
The Pi gateway
A Raspberry Pi on the J2 bus that turns a standalone Main into a connected, controllable, updatable fountain.
- Internet & relay — presence/commands/songs over a cloud relay (push), heartbeats for “online”.
- Audio — plays the show’s track in sync with the water.
- OTA — pulls firmware and flashes the boards over the bus.
- Own hotspot — a WPA2 access point with a per-device password, so you can control the pool with no venue network.
- Self-update — pulls its own daemon bundle from the cloud.
The Pi gateway, deeper
An installed Raspberry Pi is the fountain's brain and internet bridge; it reaches the cloud and the phone without any router changes at the venue.
Reaching a Pi behind the venue's network
A transparent relay carries the connection: the Pi dials out to the relay and the phone dials out to the relay, so both sides connect outward and no port-forwarding is ever needed. The link is encrypted in transit, and the fountain's control password still gates control end to end.
Board takeover on link loss
The Pi sends the Main a steady keepalive about every 2.5 s. While it keeps arriving the Main stays Pi-driven and holds its own schedule engine off; if it stops for ~8 s the Main takes over and runs its own schedule — the pool never goes dark.
- Presence / heartbeat — while the relay is up it reports the whole fleet's presence in one step, so every fountain's online state stays fresh; the Pi only sends its own heartbeat (every 20 s) when there is no relay. The app shows a fountain as offline once it has been silent for 60 s.
- Pairing the Pi — the programmer or owner issues the Pi's gateway key once (it is shown a single time, then kept only as a fingerprint). The Pi presents that key to prove it is exactly one fountain's gateway.
- Self-update — the Pi reports its own software version, and the phone can trigger an update or restart. Updates apply with a health-check and automatic rollback, and the Pi updates last — after its units.
VFD wiring & Modbus
The Driver board talks to an INVT variable-frequency drive (VFD) over its own separate wiring, using the standard Modbus protocol, and picks the spin direction from whether a show is playing.
| Drive setting | Value to set on the drive |
|---|---|
| Drives | INVT GD20/GD27/GD350 (default), GD10, CHF100 |
| Mode | Modbus RTU (default) or ASCII |
| Drive address | 1 |
| Serial | 19200 baud, 8 data bits, even parity, 1 stop bit (8E1) |
- Run / reverse / stop — the Driver tells the drive to spin forward, spin in reverse, or stop, based on the show state and the per-motor Reverse setting.
- Speed — the 0–100 pump speed is scaled against the drive's own maximum frequency and the pool's pump ceiling, then sent to the drive.
- Per model — on a GD20 the run and speed go together in one message; on a GD10 or CHF100 they are sent as two separate messages. The Driver handles this automatically.
Firmware
How the boxes talk
Every box in the fountain shares one internal language. You never type any of it — the website and phone speak it for you.
When you press Prepare, Play or Stop, set the show clock, adjust the pump ceiling, or configure a unit's nozzle, height or reverse, the app turns that into the right message and delivers it to the right unit automatically.
The language is built to grow safely: new features are added as new settings, never by changing what an existing message means. That is why a newer box and an older box in the same pool always understand each other, and why a firmware update never leaves part of the fountain unable to talk.
Where settings are stored
Every board remembers a set of values — its identity, how it's configured, and how it's doing. The website and phone read and write these for you.
| Group | You can | What it holds |
|---|---|---|
| Identity | read only | board type, firmware version, bootloader version, serial number, result of the last update |
| Unit setup | read & set | nozzle, motor type, maximum height, reverse, offset, acceleration, pump minimum/maximum — and RGB type on colour units |
| Pool setup | read & set | the pool-wide pump ceiling, the disable (kill) switch, and the anti-theft leash — all held on the Main |
| Diagnostics | read only | uptime, fault flags, drive (VFD) state |
Reading a value and setting it use the same path, so what you save is exactly what reads back — no drift between what you set and what the board runs.
On-board memory
Each board keeps its settings in permanent on-board memory that survives being powered off.
- Safe defaults — if a stored value is ever blank or out of range, the board quietly falls back to a safe default. A brand-new or just-wiped board is never born with a bad setting.
- Update-safe — a small part of memory is set aside for the update process, so a firmware update that gets interrupted can't corrupt the board's normal settings.
Over-the-air updates
Firmware updates are delivered over the air from the website — no site visit needed for the buffers and end units. Each board checks an update before it commits to it.
- Verified before install — every update is encrypted and integrity-checked as it arrives, so a board only installs a genuine, undamaged image.
- Safe if interrupted — if power drops or the update is broken off partway, the board falls back to its working firmware instead of bricking. Only a brief final moment must complete, and the process is built around surviving everything up to it.
- The Main is flashed on site — the central Main controller isn't updated over the air; an installer flashes it by hand with a PICkit. While that's happening the fountain goes quiet — that's the expected, safe state.
Provisioning & identity
- A 10-digit random serial and a 256-bit device key are burned into the PIC User ID (64B) at flash and registered with the backend.
- Anti-clone is website-only — duplicate-serial detection in the cloud warns HQ with forensic proof and never auto-disables; there is intentionally no runtime device-key verification.
- Real-serial guard: an all-zero
00000000serial is a “ghost” — never claimed, owned, or listed.
Pump & motor control
- Pump ceiling (1–8) — the pool-wide cap on how hard any pump may run. Set once on the web for the whole pool, it is applied to every pump and re-affirmed at the start of every show. It fails open — if the value is ever unreadable it is treated as uncapped, so a bad setting never chokes the fountain.
- Motor reverse — a per-pump switch that flips the drive's spin direction; it fixes a phase-swapped pump without re-wiring. Set at commissioning on the web.
- Per-unit limits — nozzle, max height, accel/decel, pump min/max % — all set per unit at commissioning.
Firmware field ops & board indicators
Units are updated over the air from the website — each buffer and end unit has its own button — while a version of 0 marks a board sitting in its startup loader with no working program yet.
Update / Re-flash
Each unit has its own button, targeting exactly that unit by its place in the chain. The button reads Update to vN when the unit is behind, or Re-flash vN for a forced re-install. It confirms first and shows live % + ETA; only one update runs at a time.
Startup-loader update
A separate, master-only button (enforced on the server too). The normal app update is the amber action; the red action re-installs the board's startup loader itself. The Main is never updated over the air — it is updated by hand with a PICkit on site.
- Version 0 = no working program — every tune/memory/test control is hidden and the unit can only be updated. An amber chip offers the one-click app update, and a buffer in this state is flagged BOOTLOADER.
- Order: end units first — a buffer relays the update through to the end units below it regardless of its own version, so end units keep working while the buffer updates.
- Update outcome — if an update fails, the unit automatically falls back to its previous program — a safe, non-destructive recovery the site shows as an "update failed" badge.
Software
The software stack
Website — arcusl
The programmer/operator console: per-unit device config over Web-Serial, the AI composer, the locker, admin/fleet pages.
Backend — RestAPI
Accounts, ownership, the show locker, billing, and the AI compose pipeline.
Phone app — arcus_app
The operator’s post-setup tool: run shows, compose, monitor, kill-switch, BLE.
Pi daemon — pi-gateway
On-site control: board link, hotspot, self-update, cloud relay, kill-switch enforcement.
The AI composer
A physics-aware author that turns a song into a fountain show — cues for every jet and light, aligned to the beat.
- Plan-then-compose — a 1-on-1 chat plans the show first; the agreed plan is built into cues.
- Animations — a fixed palette (grow, fall, wave, chase, bounce, ripple, alternating, split). Variety comes from the music, not a catalogue.
- Rig rules — the programmer’s AiSettings: mirrors, motor↔LED couplings, mutual-exclusions, per-group excludes & centres. The composer obeys; the operator respects.
- Compose defaults — the pool’s standing palette/density/flash/height. Web sets them; the phone inherits and respects them; a per-show tweak layers on per field.
Credits & billing
The price of a show is the length of the song — nothing else.
- Rate:
{{PRICE}}per second of music. A 218 s song costs218 × {{PRICE}}— before, during and after. It is multiplication, not an estimate, so it never moves. - Fixed before Compose: the model, effort, group count and token spend do NOT change the price. You see the exact final amount and Compose is gated on it.
- A failed compose = $0: if no show is delivered the whole charge is returned, even when the model ran and burned tokens — you buy a show, not an attempt.
- Balance guard (402): anyone below the price is blocked with "Not enough balance to compose. Top up to continue." Only role 100 (master) composes free.
- Minimum length: a compose needs a real billable length (≥ 60 s) or it is refused.
- Planning costs a little: each plan-chat turn charges the actual Anthropic cost × 3, taken immediately; the song analysis that grounds the plan is free. A near-empty balance blocks chat too.
- Top-up is manual today — credit is added to the account; there is no auto-recharge.
Rig rules: mirrors, centres, couplings, mutex, excludes
The AutoShow rig editor IS the core physics programming — it tells the composer how your pool is wired.
- Mirror pairs: two groups play as a symmetric wing pair. Mirroring is geometric — order each group's devices outside-in so index 0 of one wing physically mirrors index 0 of the other. (Set
swaponly when one side wasn't reverse-ordered.) - Centres: the device IDs you pick as the MIDDLE between a mirrored pair. Explicit only — leave it empty and the middle stays dark; nothing is ever auto-chosen.
- Couplings: a directional motor→LED link, "light follows water" — that LED group lights that motor group.
- Mutex: never-play-together pairs (groups or single units) the composer will never fire in the same moment.
- Excludes: whole groups the composer must not touch; skip unit drops one broken end unit (by SlaveID) from every group, server-side.
- How the composer obeys: these lists are the durable truth enforced at compose. A per-show override can switch a whole class off (mirrors, light-coupling or mutex) but cannot invent new ones.
AI composer: how deep the chat goes
The plan chat is a real control surface, not just conversation.
- It changes the build: "make it 3 minutes", "no ripple", "softer" are applied straight into the settings — duration and every rule (flash, density, heights, ramps, white, silence, transitions, arc, palette, mirrors, coupling, mutual-exclusion, colour, banned animations) take real effect. The planner confirms only what it actually applied.
- Attach a track: pin a song and the planner holds its full block grid and plans to THAT music (one track at a time — a new one replaces the old).
- Attach a show: pin an existing show to improve this; Compose then recomposes fresh from the saved inputs (brief / blocks / track), never re-sending the heavy animation.
- Model: the composer always runs on one fixed top model. Because the price is flat per second, customers always compose on that default; choosing a different model is a manufacturer-only tool.
- Effort:
low / medium / high / xhighis the quality dial — it drives how hard the model thinks. The plan chat itself runs on a lighter model. - Language: the plan replies in your website's language (Turkish or English).
Compose settings: the full vocabulary
Every override the composer will obey. Set them as pool house-style (standing defaults) or per-show in chat — a per-show change wins field by field.
| Setting | What it does — options (default) |
|---|---|
| useMirrors | honour the mirror pairs (on) |
| coupleLight | LEDs follow their motors (on) |
| useMutex | honour never-together rules (on) |
| strictColour | saturated colours only (on) |
| minRampS | slowest motor ramp, 0.2–2 s (0.2) |
| heightFloor | lowest level the show may sit at, 0–60 (0) |
| heightCeiling | highest level it may reach, 40–100 (100) |
| flashAmount | none / rare / normal / heavy (normal) |
| cueDensity | calm / normal / busy (normal) |
| whiteUsage | punctuation / free / never (punctuation) |
| silenceMode | dark / bridge / feature — what silent passages do (dark) |
| transitions | flow (hand over, no dead water) / cut (hard scene changes) (flow) |
| showArc | auto / build / waves / calmend (auto) |
| palette | auto / warm / cool / contrast (auto) |
| bannedAnims | forbid any of: grow, fall, wave, chase, bounce, ripple, alternating, split (none; can't ban all) |
Store & ordering
The store is quote-first: the customer designs a fountain, the cart prefills the parts, and the manufacturer returns a price — no money moves online.
- The sim is the configurator — the TIA-style Devices designer. The cart prefills unit quantities from that design and they stay editable.
- Catalog — Main, Buffer/Splitter, Driver, RGB, Valve, Terminator. The manufacturer keeps prices on the Database page.
- The server prices, not your browser — requesting a quote sends only the quantities and your design up; the server prices each line from the catalog and your standing discount, so a tampered browser can't invent its own pricing. Quantities are capped at 1000 per line.
- A quote is a request — its status runs new → quoted → accepted → closed. The record is deliberately order-shaped for when a payment processor lands.
Ownership & security
Roles & ownership
| Role | Who | Can |
|---|---|---|
| Owner | the customer | full control — run, compose, config, transfer, kill-switch; sees the programmer |
| Programmer | manufacturer/installer | full power until sold; after a real owner exists → support only (loses operate/edit/gateway/factory-reset) but keeps the kill-switch + leash |
| Master | HQ (role 100) | fleet admin — everything, incl. revoke |
Transfer/resale: a sale reassigns the owner and clears the seller’s shares; the buyer inherits the show locker.
Kill-switch & anti-theft
Turn a fountain off (and on) remotely — the owner's safety control and the manufacturer's non-payment lever — in layers, so it holds even if the gateway is unplugged.
Cloud + phone
Disable or enable from the website or phone (owner, programmer, master). The disabled state is durable — it survives a factory reset; a simple on/off toggle in the phone.
Gateway enforcement
The gateway holds the disabled state (survives a reboot), stops any running show, and refuses all play — manual, playlist and scheduled alike.
Board-level lock
The Main board remembers the disable (kill) switch in its own on-board memory: even standalone with the gateway unplugged, it refuses every list, solo and forever loop.
Owner-heartbeat leash
Opt-in. The fountain expects to check in with the cloud from time to time; a unit left fully offline past the window locks itself. Off by default.
BLE PIN & access
Stand by the pool with no network and control the Main over Bluetooth — behind a PIN.
- PIN gate — a 6-digit PIN unlocks a BLE session. Change it in the app; the new PIN is best-effort escrowed to the cloud for recovery.
- Brute-force lockout — a FRAM-persisted counter (survives power-cycle and reconnect): after 10 wrong PINs the board stops checking until a wired reset clears it.
- Reset-pin is wired-only — physical cabinet access is the ownership proof, so a lost PIN can never brick BLE.
Accounts & sign-in
Everyone works through a signed-in account, so the system always knows who is making a change.
- You sign in on the website or phone with your Arcus account; the cloud confirms who you are before trusting a request.
- Your role — owner, programmer, operator or master — decides what you are allowed to do.
Claiming & ownership lifecycle
Every fountain moves through a fixed ownership chain: a programmer claims it, may share it, and hands it to the buyer on sale — after which the installer keeps only support powers.
- Claim — only a programmer can claim a fountain; operators never can. A fountain whose Main still carries the all-zero placeholder serial is refused (give the Main its real serial first), and one already claimed by another programmer comes back as already claimed. Whoever claims it becomes both its Programmer and its first Owner.
- Share — owner only. You name the account by email or id and it must be a real registered account; up to 4. A shared user can play and operate but cannot edit, transfer or re-share, and may remove only themselves.
- Transfer / resale — done by the owner, the programmer, or master. It is a full handover: the seller's shares are cleared, the buyer inherits the show locker, and the first non-programmer owner gets the owner free-credit tier once.
- Support after sale — the Programmer link is kept on purpose, but once a real owner exists the programmer is demoted to support-only: no operate, edit, gateway or factory-reset.
Security operations
Four independent layers protect a fountain from theft, cloning and non-payment — most fail closed today even before login is enforced.
Anti-theft leash
Set by the programmer or master only, never the owner (who could disarm it on a financed unit). The Pi renews the Main's expiry on each cloud contact; a unit that goes the set number of days with no contact stops itself. Set the window to zero to disarm.
Kill-switch
The owner, the programmer (kept after sale), or master can disable or enable a fountain. It latches a durable flag that survives factory-reset and reboot; the Pi holds it too and refuses all play until re-enabled.
- BLE-PIN recovery — the 6-digit PIN is random at the factory and the board locks out after 10 tries. The owner (or master) can escrow and reveal it, encrypted at rest; a lost PIN is otherwise recovered through a wired reset. If no escrow key has been set up, the feature is unavailable.
- Anti-clone / real-serial guard — website-only, with no check on the fountain itself or the Pi. The all-zero placeholder serial can't claim, own or appear in any list. A duplicate serial (same serial, different key) seen at the factory is reported to HQ with forensic proof (IP, network name, PC, employee) and refused — but never auto-disabled; a clone is simply a brick until a human grants it a programmer claim.
Operations
Install & commissioning
- Mount & wire the cabinet: Main, buffers, end units on one RS485 chain; power; the Pi on J2.
- Search from the Main to enroll every unit — assigns the positional SlaveIDs.
- Configure each unit on the web (Web-Serial): type, nozzle, max height, accel/decel, limits, reverse. A programmer job.
- Set pool rules + the compose house-style.
- Provision internet (venue Wi-Fi or the Pi hotspot) and set the owner.
- Hand off — the customer runs it from the phone.
Flashing & updates
- At the bench: the ArcusFlash tool writes the firmware, serial number and key onto a new board and registers it. Access is request → approve; the firmware is pulled from the cloud.
- In the field: updates go out over the air, driven by the Pi from the published versions. The Main needs an on-site PICkit only for its deepest startup code.
- Publishing: new firmware is built, checked and published to the cloud by the manufacturer. Installers and operators only flash the published version.
Shows & scheduling
- Songs live in the cloud locker (audio + cues) and are installed onto each unit's on-board memory.
- Playlists group songs; up to 10 schedulers and 100 triggers fire shows by clock time or sunrise/sunset, and a forever list loops when nothing else is scheduled.
- How a show starts — the units first hold still, then get a prepare signal, then a short 2-second lead-in, then the show plays with all the jets moving in time to the music.
Scheduling: schedulers, triggers, forever list
When shows run — built from schedulers, triggers and one forever override, all stored on the board.
- 10 schedulers — named on/off groups. A trigger fires only when its parent scheduler is enabled — one switch arms or silences a whole set.
- 100 triggers — the flat pool that actually starts shows. Each trigger's fields are below.
- Forever list — one switch plus one playlist that loops forever and overrides all scheduling; for bare LCD units with no gateway or GPS.
- A running show is never interrupted — a trigger due while a show plays is dropped, never queued.
- All of this is saved onto the board itself, so the gateway drives the schedule while it is connected and the board runs it on its own when the gateway isn't there.
| Trigger field | Meaning |
|---|---|
| Days | any of the 7 weekdays |
| Start | a clock time, or sunrise / noon / sunset ± a minute offset (sun anchors need a GPS fix) |
| Repeat | fire every N minutes inside the window; 0 = once |
| Until | end-of-window clock time; none = one-shot |
| Playlist | which playlist this trigger starts |
| Priority | 0–255; highest wins when two fall on the same minute |
Backup & restore
One encrypted JSON that captures the whole pool, and a restore that rebuilds it.
- One file: AES-256-GCM encrypted under your account's Backup Key — a
XXXX-XXXX-XXXX-XXXXcode, minted once and then fixed. Tamper-proof and unreadable without the key. - The key is escrowed on your account and applied automatically after login. Write your copy down: it is your only way back if the cloud copy is ever lost — you type it in.
- What it captures: programmer, songs/charts, every unit's hardware config (offsets, limits, accel/decel, driver/model/nozzle/motor type, max height, reverse, RGB type, positions/shapes), groups, playlists, the schedule, the whole show library, the AI rig rules, and the pool image.
- Restore is gated first: the backup's topology must match this pool exactly — same buffer count, same units per buffer, each slot the same device type — or it stops with no change made. This lets two identically-wired pools share a backup.
- Then it rebuilds:
wipe → groups → unit config → songs → playlists → schedule → cloud. Songs merge with the pool's own; on a name clash the backup wins.
Reference
Glossary
| Term | Meaning |
|---|---|
| End unit | one jet — a Driver (motor) and/or an RGB (light) |
| Buffer | a splitter carrying up to 30 units under the Main |
| Pump ceiling | pool-wide pump limit, 1–8; a bad value defaults to fully open |
| On-board memory | each board's permanent settings memory, kept through power-off |
| OTA | over-the-air firmware update, sent from the website |
| AiSettings | the programmer's rig rules + compose house-style |
| Kill-switch | remote disable/enable, cloud → gateway → board |
| Leash | opt-in self-lock if a unit loses cloud contact |
| Ghost serial | an unflashed 00000000 board — can't be owned |