Open-Source Light Meter

Light meters, these days, are no longer a mystery: From home-improvement stores to eBay and Amazon you can find have at least a few units available for purchase. An open-source light meter, however, is one that you won’t find too easily. If such an expansible light meter cannot be bought, then why don’t we just build one ourselves? Well, here is an open-source, Arduino-based light meter that allows you to measure the amount of light with the help of a digital ambient light sensor, the BH1750FVI, from ROHM.


Light Sensor Module

There are a few different BH1750FVI modules available on the internet, and the best part is that they’re all pretty much the same. For this project, I used a GY-30 light-intensity module from eBay that is based on the same BH1750FVI digital ambient light sensor. The module is, in fact, a BH1750FVI breakout board with a built-in 16-bit ADC, which can directly output a digital signal, so there is no need for complex math. The module, with I2C interface, outputs data directly in lux (lx). In addition to the well-calibrated light sensor, you can find a low-voltage regulator and logic-level translator components in the same module. The module can be powered from any 3.3- to 5.0-V DC source. As you will have seen, the module has five pins, while we need two for power supply (VCC and GND) and two for I2C interface (SCL and SDA). The extra pin (ADD) can be used to set the I2C address of the sensor; floating or connected to GND, the I2C address will be 0x23 (default), and if connected to VCC, the address will be 0x5C.


BH1750 breakout board


Microcontroller & Display

The rest of the hardware is based on an Arduino Nano and sports a 0.96-in. OLED display with a resolution of 128 x 64. Luckily, eBay has tons of 0.96-in. OLEDs (with either SPI or I2C interfaces) and Arduino Nanos (16 MHz @ 5 V) for a few dollars. Arduino Nano is very small; thus, it does not take up too much space. Furthermore, it has more than enough I/O for our application and includes a USB port for easy programming — pretty great!


Hardware wiring schematic


The Code

That covers the hardware; now, onto the software. The code is simple, really; it’s amazingly short. I am using the excellent “u8glib library” to drive the OLED display. Take note: My OLED display doesn’t have a couple of I2C addresses, but it had a unique “hard-wired” (default) address 0x3C (thanks to my home-brewed I2C scanner). Here is a copy of the tested code:


Little Light Meter

BH1750 Ambient Light Sensor+

Arduino Nano/Uno+

0.96", 128x64, OLED (SSD1306) Display

Experimental Sketch/v1.0


Lux (lx) is the unit of illuminance in the International System of Units (SI)

Lux is defined in terms of lumens per meter squared (lm/m2)


#include ;

#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);

int BH17_add = 0x23; // I2C address of BH1750

byte buff[2];

void setup() {





void light() {

float valf = 0;


u8g.setPrintPos(0, 50);

if (BH1750_Read(BH17_add) == 2) {

valf = ((buff[0] << 8) | buff[1]) / 1.2;

if (valf < 0)u8g.print("> 65535");


u8g.setPrintPos(0, 20);

u8g.print("T.K.HAREENDRAN"); // Custom Text

u8g.setPrintPos(0, 30);


u8g.setPrintPos(0, 40);

u8g.print("Light Meter"); // Custom Text

u8g.setPrintPos(0, 60);

u8g.print((int)valf, DEC);

u8g.print(" LX/SI"); //




void loop() {


do {


} while (u8g.nextPage());


void BH750_Init(int address) {





byte BH1750_Read(int address) {

byte i = 0;


Wire.requestFrom(address, 2);

while (Wire.available()) {

buff[i] =;




return i;



Here is the prototype in action. At first, I used my trusty Arduino Uno (R3) to conduct the experiment. Look, my new Nano (v3) is waiting there in the wings!


Hardware setup showing different light level readings

Power Source Selection

If you prefer a portable light meter project, then you can enclose the finished project in a suitable, ready-made/3D-printed enclosure, of course, with a compact power supply. Because the Arduino Nano expects a 6- to 20-V unregulated power supply through its VIN terminal (pin 30), a safer solution would be to use a 2S Li-ion/LiPo battery (~7.4 V), which would be plenty to run the whole system. Shown below is the add-on circuitry for this modification with a socket for a DC barrel plug to connect the battery charger and a toggle switch to turn the system on and off. The DC socket is wired in a way that the battery supply is disconnected from the rest of the electronics when the barrel plug of the charger is inserted into it. If you want to run the light meter even while charging, you should add a suitable load-share circuitry (not included here) to fulfill the requirement.


Schematic to add a battery to allow for portability


Luckily, the Arduino Nano can be powered via the Mini-B USB connection, 6- to 20-V unregulated external power supply (pin 30), or 5-V regulated external power supply (pin 27), and the power source is automatically selected to the highest voltage source. As I get a lot of questions about how to run an Arduino off of solar panels, I want to do a bit of experimenting to come up with a simple way to run an Arduino even if we aren’t near a computer or a power outlet. I will look at the possibility of a project on this when I have a little more time. So please stay tuned to try my solar-power bank design for Arduino!


Join the conversation!

Error! Please fill all fields.
  • T.K.Hareendran

    @Adam Carlson: Yes, in order to reduce the current (low- level contrast) with the OLED on, we would have to write to the register 0x81. Very good suggestion indeed. As it is the time to add some more features to my light meter, I just started revising all in order to come out with a clean slate!

  • T.K.Hareendran

    @Adam Carlson: Thank You! As you might noticed, this 128×64 OLED display is controlled by SSD1306 ( It has 256-step (0-255) brightness/contrast control. Regarding the brightness/contrast control commands, I still need to dig in this part deeper.

    • Adam Carlson

      It looks like it would be a value write to address of 0x81 proportional to the light coming in from the meter. You would need a transfer function of the 16bit read of the sensor. In pseudo-code it might look like:

      uint_8 minDisplay setting = 50; //Value of 50 is arbitrary and should be set at the lowest that is readable in low light
      uint_16 displayBrightness;       //Value sent to display
      displayBrightness = buff[0] + minDisplay;
      if (displayBrightness <255)
          WriteI2C(0x81,displayBrightness);  //Use the appropriate command to write the value to the display
          WriteI2C(0x81,255);                //Set to max value for 8 bit brightness control
  • Adam Carlson

    TK, do you plan to mount the light sensor opposite of the OLED so as to reduce the light that might get transmitted from the screen into the sensor? Oh, another idea is that you could also have the screen display intensity be proportional to the reading. If the reading were really low, it would dim the screen so that it would have less of an influence.

    • T.K.Hareendran

      @Adam Carlson: Yes, it’s crucial to position the light sensor in such way that no other stray light is able to be incident on it. Regarding enclosure design, position of the light sensor should be at a point much higher than the OLED display panel.

      Display intensity control, based on the ambient light level, is a smart idea.Thank You! I will take a look into the possibility when I’ve enough spare time, it calls for a few sturdy code lines though.

    • Adam Carlson

      I understand the spare time issue! I have not really played with these little displays. Is the intensity of the screen control based upon a digital value written to the screen, or is it PWM controlled?

Looking for the latest from TI?