Arduino Light Sensor (Lux)

Hi,

I have just completed my first Vera Arduino GW and LightSensor.
The sensor is found and operational and i get light readings in Vera ;D

I only have one issue: the sensor will show light levels between 0 and 99Lux.
Beyond that the sensor reading will stay at 99.
I have tried to play with the adjustable resistor on the board but had no luck yet.

I assume this has something to do with the calculation and the fact that my sensor - although build based on the suggested LM393 - has a different layout and therefore reading?

This is the sensor I’m using: http://www.ebay.com/itm/310532141291

Any suggestions?

Thanks !

This line would suggest the light level is reported as a percentage - not in Lux?

int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; 

Thanks, yes this is correct.
I played around a bit and found that the sensor range is rather limited. As soon as the light level goes up beyond the 80 lux or so, the sensor returns the value 10 which results in the 99% display.

So it looks like this LED based sensor is not suitable for my application as I need to differentiate in a large lux range to control my blinds.

I’m now working on a BH1750 based sensor and will post the working code up soon (I hope…) :smiley: Fingers crossed :-X

If i’m not mistaken your sensor is digital based on a threshold set. Etc, you can read only 0/1 from it by arduino. You shield is just 3 pins - GND, VCC, digital out. It should be also 4pins shields with both digital and analog outputs.
I have a success using simple photo resistor. You will need also 50-200k fixed resistor and one analog pin on your arduino to create light sensor.

Hi Axill,

it does both. The readings work well in low light 8% to 99% is rather smooth. Issue is that once the sun is out completely it just get’s stuck while my Aeonlabs 4 in 1 runs through the range of 200-800 lux.

I have decided to upgrade and just finished the prototype of the BH1750 based sensor.
Amazingly it worked on the first try (don’t ask me why… ??? ??? ;D ;D).

Code coming up in a minute in case someone else would like to build one!

Ok, here we go.
Copied the format from the Wiki:

[size=18pt]Light (lux) Sensor[/size]

[size=14pt]Software[/size]

You will need to download the BH1750 library from github here: https://github.com/Genotronex/BH1750FVI_Master and include it in your Arduino IDE

Please find the Arduino sketch ​below.
The code is a compilation of the original light sensor from hek and BH1750FVI code from Mohannad Rawashdeh.
This sensor sleeps most of the time. You can change the sleep interval by updating SLEEP_TIME define at the top of the file.

[size=14pt]Wire things up[/size]

Follow the instructions in ConnectingRadioModule [url=http://code.mios.com/trac/mios_arduino-sensor/wiki/ConnectingRadioModule]ConnectingRadioModule[/url] – Arduino Sensor Plugin to connect radio module.

Connect the Light Sensor as follows:

[ul][li]Light Sensor VCC to 3.3V on the Arduino Board[/li]
[li]Light Sensor SDA to a 510 ohm resistor and from there to A4 (analog input) on the Arduino Board[/li]
[li]Light Sensor SCL to a 510 ohm resistor and from there to A5 (analog input) on the Arduino Board[/li]
[li]Light Sensor addr to a 510 ohm resistor and from there to A3 (analog input) on the Arduino Board[/li]
[li]Light Sensor GND to GND on the Arduino Board.[/li][/ul]

If you use a Arduino board with a I/OREF Pin you can connect SDA, SCL and addr directly to the pins on the Arduino board without the need for the resistor but you need to bridge the 3.3v and I/OREF Pin on the Arduino.
The I/OREF pin on the Arduino board provides the voltage reference with which the microcontroller operates. This should allow the selection of the appropriate power source or enable voltage translators on the outputs for working with 5V or 3.3V.
As I’m using a Arduino Nano, I have not tested whether this work though.

[size=14pt]Hardware - Purchase guide[/size]

To build this sensor you’ll need one arduino + radio specified in the base kit found here:
[url=http://code.mios.com/trac/mios_arduino-sensor/wiki/WikiStart#Buyingguide]Arduino Sensor Plugin

With the following additional parts:
1x BH1750 Digital Light Sensor
3x 510 ohm resistor

TOTAL SENSOR PRICE: $7.6 (arduino + radio) + $3.18 (digital light sensor) + $0.1 (resistors) = $10.88

[size=14pt]Code[/size]

/*
  Vera Arduino BH1750FVI Light sensor
  communicate using I2C Protocol
  this library enable 2 slave device addresses
  Main address  0x23
  secondary address 0x5C
  connect the sensor as follows :
  VCC >>> 3.3V
  SDA >>> 510 Ohm Resistor >>> A4
  SCL >>> 510 Ohm Resistor >>> A5
  addr >> 510 Ohm Resistor >>> A3
  Gnd >>>Gnd
 
*/


#include <Sleep_n0m1.h>
#include <SPI.h>
#include <RF24.h>
#include <EEPROM.h>  
#include <Sensor.h>  
#include <BH1750FVI.h> // Sensor Library - download here: https://github.com/Genotronex/BH1750FVI_Master
#include <Wire.h> // I2C Library - download here: https://github.com/Genotronex/BH1750FVI_Master

// Set RADIO_ID to something unique in your sensor network (1-254)
// or set to AUTO if you want gw to assign a RADIO_ID for you.
#define RADIO_ID AUTO
#define CHILD_ID_LIGHT 0
#define LIGHT_SENSOR_ANALOG_PIN 0

BH1750FVI LightSensor;

unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds)

Sensor gw(9,10);

int lastlux;
Sleep sleep;

void setup()  
{ 
  Serial.begin(BAUD_RATE);  // Used to type in characters
  gw.begin(RADIO_ID);

  // Register all sensors to gateway (they will be created as child devices)
  gw.sendSensorPresentation(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
  
  LightSensor.begin();
  
 /*
	Set the address for this sensor
	you can use 2 different address
	Device_Address_H "0x5C"
	Device_Address_L "0x23"
	you must connect Addr pin to A3 .
 */
 
LightSensor.SetAddress(Device_Address_H);//Address 0x5C

// To adjust the slave on other address , uncomment this line
// lightMeter.SetAddress(Device_Address_L); //Address 0x5C
//-----------------------------------------------
  /*
   set the Working Mode for this sensor
   Select the following Mode:
    Continuous_H_resolution_Mode
    Continuous_H_resolution_Mode2
    Continuous_L_resolution_Mode
    OneTime_H_resolution_Mode
    OneTime_H_resolution_Mode2
    OneTime_L_resolution_Mode
   
    The data sheet recommend to use Continuous_H_resolution_Mode
  */

  LightSensor.SetMode(Continuous_H_resolution_Mode);
}

void loop()      
{     
  gw.powerUp(); // Power up radio

  uint16_t lux = LightSensor.GetLightIntensity();// Get Lux value
  Serial.println(lux);
  if (lux != lastlux) {
      gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lux);
      lastlux = lux;
  }
  
  // Power down the radio.  Note that the radio will get powered back up
  // on the next write() call.
  delay(1000); //delay to allow serial to fully print before sleep
  gw.powerDown();
  sleep.pwrDownMode(); //set sleep mode
  sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime 
}

[size=14pt]Print it…[/size]
Below STL contains a small housing for the sensor which can be 3D printed.

The box allows the installation of the sensor board, arduino board and RF module.
It is all powered by external USB connector.

  • Solder the lux sensor to the top of the Arduino mini and the RF sensor to the bottom.
  • Keep the connection cables short for easy installation.
  • Kept the cables long enough to loop them once so that they create a barrier between the boards. If you are worried of a short circuit simply sandwich a piece of thick paper in between.

The cover snaps into place at the end.

Print Settings: 2 shells, 20% infill 0.2mm layer height.

Good one - the BH1750 is a vast improvement over the LM393 and photo diode approach and should see good results. Thanks for your efforts.

Nice one!

Thanks!

What is a benefit of BH1750 against photo resistor? Photo resistor costs 2-3$ per 10pcs
For me they work quite well, i have two sensors operated for a while

The BH1750 seems to have better characteristics than a photo resistor/diode (min. 0.11 lx, max. 100000 lx, high resolution) and is more of a ambient light detector. So they seem to complement each other (as the diode can detect focused light better).

@a-lurker & hek,
No problem. The least I can do.

@axill,
I proposed this as an alternative to the LED light sensor I used earlier as this was not working so well.
Copy and paste from what I found on the net:
The BH1750 light intensity sensor breakout board with a 16 bit AD converter built-in which can directly output a digital signal, there is no need for complicated calculations. This is a more acurate and easier to use version of the simple foto resistor which only outputs a voltage that needs to be calculated in order to obtain meaningful data. With the BH1750 Light Sensor intensity can be directly measured by the luxmeter, without the need to make calculations. The data which is output by this sensor is directly output in Lux (Lx).

@hek & @idefix
Ok i see
Than the benefit is very depend on a goal.
If you going to operate 0-100% at vera side you will have to drop 16bit resolution to 7bit. Looks like no benefit comparing to 10bit resolution of arduino ADC
May be your goal is more complex) i see photoresistor is very sufficient for my purpose.

updated above guide with the 3D printed casing for the sensor

Hi,

I am having difficulty with this SnailMail Delivery sensor, and I guess need to understand the sleep function.

I now have my external antenna and am experiencing an issue with the stock code:

[code]#include <Sleep_n0m1.h>
#include <SPI.h>
#include <RF24.h>
#include <EEPROM.h>
#include <Sensor.h>

#define CHILD_ID_LIGHT 0
#define LIGHT_SENSOR_ANALOG_PIN 0

unsigned long SLEEP_TIME = 5; // Sleep time between reads (in seconds)

Sensor gw;
int lastLightLevel;
Sleep sleep;

void setup()
{
gw.begin();

// Send the sketch version information to the gateway and Controller
gw.sendSketchInfo(“Light Sensor”, “1.0”);

// Register all sensors to gateway (they will be created as child devices)
gw.sendSensorPresentation(CHILD_ID_LIGHT, S_LIGHT_LEVEL);
}

void loop()
{
int lightLevel = (100-(1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23);
//Serial.print(“LightLevel=”);
//Serial.print(lightLevel);
//Serial.println(“%”);
if (lightLevel != lastLightLevel) {
gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lightLevel);
lastLightLevel = lightLevel;
Serial.print(“LightLevel=”);
Serial.print(lightLevel);
Serial.println(“%”);
}

// Power down the radio. Note that the radio will get powered back up
// on the next write() call.
delay(1000); //delay to allow serial to fully print before sleep
gw.powerDown();
sleep.pwrDownMode(); //set sleep mode
sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime
}[/code]

The delay

  sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime 

seems to interfere with my MailBox sensor working if the mailman is very quick.

Can I put the radio into sleep mode indefinitely and then wake it, transmit and back to sleep without the delay?

Like this pseudo code:

void loop() { int lightLevel = (100-(1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23); if (lightLevel != lastLightLevel) { lastLightLevel = lightLevel; Serial.print("LightLevel="); Serial.print(lightLevel); Serial.println("%"); tellVera(lightLevel) } } void tellVera() { WakeyWakeyRadio gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lightLevel); gw.powerDown(); sleep.pwrDownMode(); //set sleep mode JustStayAsleepWithoutDelayRadio }

Any suggestions, or does there need to be regular bilateral communication with the child/parent?

5 second intervals might be to long. If i see how quickly our postman deposits the mail a 5 second interval will not capture it each time.
Have you tried reducing it to 1 second? The issue with the loop could be that it might trigger all the time as the lux sensor is very sensitive.

Yeah, I see. So if I call the send message function only when a change registers and the send function wakes the radio, why can’t I let the radio sleep indefinitely waiting for the void loop to make the call?

Why is the 5 second sleep delay there at all?

The delay is there to conserve power. The loop should work but as said I think you would need to include a threshold as the lux redings fluctuate due to the sensitivity of the sensor which would trigger the loop constantly.
In addition a delay might be required on the radio side (hek will be able to comment)

OK, I’ll wait and hear on the radio side.

Ideally, I’m only TX when the light level exceeds say 15. That will conserve power, bury all the low light noise and keeps the threshold low such that I pick up the door opening. In testing it (shoebox test) the response time for the light delta was in low-double-digit milliseconds going from low (usually 0 or 1) to ambient light at anything over 25.

Since I have the antenna mounted externally (sort of hidden underneath) I used reflective mylar on the floor of the box. That way, I am able to get more light to the back of the box, where the sensor is located.

[quote=“idefix, post:17, topic:179715”]The delay is there to conserve power. The loop should work but as said I think you would need to include a threshold as the lux redings fluctuate due to the sensitivity of the sensor which would trigger the loop constantly.
In addition a delay might be required on the radio side (hek will be able to comment)[/quote]

would I be better off, in this application where I am waiting for a light event, using the Interrupt Sleep Function and having the pro mini sleep till something interrupts sleep?

void sleepInterrupt(int interrupt,int mode);

Is it a battery operated sensor? In that case you must let your sensor sleep as much as possible. The light sensor has a digital output that can be used to trigger an wake-up-interrupt on your Arduino. Tune trigger level with trip-pot.

If this not is battery operated you can remove sleep and delays and check the analog input as often as possible if you want. But you should NOT transmit every reading. This would probably jam the radio network. As you say check light level (with some hysteresis thresholds) and send 1/0 values back to vera.