Update documentation: Add README and revise CLAUDE.md
- Created comprehensive README.md with: - Project overview and features - Hardware requirements and wiring diagram - Installation and usage instructions - Detailed troubleshooting guide - Learning objectives for students - NextPM protocol reference - Updated CLAUDE.md to reflect: - Simplified educational implementation - Removal of particle counts - Current function structure - Educational focus and objectives 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
71
CLAUDE.md
71
CLAUDE.md
@@ -4,7 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a PlatformIO-based ESP32 Arduino project for communicating with a NextPM (NPM) particulate matter sensor over serial connection. The project reads PM1, PM2.5, and PM10 measurements in both µg/m³ and particles per liter (pcs/L).
|
||||
This is a **simplified, educational** PlatformIO-based ESP32 Arduino project for communicating with a NextPM (NPM) particulate matter sensor over serial connection. The project reads PM1, PM2.5, and PM10 mass concentration measurements in µg/m³.
|
||||
|
||||
**Educational Focus:**
|
||||
- Extensively commented code to help students understand serial communication protocols
|
||||
- Simplified implementation focusing only on PM concentration readings (particle counts removed)
|
||||
- Clear step-by-step documentation of the sensor communication process
|
||||
- Non-blocking timing pattern demonstration
|
||||
|
||||
## Build and Development Commands
|
||||
|
||||
@@ -46,46 +52,55 @@ pio run --target clean
|
||||
|
||||
### Serial Communication Protocol
|
||||
|
||||
The NextPM sensor uses a binary protocol with checksums. Communication follows a request-response pattern with specific message formats:
|
||||
The NextPM sensor uses a binary protocol with checksums. Communication follows a request-response pattern:
|
||||
|
||||
**Message Structure:**
|
||||
- Header (2 bytes): Command identifier (e.g., `0x81 0x16`)
|
||||
**Message Structure (16 bytes total):**
|
||||
- Header (2 bytes): `0x81 0x12` (concentration response identifier)
|
||||
- State (1 byte): Device state bits
|
||||
- Data (variable): Response payload
|
||||
- Data (12 bytes): 6 values × 2 bytes each
|
||||
- Bytes 0-5: N1, N2.5, N10 particle counts (not used in this simplified version)
|
||||
- Bytes 6-11: PM1, PM2.5, PM10 mass concentrations
|
||||
- Checksum (1 byte): Sum of all bytes mod 0x100 must equal 0
|
||||
|
||||
**State Machine Enums:**
|
||||
The code uses multiple enums (`NPM_waiting_for_4`, `NPM_waiting_for_8`, `NPM_waiting_for_16`) to track parsing state for different response types (4, 8, or 16 bytes total).
|
||||
|
||||
### Key Functions
|
||||
|
||||
**Initialization (`powerOnTestNPM`):**
|
||||
- Waits 15 seconds for sensor startup
|
||||
- Queries sensor state
|
||||
- Starts sensor if stopped
|
||||
- Reads firmware version and temperature/humidity
|
||||
**`checksum_valid()`**
|
||||
- Validates 16-byte messages using checksum algorithm
|
||||
- Returns true if sum of all bytes modulo 256 equals 0
|
||||
|
||||
**Measurement (`fetchSensorNPM_1min`):**
|
||||
- Sends concentration command (1-minute averaged readings)
|
||||
- Parses 16-byte response containing 6 values:
|
||||
- N1, N2.5, N10 (particle counts as pcs/L)
|
||||
- PM1, PM2.5, PM10 (mass concentrations as µg/m³ × 10)
|
||||
- Validates checksum before accepting data
|
||||
**`send_concentration_command()`**
|
||||
- Sends 3-byte command sequence: `{0x81, 0x12, 0x6D}`
|
||||
- Requests 1-minute averaged concentration readings
|
||||
|
||||
**Loop Behavior:**
|
||||
- Reads sensor every 60 seconds (configurable via `interval` constant)
|
||||
- Non-blocking timing using `millis()`
|
||||
**`read_concentration()`**
|
||||
- Main sensor reading function with 11 documented steps
|
||||
- Sends command, waits for response (3-second timeout)
|
||||
- Validates header and checksum
|
||||
- Extracts PM1, PM2.5, PM10 values from data bytes
|
||||
- Converts scaled values (÷10) to actual µg/m³
|
||||
- Displays results on serial monitor
|
||||
|
||||
**`setup()`**
|
||||
- Initializes USB serial (115200 baud) for debugging
|
||||
- Initializes sensor serial (115200 baud, 8E1 parity)
|
||||
- Waits 15 seconds for sensor power-up
|
||||
|
||||
**`loop()`**
|
||||
- Non-blocking timing implementation using `millis()`
|
||||
- Reads sensor every 10 seconds (configurable via `interval`)
|
||||
- Demonstrates proper Arduino timing patterns
|
||||
|
||||
### File Organization
|
||||
|
||||
- `src/main.cpp`: Main application logic, NPM protocol implementation, sensor state machine
|
||||
- `src/utils.h`: Protocol constants, enums, checksum validation prototypes
|
||||
- `src/utils.cpp`: Utility functions for checksum validation and NPM command transmission
|
||||
- `src/main.cpp`: Complete application in single file with extensive educational comments
|
||||
- `platformio.ini`: PlatformIO configuration for ESP32
|
||||
- `CLAUDE.md`: Developer guidance for AI assistance
|
||||
- `README.md`: User documentation and getting started guide
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The sensor requires a 3-second timeout for serial responses
|
||||
- All particle concentration values from the sensor are scaled (PM values by 10, temperature/humidity by 100)
|
||||
- The `nextpmconnected` flag prevents infinite loops if sensor disconnects
|
||||
- Comments are in French in some sections of the code
|
||||
- PM values from the sensor are scaled by 10 (e.g., 25.3 µg/m³ sent as 253)
|
||||
- The 15-second startup delay is critical - sensor won't respond if queried too early
|
||||
- All comments are in English for educational purposes
|
||||
- Code emphasizes readability and learning over performance optimization
|
||||
|
||||
369
README.md
Normal file
369
README.md
Normal file
@@ -0,0 +1,369 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user