Autonomous weather display for the iDotMatrix 32Γ32 LED pixel panel β no phone, no cloud, no interaction required. Current weather is fetched from the internet, rendered into a looping pixel animation, and pushed to the panel over Bluetooth Low Energy. π‘
A pixel cat π± lives on the display and wanders around between weather updates.
- 9 animated weather scenes β clear day, clear night, partly cloudy, cloudy, fog, rain, heavy rain, snow, thunderstorm
- Smooth animations β each scene loops with 6β12 frames; only changed pixels are sent over BLE, so the panel never flashes
- Live temperature β rendered in a custom pixel font
- Night tinting β colours shift warmer after sunset
- Automatic refresh β fetches weather from Open-Meteo on a configurable interval (default: every 10 minutes)
A 5-pixel-wide cat overlaid on every frame. It has a full behaviour state machine:
| Behaviour | Description |
|---|---|
| walk | Strolls back and forth, blinks occasionally |
| sit | Sits and breathes |
| lie | Flops down |
| jump | Leaps and lands |
| perch | Climbs to a weather icon and sits on top |
| dream | Sleeps with floating dream bubbles |
| burp | Special move β leaves a little residue |
| poo | Special move β also leaves a little residue |
Day and night have different behaviour weights (night is calmer: more dreaming, less jumping).
A local HTTP server (port 3000) exposes a REST API and a web UI for live control:
| Endpoint | Description |
|---|---|
GET /api/health |
Current state: weather, pet behaviour, brightness, schedules |
GET /api/state |
Server-sent events stream of the health object |
GET /api/frame |
Server-sent events stream of the current rendered frame (base64 PNG) |
GET /api/logs |
Live log stream |
POST /api/control/brightness |
Set day/night brightness (0β100) |
POST /api/control/night-hours |
Configure dimming window |
POST /api/control/power-schedule |
Auto on/off by hour of day |
POST /api/control/behavior |
Force the pet into a specific behaviour |
POST /api/control/weather |
Override the weather (useful for testing) |
POST /api/control/pause |
Pause/resume rendering |
npm run dev:sim opens a browser-based dev app with three tabs:
Simulator β live pixel preview with weather and pet controls, no hardware needed.
Studio β pixel sprite editor for the pet. Edit individual frames, preview them live in the simulator, and save directly to src/sprites.ts.
Logs β streamed output from the running app.
| Target | How |
|---|---|
| macOS (dev) | npm run dev β sidecar + TypeScript with hot-reload |
| macOS (background) | npm run service:install β launchd Login Item, auto-restarts on crash |
| Raspberry Pi | Docker Compose β two containers (app + sidecar), push-based deploy via GitHub Actions self-hosted runner |
Open-Meteo API
β HTTPS
βΌ
ββββ TypeScript (Node.js) βββββββββββββββββββββββ
β weather/ β WeatherSnapshot β
β render/ β 32Γ32 RGB buffer β PNG β
β scheduler/ β every N minutes β
β transport/ β POST PNG βββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββΌββββββββββ
β HTTP localhost
βΌ
ββββ Python sidecar (bleak) ββββ
β FastAPI: /display, /health β
β idotmatrix-api-client β
ββββββββββββββββ¬ββββββββββββββββ
β BLE GATT
βΌ
iDotMatrix 32Γ32 panel
The BLE protocol is undocumented and only exists as a reverse-engineered Python library. TypeScript handles everything else; the Python sidecar is the only part that touches Bluetooth. The two communicate over a local HTTP boundary: TypeScript sends a 32Γ32 PNG, the sidecar pushes it to the panel.
- iDotMatrix 32Γ32 LED panel (the AliExpress model, Bluetooth name
IDM_32*32_*) - macOS or Linux host within BLE range of the panel
- Node.js β₯ 20
- Python 3.11+
- macOS: Bluetooth permission granted to your terminal app (System Settings β Privacy & Security β Bluetooth)
# 1. Clone and install
git clone https://github.com/brmk/iDotMatrix-Meoweather.git
cd iDotMatrix-Meoweather
npm install
# 2. Set up the Python sidecar
cd sidecar
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
cd ..
# 3. Configure
cp .env.example .env
# Edit LATITUDE, LONGITUDE, and optionally INTERVAL_SECONDS
# 4. Run
npm run devThe TypeScript app and Python sidecar start together. The panel updates within a minute on the first cycle (BLE scan takes ~15 s on first connect).
npm install
npm run dev:sim
# Open http://localhost:8766One-time host prep:
# On the Pi
sudo apt-get install -y docker.io docker-compose-plugin
sudo usermod -aG docker "$USER"
sudo loginctl enable-linger "$USER"Deploy:
cp .env.example .env
# Edit LATITUDE, LONGITUDE
# Edit APP_IMAGE and SIDECAR_IMAGE to your GHCR namespace
./scripts/deploy-rpi.sh
./scripts/install-rpi-user-service.shAll variables are read from .env (copy from .env.example). All have sensible defaults.
| Variable | Default | Description |
|---|---|---|
LATITUDE / LONGITUDE |
49.5535 / 25.5948 |
Your location |
INTERVAL_SECONDS |
600 |
Weather refresh interval |
SHOW_CLOCK |
true |
Temperature (left) and clock (right) share the bottom line; false = temperature only |
BLE_ADAPTER_MAC |
β | Linux only: pin the panel to this Bluetooth adapter |
BLE_PANEL_ADDRESS |
β | Linux only: drop a stale BlueZ link to the panel on startup |
BLE_FRAGMENT_SIZE |
negotiated MTU β 3 | Cap the size of a single BLE write |
SIDECAR_URL |
http://127.0.0.1:8765 |
Local sidecar address |
DEVICE_NAME_PREFIX |
IDM |
BLE name prefix used for discovery |
SCAN_TIMEOUT |
15 |
BLE discovery timeout (seconds) |
DAY_BRIGHTNESS |
80 |
Panel brightness during the day (0β100) |
NIGHT_BRIGHTNESS |
25 |
Panel brightness at night (0β100) |
Brightness and night-hours settings persist across restarts in runtime.json and can be updated at runtime via the control API.
src/
weather/ # Open-Meteo client β WeatherSnapshot
render/
icons/ # 9 weather icon animators
text/ # Pixel font renderer
pet/ # Pet sprite system and behaviour state machine
scene/ # Frame composer, night tinting, temperature overlay
scheduler/ # Interval loop
transport/ # HTTP client for the sidecar
control.ts # REST API + SSE server
sidecar/ # Python BLE bridge (FastAPI + bleak)
dev/ # Vite + React dev app (simulator, studio, logs)
docs/ # Architecture, runbook, ADRs
| Layer | Tech |
|---|---|
| App | TypeScript / Node.js |
| BLE bridge | Python, FastAPI, bleak, idotmatrix-api-client |
| Weather data | Open-Meteo (free, no API key) |
| Dev UI | Vite + React |
| Tests | Vitest (unit + deterministic render regression) |
| Production deploy | Docker Compose + GitHub Actions |
MIT β see LICENSE.



