Skip to content

Repository files navigation

echo

LED Matrix Proxy — turn any event into a light show on your ESP8266 matrix display.

GoDockerCILicense: MIT

echo is a lightweight HTTP proxy that sits between your home automation, monitoring stack, or any webhook source and an ESP8266-based 8×8 LED matrix. Send a JSON event, watch the matrix light up.

 Webhook / Home Assistant / n8n
│
▼
┌─────────────┐ TCP / binary protocol ┌──────────────┐
│ echo │ ──────────────────────────► │ ESP8266 LED │
│ (Go proxy) │ ◄────────────────────────── │ Matrix 8×8 │
└─────────────┘ auto-reconnect └──────────────┘
│
Prometheus /metrics
Swagger UI /docs
Readiness /readyz

Features

  • Event-driven — POST a JSON event; rules decide which animation plays
  • Multi-device — manage several matrices from one service, each with independent queues and backgrounds
  • Idle background — set a per-device animation that the scheduler restores whenever the display goes idle
  • Config-authored animations — write 8×8 pixel art in YAML, no code required
  • 22 firmware presets — trigger built-in ESP8266 effects (matrix_rain, fire, rainbow, heartbeat …) via API
  • Auto-reconnect — robust TCP reconnect with exponential backoff and heartbeat probing
  • Prometheus metrics — per-device counters, gauges, and histograms out of the box
  • Swagger UI — interactive API explorer at /docs
  • ARM-ready — multi-arch Docker images (amd64 · arm64 · arm/v7) for Raspberry Pi

Quick Start

Docker (recommended)

# 1. Create config files
cp configs/config.example.yaml configs/config.yaml
# → edit matrix.host to your device IP
cp .env.example .env
# → set MATRIX_PROXY_ADMIN_TOKEN=your-secret# 2. Run
docker compose up -d
# 3. Verify
curl http://localhost:8080/healthz
# {"status":"ok"}

Send your first notification

curl -X POST http://localhost:8080/api/v1/devices/living-room/notify \
-H "Content-Type: application/json" \
-d '{"message": "Hello!", "duration": "3s"}'

The matrix plays the notification animation, then returns to the configured idle background.

Play a firmware preset

# Play matrix_rain by animation ID (look up effect config from registry)
curl -X POST http://localhost:8080/api/v1/devices/living-room/preset/matrix_rain_background \
-H "Authorization: Bearer your-secret"# Or send custom preset parameters directly
curl -X POST http://localhost:8080/api/v1/devices/living-room/matrix/preset \
-H "Authorization: Bearer your-secret" \
-H "Content-Type: application/json" \
-d '{"effect_id": 11, "interval": "80ms", "color": {"r": 255, "g": 40, "b": 0}}'

Pull the pre-built image

docker pull ghcr.io/w0rxbend/echo:latest

Configuration at a Glance

configs/config.yaml controls everything. The minimal required fields:

devices:
living-room: # device ID used in API pathshost: "192.168.1.127"# ESP8266 IPport: 7777background:
animation: "matrix_rain_background"restore_on_idle: trueanimations_file: "configs/animations.yaml"rules_file: "configs/rules.yaml"

Multiple devices, each with independent idle animations, queues, and connection settings:

devices:
living-room:
host: "192.168.1.127"background:
animation: "matrix_rain_background"restore_on_idle: trueoffice:
host: "192.168.1.128"layout:
rotation: 90# compensate for physical mountingbackground:
animation: "amber_rain_background"restore_on_idle: true

See configs/config.example.yaml for all options.

Animations

Drop YAML into configs/animations.yaml. Three authoring styles:

Pixel art frames — draw your own 8×8 art with a palette:

animations:
status_check:
type: framespalette:
".": "#000000"G: "#00FF55"W: "#FFFFFF"frames:
- delay: 120msrows:
- "........"
- "......G."
- ".....GG."
- ".W..GG.."
- ".WW.G..."
- "..WWW..."
- "...W...."
- "........"

Firmware presets — trigger built-in ESP8266 effects (matrix_rain, fire, rainbow, heartbeat, and 18 more):

animations:
matrix_rain_background:
type: firmware_preseteffect_id: 12interval: 90mscolor: "#00FF55"

Generated — aliases for built-in app renderers:

animations:
alert_pulse:
type: generatedgenerator: notification

See configs/animations.example.yaml for a full library including spinner, wipe_down, checkerboard, alert_blink, and more.

Rules

Rules map incoming events to animations. configs/rules.yaml:

rules:
- id: http_notify_defaultwhen:
source: httptype: notifyplay:
animation: alert_pulsepriority: 50duration: 2srestore: background # ← return to idle background when done

API

Interactive docs:http://localhost:8080/docs

All device-specific endpoints are namespaced by device ID:

EndpointMethodDescription
/api/v1/devices/{device}/notifyPOSTSend a notification
/api/v1/devices/{device}/eventsPOSTPublish a generic event
/api/v1/devices/{device}/playPOST ¹Play a renderable animation
/api/v1/devices/{device}/preset/{id}POST ¹Play a firmware preset by animation ID
/api/v1/devices/{device}/backgroundGET / PUT ¹Read or change the idle animation
/api/v1/devices/{device}/queueGET / DELETE ¹Inspect or clear the play queue
/api/v1/devices/{device}/matrix/*POST ¹Direct display controls
/api/v1/animationsGETList playable animation IDs
/api/v1/animations/catalogGETFull animation catalog
/api/v1/devicesGET ¹List configured device IDs
/openapi.jsonGETOpenAPI 3.0 spec
/metricsGETPrometheus metrics
/readyzGETReadiness (per-device breakdown)
/healthzGETLiveness

¹ Requires Authorization: Bearer <token> when bound to a non-loopback address.

Change the idle background at runtime

curl -X PUT http://localhost:8080/api/v1/devices/living-room/background \
-H "Authorization: Bearer your-secret" \
-H "Content-Type: application/json" \
-d '{"animation": "amber_rain_background", "restore_on_idle": true}'

Observability

Prometheus

All metrics carry a device label. Scrape /metrics — key signals:

MetricWhat it tells you
matrix_proxy_matrix_connected{device}Is the device reachable?
matrix_proxy_play_queue_depth{device}Animations waiting to play
matrix_proxy_background_state{device,kind,state}Idle background convergence
matrix_proxy_events_total{source,type}Event throughput
matrix_proxy_matrix_reconnects_total{device,source}Reconnect attempts

Optional observability stack

docker compose --profile observability up -d
# Prometheus → http://localhost:9090# Grafana → http://localhost:3000 (admin / admin)

Readiness

curl http://localhost:8080/readyz | jq .devices
{
"living-room": {
"scheduler_state": "ready",
"matrix_connected": true,
"background": {
"state": "converged",
"configured_id": "matrix_rain_background"
}
}
}

Running Locally (without Docker)

go build -o bin/matrix-proxy ./cmd/matrix-proxy
MATRIX_PROXY_ADMIN_TOKEN=dev \
./bin/matrix-proxy -config configs/config.yaml -log-level debug

Full setup guide including native Go, Docker Compose, and hardware validation tips: RUNNING_LOCALLY.md.

Development

go test ./... # run all tests
go build ./... # build check

For internal contracts, implementation notes, and Prometheus metric reference, see docs/dev-guide.md.

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages