Tick + ATOM Matrix
A pressure mat and a 5×5 LED grid. Someone sits down — the device lights up orange and counts. Grab the firmware from GitHub. Configure from the setup page.
ATOM Matrix — 24 × 24mm. 25 RGB LEDs. Accelerometer. Wi-Fi. USB-C. ~$15. Pressure mat adds ~$2.
The ATOM Matrix — same board as the Swamp Glow. Everything built in except the pressure mat, which connects with two wires.
| LEDs | 5×5 WS2812C RGB matrix — 25 LEDs, any color |
| Chip | ESP32-PICO-D4, dual-core 240 MHz, 4MB flash |
| Motion | MPU6886 accelerometer + gyroscope |
| Wireless | Wi-Fi (built in) |
| Power | USB-C, 5V |
| Firmware | CircuitPython + Tick — get from GitHub |
| Button | 1 button hidden under the LED grid |
| Trigger | Pressure mat on GPIO 32 — two wires + 10K pull-up resistor |
Download the firmware zip and extract it on your computer.
Connect the ATOM Matrix via USB-C. It shows up as a drive called CIRCUITPY. Copy the route-13 folder contents onto the drive. The device reboots automatically and starts running. It boots in about 2 seconds.
What happens on boot:
Wiring the mat: One mat wire to GPIO 32 (G32). Other mat wire to GND. A 10K resistor between G32 and 3V3. Three connections total. When someone steps on the mat, GPIO 32 goes LOW and the firmware triggers the display.
The device becomes its own Wi-Fi hotspot. You connect to it and configure from a web page.
Hold the button for 3 seconds. The LED grid turns yellow — the ATOM Matrix is now running as a Wi-Fi access point.
Wi-Fi name: Tick Password: 11111111
Go to http://192.168.4.1 in your phone’s browser. A setup page loads — it’s stored on the device itself, not the internet.
Set the trigger color, brightness, display pattern (“13” or passenger count), and how long the LEDs stay lit after the pressure is released.
The setup page is embedded in the firmware — a single HTML file served from the device. No internet needed. Dark background, orange accents, Route 13 theme. It looks like it belongs to the book.
The AP page also lets you enter Wi-Fi credentials for Step 3 — but that’s optional. You can use the device with just the AP page forever.
Optional. Connect to your home network for remote control.
On the AP setup page, there’s a section for Wi-Fi credentials. Enter your network name and password. Hit save. The device reboots, connects to your Wi-Fi, and now you can reach it from any device on the same network.
With Wi-Fi, you can check the passenger count from another room. Reset the counter remotely. Change the trigger pattern. All from your browser.
If you have multiple devices on the same network — a Swamp Glow and a Route 13, for example — each one has its own IP. Bookmark them. Control any device from any browser on your network.
What’s running on the device. CircuitPython.
The ATOM Matrix runs CircuitPython with the Tick library. All the code lives on the CIRCUITPY drive. Here’s what it does:
The mat connects to GPIO 32 with a pull-up resistor. When someone sits down, the pin goes LOW:
import board
import digitalio
# Pressure mat on GPIO 32 with internal pull-up
mat = digitalio.DigitalInOut(board.G32)
mat.direction = digitalio.Direction.INPUT
mat.pull = digitalio.Pull.UP
def is_pressed():
return not mat.value # LOW when pressed
The 5×5 grid shows “13” in orange when triggered. Each LED maps to a position on the grid:
import neopixel
NUM_LEDS = 25
np = neopixel.NeoPixel(board.G27, NUM_LEDS, auto_write=False)
# "13" on a 5x5 grid (0=off, 1=on)
PATTERN_13 = [
0,1,0,1,1, # row 0
0,1,0,0,1, # row 1
0,1,0,1,1, # row 2
0,1,0,0,1, # row 3
0,1,0,1,1, # row 4
]
def show_13(r, g, b, brightness=20):
for i in range(NUM_LEDS):
if PATTERN_13[i]:
np[i] = (r * brightness // 255,
g * brightness // 255,
b * brightness // 255)
else:
np[i] = (0, 0, 0)
np.show()
Every time the mat is pressed and released, the count goes up. The grid flashes the new number:
passenger_count = 0
was_pressed = False
display_until = 0
while True:
pressed = is_pressed()
# New press — count goes up
if pressed and not was_pressed:
passenger_count += 1
show_13(255, 140, 66) # orange-sodium
display_until = time.monotonic() + 30
# Display timeout
if time.monotonic() > display_until:
np.fill((0, 0, 0))
np.show()
was_pressed = pressed
time.sleep(0.05)
When you hold the button, the device starts a web server:
import wifi
import socketpool
from adafruit_httpserver import Server, Request, Response
# Start AP mode
wifi.radio.start_ap(ssid="Tick", password="11111111")
pool = socketpool.SocketPool(wifi.radio)
server = Server(pool, "/static")
@server.route("/")
def index(request: Request):
return Response(request, body=SETUP_HTML,
content_type="text/html")
@server.route("/save", methods=["POST"])
def save(request: Request):
save_settings(request.form_data)
return Response(request, body="Saved. Rebooting...")
server.serve_forever(str(wifi.radio.ipv4_address_ap))
Two things to hide: the mat and the device.
No soldering on the ATOM Matrix itself. The pressure mat connects with two jumper wires and a 10K resistor. The device is 24mm square — it fits behind almost anything.
Plug in USB. Drag and drop. Done.
The device runs CircuitPython. When you plug it into a computer, it shows up as a USB drive called CIRCUITPY. The Tick code is a set of .py files on that drive. To update:
Download the latest files from the i4Seer GitHub repo:
github.com/i4seer/tick-route-13
Click the green Code button, then Download ZIP. Or use git clone if you know git.
Connect via USB-C. A drive called CIRCUITPY appears on your computer — just like a thumb drive.
Drag the updated .py files from the download onto the CIRCUITPY drive. Replace the old files.
CIRCUITPY/
code.py ← main program
tick_led.py ← LED patterns + "13" display
tick_web.py ← AP setup page
tick_trigger.py ← pressure mat input + counter
settings.toml ← saved settings
The device reboots automatically when you save files. Your settings (color, brightness, pattern, trigger duration) are preserved. Unplug USB and it runs on its own.
Updates are optional. The device works out of the box. But if i4Seer releases new patterns, bug fixes, or features — this is how you get them. No special tools. Just copy files.