RoomSensorProject combines real BME280 and BH1750 measurements, a custom SSD1306 display driver, FreeRTOS task separation, local visual and audible alerts, and Python telemetry in one embedded system.
STM32
Embedded C++
FreeRTOS
CMSIS-RTOS2
I2C
UART
Python
PySerial
Matplotlib
BME280
BH1750
SSD1306
StatusCompleted
FocusFeatured · Embedded systems
Core toolsSTM32 · Embedded C++ · FreeRTOS
ROOMSENSOR / LIVEREAL SENSORS
Temperature72.4°F
Humidity45.1%
Pressure1012.8hPa
Room statusIDEALGREEN
BME280 + BH1750→8-message queue→OLED + USART2
Project overview
RoomSensorProject is a completed real-time environmental monitoring and alert system built around the STM32 NUCLEO-L476RG. It reads temperature, humidity, and pressure from a BME280 and ambient light from a BH1750, presents room conditions on an SSD1306 OLED, classifies comfort as IDEAL, CLOSE, or ALERT, and drives an RGB LED and active-low buzzer. FreeRTOS tasks and an eight-message CMSIS-RTOS2 queue separate acquisition from USART2 telemetry, while Python tools provide serial monitoring, timestamped CSV logging, reset detection, and live Matplotlib graphs.
Completed system
Real sensors, local alerts, and telemetry—all working together.
The STM32 now reads the BME280 and BH1750, updates the OLED, evaluates room comfort, drives the RGB LED and buzzer, and streams each sample to Python. The complete hardware-to-dashboard path is implemented and working; the only portfolio addition still to come is a recorded demo.
01Sense + display
BME280 and BH1750 measurements share I2C with the SSD1306 OLED.
02Classify + alert
Comfort logic drives the RGB LED and a push-button-muted repeating buzzer.
03Transmit + visualize
FreeRTOS queues RoomData for USART2, CSV logging, reset detection, and live graphs.
Video demonstration
System walkthrough coming soon.
I'll add a recorded demonstration showing live sensor readings, the OLED interface, comfort-state changes, RGB and buzzer alerts, push-button muting, and the Python dashboard.
Demonstration video
Recording coming soon
Technical details
How the system works.
A closer look at the architecture, implementation decisions, and validation behind this project.
01
Firmware architecture
STM32CubeMX-generated peripheral initialization remains in main.c, while application behavior is separated into app.cpp. The mixed C and C++ design preserves the generated STM32 setup and uses extern "C" at the language boundary.
The BME280, BH1750, and SSD1306 each have dedicated C++ header and source files. Keeping the hardware drivers separate from the RTOS application logic made individual device bring-up, calibration, display work, and debugging easier to isolate.
STM32 HAL and STM32CubeMX / STM32CubeIDE
CubeMX-generated C initialization with a modular C++ application layer
Dedicated BME280, BH1750, and SSD1306 drivers
02
Shared I2C sensor and display bus
The BME280, BH1750, and SSD1306 share the STM32 I2C bus at addresses 0x76, 0x23, and 0x3C. I verified each address with an I2C scanner before integrating the devices into the full application.
For the BME280, I read chip ID register 0xD0 and confirmed the expected 0x60 value before implementing its calibration and compensation calculations. The BH1750 supplies ambient-light measurements, and the custom SSD1306 driver continuously updates the local display.
03
RTOS tasks and telemetry
Three FreeRTOS tasks divide the application: defaultTask handles heartbeat and alert behavior, roomDataTask acquires the sensors and creates each RoomData sample, and serialTask owns UART transmission.
An eight-message CMSIS-RTOS2 queue decouples sensor acquisition from serial output. serialTask receives each message and transmits telemetry through USART2 at 115200 baud over the Nucleo ST-LINK virtual COM port.
Three focused FreeRTOS tasks
Eight-message producer / consumer queue
Task stack and FreeRTOS heap tuning
USART2 telemetry through ST-LINK virtual COM
04
Display, alerts, and PC monitoring
The OLED shows temperature in Fahrenheit, humidity, pressure, the light state, and the current room-comfort classification. The RGB LED provides an immediate indicator: green for IDEAL, red plus green for CLOSE, and red for ALERT.
In ALERT, the active-low buzzer on PB10 produces a short beep about every two seconds. A push button mutes the buzzer without clearing the red condition; leaving ALERT turns it off and resets the mute state for the next alert. On the PC, PySerial and Matplotlib tools display telemetry, write timestamped CSV data, maintain rolling plots, and detect board resets from the sample counter.
Engineering approach
From idea to working system.
01
Structure the firmware
Kept CubeMX-generated initialization in C, moved application logic into C++, and resolved the C/C++ boundary with extern "C" while preserving the STM32 HAL workflow.
02
Bring up the I2C devices
Scanned the shared bus, verified the BME280 chip ID, implemented calibration and compensation, added BH1750 light acquisition, and built a custom SSD1306 text driver.
03
Separate real-time work
Assigned acquisition, telemetry, and heartbeat / alert behavior to three FreeRTOS tasks, then tuned heap and stack sizes and connected the producer and consumer with an eight-message queue.
04
Complete the feedback loop
Added OLED status output, RGB comfort indication, muted repeating buzzer alerts, USART2 telemetry, timestamped CSV logging, and a live Python dashboard.
Technical highlights
What this project demonstrates.
01
Real BME280 temperature, humidity, and pressure measurements
02
BH1750 ambient-light acquisition and custom SSD1306 OLED driver
03
Three FreeRTOS tasks with an eight-message CMSIS-RTOS2 queue
04
Green, yellow, and red comfort indication with a resettable mute state
05
PySerial telemetry, timestamped CSV logging, and live Matplotlib graphs
What I learned
This project reinforced that reliable embedded systems come from disciplined integration: verify each device independently, keep drivers and application logic separated, use RTOS boundaries deliberately, and debug the complete path from a physical measurement to local feedback and host-side visualization.