This is an ESP32-based configurable sensor monitoring system for IoT applications. It provides a complete foundation for collecting data from multiple sensors and publishing it to MQTT. The system includes web-based configuration, over-the-air updates, and robust connectivity with automatic recovery features.
Key Feature: Runtime configurable sensors! Enable/disable individual sensors through the web interface without code changes. Currently supports BH1750 light sensor, BME680 environmental sensor, and SN-3000-FSJT-N01 wind speed sensor with framework ready for additional sensors.
- Configurable Sensor Support: Runtime enable/disable of individual sensors through web interface
- Multiple Sensor Types: BH1750 light sensor, BME680 environmental sensor, SN-3000-FSJT-N01 wind speed sensor
- Individual MQTT Topics: Each sensor publishes to its own configurable topic
- MQTT Publishing: Automatic data publishing with configurable intervals
- Web Configuration: Captive portal for easy WiFi, MQTT, and sensor setup
- Over-the-Air Updates: Remote firmware and file system updates
- System Monitoring: WiFi signal strength, CPU temperature, and system metrics
- Watchdog Protection: Automatic recovery from system failures
- Persistent Configuration: Settings stored in ESP32 NVS (Non-Volatile Storage)
NEW: This project now includes a configurable sensor system! See SENSOR_CONFIGURATION.md for detailed documentation.
The BH1750 light sensor is fully implemented and ready to use:
- Connect BH1750 to ESP32 (VCC->3.3V, GND->GND, SDA->GPIO21, SCL->GPIO22)
- Flash the firmware and enter configuration mode (after booting press boot button within 10 seconds)
- Enable BH1750 sensor in the web interface
- Configure MQTT topic (default:
sensors/light/bh1750) - Save and reboot - sensor data will be published automatically
The BME680 environmental sensor is fully implemented and ready to use:
- Connect BME680 to ESP32 (VCC->3.3V, GND->GND, SDA->GPIO21, SCL->GPIO22, SDO->GND)
- Flash the firmware and enter configuration mode (after booting press boot button within 10 seconds)
- Enable BME680 sensor in the web interface
- Configure MQTT topic (default:
sensors/environment/bme680) - Save and reboot - sensor data will be published automatically
Note: BME680 uses I2C address 0x76 (SDO pin connected to GND). Both sensors share the same I2C bus without conflicts.
The SN-3000-FSJT-N01 wind speed sensor is fully implemented and ready to use:
- Connect wind sensor to 12V power supply and MAX485 converter to ESP32 (TX->GPIO17, RX->GPIO16, DE/RE->GPIO4)
- Flash the firmware and enter configuration mode (after booting press boot button within 10 seconds)
- Enable wind speed sensor in the web interface
- Configure MQTT topic (default:
sensors/site_name/weather/device_id) - Save and reboot - sensor data will be published automatically
Note: Wind sensor requires 12V power supply and MAX485 RS485-to-TTL converter. See ESP32_WindSensor_MAX485_Wiring.md for complete wiring diagram.
The framework supports easy addition of new sensors. BME680 environmental sensor is now fully implemented alongside BH1750. Search for "TEMPLATE:" comments in the source code to find areas that need customization:
- Sensor Configuration: Pin assignments and communication protocol setup
- Data Structure: Define your sensor-specific data fields
- Sensor Initialization: Add your sensor's initialization sequence
- Data Reading: Implement your sensor's reading logic
- JSON Output: Customize the MQTT data format
This project includes a configurable sensor system with runtime enable/disable:
-
BH1750: Light sensor (I2C) - fully implemented with responsive readings
- Default topic:
sensors/light/bh1750 - Data: Light intensity in lux with real-time responsiveness
- Implementation: One-time measurement mode for accurate readings
- Configuration: Enable/disable via web interface
- Default topic:
-
BME680: Environmental sensor (I2C) - fully implemented for environmental monitoring
- Default topic:
sensors/environment/bme680 - Data: Temperature (°C), humidity (%), pressure (hPa)
- Gas sensor: Basic resistance reading (advanced gas analysis via BSEC library - see enhancement below)
- Configuration: Enable/disable via web interface
- Default topic:
-
SN-3000-FSJT-N01: Wind speed sensor (RS485/Modbus RTU) - fully implemented for weather monitoring
- Default topic:
sensors/site_name/weather/device_id - Data: Instantaneous wind speed, rolling average, gust detection, raw sensor values
- Protocol: Modbus RTU over RS485 at 4800 baud
- Configuration: Enable/disable via web interface with configurable timing parameters
- Hardware: Requires MAX485 TTL-to-RS485 converter module
- Default topic:
🚀 Future Enhancement - BSEC Library Integration
TODO: Consider implementing Bosch BSEC (Bosch Sensortec Environmental Cluster) library for advanced BME680 gas sensor functionality.
Benefits of BSEC Integration:
- Professional Air Quality Monitoring: Indoor Air Quality (IAQ) index (0-500 scale)
- Advanced Gas Analysis: CO₂ equivalent and VOC equivalent measurements
- Intelligent Calibration: Self-calibrating algorithms with baseline management
- Breath VOC Detection: Enhanced volatile organic compound detection
- Static IAQ Assessment: Air quality without motion dependency
- Accuracy Enhancement: Professional-grade sensor fusion algorithms
Implementation Complexity: Moderate (6/10) - requires proprietary library integration, calibration system, and extended testing period for baseline establishment.
Estimated Benefits: Transform basic environmental monitoring into professional-grade air quality assessment suitable for smart home automation, health monitoring, and industrial applications.
Target Applications: Smart HVAC control, indoor air quality alerts, health monitoring systems, building automation with air quality-based ventilation control.
- DHT22: Temperature and humidity sensor (GPIO)
- DS18B20: Temperature sensor (1-Wire)
- MQ sensors: Gas sensors (ADC)
- Analog sensors: Using ESP32's ADC
- BME280: Temperature, humidity, pressure (I2C/SPI)
- SHT30: Temperature and humidity (I2C)
See SENSOR_CONFIGURATION.md for detailed sensor addition instructions.
- ESP32 Development Board (tested with ESP32 DevKit V1)
- BH1750 Light Sensor (optional, I2C interface)
- BME680 Environmental Sensor (optional, I2C interface)
- SN-3000-FSJT-N01 Wind Speed Sensor (optional, RS485/Modbus RTU interface)
- MAX485 TTL-to-RS485 Converter (required for wind speed sensor)
- Other Sensor Modules (customize based on your needs)
- Power Supply: 5V USB or 3.3V-5V power source (12V for wind sensor)
- Pull-up resistors: 4.7kΩ for I2C sensors (usually built-in on sensor modules)
| Function | ESP32 Pin | Purpose |
|---|---|---|
| I2C SCL | GPIO22 (D22) | I2C Clock (if using I2C sensors) |
| I2C SDA | GPIO21 (D21) | I2C Data (if using I2C sensors) |
| Status LED | GPIO2 (D2) | System status and MQTT heartbeat |
| Boot Button | GPIO0 (D0) | Enter configuration mode |
| Wind TX | GPIO17 (D17) | UART2 TX for MAX485 converter |
| Wind RX | GPIO16 (D16) | UART2 RX for MAX485 converter |
| Wind DE/RE | GPIO4 (D4) | MAX485 Direction Enable/Receive Enable |
Note: Pin assignments can be changed in the source code based on your sensor requirements.
The ESP32 publishes sensor data in JSON format to the configured MQTT topic. The message includes both system metrics and data from all enabled sensors in a single combined message.
{
// ESP32 processor metrics
"processor": {
"WiFiRSSI": 75, // WiFi signal strength (% - 0-100%)
"IPAddress": "192.168.1.150", // Current IP address
"CPUTemperature": 32.0, // ESP32 CPU temperature (°C - placeholder)
"SoftwareVersion": "1.3.0", // Firmware version
"ChipID": "A1B2C3D4E5F6", // ESP32 unique chip identifier
"WDTRestartCount": 2 // Watchdog restart counter
},
// All enabled sensor data
"sensors": {
"bh1750": { // BH1750 light sensor (if enabled)
"name": "BH1750 Light Sensor",
"valid": true,
"timestamp": 12345,
"lux": 1250.5
},
"bme680": { // BME680 environmental sensor (if enabled)
"name": "BME680 Environmental",
"valid": true,
"timestamp": 12345,
"temperature": 25.2,
"humidity": 65.5,
"pressure": 1013.25,
"gas_resistance": 0
},
"wind_speed": { // SN-3000-FSJT-N01 wind speed sensor (if enabled)
"name": "SN-3000 Wind Speed",
"valid": true,
"timestamp": 12345,
"instantaneous": 5.2,
"average": 4.8,
"gust": 7.1,
"raw_reading": 52
}
// Additional sensors will be added here as they are enabled
}
}- WiFiRSSI: WiFi signal strength as percentage (0-100%)
- IPAddress: Current IP address assigned by DHCP
- CPUTemperature: ESP32 internal temperature (placeholder implementation)
- SoftwareVersion: Firmware version (auto-generated from CMakeLists.txt VERSION field)
- ChipID: Unique ESP32 chip identifier (MAC-based)
- WDTRestartCount: Number of watchdog-triggered restarts (reliability metric)
Each enabled sensor appears as a separate object within the "sensors" section:
- name: Human-readable sensor name
- valid: Boolean indicating successful sensor reading
- timestamp: Timestamp of the reading in milliseconds
- sensor-specific fields: Data fields specific to each sensor type
- Successful Reading: MQTT message published with current data from all enabled sensors
- Failed Reading: No MQTT message published (prevents invalid data)
- Partial Success: Message published with data from successfully read sensors only
- Watchdog Protection: ESP32 resets if no successful MQTT publish within timeout period
- Hardware Connection: Wire your sensor(s) to ESP32 according to your sensor's requirements
- Power On: Connect ESP32 to power source via USB
- Configuration Mode:
- After booting you have 10 seconds to press the boot button (GPIO0)
- ESP32 will create a WiFi access point named "ESP32-CONFIG-XXXX"
- Web Configuration:
- Connect to the ESP32 access point
- Open any website in your browser (captive portal will redirect)
- Configure WiFi credentials and MQTT broker settings
- Set device name and sampling interval
- Normal Operation: ESP32 will restart and begin collecting/publishing data
- WiFi SSID/Password: Network credentials for internet connectivity
- MQTT Broker URL: MQTT server address (e.g., mqtt://192.168.1.100)
- Data Topic: MQTT topic for sensor data publishing
- Sample Interval: Time between sensor data being read and sent to MQTT (milliseconds)
- System Information: View current configuration and system status
- OTA Updates: Upload new firmware or file system images
- Configuration Export: Download current settings as JSON
- Reset Options: Watchdog counter reset
The SN-3000-FSJT-N01 wind speed sensor communicates via Modbus RTU protocol over RS485. A MAX485 converter is required to interface with the ESP32's UART pins.
Technical Specifications:
- Communication: Modbus RTU over RS485
- Baud Rate: 4800, 8N1
- Device Address: 0x01
- Register: 0x0000 (wind speed data)
- Power: 12V DC
- Output Range: 0-60 m/s
Data Format: The sensor publishes four types of wind speed data in the MQTT payload:
instantaneous: Current wind speed reading (m/s)average: Rolling average over configured period (m/s)gust: Maximum wind speed detected in period (m/s)raw_reading: Raw 16-bit Modbus register value (divide by 10 to get m/s)
Hardware Connections:
- Wind sensor 12V power supply
- RS485 A/B differential pair to MAX485
- MAX485 to ESP32: RX→GPIO16, TX→GPIO17, DE/RE→GPIO4
- See
ESP32_WindSensor_MAX485_Wiring.mdfor complete wiring diagram
Configuration:
The wind sensor can be enabled/disabled and configured through the web interface at /parameters. Rolling buffer settings allow customization of averaging periods and gust detection sensitivity.
This configurable sensor system can be adapted for various IoT monitoring applications:
- Environmental Monitoring: Temperature, humidity, air quality sensors
- Smart Home: Light, motion, door/window sensors
- Industrial IoT: Pressure, vibration, current sensors
- Agriculture: Soil moisture, pH, light sensors
- Energy Management: Power consumption, solar panel monitoring
- Security Systems: Motion detection, door/window status
- Weather Stations: Temperature, humidity, pressure, rainfall
- Building Automation: HVAC monitoring and control
# configuration.yaml - Updated for combined sensor data format
sensor:
# BH1750 Light Sensor
- platform: mqtt
name: "ESP32 Light Level"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.bh1750.lux if value_json.sensors.bh1750 else 'unavailable' }}"
unit_of_measurement: "lx"
availability_template: "{{ 'online' if value_json.sensors.bh1750.valid else 'offline' }}"
# BME680 Environmental Sensor
- platform: mqtt
name: "ESP32 Temperature"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.bme680.temperature if value_json.sensors.bme680 else 'unavailable' }}"
unit_of_measurement: "°C"
availability_template: "{{ 'online' if value_json.sensors.bme680.valid else 'offline' }}"
- platform: mqtt
name: "ESP32 Humidity"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.bme680.humidity if value_json.sensors.bme680 else 'unavailable' }}"
unit_of_measurement: "%"
availability_template: "{{ 'online' if value_json.sensors.bme680.valid else 'offline' }}"
- platform: mqtt
name: "ESP32 Pressure"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.bme680.pressure if value_json.sensors.bme680 else 'unavailable' }}"
unit_of_measurement: "hPa"
availability_template: "{{ 'online' if value_json.sensors.bme680.valid else 'offline' }}"
# SN-3000-FSJT-N01 Wind Speed Sensor
- platform: mqtt
name: "ESP32 Wind Speed"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.wind_speed.instantaneous if value_json.sensors.wind_speed else 'unavailable' }}"
unit_of_measurement: "m/s"
availability_template: "{{ 'online' if value_json.sensors.wind_speed.valid else 'offline' }}"
- platform: mqtt
name: "ESP32 Wind Speed Average"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.wind_speed.average if value_json.sensors.wind_speed else 'unavailable' }}"
unit_of_measurement: "m/s"
availability_template: "{{ 'online' if value_json.sensors.wind_speed.valid else 'offline' }}"
- platform: mqtt
name: "ESP32 Wind Gust"
state_topic: "sensors/data"
value_template: "{{ value_json.sensors.wind_speed.gust if value_json.sensors.wind_speed else 'unavailable' }}"
unit_of_measurement: "m/s"
availability_template: "{{ 'online' if value_json.sensors.wind_speed.valid else 'offline' }}"
# System Information
- platform: mqtt
name: "ESP32 WiFi Signal"
state_topic: "sensors/data"
value_template: "{{ value_json.processor.WiFiRSSI }}"
unit_of_measurement: "%"
- platform: mqtt
name: "ESP32 IP Address"
state_topic: "sensors/data"
value_template: "{{ value_json.processor.IPAddress }}"
binary_sensor:
# Overall sensor status
- platform: mqtt
name: "ESP32 Online"
state_topic: "sensors/data"
value_template: "{{ 'ON' if value_json.processor else 'OFF' }}"
payload_on: "ON"
payload_off: "OFF"# Combined sensor data - parse JSON and create multiple measurements
sensor_data,device=ESP32-Sensor,sensor=bh1750 lux=1250.5,valid=1 1642234567890000000
sensor_data,device=ESP32-Sensor,sensor=bme680 temperature=25.2,humidity=65.5,pressure=1013.25,gas_resistance=0,valid=1 1642234567890000000
sensor_data,device=ESP32-Sensor,sensor=wind_speed instantaneous=5.2,average=4.8,gust=7.1,raw_reading=52,valid=1 1642234567890000000
system_data,device=ESP32-Sensor wifi_rssi=75,cpu_temp=32.0,wdt_restarts=2 1642234567890000000
[
{
"id": "mqtt_in",
"type": "mqtt in",
"topic": "sensors/data",
"broker": "mqtt_broker"
},
{
"id": "json_parse",
"type": "json"
},
{
"id": "sensor_switch",
"type": "switch",
"property": "payload.data.sensor_value_1",
"rules": [
{"t": "lt", "v": "threshold", "vt": "num"},
{"t": "gte", "v": "threshold", "vt": "num"}
]
}
]To adapt this template for your specific sensor:
-
Update Sensor Configuration:
- Modify the
#definestatements for your sensor's I2C address and commands - Change pin assignments if needed
- Modify the
-
Customize Data Structure:
- Edit the
sensor_data_tstruct to match your sensor's data fields - Update variable names and data types as needed
- Edit the
-
Implement Sensor Functions:
- Replace
sensor_init()with your sensor's initialization sequence - Modify
read_sensor_value()to read your sensor's data format - Update
read_sensor_data()to populate your data structure
- Replace
-
Update MQTT Format:
- Customize the JSON output in
publish_sensor_data_mqtt() - Change field names and add/remove data fields as needed
- Customize the JSON output in
-
Update Documentation:
- Modify this README for your specific sensor and use case
- Update the MQTT data structure documentation
- Check Wiring: Verify sensor connections according to your sensor's datasheet
- Communication Protocol: Ensure correct I2C address, SPI settings, or GPIO configuration
- Power Supply: Verify sensor voltage requirements (3.3V vs 5V)
- Pull-up Resistors: Add 4.7kΩ pull-ups for I2C if not already present
- Pull-up Resistors: Most BH1750 modules include built-in pull-ups
- Signal Strength: Check WiFi signal strength in system info
- Credentials: Verify SSID and password in configuration
- Network: Ensure 2.4GHz WiFi (ESP32 doesn't support 5GHz)
- Firewall: Check if network blocks MQTT traffic
- Broker Connection: Verify MQTT broker URL and port
- Network Connectivity: Ensure ESP32 can reach MQTT broker
- Topic Permissions: Check if broker requires authentication
- QoS Settings: Verify MQTT quality of service configuration
Common MQTT Connection Errors:
E (xxxxx) esp-tls: [sock=xx] select() timeout
E (xxxxx) transport_base: Failed to open a new connection
E (xxxxx) mqtt_client: Error transport connect
Solutions:
- Check MQTT Broker URL: Ensure format is
mqtt://IP_ADDRESSormqtt://IP_ADDRESS:PORT- ✅
mqtt://192.168.1.100(uses default port 1883) - ✅
mqtt://192.168.1.100:1883(explicit port) - ❌
192.168.1.100(missing mqtt:// protocol)
- ✅
- Network Reachability: Ping MQTT broker from same network as ESP32
- Firewall Rules: Check if port 1883 is blocked by router/firewall
- Broker Status: Verify MQTT broker service is running and accepting connections
- Authentication: If broker requires login, ensure credentials are configured
- URL Format: Use IP address instead of hostname if DNS issues suspected
- Configuration Mode: After booting you have 10 seconds to press the boot button
- AP Mode: Look for "ESP32-CONFIG-XXXX" WiFi network
- Browser Issues: Try different browser or clear cache
- Firewall: Disable firewall/antivirus temporarily
- Serial Monitor: Connect via USB for detailed log output
- System Info: Check
/sysinfo.jsonendpoint for system status - LED Indicator: GPIO2 LED blinks on successful MQTT publish
- Watchdog Counter: Monitor restart count for stability issues
- ESP32: ~80mA active, ~10µA deep sleep
- BH1750: ~120µA active, <1µA standby
- BME680: ~2.1µA @ 1Hz, ~90µA @ 10Hz (typical)
- SN-3000-FSJT-N01: ~200mA @ 12V DC (2.4W)
- Total System: ~85-100mA during normal operation (excluding wind sensor)
- Sensor Resolution: 16-bit (65,536 levels)
- Measurement Time: ~120ms (high resolution mode)
- I2C Speed: 100kHz (configurable up to 400kHz)
- MQTT Publish Rate: Configurable (default: 5 seconds)
- WiFi Reconnection: Automatic with exponential backoff
- Flash: ~1.5MB firmware, ~500KB file system
- RAM: ~200KB free heap during operation
- NVS: <4KB for configuration storage
- Framework: ESP-IDF v4.4 or later
- Platform: PlatformIO or Arduino IDE
- Compiler: Xtensa GCC cross-compiler
- Dependencies: ESP-IDF components (WiFi, MQTT, NVS, I2C)
The project implements automatic version management with a single source of truth approach to eliminate version synchronization issues and ensure consistency across all project components.
CMakeLists.txt (VERSION "X.Y.Z")
↓ (CMake configure_file)
include/project_version.h.in (template)
↓ (Auto-generated during build)
include/project_version.h (header with constants)
↓ (Included by source code)
All project components use same version
Source of Truth:
CMakeLists.txt: Containsproject(ESP32-MQTT-TEMPLATE VERSION "X.Y.Z")- THIS IS THE ONLY FILE YOU SHOULD EDIT FOR VERSION CHANGES
- Format:
project(ESP32-MQTT-TEMPLATE VERSION "1.4.0") - Supports semantic versioning (MAJOR.MINOR.PATCH)
Template System:
include/project_version.h.in: CMake template file- Contains
#define PROJECT_VERSION "@PROJECT_VERSION@" - Do not edit manually - CMake processes this file
- Template placeholders are replaced during build
- Contains
Generated Files (DO NOT EDIT MANUALLY):
include/project_version.h: Auto-generated header- Created by CMake during build process
- Contains actual version constants
- Included by C/C++ source files
- Regenerated on every build if CMakeLists.txt changes
The version system automatically integrates with all project components:
1. Firmware Boot Logs:
I (1234) ESP32-MQTT-TEMPLATE: Software Version: 1.4.0
I (1235) ESP32-MQTT-TEMPLATE: Build Date: Jul 23 2025
2. MQTT JSON Messages:
{
"processor": {
"SoftwareVersion": "1.4.0",
"BuildDate": "Jul 23 2025",
...
},
"data": { ... }
}3. Web Interface:
- System information page displays current version
- About page shows version and build information
- OTA update pages reference current version
4. System API Endpoints:
GET /sysinfo.json
{
"firmware_version": "1.4.0",
"build_date": "Jul 23 2025",
...
}Step 1: Edit CMakeLists.txt
# Change this line only:
project(ESP32-MQTT-TEMPLATE VERSION "1.5.0")Step 2: Build Project
pio run
# or
cmake --build buildStep 3: Automatic Propagation
- CMake detects version change
- Regenerates
include/project_version.h - All source files pick up new version
- Build output shows new version
- Runtime logs display new version
Check Current Version:
- Build logs: Version appears in compilation output
- Serial monitor: Boot sequence shows version
- Web interface: System information page
- MQTT messages: Published in processor metrics
- Source code:
PROJECT_VERSIONconstant
Build-Time Verification:
# Check generated header
cat include/project_version.h
# Verify CMake configuration
cmake --build build --verbose✅ Single Source of Truth: Only one place to update versions
✅ Automatic Synchronization: No manual file editing required
✅ Build-Time Generation: Version always matches build
✅ Runtime Availability: Version accessible in all code
✅ Zero Maintenance: No version file management needed
✅ Error Prevention: Eliminates version mismatch issues
Problem: Old version still showing after update
# Solution: Clean and rebuild
pio run -t clean
pio runProblem: Version header not found
# Solution: Ensure template file exists
ls include/project_version.h.inProblem: CMake not detecting version change
# Solution: Force CMake reconfiguration
rm -rf .pio/build
pio runThe project maintains semantic versioning (MAJOR.MINOR.PATCH):
- MAJOR: Breaking changes or major feature additions
- MINOR: New features, backward compatible
- PATCH: Bug fixes, minor improvements
Example progression:
1.0.0- Initial BH1750 implementation1.1.0- Added web configuration interface1.1.1- Fixed MQTT connection timeout1.2.0- Added OTA update capability1.3.0- Enhanced sensor error handling1.4.0- Implemented automatic version management
The codebase is designed for easy expansion:
// Add new sensor to data structure
typedef struct {
float sunlight; // BH1750 light sensor
float temperature; // Additional temperature sensor
float humidity; // Additional humidity sensor
bool sensors_ok; // Combined sensor status
} input_data_t;// Multiple topic publishing
esp_mqtt_client_publish(client, "sensors/light/lux", lux_string, 0, 1, 0);
esp_mqtt_client_publish(client, "sensors/light/status", status_string, 0, 1, 0);
esp_mqtt_client_publish(client, "sensors/system/wifi", wifi_string, 0, 1, 0);This project is based on the ESP32MQTTBase template and has been adapted for BH1750 light sensor applications.
- Original Template: ESP32 MQTT Data Template
- Sensor Integration: BH1750 I2C Light Sensor
- Current Version: Specialized for ambient light monitoring applications
For technical support or contributions, please refer to the project documentation and issue tracker.