Real-time Raspberry Pi monitor for an SSD1306 OLED display (128x64, I2C) with one or two BH1750 light sensors.
Displayed information:
- User and hostname
- Local IP address
- CPU temperature
L1andL2with individual sensor readingsAvwith the average of all available sensors- Right-side vertical trend graph
- Low-light warning
NoSwhen a sensor is not responding
- Raspberry Pi (tested on Raspberry Pi 5)
- SSD1306 I2C OLED display (typical address:
0x3C) - Primary BH1750 at
0x23(ADDRtied to GND) - Optional secondary BH1750 at
0x5C(ADDRtied to 3.3V)
Typical GPIO wiring:
- VCC -> 3.3V
- GND -> GND
- SDA -> GPIO2 (pin 3)
- SCL -> GPIO3 (pin 5)
If you use two BH1750 sensors, both share the same I2C bus. The only difference is the ADDR pin:
- Sensor 1:
ADDR-> GND ->0x23 - Sensor 2:
ADDR-> 3.3V ->0x5C
sudo raspi-config nonint do_i2c 0Optional verification:
i2cdetect -y 1You should normally see:
23for the first BH17505cfor the second BH1750, if connected3cfor the OLED display
cd ~
python3 -m venv screen_sensor --system-site-packages
source screen_sensor/bin/activate
pip install --upgrade pip
pip install luma.oled smbus2 pillowcd ~
source screen_sensor/bin/activate
python3 rpi_lux_monitor_bh1750_oled.pyCurrent on-screen layout:
- Top row:
user@hostand CPU temperature - Next row: full local IP address
- Next row:
L1andL2on the same line - Lower-left row:
Avwith the average of valid sensor readings - Right side: vertical trend graph
Behavior:
- If one sensor fails, its field shows
NoS - If both sensors fail, the display shows
SENSOR ERROR - If only one sensor fails,
Avis calculated from the remaining valid sensor
Create the service file:
sudo nano /etc/systemd/system/rpi_lux_monitor_bh1750_oled.serviceContents:
[Unit]
Description=Rpi Lux Monitor BH1750 OLED service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=rvx
WorkingDirectory=/home/rvx
ExecStart=/home/rvx/screen_sensor/bin/python /home/rvx/rpi_lux_monitor_bh1750_oled.py
Environment=PYTHONUNBUFFERED=1
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.targetEnable and start it:
sudo systemctl daemon-reload
sudo systemctl enable rpi_lux_monitor_bh1750_oled.service
sudo systemctl restart rpi_lux_monitor_bh1750_oled.servicesudo systemctl status rpi_lux_monitor_bh1750_oled.service
sudo journalctl -u rpi_lux_monitor_bh1750_oled.service -fIf something is not working, check these three areas in this order.
systemctl is-active rpi_lux_monitor_bh1750_oled.service
systemctl is-enabled rpi_lux_monitor_bh1750_oled.serviceExpected result:
active: the monitor is currently runningenabled: the monitor will start automatically at boot
If you do not see those values, restart the service:
sudo systemctl restart rpi_lux_monitor_bh1750_oled.servicesudo journalctl -u rpi_lux_monitor_bh1750_oled.service -n 50 --no-pagerExpected log entries:
Started rpi_lux_monitor_bh1750_oled.serviceOLED monitor iniciado.
If you see errors such as Error inicializando hardware, the issue is usually related to I2C, wiring, device addressing, or permissions.
i2cdetect -y 1Expected result:
23for the primary BH17505cfor the secondary BH1750, if connected3cfor the SSD1306 OLED display
Quick interpretation:
- If
23or3cis missing, check wiring, power, and confirm that I2C is enabled. - If you are using two sensors and
5cis missing, check the second BH1750 wiring and itsADDRpin. - If all expected addresses are visible, the I2C bus is working and the issue is more likely in the service configuration or the script.
- Removed
shell=Truefrom command execution - Optimized temperature reading through
/sys/class/thermal/thermal_zone0/temp - Added system telemetry caching for IP and temperature to reduce CPU load
- Added support for two BH1750 sensors at
0x23and0x5C - Added automatic averaging of valid sensor readings
- Added robust sensor error handling (
NoSper sensor andSENSOR ERRORif all sensors fail) - Added clean shutdown handling with
SIGINTandSIGTERM - Added a compact vertical graph to preserve space for individual readings
Useful parameters:
REFRESH_SECONDS: display refresh intervalSYSINFO_REFRESH_SECONDS: IP/temperature update intervalLOW_LUX_THRESHOLD: low-light warning thresholdNIGHT_LUX_THRESHOLD: night contrast thresholdMIN_CONTRAST/MAX_CONTRAST: OLED contrast range