# ESP32 NextPM Sensor Reader An educational ESP32 project for reading particulate matter (PM) concentrations from a NextPM sensor via UART serial communication. This simplified implementation is designed to help students understand serial communication protocols, binary data parsing, and sensor integration. ## ๐Ÿ“‹ Table of Contents - [About Particulate Matter](#about-particulate-matter) - [Features](#features) - [Hardware Requirements](#hardware-requirements) - [Wiring Connections](#wiring-connections) - [Software Requirements](#software-requirements) - [Installation](#installation) - [Usage](#usage) - [Understanding the Code](#understanding-the-code) - [Expected Output](#expected-output) - [Troubleshooting](#troubleshooting) - [Learning Objectives](#learning-objectives) - [License](#license) ## About Particulate Matter Particulate Matter (PM) refers to tiny particles suspended in the air that can be harmful to human health. This project measures three types: - **PM1.0**: Particles with diameter < 1.0 micrometers - **PM2.5**: Particles with diameter < 2.5 micrometers (common air quality metric) - **PM10**: Particles with diameter < 10 micrometers Values are reported in **ยตg/mยณ** (micrograms per cubic meter). ## Features - โœ… Reads PM1.0, PM2.5, and PM10 concentrations from NextPM sensor - โœ… Uses UART serial communication with 8E1 parity - โœ… Binary protocol with checksum validation - โœ… Non-blocking timing pattern with `millis()` - โœ… Extensively commented code for educational purposes - โœ… Real-time data output to Serial Monitor - โœ… Error handling and debugging support ## Hardware Requirements | Component | Specification | |-----------|--------------| | **Microcontroller** | ESP32 development board | | **Sensor** | NextPM (NPM) particulate matter sensor | | **Connections** | UART (Serial) communication | | **Power Supply** | USB (for ESP32) + sensor power supply | ## Wiring Connections Connect the NextPM sensor to your ESP32 as follows: | NextPM Sensor | ESP32 Board | |---------------|-------------| | TX (Transmit) | GPIO 39 (RX) | | RX (Receive) | GPIO 32 (TX) | | GND | GND | | VCC | External power supply (check sensor voltage requirements) | **Important Notes:** - The NextPM sensor typically requires an external power supply (check your sensor's datasheet) - ESP32 GPIO 39 is input-only (perfect for RX) - Do not connect sensor VCC to ESP32 3.3V unless your sensor specifically supports it ### Connection Diagram ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ NextPM โ”‚ โ”‚ ESP32 โ”‚ โ”‚ Sensor โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ TX โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ†’ GPIO 39 โ”‚ โ”‚ โ”‚ โ”‚ (RX) โ”‚ โ”‚ RX โ†โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€ GPIO 32 โ”‚ โ”‚ โ”‚ โ”‚ (TX) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ GND โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€ GND โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ VCC โ”€โ”€โ”ผโ”€โ†’ External โ”‚ โ”‚ โ”‚ โ”‚ Power โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ## Software Requirements - **PlatformIO** - Modern embedded development platform - Recommended: Use PlatformIO IDE extension for VS Code - Alternative: PlatformIO Core CLI - **VS Code** (optional but recommended) - Download from: https://code.visualstudio.com/ ## Installation ### Step 1: Install PlatformIO **Option A: VS Code Extension (Recommended)** 1. Open VS Code 2. Go to Extensions (Ctrl+Shift+X) 3. Search for "PlatformIO IDE" 4. Click Install **Option B: Command Line** ```bash pip install platformio ``` ### Step 2: Clone the Repository ```bash git clone http://gitea.aircarto.fr/PaulVua/esp32_NPM_only.git cd esp32_NPM_only ``` ### Step 3: Open in PlatformIO **Using VS Code:** 1. Open the project folder in VS Code 2. PlatformIO will automatically detect the project **Using CLI:** ```bash pio project init ``` ## Usage ### Building the Project ```bash pio run ``` ### Uploading to ESP32 1. Connect your ESP32 to your computer via USB 2. Upload the code: ```bash pio run --target upload ``` ### Monitoring Serial Output View real-time sensor readings: ```bash pio device monitor ``` Or combine upload and monitor: ```bash pio run --target upload && pio device monitor ``` **Exit the monitor:** Press `Ctrl+C` ### Cleaning Build Files ```bash pio run --target clean ``` ## Understanding the Code The code is organized into clear sections with extensive comments: ### Main Components 1. **Hardware Configuration** (`main.cpp:18-30`) - Serial port definitions - GPIO pin assignments 2. **Helper Functions** (`main.cpp:50-107`) - `checksum_valid()`: Validates sensor messages - `send_concentration_command()`: Sends read request to sensor - `print_data()`: Debug output for troubleshooting 3. **Sensor Reading Function** (`main.cpp:109-242`) - `read_concentration()`: 11-step process documented in detail - Protocol parsing and data extraction - Error handling with timeout protection 4. **Arduino Functions** - `setup()`: One-time initialization (`main.cpp:244-286`) - `loop()`: Non-blocking repeated execution (`main.cpp:288-318`) ### Key Concepts Demonstrated - **Binary Serial Protocol**: Reading structured binary data - **Checksum Validation**: Ensuring data integrity - **Non-blocking Timing**: Using `millis()` instead of `delay()` - **UART Communication**: 8E1 parity configuration - **Error Handling**: Timeout protection and validation checks - **Data Scaling**: Converting sensor's fixed-point integers to floats ## Expected Output After uploading and opening the Serial Monitor, you should see: ``` === NextPM Sensor Reader === Simplified version - Concentration readings only Averaging: 60 seconds, Update: every 10 seconds Waiting 15 seconds for sensor initialization... Sensor ready. Starting measurements... --- Reading NextPM Concentrations --- === Particulate Matter Concentrations === PM1.0: 12.3 ยตg/mยณ PM2.5: 18.7 ยตg/mยณ PM10: 24.5 ยตg/mยณ ====================================== ``` Readings update every 10 seconds. ## Troubleshooting ### No sensor response **Symptom:** `ERROR: No response from sensor` **Solutions:** 1. Check wiring connections (TX/RX crossed correctly?) 2. Verify sensor has power 3. Wait for full 15-second initialization period 4. Check sensor is compatible with 115200 baud, 8E1 parity ### Invalid checksum errors **Symptom:** `ERROR: Invalid checksum` **Solutions:** 1. Check for electrical noise on signal wires 2. Verify correct parity setting (8E1) 3. Ensure ground connection between ESP32 and sensor 4. Try shorter wire lengths ### Header not found **Symptom:** `ERROR: Header not found` **Solutions:** 1. Sensor may not be responding correctly 2. Check baud rate matches (115200) 3. Verify sensor is in measurement mode 4. Power cycle the sensor ### Can't upload to ESP32 **Symptom:** Upload fails or port not found **Solutions:** 1. Press and hold BOOT button on ESP32 during upload 2. Check USB cable (must support data, not just power) 3. Install USB drivers for your ESP32 board 4. Try a different USB port ## Learning Objectives This project helps students learn: ### Communication Protocols - Understanding binary serial communication - Request-response patterns - Header/state/data/checksum message structure - Big-endian vs little-endian byte ordering ### Embedded Systems Concepts - UART configuration (baud rate, parity, stop bits) - GPIO pin assignment and usage - Non-blocking vs blocking code patterns - Timeout handling in real-time systems ### Data Processing - Binary data parsing and extraction - Checksum validation algorithms - Fixed-point to floating-point conversion - Byte manipulation with `word()` function ### Arduino/ESP32 Patterns - Proper use of `setup()` and `loop()` - Non-blocking timing with `millis()` - Multiple serial ports (Serial vs Serial1) - Error handling and debugging techniques ## Configuration ### Adjusting Read Interval To change how often the sensor is read, modify the `interval` constant: ```cpp const long interval = 10000; // Read every 10 seconds (in milliseconds) ``` ### Changing GPIO Pins To use different pins, modify these definitions: ```cpp #define PM_SERIAL_RX 39 // Change RX pin #define PM_SERIAL_TX 32 // Change TX pin ``` **Note:** GPIO 39 is input-only on ESP32, so it's ideal for RX. ## Project Structure ``` esp32_NPM_only/ โ”œโ”€โ”€ src/ โ”‚ โ””โ”€โ”€ main.cpp # Main application with extensive comments โ”œโ”€โ”€ include/ # Header files (currently empty) โ”œโ”€โ”€ lib/ # Custom libraries (currently empty) โ”œโ”€โ”€ test/ # Unit tests (currently empty) โ”œโ”€โ”€ platformio.ini # PlatformIO configuration โ”œโ”€โ”€ CLAUDE.md # AI assistant guidance โ””โ”€โ”€ README.md # This file ``` ## NextPM Protocol Reference ### Concentration Request Command | Byte | Value | Description | |------|-------|-------------| | 0 | 0x81 | Command prefix | | 1 | 0x12 | Concentration request | | 2 | 0x6D | Checksum | ### Concentration Response (16 bytes) | Bytes | Description | Used? | |-------|-------------|-------| | 0-1 | Header (0x81 0x12) | โœ… For validation | | 2 | State byte | โœ… Read but not parsed | | 3-4 | N1.0 particle count | โŒ Not used | | 5-6 | N2.5 particle count | โŒ Not used | | 7-8 | N10 particle count | โŒ Not used | | 9-10 | PM1.0 ร— 10 | โœ… Extracted | | 11-12 | PM2.5 ร— 10 | โœ… Extracted | | 13-14 | PM10 ร— 10 | โœ… Extracted | | 15 | Checksum | โœ… Validated | ## Contributing This is an educational project. Suggestions for improving code clarity and educational value are welcome! ## License This project is provided for educational purposes. ## Acknowledgments - NextPM sensor documentation - ESP32 Arduino core community - Students and educators using this project --- **Questions or Issues?** If you encounter problems or have questions about the code, please open an issue on the repository.