Air360 is a multi-target air-quality firmware for an ESP32-S3 device: it reads a wide range of environmental sensors and uploads the same measurements to several services at once. Each upload target is enabled independently and has its own interval, so one device can publish to its own service, to a community network, and to your own database simultaneously — and if one target is unavailable, the others keep working.
Supported upload targets:
- Air360 API — the project's native backend and public map (this repository).
- Sensor.Community — the volunteer global air-quality network.
- openSenseMap — the open environmental-data platform.
- InfluxDB — your own time-series database (for Grafana and self-hosting).
- Custom Upload — any HTTP endpoint you control.
This is the core of how Air360 positions itself: not as a walled-garden replacement for existing air-quality projects, but as a device that interoperates with them. Air360 keeps explicit compatibility with the Sensor.Community upload and registration flow (a device can still be registered on devices.sensor.community) and fetches your sensor mapping directly from openSenseMap — so you can join those ecosystems and Air360 at the same time, from one device.
Around that firmware, the repository also grows a native Air360 backend API and a public web portal.
New to Air360? The build guide walks through assembling, flashing, and configuring a device end to end.
At the device level, the project is centered on a local-first firmware runtime with setup AP onboarding, a station-mode web UI, configurable sensor support, and the multi-target backend uploads described above.
The repository intentionally separates:
docs/for architecture, planning, deployment notes, and implementation-oriented navigationfirmware/for the actual ESP-IDF device firmwarebackend/for the native Air360 API backendportal/for the user-facing web application
When documentation and code disagree, treat the relevant implementation directory as the source of truth for current behavior.
Based on the current tree, the repository now contains more than the original firmware replacement effort:
- an ESP-IDF firmware runtime for
esp32s3with multi-target measurement uploads (Air360 API, Sensor.Community, openSenseMap, InfluxDB, Custom Upload) - compatibility with the Sensor.Community upload endpoint and registration flow
- a Fastify-based Air360 backend with device registration, authenticated persisted ingest, public device lists, and measurement history queries
- a Next.js public portal application
- design and deployment documentation that connects those pieces
The older planning documents in docs/ still matter, but they should be read as design context unless the implementation confirms them.
.
├── backend/
├── docs/
├── firmware/
├── portal/
├── CLAUDE.md
├── LICENSE
└── README.md
docs/Project context, architecture notes, compatibility analysis, firmware docs, backend docs, and portal deployment notes.firmware/ESP-IDF firmware project for the device. This is the source of truth for implemented device behavior.backend/Native Air360 API backend in TypeScript/Fastify.portal/Next.js portal application.CLAUDE.mdRepository-level guidance. In particular, it separates design context indocs/from implementation truth infirmware/.
Start here depending on what you need.
- Build guide (assemble, flash, and configure a device): docs/guide/README.md
- Firmware documentation map (all subsystems): docs/firmware/README.md
- Firmware architecture overview: docs/firmware/ARCHITECTURE.md
- Firmware source layout: docs/firmware/PROJECT_STRUCTURE.md
- Firmware startup sequence: docs/firmware/startup-pipeline.md
- Firmware configuration reference: docs/firmware/configuration-reference.md
- Firmware sensor subsystem: docs/firmware/sensors/README.md
- Firmware measurement pipeline: docs/firmware/measurement-pipeline.md
- Firmware architecture decision records: docs/firmware/adr/README.md
- Firmware release-packaging skill: .claude/skills/air360-firmware-release-bundle/
- Backend documentation map: docs/backend/README.md
- Portal documentation map: docs/portal/README.md
The buildable device application lives in firmware/README.md.
Current firmware implementation includes:
- ESP-IDF 6.x application for
esp32s3 - persisted device, sensor, and backend configuration in NVS
- station-mode join with SNTP time sync, background time-sync retry, and setup AP fallback
- local web UI at
/,/status,/config,/sensors, and/backends - setup AP onboarding at
/configwith scanned SSID list from/wifi-scan - embedded frontend assets under
firmware/main/webui/, served by the firmware at/assets/* - category-based sensor configuration, background polling, and bounded measurement queueing
- multi-target backend upload support for
Air360 API,Sensor.Community,openSenseMap,InfluxDB, andCustom Upload, each enabled independently with its own interval Sensor.Communitycompatibility through the same device identity model exposed in the firmware UI asShort ID
The native API backend source lives in backend/. Backend documentation lives in
docs/backend/README.md.
Current backend implementation includes:
- Fastify service in TypeScript
GET /- device registration at
PUT /v1/devices/:device_id/register - persisted batch ingest at
PUT /v1/devices/:device_id/batches/:batch_id - public device list endpoints at
GET /v1/devicesandGET /v1/devices/offline - measurement history by public device ID at
GET /v1/devices/:public_id/measurements?period=<period>
The web portal lives in portal/README.md.
Current portal implementation includes:
- Next.js 16 / React 19 / TypeScript application
- public home page at
/ - public device map at
/map - device assembly guide at
/buildwith shield-board and direct ESP32-S3 wiring paths - privacy page at
/privacy - public device measurement charts at
/devices/:public_id - deployment notes under
docs/portal/
If you need to work on device behavior:
- Read firmware/README.md
- Then use docs/firmware/README.md as the firmware documentation map
If you need to publish a firmware beta or stable build:
- Read firmware/README.md for the release packaging workflow
- On
main, run the release script from .claude/skills/air360-firmware-release-bundle/; it tags, builds, and packages the versioned bundle underfirmware/release/
If you need to operate or provision a device rather than change firmware code:
- Read the build guide — assemble, flash, configure, and operate a device end to end
- For release binaries, flash the merged
full.binthroughhttps://espflash.app/ - Then use firmware/README.md only for build, flash, and implementation details
If you need to understand the Sensor.Community overlap specifically:
- Read this file for the project-level compatibility statement
- Read the backends guide for the actual registration and backend setup flow
If you need repository context first:
- Read this file
- Read docs/firmware/README.md
- Read docs/firmware/ARCHITECTURE.md
If you need backend work:
- Read backend/CLAUDE.md
- Read docs/backend/README.md
If you need portal work:
- Read portal/CLAUDE.md
- Read portal/README.md
- Read docs/portal/README.md
Current implementation status appears to be:
firmware/is the most substantial implemented part of the repositorybackend/is a native API backend with registration, authenticated ingest persistence, public device lists, measurement history, and reverse-geocoded display fieldsportal/is a public frontend with home, map, build guide, privacy page, and device measurement pages- many documents in
docs/still describe intended direction, rollout phases, and compatibility constraints rather than completed work
- Keep repository-level docs focused on project navigation and boundaries between subsystems.
- Keep firmware implementation details in
firmware/README.mdanddocs/firmware/. - Keep backend operational details in
docs/backend/. - Keep portal operational details in the portal docs.
- Do not treat generated files under
firmware/build/as maintained source. - Preserve the distinction between planned behavior in
docs/and implemented behavior infirmware/,backend/, andportal/.
