A web controller for the Divoom Times Gate (five 128×128 screens), running as a small Node server on your own network. Use it from a PC or phone browser, and it keeps working with the page closed.
- Pictures, animations, banners, effects, scenes, a timer, a scoreboard and light shows
- Plugins for everything that shows live data. The built-in ones are Weather, Spotify now playing, Claude Code status, GitHub repository stats, a music visualizer, vinyl record recognition and listening reports. They can be installed or removed from the page.
- A USB microphone for the visualizer (beat-synced lights) and for recognising records (AudD and/or ACRCloud). You can also listen to it live from your PC, or, for a direct connection such as a turntable, from any phone or computer on your network, in stereo. The page also shows how hard the controller's computer is working (CPU, temperature on a Pi, memory).
- A USB button box (an arcade joystick kit) or game controller: map each button to any action. The box can also go on Wi-Fi with an ESP32 in place of its USB board
- Several Times Gates, each with its own screens and settings
The five screens as the page previews them. Weather:
Claude status: your turn / working, and session and weekly usage.
GitHub: stars, visitors and clones for your repositories, activity, and your contribution graph (shown here with example numbers):
When a repository gets a new star, fork, issue or pull request, it celebrates with confetti and a rainbow edge light:
Mowing: which lawns and areas are due for mowing, from Mowing Tracker: a map of the property coloured by status, the area to mow next, and how many are overdue.
Baseball (MLB): live-ish scores for your team from MLB's public stats feed: the score, inning, runners, outs and count, and who's batting and pitching, with the rainbow edge light when your team scores.
Music visualizer: dances in time with the beat it hears through the microphone.
Vinyl: identifies the record that's playing, within a monthly request budget.
While it listens, the card shows the sound live: a scrolling waveform of the last 9 seconds and a trace of the sound right now. The clip being identified shows in orange. This is only on the page, not the Times Gate.
The card also has the input controls: which microphone or input to use, and Listen live with a volume slider, to hear the record in this browser (the same controls as the Microphone card).
Its settings: the recognition service (AudD, ACRCloud, or AudD with ACRCloud as a backup) and monthly limits, when to switch off, and for records, a turntable speed correction. A turntable that runs even 2% fast isn't recognised, so you enter its measured speed and clips are corrected before they're sent. Vinyl also learns the records you play: each track is fingerprinted as it plays, and next time it's recognised on the controller itself, with no request to the service. If your records are listed on Discogs, add your username and a token and each song is matched to the record you own: the right album, year and cover, and which side and track it is. You can also skip the recognition service altogether: choose the record and side you're about to play from your collection, and its track list names each track.
Now Playing: a full-screen page for a separate display (a small HDMI screen on the Pi, a tablet or a TV),
at /plugins/nowplaying/now.html. It shows the record or Spotify song playing with large cover art and a
progress bar, and works by touch: favourite, identify, start listening. See plugins/nowplaying/README.md.
Listening reports: everything Vinyl identifies and Spotify plays is saved to a listening log. The reports show top artists and songs, plays over time and when you listen, on the page and on the screens.
Button box: give each button a press and a hold action.
Plugins: turn them on or off, move them up or down the page, read their docs, or install new ones from a GitHub link.
This computer: gauges for how hard the controller's computer is working, here a Raspberry Pi 4 streaming stereo audio and listening for records.
It works on a phone too:
- A Divoom Times Gate, already set up on your Wi-Fi with the Divoom app.
- A computer that stays on, on the same network: a Windows PC, a Mac, Linux, or a Raspberry Pi.
- Node.js 18 or newer (the LTS download is fine).
Either use git:
git clone https://github.com/imapping/timesgate-controller.gitor, without git, click the green Code button on GitHub, choose Download ZIP, and unzip it
somewhere permanent (for example C:\TimesGate or ~/timesgate-controller).
Open a terminal in that folder (in Windows Explorer, right-click inside the folder and choose Open in Terminal), then install the two libraries it uses:
npm installThen start the controller:
npm startIt prints the addresses it's running on. Leave that window open while you use it.
- Open
http://localhost:8080in a browser on the same computer. - Press Find on network and click your Times Gate. This asks Divoom's servers which Divoom devices share your internet connection; no account is needed. You can also type the Times Gate's IP address (shown in the Divoom app) and press Connect.
- Give the Times Gate a fixed address (a DHCP reservation in your router), so it's always found in the same place. Do the same for the computer if you'll use it from a phone.
To use it from a phone, open http://<the computer's IP>:8080. On Windows, allow Node.js through
the firewall on private networks the first time it asks.
If you have more than one Times Gate, press Find on network again and add each one. A picker appears at the top of the page.
With a button box and several Times Gates, give one button the Switch Times Gate action. Each press moves the box to the next Times Gate, which flashes its edge light. Buttons set to on the selected one (the default) then act on that Times Gate. You can still tie a button to a particular Times Gate, or to all of them.
Everything (keeping screens updated, alerts, buttons, the timer) runs in the controller itself, so the page doesn't need to stay open, but the controller does.
-
Windows: to start it automatically when you sign in, run this once from the controller's folder in PowerShell (it writes output to
server.log):$run = New-ScheduledTaskAction -Execute powershell.exe -WorkingDirectory $PWD -Argument '-NoProfile -WindowStyle Hidden -Command "& node server.js *> server.log"' Register-ScheduledTask -TaskName "TimesGate Controller" -Action $run -Trigger (New-ScheduledTaskTrigger -AtLogOn -User $env:USERNAME)
Run
Start-ScheduledTask "TimesGate Controller"to start it straight away. To remove it later, runUnregister-ScheduledTask "TimesGate Controller". -
Raspberry Pi or other Linux: use the installer, which sets it up as a service. See Running on a Raspberry Pi.
Each plugin has a Read me link in the Plugins card on the page, and its own card. They all work without setup except:
-
Spotify: create a free app at the Spotify developer dashboard, tick Web API, and add the redirect URI
http://127.0.0.1:8080/api/spotify/callback. Paste its Client ID into the Spotify card and click Connect. Do this on the computer running the controller, because Spotify only accepts that127.0.0.1address (on a Pi, see below). -
Vinyl: choose a recognition service in the Vinyl card: AudD (an API token), ACRCloud (often better with records through speakers; a project host, access key and secret), or AudD with ACRCloud as a backup. Paste the keys into the card from the computer running the controller. Set monthly limits to match your plans. Playing records rather than digital music? They're only recognised at the right speed: check your turntable runs at 33.3 RPM (a turntable speed app, with the phone on the platter), or enter its measured speed in the card's settings and clips are corrected before they're sent. A direct connection (a turntable's USB output, or a line-in sound card) works better than a microphone.
-
Weather: search for your town in the Weather card.
-
GitHub: add your repositories in the GitHub card. For visitors and clones, add a fine-grained token with Administration: Read-only (see the plugin's Read me).
-
Mowing: create an API key on Mowing Tracker's Setup page and paste it into the Mowing card from the computer running the controller.
-
Claude status: tell Claude Code to send its events to the controller. Add to
~/.claude/settings.jsonon the same computer, one entry for each ofSessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Notification,Stop,StopFailureandSessionEnd:{ "hooks": { "Notification": [{ "hooks": [{ "type": "http", "url": "http://127.0.0.1:8080/api/claude/hook", "timeout": 2 }] }] }, "statusLine": { "type": "command", "command": "node /path/to/timesgate-controller/claude-statusline.js" } }The status line entry is optional. It adds your session and weekly usage.
If you used git, run git pull, then npm install, and restart the controller. If you downloaded
a ZIP, download the new one and copy your data/ folder and engine.json into it. Those hold your
settings, logins and Times Gates.
Optional extras:
- Microphone: ffmpeg on Windows, or
arecord(alsa-utils) on Linux. - Button box: set up and tested with a common USB arcade kit: a joystick and 10 buttons on a
DragonRise "zero delay" USB encoder (USB ID
0079:0006, shown as "Generic USB Joystick"). These come in many cheap arcade DIY kits. Other USB gamepads and joysticks should also work: the controller reads the raw USB input, so any joystick, D-pad or button just appears on the page when pressed, with no setup file to write. It works throughnode-hid, whichnpm installinstalls. - Wi-Fi button box: replace the box's USB board with an ESP32 that reads the buttons and sends
each press to the controller, so the box can sit anywhere in the house on a phone charger. It
reports the same inputs as the USB board, so the buttons keep their actions. In the Buttons card,
click Create key (from the controller's computer or one it trusts) and put the key in the
ESP32's settings. The card shows when the box was last heard from. The box sends
POST /api/buttons/input{ "id": "b5.4", "down": true }on each press and release, andPOST /api/buttons/heartbeat{ "held": [...] }every 10 seconds, both withAuthorization: Bearer <key>. A USB box and a Wi-Fi box can be used at the same time.
A Raspberry Pi 4 (or a Pi 400, or a Zero 2 W) makes a quiet, always-on home for the controller, with the USB microphone and button box plugged into it. It has no screen: you use the page from your PC or phone.
-
Prepare the SD card with Raspberry Pi Imager:
- Choose Raspberry Pi OS Lite (64-bit), under Raspberry Pi OS (other).
- Under Edit settings, set the hostname (e.g.
timesgate), a username and password, and your Wi-Fi. Under Services, turn on SSH.
-
Start the Pi with the microphone and button box plugged in. Give it a fixed address (a DHCP reservation) in your router.
-
Connect to it over SSH from your PC, using your username:
ssh yourname@timesgate.local
-
Run the installer on the Pi:
curl -fsSL https://raw.githubusercontent.com/imapping/timesgate-controller/main/scripts/install-pi.sh | bashIt installs Node.js, arecord and fonts, sets the controller up as a service that starts at boot, and lets it read the button box. It also lets the PC you ran it from change setup and tokens (saved in
data/trusted.json), since nobody sits at the Pi itself. At the end it shows the page's address, e.g.http://timesgate.local:8080.When it's done, it ends like this:
== 6/6 Checking it started The TimesGate controller is running: http://192.168.1.128:8080 (or http://timesgate.local:8080) Moving from a PC? Stop the controller there, copy its data/ folder and engine.json into /home/yourname/timesgate-controller, then run: sudo systemctl restart timesgate Logs: journalctl -u timesgate -fTo update later, run the same command again. Your settings are kept.
Moving from a PC: stop the controller on the PC so the two don't both drive the Times Gates. For the Windows task from step 5, that's:
Stop-ScheduledTask "TimesGate Controller"; Disable-ScheduledTask "TimesGate Controller"Then copy your settings across from the PC's controller folder, and restart the service on the Pi:
scp -r data engine.json yourname@timesgate.local:timesgate-controller/ssh yourname@timesgate.local sudo systemctl restart timesgateThis keeps your Times Gates, plugin settings, Spotify login, tokens and button assignments. Button assignments made on Windows work unchanged on the Pi. The Pi finds a USB microphone by itself (or choose it in the Microphone card):
Claude status from a PC: point Claude Code's hooks at the Pi instead of 127.0.0.1, using its
address in each hook's url (e.g. http://192.168.1.128:8080/api/claude/hook). The PC must be
listed in the Pi's data/trusted.json, which it is if you ran the installer from it. For the status
line, keep claude-statusline.js on the PC and tell it where the Pi is, in ~/.claude/settings.json:
{ "env": { "TIMESGATE_URL": "http://192.168.1.128:8080" } }Logging in to Spotify on a Pi: Spotify only sends the login back to 127.0.0.1. Copying your
settings from a PC keeps an existing login. For a new one, connect with a tunnel so the PC's
127.0.0.1:8080 reaches the Pi, then open http://127.0.0.1:8080 on the PC and log in there:
ssh -L 8080:127.0.0.1:8080 yourname@timesgate.localA screen on the Pi: a small HDMI screen (a 7" touch screen suits it) can show the Now Playing page full-screen from boot, with no desktop installed. Plug it in (HDMI, plus USB for touch), then run:
curl -fsSL https://raw.githubusercontent.com/imapping/timesgate-controller/main/scripts/install-kiosk.sh | bashIt installs cage (a minimal kiosk display) and Chromium, and
runs them on the first console in place of the text login. Its log is journalctl -u timesgate-kiosk -f.
To show another page, set KIOSK_URL before bash. To go back to the text login, add -s remove
after bash. If the picture is the wrong size, the screen may not be telling the Pi its resolution:
add a mode to /boot/firmware/cmdline.txt, e.g. video=HDMI-A-1:1024x600@60, and reboot.
A 3D-printable case for the 7" Duinotech XC9026 screen, with a stand and keyholes for a wall, is in
hardware/screen-case.
Useful commands on the Pi: journalctl -u timesgate -f shows the log, and
sudo systemctl restart timesgate restarts it.
See PLUGINS.md, which can also be read from the page, and copy examples/hello/ to
start. CLAUDE.md describes the architecture.
Some plugins use online services. Each user sets up their own account or key; none are included.
- Weather: data by Open-Meteo.com, licensed CC BY 4.0. The free API is for non-commercial use.
- Spotify: needs your own Client ID from the Spotify developer dashboard. Use is subject to Spotify's developer terms.
- Vinyl: uses AudD and/or ACRCloud music recognition, paid services with your own keys. Missing album art and links are looked up on Spotify (oEmbed, or a search through your connected Spotify) and in Apple's iTunes Search. The plugin only listens on request and has monthly caps. Optionally, it reads your own record collection from the Discogs API with your personal access token, to match songs to the records you own. That data is provided by Discogs and is subject to its API terms of use.
- GitHub: uses the GitHub API. It works without a token; an optional read-only token of your own adds visitors, clones and your contribution graph.
- Baseball (MLB): uses MLB's public stats feed (statsapi.mlb.com), no key needed; its data is for personal, non-commercial use.
- Mowing: uses Mowing Tracker's read-only status API with your own API key.
- Divoom cloud: used only to find Times Gates on your network, and to list clock faces.
Every song Vinyl identifies, and every song you play on Spotify (once it has played for 30 seconds),
is saved to a listening log, an SQLite database at data/listening.db. The Listening reports
plugin shows it: top artists and songs, plays over time, and when you listen. You can star songs as favourites, and add a note to any play (it skips,
crackles, needs cleaning, was matched wrongly, or your own comment); the reports list every noted track.
Settings, logins and tokens are saved in data/, which is never served by the web server and is
excluded from git.
This is an unofficial project, not affiliated with or endorsed by Divoom, Spotify, AudD, ACRCloud, Discogs, MLB or Anthropic. Divoom and Times Gate are trademarks of Divoom; Spotify is a trademark of Spotify AB; Claude is a trademark of Anthropic.
MIT © 2026 Gary Nicholson · @imapping on X
The dependencies are also permissively licensed: @napi-rs/canvas (MIT, bundles Skia, BSD-3),
node-hid (MIT/X11, with hidapi used under its BSD licence), node-addon-api and
pkg-prebuilds (MIT). ffmpeg and arecord are separate programs. They are not included and are
only run when needed.























