Skip to content

Repository files navigation

AirMonitor

AirMonitor — Monitor. Understand. Don’t Die.

Monitor. Understand. Don’t Die.

AirMonitor is a source-available DIY measurement platform, free to use for non-commercial purposes, for evaluating air-filtration performance in 3D-printing spaces. See License.

The primary goal is not to treat inexpensive or cross-sensitive sensor readings as laboratory-grade measurements of indoor VOC concentration, particulate exposure, or personal safety. Instead, AirMonitor uses repeatable sensor signals to answer practical comparative questions:

  • Does a filter reduce the peak response produced by a print?
  • Does it reduce the total measured response over the full print and post-print period?
  • Does the room return to baseline faster with filtration enabled?
  • How do different filters, fan speeds, placements, enclosures, and filament materials compare?

AirMonitor combines commercially available sensor modules, USB-connected interfaces, local data storage, Grafana dashboards, printer awareness, and filter automation in a Raspberry Pi-based appliance.

The current AirMonitor Sensors are built around:

These are DIY-built sensor assemblies, not custom sensing chips. Each AirMonitor Sensor packages a commercial sensor module with the required interface electronics, wiring, and a purpose-built enclosure.

See the Hardware Guide for the current USB architecture, supported sensor modules, enclosure plans, device configuration, and advanced UART notes.

DIY project notice: AirMonitor is not a certified air-quality instrument and should not be relied upon for regulatory, medical, occupational-exposure, or life-safety decisions.

The Setup

Bambu X1-Carbon with AMS, Bento filter, and Levoit room purifier AirMonitor sensor mounted between the AMS and printer top

SGX PS1-VOC-1000-MOD sensor element close-up Sensor enclosure internals with wiring

Screenshots

AirMonitor status page showing live environment, printer state, and air handling AirMonitor alerts page with active alerts and resolved history

Grafana Print Window dashboard for a single print Grafana Compare Prints dashboard overlaying two runs

Project Overview

AirMonitor currently provides:

  • USB-connected AirMonitor Sensors
  • Explicit, host-configured serial device paths
  • Modular Python sensor drivers
  • Local SQLite storage
  • Provisioned Grafana dashboards
  • Bambu printer-state integration
  • Bento Box and Levoit filter automation
  • Planned 3D-printable enclosures, with printable releases to be linked from MakerWorld

Project Philosophy

  • Measure filter efficacy, not claim laboratory air analysis
  • Prefer controlled comparisons over isolated absolute readings
  • Change one experimental variable at a time whenever practical
  • Reproducible experiments
  • Repeatability over claims of absolute accuracy
  • Engineering decisions backed by measurements
  • AI-assisted development with human review and real-world validation
  • Documentation as a first-class project deliverable

Measurement Model

AirMonitor treats its sensors as instruments for comparative experiments.

A typical test records:

  1. a pre-print baseline
  2. the active print period
  3. a configurable post-print recovery period
  4. whether each filter was enabled, disabled, or manually overridden
  5. the printer, filament, and other experimental context

Useful comparisons include unfiltered versus filtered runs, different filter media, fan speeds, filter placements, enclosure states, and room ventilation conditions. Absolute values remain visible because they are useful for plotting and repeatability, but the project emphasizes changes in peak, area under the response curve, and time to return toward baseline.

See docs/experiments for real recorded runs using this model, including a baseline-vs-chamber-filters-vs-room-filter comparison with charts and raw numbers.

AI-Assisted Development

AirMonitor was developed with extensive AI assistance. The majority of the software and documentation, along with portions of the CAD and project-planning work, were generated collaboratively with AI tools and then reviewed, tested, modified, and integrated by the project author.

AI accelerates implementation and documentation, but it is not treated as a source of experimental truth. Hardware behavior, sensor communications, installation procedures, and reported results are validated against physical devices and collected measurements. The repository and repeatable real-world testing remain the sources of truth for the project.

Hardware Model

Commercial sensor module
        │ TTL UART
USB-UART interface
        │ USB
Configured Linux serial device
        │
Python sensor driver
        │
SQLite / Grafana / filter analysis and automation

USB is the recommended connection method because it is convenient, replaceable, and easy to route outside an enclosure. AirMonitor currently favors explicit device configuration over a custom EEPROM identity and automatic hardware-matching scheme.

Native UART wiring remains documented as an advanced option for builders using a Raspberry Pi GPIO UART or another embedded host.

Why the Amphenol SGX PS1-VOC-1000-MOD?

AirMonitor is intended for comparative filter testing during FDM 3D printing. The Amphenol SGX PS1-VOC-1000-MOD occupies a useful middle ground between inexpensive metal-oxide-semiconductor sensors commonly used in hobbyist air-quality monitors and professional photoionization-detector instruments.

The SGX PS1 uses Solid Polymer Electrolyte (SPE) electrochemical sensing technology. The complete MOD assembly combines the sensing element with onboard processing, temperature and humidity measurement, environmental compensation, factory-matched calibration, and a UART interface. This avoids the analog-front-end design and initial calibration work required by a bare sensing element.

A primary reason for selecting the SGX module is its published cross-sensitivity table. The listed gases include styrene, a compound of particular interest when printing materials such as ABS and ASA. This does not make the device a selective styrene analyzer. It does, however, provide a documented reason to expect a repeatable response to VOC mixtures relevant to the intended filter-comparison experiments.

The module is calibrated with isobutylene and reports a cross-sensitive TVOC value. See the SGX hardware notes and the manufacturer datasheet for its specifications, cross-sensitivity table, and operating guidance.

What Runs

The install provides one Python package with separate systemd services:

airmonitor.target               Umbrella lifecycle for the AirMonitor application
airmonitor-voc.service          SGX VOC / temperature / humidity logger
airmonitor-sps30.service        SPS30 particulate logger
airmonitor-printer-mqtt.service Bambu MQTT normalizer
airmonitor-bento.service        Bento Box outlet automation
airmonitor-levoit.service       Levoit/Core room-filter automation
airmonitor-status.service       Read-only appliance status landing page
airmonitor-export.service       Read-only print report and data exports
mosquitto.service               Local MQTT broker
grafana-server.service          Grafana dashboard

Repository Layout

src/airmonitor/sensors/sgx/ps1_voc/       SGX protocol implementation
src/airmonitor/sensors/sensirion/sps30/   SPS30 SHDLC UART driver
src/airmonitor/printers/bambu/            Bambu printer MQTT support
src/airmonitor/filters/bento/             Kasa/Bento filter automation
src/airmonitor/filters/levoit/            Levoit room-filter automation
src/airmonitor/database/                  SQLite schema and repositories
grafana/                                  Provisioned datasource and dashboard
systemd/                                  Service units
config/                                   Example environment and hardware files
hardware/                                 Wiring and USB-UART notes
docs/                                     Architecture and operating notes
tests/                                    Offline protocol and dashboard tests

Data Flow

The printer MQTT normalizer publishes local state to Mosquitto:

printer/state
printer/available

The SGX logger records VOC response samples and associates them with the active print and a configurable post-print context window. The SPS30 logger records particulate samples independently. Filter services use printer state, filament policy, sensor state, and manual override state to decide whether the Bento or Levoit filter should run.

Manual filter override state is persisted in SQLite:

airmonitor filter bento auto
airmonitor filter bento on
airmonitor filter bento off
airmonitor filter levoit status

Manual on or off wins over automation until set back to auto.

SQLite Storage

AirMonitor uses a local SQLite file. There is no separate database server, database user, password, grant, or manual schema load.

Default path:

/var/lib/airmonitor/airmonitor.sqlite3

Main tables:

sensors              physical sensor inventory
sensor_sessions      logger runtime sessions
prints               print jobs detected from normalized printer MQTT state
sgx_voc_samples      SGX VOC, temperature, and humidity samples
sps30_samples        SPS30 particulate samples
filter_control_state persisted filter manual/automation state

Grafana

The appliance root URL presents a read-only status landing page built from normalized AirMonitor service state. It links to the detailed Grafana dashboard and never accesses sensor hardware directly. See Status Page.

The provisioned AirMonitor Print Window dashboard includes an Export Selected Print link. Public exports are served at:

/exports/print?print_id=<print-id>

Available formats are a publication PNG, multipage PDF report, Excel workbook, raw CSV ZIP, and complete experiment ZIP. Every format is generated from SQLite without contacting sensor hardware. The selected window starts 30 minutes before the print and ends 30 minutes after ended_at, or last_seen_at for an active print. See Print Exports.

Grafana is provisioned from this repository:

grafana/provisioning/datasources/airmonitor-sqlite.yaml
grafana/provisioning/dashboards/airmonitor.yaml
tools/generate-grafana-dashboard.py
grafana/dashboards/airmonitor-live.json

The dashboard is generated in light mode and uses the SQLite datasource UID airmonitor-sqlite. Manual Grafana dashboard edits are temporary; the installer regenerates and reprovisions the dashboard from the repository.

Install or refresh Grafana provisioning:

bash tools/install-grafana.sh

Host Install and Update

Run clone, pull, and install/update steps as the normal local administrative user. Do not maintain the checkout as the service account.

Typical update on an already-installed host:

cd ~/airmonitor
git pull --ff-only
bash tools/update.sh

Once installed, airmonitor update and airmonitor install are equivalent shorthand runnable from anywhere (they locate the checkout via REPO_DIR in /etc/airmonitor/install.conf, written automatically by tools/install.sh):

airmonitor update            # dry-run by default; add --no-dry-run to execute
airmonitor install --full    # extra flags pass through to tools/install.sh

Neither needs sudo itself — tools/update.sh/tools/install.sh escalate internally only where needed, and the git pull must run as whichever user actually has the checkout's Git credentials, not root.

Supported fresh install:

sudo apt update && sudo apt install -y git
git clone https://github.com/ddivins/airmonitor.git
cd airmonitor
bash tools/install.sh

With no arguments and nothing configured yet, the installer asks a few short questions (core or full, and — for full — a domain and Let's Encrypt contact email) and saves the answers to /etc/airmonitor/install.conf for future reruns. Pass --config path/to/install.conf for an unattended install from a file (see config/install.conf.example); a full install adds Grafana, nginx, Certbot, and the Cloudflare DNS plugin. The installer is idempotent, preserves existing configuration, and will not enable public nginx routing until a TLS certificate exists for the configured domain. See Fresh Host Installation.

tools/install.sh leaves the per-integration credential files below as blank templates (printer, Kasa, VeSync). Fill them in interactively instead of hand-editing each file:

sudo airmonitor setup

It walks through the printer, sensors, filters, and local MQTT broker connection, showing the current value in [brackets] — press Enter to keep it. Requires a real terminal and root (it writes root-owned files under /etc/airmonitor).

Local secret and host-specific configuration files live outside the repository and should be preserved across updates:

/etc/airmonitor/sgx-voc.env
/etc/airmonitor/sps30.env
/etc/airmonitor/printer-mqtt.env
/etc/airmonitor/bento.env
/etc/airmonitor/levoit.env
/etc/airmonitor/hardware.yaml
/etc/airmonitor/filament-policy.yaml
/etc/airmonitor/install.conf
/etc/airmonitor/airmonitor.env

Dependency pinning

requirements-lock.txt pins exact versions for every third-party dependency (direct and transitive) and is passed to pip as a constraints file during install/update, so a fresh appliance gets the same dependency versions as CI rather than whatever the version ranges in pyproject.toml happen to resolve to on a given day. uv.lock is the authoritative source it's generated from. After changing a dependency in pyproject.toml, regenerate both:

uv lock
uv export --format requirements.txt --no-hashes --no-emit-project -o requirements-lock.txt

Hardware Configuration

The current build uses USB-UART interfaces and explicit serial device configuration. Depending on the adapter and Linux host, the configured path may be a stable /dev/serial/by-id/... symlink, a custom udev symlink, or another known device path.

The deployed AirMonitor appliance uses a Silicon Labs CP2105 dual USB-UART adapter. Repository-managed udev rules identify serial 00B9A86D and assign each interface a stable sensor name:

/dev/airmonitor-sgx   -> CP2105 interface 00
/dev/airmonitor-sps30 -> CP2105 interface 01

These aliases remain stable if Linux assigns different /dev/ttyUSB* numbers.

AirMonitor does not require builders to reprogram an FTDI EEPROM or depend on automatic manufacturer/product/serial matching. Earlier EEPROM and registry-based discovery work remains in the repository as historical or optional implementation material, but it is not the recommended public build path.

version: 1
devices:
  sgx-voc-01:
    driver: airmonitor.sensors.sgx.ps1_voc
    transport: usb-uart
    device: /dev/airmonitor-sgx
  sps30-01:
    driver: airmonitor.sensors.sensirion.sps30
    transport: usb-uart
    device: /dev/airmonitor-sps30

See the Hardware Guide for the current USB connection model, device-path configuration, and advanced native UART information.

Operations

Check service state:

systemctl --no-pager --full status \
  airmonitor.target \
  airmonitor-voc.service \
  airmonitor-sps30.service \
  airmonitor-printer-mqtt.service \
  airmonitor-bento.service \
  airmonitor-levoit.service \
  airmonitor-status.service \
  airmonitor-export.service \
  grafana-server.service \
  mosquitto.service

Follow logs:

sudo journalctl -u airmonitor-voc.service -f
sudo journalctl -u airmonitor-sps30.service -f
sudo journalctl -u grafana-server.service -f

Public Repository Notes

Do not commit populated environment files, printer serial numbers, printer access codes, device IP addresses, private hostnames, logs containing secrets, or local-only credentials.

Interpreting Sensor Measurements

AirMonitor is designed to produce repeatable comparative measurements of filter performance, not laboratory chemical analysis or regulatory occupational-exposure measurements.

The SGX module is factory calibrated with isobutylene, but it is cross-sensitive to multiple VOCs and cannot identify which individual compound or mixture produced a reading. AirMonitor therefore treats its reported value primarily as a relative VOC-response signal.

The SPS30 produces real particulate mass and count estimates, but placement, airflow, room mixing, print geometry, and experimental timing still affect comparisons. Controlled tests should keep those factors as consistent as practical.

Useful questions include:

  • Does a filter reduce the VOC or particulate peak compared with no filtration?
  • Does it reduce the total response across the print and recovery period?
  • Does a higher fan speed materially improve removal?
  • Does filter placement change measured effectiveness?
  • How quickly does the room return toward its pre-print baseline?

The displayed VOC ppm value must not be interpreted as a compound-specific styrene concentration or compared directly with OSHA, NIOSH, or other exposure limits. Regulatory limits apply to specific compounds, defined sampling periods, and validated measurement methods. AirMonitor's value is in trends, controlled comparisons, and documenting the relative effect of filtration, ventilation, materials, and operating conditions.

License

AirMonitor is licensed under the PolyForm Noncommercial License 1.0.0: free to use, modify, and share — including the software, hardware designs, and documentation in this repository — for personal, educational, research, nonprofit, or other non-commercial purposes. Commercial use requires a separate arrangement with the copyright holder. This is a source-available license, not an OSI-approved open-source license, because of that non-commercial restriction.

About

Raspberry Pi air-quality monitoring, pluggable sensor drivers, and enclosure CAD

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages