Lumatron is a LED sculpture system. You are free to play with this code, but as per the license you may not make money from it.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Controller │ │ Admin │ │ Emulator │
│ (browser) │ │ (browser) │ │ (browser) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ WSS :7777 │ HTTPS │ WSS
▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ Relay server (HTTPS + WSS) │
│ e.g. my.lumatron.art / localhost │
└──────┬─────────────────┬─────────────────────────┘
│ │ ▲
│ WSS │ WSS (out) │
▼ ▼ │
┌──────────────┐ ┌─────────────┐ │ stls
│ Raspberry Pi │ │ Arduino │◄─────────┐ │
│ Node + Py │◄─│ esp32.ino │──────────┤ │
└──────┬───────┘ └────┬────────┘ pixels │ │
│ drives │ drives info │ │
▼ ▼ │ │
╔═══════════════════════╗ ┌────────┴─┴────┐
║ Physical piece ║◄────────┤ Creation │
║ (LED sculpture) ║ designs │ console (dev) │
╚═══════════════════════╝ └───────────────┘
- Orbs always connect outbound to the relay, so they work behind NATs without port forwarding.
- The relay routes controller / admin / emulator messages to the right orb over its open WebSocket, and serves the websites for the controller, admin, and emulator.
- The Creation console is a dev-time tool (port 8000): it designs the physical piece (3D-printable parts) and writes geometry (pixel info and stls) into the repo.
- Each physical piece is driven by exactly one orb (Pi or Arduino).
- In dev (
DEV_MODE: true), a single machine plays all roles: relay, local Pi-style orb, and emulator standing in for a real piece.
Here's how to connect a piece that does not already have an internet connection (if no piece is already connected to the same wifi you're on these instructions can also be viewed by visiting https://my.lumatron.art)
- Plug in the Lumatron box into the power source and the box into the piece (do not plug the piece directly into the usb-c wall plug)
- Wait for the box to boot up and the access point pattern (waves eminating from the bottom point) to show (takes a couple minutes for the raspberry pi based boxes)
- Join the wifi named Lumatron-name
- Enter the wifi name (SSID) and password in the captive portal
- Visit or refresh
https://my.lumatron.artonce the first pixel turns off
- Visit
https://my.lumatron.art - (optional) Turn the site into a progressive web app by following the instructions at the bottom of the page
- Clone (optionally fork first) this repo (
git clone https://github.com/adrianmarple/orbitron) on your local machine (Windows not supported) - cd to the root of the repo (folder should be named
orbitron) - Install node if you haven't already
- Run
scripts/admin_install.sh(in thescriptsfolder of the newly cloned repo) - Start the emulator by running
sudo ./startscript.sh - Visit
http://localhost:1337for the controller - Visit
http://localhost:1337/test/viewfor the emulator (which also contains a controller)
- Make sure you've run
./admin_install.sh - Ensure the local server (
sudo ./startscript.sh) is running - Visit url
http://localhost:1337/admin - Follow instructions for entering a master key
- More details in the admin folder README
See the idlepatterns folder README
- Fork this repo
- Create an ubuntu server, for instance the lumatron.art is currently hosted through Digital Ocean
- Add a domain (or subdomain of an existing domain you control) to the server (this is required to serve over https)
- Wait and make sure the DNS records are in place (i.e. by checking https://www.whatsmydns.net/)
- Open a console into root of your new server
- Clone your forked repo, i.e.
git clone https://github.com/YOUR_GITHUB_NAME/orbitron - Run
cd orbitronthenscripts/server_install.shand enter your domain (and eventually email and other certbot prompts) - Test by visiting
https://your_domain.com(you should see "No pieces found on the same wifi")
- Arduino
- Clear entire arduino flash
esptool.py --chip esp32c3 --port /dev/ttyUSB0 erase_flash - Edit arduino/esp32/esp32.ino: find and replace "my.lumatron.art" with your server
- Install adruino cli if you haven't already:
scripts/arduino_install.sh- Note two github hooks are installed with this script. One runs
scripts/arduino_build.shon git push and uploads the compiled firmware to the server - The server url is currently hardcoded, so you should edit "arduino_build.sh" to use your own server, if you want to push to your own repo.
- Note two github hooks are installed with this script. One runs
- Upload to the arduino using
scripts/arduino_upload.sh
- Clear entire arduino flash
- Raspberry pi
- Request an unlocked SD along with a piece, email adrian@marplebot.com an request it be unlocked remotely, or follow the Micro SD card setup instructions below
- Get local IP address (once the admin console is set up, you'll be able to get the ip address directly from there)
- MacOS:
sudo nmap -sn $(ipconfig getifaddr en0)/24 - Linux:
sudo nmap -sn $(hostname -I | cut -d' ' -f1)/24
- MacOS:
ssh pi@<IP address>(passwordlumatron) into the piece- Change the password by running
passwd - Edit
orbitron/config.jsto add the lineRELAY_HOST: "your-domain-or-ip",(also removeORB_KEYif it's there) - Run
pm2 restart all
- Test by visiting
https://your_domain.comagain (you should now see the piece)
- Ensure your server is properly set up
- Visit url
https://your-domain.com/admin - Enter the masterkey (from
masterkey.txtfrom your server's console) as prompted - I recommend hitting the "Set ORB_KEY" button followed by the "Save config.js" button for all connected orbs (including the server itself - default named "demo")
- Note: if this button is not visible hit the "config" button first
- Again see the admin folder README for more details
You can set up pieces so that pushing to github automatically triggers pieces to restart and pull changes:
- Direct a github action to point to your server
- Add
CONTINUOUS_INTEGRATION: true,to the config of a piece you want to restart on receiving updates
Most things the controller can do can also be done over plain HTTP (useful for scripting: Home Assistant, Shortcuts, cron, or any other forms of automation). This includes preferences, saved presets, the timer schedule, and dimming, but omits game inputs. It is served by the server (i.e. my.lumatron.art) under /api/v1.
GET /api/v1/orbs lists the pieces available to you. Every other path is relative to /api/v1/orbs/<piece>, where <piece> is a piece's name or its alias (e.g. https://my.lumatron.art/api/v1/orbs/kitchen/prefs).
| Method | Path | Body | Description |
|---|---|---|---|
GET |
/prefs |
— | All current settings (pattern, colors, brightness) |
PATCH |
/prefs |
{"<key>": value, ...} |
Change one or more settings, leaving the rest alone |
DELETE |
/prefs |
— | Reset all settings back to defaults |
POST |
/dim |
— | Step brightness, the same as the hardware button |
GET |
/presets |
— | Saved preset names, which one is current, and cycle membership |
PUT |
/presets/<name> |
— | Save the current settings as <name> |
POST |
/presets/<name>/load |
— | Switch to <name> |
DELETE |
/presets/<name> |
— | Delete <name> |
POST |
/presets/<name>/copy |
{"copyName": "..."} |
Copy <name> to a new preset |
POST |
/presets/<name>/rename |
{"newName": "..."} |
Rename <name> |
POST |
/presets/<name>/reorder |
{"targetName": "..."} |
Move <name> in front of targetName |
POST |
/presets/cycle |
— | Advance to the next preset in the cycle |
GET |
/schedule |
— | Timer settings, plus the daily and weekly schedules |
PUT |
/schedule |
{"useTimer": true, "schedule": [...]} |
Update timer settings |
GET |
/state |
— | All of the above at once |
Preset names may contain spaces, so URL-encode them (/presets/Evening%20Glow/load).
A few things worth knowing:
- There's no authentication by default, which is the same as the controller — anyone who knows a piece's name can already control it. To lock it down, add
REST_API_KEY: "some-secret",to your server'sconfig.jsand sendAuthorization: Bearer some-secretwith every request. GET /api/v1/orbsonly lists pieces on the same wifi as whoever is asking, so the whole fleet isn't enumerable.- The API connects to a piece the same way a controller does, but without claiming one of the six player slots, so it won't interfere with games or with anyone using the controller. Changes made either way show up in the other immediately.
See API.md for the full endpoint reference.
Here's a list of things I would welcome receiving PRs for.
- New idle patterns — See idlepatterns/README.md for details
- New games — See games/README.md for details
- Clarifications or other improvements to any READMEs
- UX improvements or other quality of life features for the controller
- General optimizations or improvements
Requires a Xiao esp32c3, esp32c6, or esp32s3
- Run
scripts/arduino_install.sh - Plug into your computer
- Run
scripts/arduino_upload.shto compile and upload to your arduino - For the first time after installing, check for an access point and add a wifi connection
- Download an unlocked SD card image from dropbox
- Burn to SD card using
ddor Balena Etcher - Using
dd- Update
/dev/disk4or/dev/sdabelow with the correct drive as determined fromdiskutil listorlsblkon Linux diskutil unmountDisk /dev/disk4orsudo umount /dev/sda1 && sudo umount /dev/sda2on Linux- go to Download directory or wherever the SD image download is
sudo dd if=lumatron.img of=/dev/disk4 status=progress- On MacOS use
gddinstead- Install with
brew install coreutils sudo gdd if=lumatron.img of=/dev/disk4 status=progress
- Install with
- Update
- Insert SD card into raspberry pi and power on
- Connect via
ssh pi@<<IP_ADDRESS>>passwordlumatron - Change to your own password
- Download Raspberry Pi Imager: https://www.raspberrypi.org/software/
- Select the latest 64-bit Raspberry PI OS
- Click the gear icon to change the settings of the install
- Set hostname to
orbitron - Enable SSH with password authentication
- enter pi as the username and enter a password
- Configure wireless LAN to connect to your local wifi
- Set timezone and select us Keyboard layout
- Save and click
WRITEto burn the image - Plug SD Card into PI
- Connect PI to monitor/TV via HDMI cable
- Connect USB keyboard to PI as well
- Power on the PI
- Wait for some time, it may need to reboot 2 or more times
- You should see
orbitron login:when it is ready - Login with the username and password you set
sudo apt install git
git clone https://github.com/adrianmarple/orbitron~/orbitron/scripts/pi_install.sh
- Update
/dev/disk4below with the correct drive as determined fromdiskutil listorlsblk sudo dd if=/dev/disk4 of=lumatron.img bs=8M count=820 status=progress- On MacOS use
gddinstead- Install with
brew install coreutils sudo gdd if=/dev/disk4 of=lumatron.img bs=8M count=820 status=progress
- Install with