Skip to content

Commit 4189196

Browse files
authored
ovidiu.defta: architecture diagrams and Week 5 log (#1026)
* ovidiu.defta: add architecture diagrams and Week 5 log Add functional and power architecture PNG diagrams and document the Week 5 progress (architecture decisions, Rust driver audit, parts ordered). * Convert architecture diagrams to SVG CI requires SVG/WebP only; replace PNG diagrams with SVG equivalents. * Update project page - architecture, BOM and log
1 parent 0c3ecd6 commit 4189196

2 files changed

Lines changed: 71 additions & 39 deletions

File tree

website/versioned_docs/version-acs_cc/project/2026/ovidiu.defta/architecture.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# AeroGuard
2-
Monitor Solar de Poluare Atmosferica cu GPS
32

4-
:::info
3+
Solar-powered air quality monitor with GPS.
4+
5+
:::info
56

67
**Author**: Defta Ovidiu 344C2 \
78
**GitHub Project Link**: [UPB-PMRust-Students/acs-project-2026-odefta](https://github.com/UPB-PMRust-Students/acs-project-2026-odefta)
@@ -10,69 +11,99 @@ Monitor Solar de Poluare Atmosferica cu GPS
1011

1112
## Description
1213

13-
Sistem portabil de monitorizare a calitatii aerului, alimentat solar. Achizitioneaza periodic date de la senzori de particule in suspensie (PM2.5/PM10), gaze (NOx, CO, VOC), temperatura si umiditate, corelate cu coordonate GPS si timestamp. Datele sunt stocate local pe card microSD in format JSON si expuse printr-un server web embedded via WiFi, prin endpoint-uri REST. O aplicatie mobila consuma API-ul si afiseaza grafice de poluare, pozitia pe harta si nivelul bateriei. Sistemul functioneaza autonom prin alimentare solara cu modul de incarcare si baterie Li-Ion.
14+
Portable air quality station running off a solar panel and an 18650 cell. An STM32 reads particulate matter (PM2.5 / PM10), gases (CO, NO₂, NH₃, VOCs), temperature, humidity, and pressure, and tags every sample with GPS coordinates plus a timestamp. Readings are logged as JSON on a microSD card and served over Wi-Fi by a XIAO ESP32-C6 co-processor that runs a small REST server. A companion mobile app pulls the API and renders charts, the location on a map, and the battery state.
1415

1516
## Motivation
1617

17-
Statiile de monitorizare a calitatii aerului sunt rare si costisitoare, iar datele publice au granularitate scazuta. AeroGuard propune o solutie portabila, autonoma energetic, care permite monitorizarea locala a poluarii si vizualizarea datelor in timp real printr-o aplicatie mobila.
18+
Professional air quality stations are lab-accurate but cost tens of thousands of euros each, so they end up sparse — only a handful per city — and the data they publish online is averaged over an entire district. AeroGuard takes the opposite trade-off: a solar-powered monitor built from off-the-shelf modules, for a small fraction of the price of a real station, that pulls in particulate matter (PM1.0 / PM2.5 / PM10), common pollutant gases (CO, NO₂, NH₃), a VOC index, temperature, humidity, atmospheric pressure, and GPS coordinates with an accurate UTC timestamp — and logs all of it every few seconds. The numbers are not lab-grade, but the device runs unattended for days on the balcony, can be moved wherever I want to measure, and gives me a far richer picture of what is actually in the air around it than any public source.
1819

1920
## Architecture
2021

21-
<!-- TODO: Add architecture diagram -->
22+
![AeroGuard architecture](architecture.svg)
23+
24+
Battery monitoring uses a 2 × 100 kΩ divider into an STM32 ADC pin and is exposed through `/api/battery`. Reverse-polarity protection on the SOLAR+ and BATT+ rails is done with 1N5819 Schottky diodes. Overcurrent / overcharge / overdischarge protection is taken care of by the Seiko S-8261 PCB built into the protected NCR18650B cell — no external polyfuse needed (a 1 A polyfuse would have nuisance-tripped on the Wi-Fi TX bursts anyway). A 470 µF bulk cap sits on the MP1584 output to keep the buck converter stable under PMS5003 fan inrush.
2225

2326
## Log
2427

25-
### Week 5 - 11 May
28+
### Week 14 — 20 April
2629

27-
### Week 12 - 18 May
30+
Picked the MCU stack: STM32 Nucleo U545RE-Q + XIAO ESP32-C6 as a Wi-Fi co-processor, both in Rust with embassy, talking to each other over UART with JSON. Checked drivers on crates.io — most sensors are covered, the MiCS-4514 is not, so I'll port the DFRobot Arduino library by hand. Sketched the power chain (panel → buck → charger → 18650 → boost) and made a buy list.
2831

29-
### Week 19 - 25 May
32+
### Week 21 — 27 April
33+
34+
Ordered everything on April 22 from eMag, Optimus Digital, depozitulcubaterii, sigmanortec, DigiKey and Robofun. All parts arrived by the end of the week. Wrote most of this documentation page and put together the architecture diagram.
3035

3136
## Hardware
3237

33-
Microcontrolerul **STM32** citeste date de la senzorii de calitate a aerului prin **I2C** (BME280, SGP40), **UART** (PMS5003, NEO-6M) si **ADC** (MICS-4514). Datele sunt stocate pe **card microSD** via **SPI**. Comunicatia WiFi se realizeaza printr-un modul **ESP** conectat prin UART.
38+
The STM32 talks to all sensors over standard buses: **I2C** for BME280, SGP40 and MiCS-4514, **UART** for PMS5003 and NEO-6M GPS, **SPI** for the microSD card. The XIAO ESP32-C6 sits on another UART and handles Wi-Fi and the REST API.
39+
40+
Power flows like this: a 9V / 2W polycrystalline panel feeds an MP1584 buck converter trimmed to 5.5 V (the upper limit on the CN3065 input). The CN3065 is a solar-optimised single-cell Li-Ion charger — unlike a TP4056, it does not collapse the panel under low light, which matters when the sun is behind a cloud. It charges a Panasonic NCR18650B Protected cell (3.7 V, 3400 mAh, with the Seiko S-8261 PCB built into the cell). A MT3608 boost converter lifts the battery voltage to a clean 5 V rail that feeds three loads: the PMS5003 fan, the STM32 Nucleo via its E5V pin, and the XIAO ESP32-C6 via its 5V pin. The Nucleo's onboard LDO (U15, LD39050PU33R, max 500 mA) generates the 3.3 V rail that powers every I2C / UART sensor and the SD module — no external AMS1117 needed.
3441

35-
Alimentarea se face printr-un **panou solar 5V/1W** conectat la un modul de incarcare **TP4056**, care incarca o **baterie Li-Ion 18650**. Nivelul bateriei este monitorizat prin ADC.
42+
The two trimmer-based switching modules (MP1584 and MT3608) ship from the factory at unpredictable output voltages (the MT3608 in particular can be set to 28 V out of the box). Both get calibrated against a multimeter **before** anything else is connected to them.
3643

3744
### Schematics
3845

39-
<!-- TODO: Place KiCAD schematics here in SVG format -->
46+
<!-- TODO: KiCad schematics, exported as SVG. -->
4047

4148
### Bill of Materials
4249

43-
| Device | Usage | Price |
44-
|--------|-------|-------|
45-
| STM32 (TBD) | Microcontroler principal | TBD |
46-
| ESP module (TBD) | Comunicatie WiFi | TBD |
47-
| [PMS5003](https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf) | Senzor particule PM2.5/PM10 | TBD |
48-
| [MICS-4514](https://www.sgxsensortech.com/content/uploads/2023/03/MiCS-4514-rev-16.pdf) | Senzor NOx/CO | TBD |
49-
| [SGP40](https://sensirion.com/products/catalog/SGP40/) | Senzor VOC | TBD |
50-
| [BME280](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/) | Senzor temperatura/umiditate | TBD |
51-
| [NEO-6M](https://www.u-blox.com/en/product/neo-6-series) | Modul GPS | TBD |
52-
| Card microSD + cititor SPI | Stocare date | TBD |
53-
| Panou solar 5V/1W | Alimentare | TBD |
54-
| TP4056 | Modul incarcare | TBD |
55-
| Baterie Li-Ion 18650 | Stocare energie | TBD |
50+
Unit prices in RON (VAT included), at the quantity actually needed for one AeroGuard. I bought a few extras (one or two spares on the modules that are most likely to fail at first power-up), but those are not counted here.
51+
52+
| Device | Usage | Price (RON) |
53+
|--------|-------|-------------|
54+
| [STM32 Nucleo U545RE-Q](https://www.st.com/en/evaluation-tools/nucleo-u545re-q.html) | Main MCU (Cortex-M33 @ 160 MHz, 512 KB flash, ultra-low-power U5) | lab provided |
55+
| [Seeed XIAO ESP32-C6](https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/) | Wi-Fi 6 / BLE 5.3 co-processor | 110 |
56+
| [DFRobot SEN0377 (MiCS-4514)](https://www.dfrobot.com/product-2417.html) | CO / NO₂ / NH₃ via I2C | 175 |
57+
| [Plantower PMS5003](https://github.com/m2mlorawan/datasheet/blob/master/plantower-pms5003-manual_v2-3.pdf) | PM1.0 / PM2.5 / PM10 via UART (5 V fan + laser) | 90 |
58+
| [Sensirion SGP40](https://sensirion.com/products/catalog/SGP40/) (Gravity module) | VOC index via I2C | 50 |
59+
| [Bosch BME280](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/) breakout | Temperature / humidity / pressure via I2C | 15 |
60+
| [u-blox NEO-6M GPS](https://www.u-blox.com/en/product/neo-6-series) module + antenna | GPS over UART (NMEA) | 20 |
61+
| microSD module (SPI) + 16 GB card | JSON log storage (FAT32) | 40 |
62+
| 9V / 2W polycrystalline solar panel (130 × 200 mm) | Energy harvesting | 25 |
63+
| [MP1584](https://www.monolithicpower.com/en/mp1584.html) buck module | 9 V → 5.5 V (panel → CN3065 input) | 7 |
64+
| [CN3065](https://content.instructables.com/FGJ/QXX8/MH9I7U1D/FGJQXX8MH9I7U1D.pdf) solar charger | Single-cell Li-Ion charging (4.2 V out, 4.4–6 V in) | 10 |
65+
| [Panasonic NCR18650B Protected](https://depozitulcubaterii.ro/home/1767-acumulator-li-ion-panasonic-ncr18650b-3400mah-3-7v-made-in-japan-1767.html) | 3400 mAh Li-Ion with Seiko S-8261 PCB | 75 |
66+
| 18650 holder with leads | Battery mount | 15 |
67+
| [MT3608](https://www.olimex.com/Products/Breadboarding/BB-PWR-3608/resources/MT3608.pdf) boost module | 3.7 V → 5 V single rail | 25 |
68+
| 1N5819 Schottky diodes ×2 | Reverse-polarity protection on SOLAR+ and BATT+ | 10 |
69+
| 470 µF / 25 V electrolytic | Bulk cap on MP1584 output | 5 |
70+
| JST-PH 2.0 mm 2-pin pigtails ×3 | CN3065 solar / battery / system connectors | 6 |
71+
| Hookup wire (22 AWG, ~3 m) | Wiring | 5 |
5672

5773
## Software
5874

5975
| Library | Description | Usage |
6076
|---------|-------------|-------|
61-
| `embassy-rs` | Framework async pentru microcontrolere | Runtime si task-uri async |
62-
| `embassy-stm32` | Suport Embassy pentru STM32 | Acces hardware low-level |
63-
| `embassy-time` | Functionalitati de timp | Timere si delay-uri |
64-
| `embassy-net` | Stack de retea | Comunicatie TCP/IP |
65-
| `embedded-hal` | Abstractizari hardware | Interfete I2C, SPI, UART, ADC |
66-
| `serde` / `serde_json_core` | Serializare/deserializare | Format JSON pentru date si API |
67-
| `embedded-sdmmc` | Suport card microSD | Stocare fisiere FAT32 |
68-
| `bme280` | Driver BME280 | Citire temperatura/umiditate |
69-
| `nmea0183` | Parser date GPS | Parsare coordonate NMEA |
70-
| `defmt` | Logging embedded | Debug si logging |
71-
| `heapless` | Structuri de date fara alocare dinamica | Buffere si colectii no_std |
77+
| [embassy-executor](https://docs.embassy.dev/embassy-executor/) | Async task executor | Runs the main loop on both MCUs |
78+
| [embassy-stm32](https://docs.embassy.dev/embassy-stm32/) | STM32 async HAL | Peripheral access on the Nucleo (feature `stm32u545re`) |
79+
| [embassy-time](https://docs.embassy.dev/embassy-time/) | Async timers and delays | Sensor polling intervals, debouncing |
80+
| [embassy-net](https://docs.embassy.dev/embassy-net/) | Async TCP/IP stack | Network layer on the ESP32-C6 side |
81+
| [embassy-sync](https://docs.embassy.dev/embassy-sync/) | Async sync primitives | Channels and signals between tasks |
82+
| [esp-hal](https://github.com/esp-rs/esp-hal) | ESP32-Cx HAL | XIAO ESP32-C6 peripherals, target `riscv32imac-unknown-none-elf` |
83+
| [esp-hal-embassy](https://docs.rs/esp-hal-embassy) | Embassy time driver | Glues Embassy executor to esp-hal |
84+
| [esp-wifi](https://github.com/esp-rs/esp-wifi) | Wi-Fi / BLE driver | Wi-Fi connection on the ESP32-C6 |
85+
| [picoserve](https://docs.rs/picoserve) | Embassy-native HTTP server | Serves the REST API to the mobile app |
86+
| [bme280-rs](https://docs.rs/bme280-rs) | BME280 async driver | Reading temperature / humidity / pressure |
87+
| [sgp40](https://docs.rs/sgp40) | SGP40 VOC sensor driver | Reading the VOC index |
88+
| [pmsx003](https://docs.rs/pmsx003) | PMS5003 frame parser | Decoding the 32-byte particulate matter packets |
89+
| [nmea](https://docs.rs/nmea) | NMEA-0183 parser | Parsing GPS sentences from the NEO-6M |
90+
| [embedded-sdmmc](https://docs.rs/embedded-sdmmc) | FAT32 over SPI | Writing JSON log lines to the microSD card |
91+
| [serde](https://docs.rs/serde) + [serde-json-core](https://docs.rs/serde-json-core) | `no_std` JSON serializer | Encoding REST responses and SD log lines |
92+
| [heapless](https://docs.rs/heapless) | `no_std` collections | Fixed-capacity buffers and string types |
93+
| [defmt](https://docs.rs/defmt) | Embedded logger | Debug logs streamed via [probe-rs](https://probe.rs/) |
94+
95+
For the MiCS-4514 there is no Rust crate, so I'm porting [DFRobot's Arduino library](https://github.com/DFRobot/DFRobot_MICS). The chip exposes its readings over I2C through a simple register interface, so the port is mostly translating a handful of read/write helpers and the calibration math.
7296

7397
## Links
7498

75-
1. [Embassy-rs Documentation](https://embassy.dev/)
76-
2. [PMS5003 Datasheet](https://www.aqmd.gov/docs/default-source/aq-spec/resources-page/plantower-pms5003-manual_v2-3.pdf)
77-
3. [BME280 Datasheet](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/)
78-
4. [SGP40 Datasheet](https://sensirion.com/products/catalog/SGP40/)
99+
1. [Embassy book](https://embassy.dev/)
100+
2. [esp-rs book](https://docs.esp-rs.org/book/)
101+
3. [STM32U5 reference manual (RM0456)](https://www.st.com/resource/en/reference_manual/rm0456-stm32u575585-armbased-32bit-mcus-stmicroelectronics.pdf)
102+
4. [Nucleo-64 user manual UM3062 (MB1841)](https://www.st.com/resource/en/user_manual/um3062-stm32u5-series-nucleo64-board-stmicroelectronics.pdf)
103+
5. [XIAO ESP32-C6 wiki](https://wiki.seeedstudio.com/xiao_esp32c6_getting_started/)
104+
6. [PMS5003 datasheet](https://github.com/m2mlorawan/datasheet/blob/master/plantower-pms5003-manual_v2-3.pdf)
105+
7. [MiCS-4514 datasheet](https://www.sgxsensortech.com/content/uploads/2023/03/MiCS-4514-rev-16.pdf)
106+
8. [SGP40 datasheet](https://sensirion.com/products/catalog/SGP40/)
107+
9. [BME280 datasheet](https://www.bosch-sensortec.com/products/environmental-sensors/humidity-sensors-bme280/)
108+
10. [DFRobot SEN0377 product page](https://www.dfrobot.com/product-2417.html)
109+
11. [DFRobot_MICS Arduino driver (source for the Rust port)](https://github.com/DFRobot/DFRobot_MICS)

0 commit comments

Comments
 (0)