System Requirements
| Parameter | Requirement | Target |
|---|---|---|
| Temperature range | −40°C to +85°C | BME280 (±1°C) |
| Humidity | 0–100% RH | BME280 (±3% RH) |
| Air quality | eCO2 + TVOC | CCS811 (400–8192 ppm) |
| Particulate matter | PM2.5 / PM10 | PMS5003 laser sensor |
| Connectivity | >2 km range, low power | LoRa (SX1276, 868/915 MHz) |
| Power | Solar + battery, >7 days autonomy | 6V/2W panel + 3.7V 3400mAh Li-Ion |
| Enclosure | Outdoor, IP65 | ABS with Stevenson screen |
| Size | <120 × 80 × 50 mm (PCB) | 4-layer, 100 × 70 mm |
System Architecture & BOM
flowchart TD
A["Solar Panel
6V / 2W"] --> B["MPPT Charger
BQ25504"]
B --> C["Li-Ion Battery
3.7V 3400mAh"]
C --> D["LDO 3.3V
TPS7A20"]
D --> E["STM32L4
MCU"]
E -->|I2C| F["BME280
Temp/Hum/Pres"]
E -->|I2C| G["CCS811
Air Quality"]
E -->|UART| H["PMS5003
Particulate"]
E -->|SPI| I["SX1276
LoRa Radio"]
I --> J["Antenna
868/915 MHz"]
E -->|I2C| K["EEPROM
Data Log"]
style E fill:#3B9797,color:#fff
style A fill:#f5a623,color:#fff
# Bill of Materials — cost analysis for environmental monitor
# Prices in USD at qty 100
bom = [
("STM32L476RG", "MCU, ARM Cortex-M4, 1MB Flash", 3.85, 1),
("BME280", "Temp / Humidity / Pressure", 2.50, 1),
("CCS811", "eCO2 / TVOC gas sensor", 5.80, 1),
("PMS5003", "Laser particulate sensor", 12.50, 1),
("SX1276", "LoRa transceiver 868/915MHz", 3.20, 1),
("BQ25504", "MPPT solar charger IC", 3.40, 1),
("TPS7A20", "LDO 3.3V 250mA ultra-low Iq", 0.65, 1),
("3400mAh Li-Ion", "18650 battery cell", 2.80, 1),
("6V 2W Solar", "Monocrystalline panel", 4.50, 1),
("SMA Antenna", "868/915MHz whip, 3dBi", 1.20, 1),
("PCB 4-layer", "100x70mm, ENIG, 1.6mm", 2.40, 1),
("ABS Enclosure", "IP65, 158x90x60mm", 3.50, 1),
("Passives kit", "Caps, resistors, inductors", 1.20, 1),
("Connectors", "JST-PH, SMA, headers", 0.80, 1),
]
print("Environmental Monitor BOM — Qty 100")
print("=" * 65)
print(f"{'Component':<20} {'Description':<35} {'Unit $':>7}")
print("-" * 65)
total = 0
for name, desc, price, qty in bom:
line_total = price * qty
total += line_total
print(f"{name:<20} {desc:<35} ${price:>6.2f}")
print("-" * 65)
print(f"{'TOTAL BOM COST':<55} ${total:>6.2f}")
print(f"\nWith 15% assembly + overhead: ${total * 1.15:.2f}")
print(f"Suggested retail (3x markup): ${total * 3:.2f}")
Schematic Highlights
/* Sensor initialization — I2C bus scan and verify
All sensors on single I2C1 bus (PB6=SCL, PB7=SDA) */
#include <stdint.h>
#include <stdio.h>
/* I2C addresses (7-bit) */
#define BME280_ADDR 0x76 /* SDO=GND: 0x76, SDO=VDD: 0x77 */
#define CCS811_ADDR 0x5A /* ADDR=LOW: 0x5A, ADDR=HIGH: 0x5B */
#define EEPROM_ADDR 0x50 /* A0=A1=A2=GND */
typedef struct {
const char *name;
uint8_t addr;
uint8_t id_reg;
uint8_t expected_id;
} sensor_info_t;
sensor_info_t sensors[] = {
{"BME280", BME280_ADDR, 0xD0, 0x60}, /* Chip ID register */
{"CCS811", CCS811_ADDR, 0x20, 0x81}, /* HW_ID register */
{"EEPROM", EEPROM_ADDR, 0x00, 0x00}, /* No ID — ACK check only */
};
/* Power budget for sleep/wake cycle */
/*
* Mode | Current | Duration | Energy (mAh)
* --------------|----------|----------|-------------
* Deep sleep | 2.1 µA | 595 s | 0.00035
* Sensor warmup | 25 mA | 3 s | 0.02083
* Measurement | 15 mA | 1 s | 0.00417
* LoRa TX | 120 mA | 1 s | 0.03333
* Total/cycle | — | 600 s | 0.05868
* Per day (144) | — | — | 8.45 mAh
* Battery life | — | — | 402 days
*/
Solar Power Budget
# Solar power budget — daily energy balance
# Determines battery autonomy and solar panel sizing
# Battery
battery_capacity_mah = 3400 # 18650 cell
battery_voltage = 3.7 # Nominal voltage
battery_energy_wh = battery_capacity_mah * battery_voltage / 1000
# Power consumption per cycle (10-minute interval)
sleep_current_ua = 2.1
sleep_duration_s = 595
warmup_current_ma = 25
warmup_duration_s = 3
measure_current_ma = 15
measure_duration_s = 1
lora_current_ma = 120
lora_duration_s = 1
# Energy per cycle (mAh)
cycle_energy_mah = (
sleep_current_ua / 1000 * sleep_duration_s / 3600 +
warmup_current_ma * warmup_duration_s / 3600 +
measure_current_ma * measure_duration_s / 3600 +
lora_current_ma * lora_duration_s / 3600
)
cycles_per_day = 24 * 60 / 10 # every 10 minutes
daily_consumption_mah = cycle_energy_mah * cycles_per_day
# Solar harvest (conservative: 4 peak sun hours)
solar_panel_w = 2.0
mppt_efficiency = 0.80
peak_sun_hours = 4
daily_harvest_wh = solar_panel_w * mppt_efficiency * peak_sun_hours
daily_harvest_mah = daily_harvest_wh / battery_voltage * 1000
# Results
print("Solar Power Budget — Environmental Monitor")
print("=" * 55)
print(f"\nBattery: {battery_capacity_mah} mAh @ {battery_voltage}V = {battery_energy_wh:.1f} Wh")
print(f"\nPer cycle ({int(sleep_duration_s+warmup_duration_s+measure_duration_s+lora_duration_s)}s):")
print(f" Sleep: {sleep_current_ua} µA × {sleep_duration_s}s")
print(f" Warmup: {warmup_current_ma} mA × {warmup_duration_s}s")
print(f" Measure: {measure_current_ma} mA × {measure_duration_s}s")
print(f" LoRa TX: {lora_current_ma} mA × {lora_duration_s}s")
print(f" Cycle total: {cycle_energy_mah:.5f} mAh")
print(f"\nDaily ({int(cycles_per_day)} cycles): {daily_consumption_mah:.2f} mAh")
print(f"\nSolar harvest: {solar_panel_w}W × {mppt_efficiency:.0%} eff × {peak_sun_hours}h")
print(f" = {daily_harvest_wh:.1f} Wh/day = {daily_harvest_mah:.0f} mAh/day")
print(f"\nEnergy balance: +{daily_harvest_mah - daily_consumption_mah:.0f} mAh/day (surplus)")
battery_only_days = battery_capacity_mah / daily_consumption_mah
print(f"Battery-only autonomy: {battery_only_days:.0f} days")
Firmware State Machine
stateDiagram-v2
[*] --> INIT
INIT --> SLEEP : Config OK
SLEEP --> WAKE : RTC alarm
WAKE --> MEASURE : Sensors ready
MEASURE --> TRANSMIT : Data valid
MEASURE --> LOG_ERROR : Sensor fail
TRANSMIT --> SLEEP : TX complete
LOG_ERROR --> SLEEP : Error stored
TRANSMIT --> RETRY : TX fail
RETRY --> TRANSMIT : Attempt < 3
RETRY --> SLEEP : Max retries
BOM Cost Calculator
Environmental Monitor BOM Calculator
Estimate BOM cost at different production volumes. Download as Word, Excel, or PDF.
Conclusion
This capstone project integrates sensor interfacing, solar power harvesting, LoRa wireless communication, and ultra-low-power firmware design into a production-ready environmental monitoring system. The complete BOM under $50 makes this viable for small-run manufacturing.
Next Capstone
In Capstone 2: AI Smart Power Supply, we’ll design a digitally-controlled bench power supply with current sensing, USB-PD negotiation, and an intelligent load management system.