01Overview
Live demo: https://sebzuddas.github.io/axiometa-digital-twin/ (interactive 3D building, runs in the browser)
Built at an Axiometa hackathon. Firmware for an Axiometa Genesis Mini ("ENV" node) that reads temperature, humidity, light and a dial, and streams them to a live 3D digital twin of a building.
02Why it matters: sensing a whole building, cheaply
Most building monitoring is either one thermostat per zone or an expensive, installer-only system. This project goes the other way: a building owner can deploy many identical, low-cost sensor nodes and have each one appear in the twin automatically.
- One board, one firmware. Every room runs the same Genesis Mini image. Rooms differ only by node ID.
- No soldering, no custom PCBs. Sensors are Axiometa AX22 modules that click into any of the board's four ports, so changing what a node measures means swapping a module, not redesigning hardware.
- Scale by repetition. A new room means another node on USB or battery power. It publishes to its own topic (
axm/<node-id>/telemetry) and shows up in the viewer with no code changes. - See the whole building at once. Rooms are colour-coded by temperature, humidity or light in 3D, so hot spots, stuffy rooms and sunlit zones are visible at a glance.
- Cheap hardware. An ESP32-S3 board plus a few hobby-grade sensors per room (a DHT11 and an LDR here), so instrumenting every room is realistic, not just a showcase floor.
- A twin, not just a dashboard. The sensed values feed a building simulation (heat flow, occupants, HVAC control), so owners can ask "what if" as well as "what is".
The demo page lets you click rooms to deploy nodes and watch the building fill in. It is a simulation of the viewer; no hardware is needed.
sensors ──► Genesis Mini ──USB serial──► serial→MQTT bridge ──► simulation ──► 3D twin
(DHT11, LDR, encoder) KEY:value @ 5 Hz (Rust) (three.js)
Status: hackathon prototype. This repo holds the ENV node firmware and the project page. The serial→MQTT bridge, Rust simulation and full spec live in the companion hackathon project (
AxiometaHack, not yet published) and are not in this repo.
03Credits
Built using Axiometa hardware: the Genesis Mini board and AX22 modules. Hackathon project by Seb Zuddas.
04Hardware
| Port | Part | Pins | Signal |
|---|---|---|---|
| P1 | DHT11 | data on P1_IO1 |
temperature, humidity |
| P2 | Rotary enc. | BTN P2_IO0, CLK P2_IO1, DT P2_IO2 |
dial (0–100) + button |
| P3 | LDR | analog out P3_IO0 (GPIO9, ADC1) |
light level |
Board: ESP32-S3-N4R2 (4 MB flash, 2 MB QSPI PSRAM), custom axiometa_genesis_mini variant so the Px_IOy pin aliases exist.
05Serial protocol
115200 baud. After boot the board prints READY, then emits one frame every 200 ms (5 Hz), one KEY:value per line:
| Key | Range / unit | Notes |
|---|---|---|
TEMP |
°C, 1 dp | DHT11, sampled every 2 s; 0.0 until first valid read |
HUM |
% RH, 1 dp | DHT11, same cadence |
SOLAR |
0.0–1.0 | LDR, mean of 5 ADC reads, 12‑bit. Flip to 1 - x if dark reads bright |
ENC |
0–100 | Encoder dial, starts at 50, clamped. Bridge maps it to outdoor.temp_bias (−10…+10) |
BTN |
0 / 1 | Push switch. Pressing re-centres ENC to 50 |
The encoder switch is active-HIGH on this board (read with INPUT_PULLDOWN), verified empirically.
Intended MQTT topics (per the firmware comments): axm/env-01/telemetry and twin/set.
06Build & flash
Requires PlatformIO.
pio run -t upload # build and flash
pio device monitor # 115200 baudLibraries (auto-installed): adafruit/DHT sensor library, adafruit/Adafruit Unified Sensor, mathertel/RotaryEncoder.
Notable config in platformio.ini: pioarduino platform, 4 MB flash with the huge_app.csv partition table (the devkit default assumes 8 MB and won't boot), USB-CDC on boot.
07Repo layout
src/sketch.ino active firmware (ENV serial bring-up)
src/main.cpp PlatformIO template stub (excluded from build)
src/blink.cpp P4 blink test (excluded from build)
platformio.ini board, flash, libs; build_src_filter selects sketch.ino
docs/ GitHub Pages site (static, no build step)
main.cpp, blink.cpp and sketch.ino each define setup()/loop(), so build_src_filter compiles only sketch.ino for now.
08Project page
docs/index.html is a single static file: Three.js (pinned to 0.160.0 from jsDelivr) with a simulated building, no build step. It matches the palette of sebzuddas.com.
- Publish: Settings → Pages → Deploy from a branch →
main//docs. - Preview locally:
python3 -m http.server -d docs - Embed in sebzuddas.com/projects:
<iframe src="https://sebzuddas.github.io/axiometa-digital-twin/?embed" style="width:100%;height:560px;border:0" loading="lazy"></iframe>.?embedhides the surrounding text;?theme=light|darkforces a theme.