A CircuitPython project for the Adafruit MagTag that turns it into a low-power home info display. Four buttons drive four modes; the board deep-sleeps between interactions and draws ~250 µA at rest.
| Button | LED color | What it shows |
|---|---|---|
| A (leftmost) | Red | WiFi QR code - scan to join the network |
| B | Blue | Current weather + 5-day forecast (Open-Meteo, no API key needed) |
| C | Purple | Party mode - fires a Home Assistant webhook, then does a 15-second NeoPixel rainbow |
| D (rightmost) | Amber | Battery voltage, estimated charge percentage, time on battery, and light level |
Every mode auto-refreshes every 4 hours without requiring a button press. When Datadog telemetry is configured, each wake sends battery voltage, battery percentage, battery uptime, raw light level, and light level normalized to a 0-100 scale. Button presses also send the latest stats immediately.
On first boot, the WiFi QR screen silently connects to fetch the current time and stores it as the uptime anchor. Time on battery resets whenever the device loses power - which is exactly when you'd want it to.
- Adafruit MagTag (ESP32-S2, pre-2025 edition)
- 2.9" grayscale e-ink display (296×128, ILI0373)
- 4 NeoPixels, 4 buttons, built-in LiPo connector
-
CircuitPython 10.1.3 - grab the
.uf2from circuitpython.org -
Libraries (copy to
CIRCUITPY/lib/):adafruit_magtagadafruit_portalbaseadafruit_display_textadafruit_bitmap_fontadafruit_imageloadadafruit_requestsadafruit_miniqrdatadog.pyfrom q/circuitpython-datadog if Datadog telemetry is enabledneopixelsimpleio
Get them from the CircuitPython Library Bundle matching your CP version.
-
Copy everything inside
CIRCUITPY/to your MagTag'sCIRCUITPYdrive. -
Copy
settings.toml.exampletoCIRCUITPY/settings.tomland fill it in:
CIRCUITPY_WIFI_SSID = "your-network"
CIRCUITPY_WIFI_PASSWORD = "your-password"
# Optional: serial debug logs
DEBUG = 0
# Light sensor calibration
LIGHT_SENSOR_MIN = 0
LIGHT_SENSOR_MAX = 65535
# Weather location - find coordinates at latlong.net
WEATHER_LAT = "37.7749"
WEATHER_LON = "-122.4194"
# Optional: Home Assistant webhook for party mode
HA_URL = "http://homeassistant.local:8123"
HA_PARTY_WEBHOOK_ID = ""
# Optional: Datadog metrics
DATADOG_API_KEY = ""
DATADOG_SITE = "datadoghq.com"
DATADOG_METRIC_PREFIX = "magtag.home"
MAGTAG_NAME = "home"- The board resets automatically when
settings.tomlis saved. Button B shows weather immediately; the other modes work offline.
settings.tomlis gitignored - never commit credentials.
The board uses deep sleep between button presses and scheduled refreshes. On wake, alarm.wake_alarm identifies which button fired, the matching mode runs, optional telemetry flushes, and the board sleeps again with PinAlarms on all four buttons plus a 4-hour TimeAlarm. This means the code restarts from scratch on every wake - there's no persistent loop.
Party mode is the exception: it stays awake for 30 seconds (15s rainbow + 15s cooldown), then reloads into WiFi QR mode.
Set DEBUG = 1 in settings.toml and connect over serial to see wake source, WiFi connection state, NTP time, sampled board stats, weather fetches, Datadog intake URL, Datadog tags, and flush result. Secrets such as the Datadog API key are never printed.
For light calibration, collect a few light_raw readings in the actual places/lighting you care about. Set LIGHT_SENSOR_MIN to a useful dark reading and LIGHT_SENSOR_MAX to a useful bright reading; light.percent is clamped to 0-100 across that calibrated range.
Datadog telemetry is disabled unless DATADOG_API_KEY is set. When enabled, the MagTag sends these gauge metrics on each wake:
magtag.home.battery.voltagemagtag.home.battery.percentmagtag.home.battery.uptime_secondsmagtag.home.light.rawmagtag.home.light.percent
DATADOG_METRIC_PREFIX changes the magtag.home prefix, DATADOG_SITE supports non-US1 Datadog sites, and MAGTAG_NAME becomes the device: tag. The light percentage is the raw analog sensor reading mapped across LIGHT_SENSOR_MIN and LIGHT_SENSOR_MAX.
Metrics include wake:startup, wake:timer, or wake:button; button wakes also include button:A, button:B, button:C, or button:D.
Keep the Datadog helper source in the separate q/circuitpython-datadog project. For deployment, copy its datadog.py onto the device at CIRCUITPY/lib/datadog.py; this MagTag repo intentionally does not track that library file.
Weather comes from Open-Meteo - free, no account or API key required. The display shows current temperature, today's high/low, wind speed/direction, sunrise/sunset, and a 5-day forecast with icon sprites.
MIT