Lux night lamp on an Arduino Uno
A BH1750 light meter on I2C and an LED on a PWM pin: the darker the room, the brighter the lamp, with the reading in lux on the serial monitor. The whole build, an Arduino Uno and 3 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $34. On Mokxi they're free.
Step by step, with the wiring and the common mistakes: Arduino BH1750 Light Sensor: Lux, Wiring, Code
What you'll learn
- I2C sensors on SDA and SCL
- Lux as a real unit of light
- Mapping a range onto PWM brightness
- Using thresholds with a smooth fade between
- Checking that a sensor was found at startup
- Difficulty: Beginner
- Time: About 15 minutes
- Board: Arduino Uno R3
- Parts: 5
How it works
The BH1750 light sensor measures real lux and reports it over I2C on SDA and SCL. The Uno reads it, and the lamp LED on pin 9 gets brighter the darker the room is.
At 20 lux or less the lamp is fully on. At 500 lux or more it is off. In between, the brightness fades in a straight line. It prints the lux and lamp level every 200 ms when a new measurement is ready.
Parts list
5 parts, plus the jumper wires. They retail for about $34; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Full-size breadboard
- 1 × Light sensor, BH1750
- 1 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × LED, yellowIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Light sensor, BH1750 pin SCL | Arduino Uno R3 pin SCL |
| Light sensor, BH1750 pin SDA | Arduino Uno R3 pin SDA |
| Resistor, 220 Ω pin 1 | Arduino Uno R3 pin 9 |
| Light sensor, BH1750 pin VCC | Arduino Uno R3 pin 5V |
| Light sensor, BH1750 pin GND | Arduino Uno R3 pin GND |
| LED, yellow pin C | Arduino Uno R3 pin GND |
| LED, yellow pin A | Resistor, 220 Ω pin 2 |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Lux night lamp: a BH1750 light meter on I2C, and an LED that gets brighter
// as the room gets darker.
//
// A4, A5 SDA and SCL to the BH1750 (GY-302 module, address 0x23)
// pin 9 through 220 ohm to the LED's anode; its cathode to GND
// 5V/GND the module (it has its own 3.3 V regulator and pull-ups)
//
// An LDR in a divider gives a number that depends on the resistor and the
// cell. The BH1750 gives lux: its count is the light times 1.2, so the
// library's readLightLevel() is count / 1.2 and nothing else. A classroom is
// a few hundred lux, a cloudy day outdoors a few thousand, full sun past the
// 54612 the chip can count to.
//
// # The lamp
//
// Under 20 lux the lamp is full on; over 500 it is off; in between it fades,
// in whole numbers:
//
// brightness = 255 x (500 - lux) / 480
//
// readLightLevelCentis() gives the lux in hundredths, because this board has
// no floating point to do the sum with.
#include <Wire.h>
#include <BH1750.h>
const int LAMP = 9;
const long DARK = 20;
const long BRIGHT = 500;
BH1750 lightMeter;
void setup() {
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: BH1750 lux night lamp");
Wire.begin();
if (!lightMeter.begin()) {
Serial.println("no BH1750: check SDA, SCL and power");
}
pinMode(LAMP, OUTPUT);
}
void loop() {
if (lightMeter.measurementReady()) {
long lux = lightMeter.readLightLevelCentis() / 100;
int level;
if (lux <= DARK) {
level = 255;
} else if (lux >= BRIGHT) {
level = 0;
} else {
level = (int)(255 * (BRIGHT - lux) / (BRIGHT - DARK));
}
analogWrite(LAMP, level);
Serial.print("light ");
Serial.print(lux);
Serial.print(" lx lamp ");
Serial.println(level);
}
delay(200);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
Opens the serial port and starts I2C with Wire.begin(). Then lightMeter.begin() starts the BH1750, and if that fails it prints a hint to check SDA, SCL and power. It makes the lamp pin an output.
void setup() {
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: BH1750 lux night lamp");
Wire.begin();
if (!lightMeter.begin()) {
Serial.println("no BH1750: check SDA, SCL and power");
}
pinMode(LAMP, OUTPUT);
}loop sketch.ino
When a measurement is ready, it reads lux in hundredths and divides by 100. At or below DARK the level is 255, at or above BRIGHT it is 0, and between them it scales with 255 * (BRIGHT - lux) / (BRIGHT - DARK). It writes the level to the lamp and prints it.
void loop() {
if (lightMeter.measurementReady()) {
long lux = lightMeter.readLightLevelCentis() / 100;
int level;
if (lux <= DARK) {
level = 255;
} else if (lux >= BRIGHT) {
level = 0;
} else {
level = (int)(255 * (BRIGHT - lux) / (BRIGHT - DARK));
}
analogWrite(LAMP, level);
Serial.print("light ");
Serial.print(lux);
Serial.print(" lx lamp ");
Serial.println(level);
}
delay(200);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The monitor says no BH1750 This project
Check SDA and SCL, and that the sensor has 5V and ground. - The lamp is always off This project
In a bright room the lux is over 500, so the lamp turns off. Cover the sensor to test. - The sensor is not found, or reads 0 or 65535. Light sensor
Connect SDA and SCL to the right pins and pull them up. The address is 0x23 with ADDR low, or 0x5C with ADDR high. Send the power on and mode commands before you read. - The lux value looks off by a factor. Light sensor
The raw count divided by 1.2 gives lux. Libraries do this for you, so do not divide twice. In high resolution mode, wait about 120 ms after starting a measurement. - The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure. - A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground. - The LED does not light, or it lights once and then dies. LED
LEDs have polarity. The longer leg (anode) goes toward the positive side. Always add a series resistor, about 220 ohms to 1 k ohm on a 5 V pin. - A blue or white LED stays dark on 3.3 V. LED
Blue and white LEDs drop about 3 V, so 3.3 V leaves almost nothing for the resistor. Use a 5 V supply, or a smaller resistor and a red or green LED.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.