Building a Light Level Sensor for Home Assistant – Part 1

(This turned from a light sensor into a light/temperature/humidity/pressure multi-sensor in Part 2. By Part 3 it might be sentient.)

I’ve been mucking about with Home Assistant for several months now after buying wifi lights (and shamefully haven’t been blogging about it). Home Assistant is a hugely configurable, Python-based home automation server. I recommend checking it out.

The first thing I set up is automation of our main lights. They turn off when we go out, and turn on when we arrive home. This works fine, but I’d also like the lights to turn off when not required during the day. Home Assistant natively knows about sunrise & sunset, so the obvious thing is to turn the lights off maybe 45 minutes after sunrise. This is fine on sunny days, but on rainy day the lights end up turning off while it’s still quite dim inside.


There are options to solve this with sensors, but they’re pretty expensive off-the-shelf, especially if you factor in an often-required z-wave controller. Fortunately, Mal introduced me to the wonderful world of ESP8266: incredibly cheap Arduino-compatible boards with built in WiFi.

Luminance sensor module connected to Arduino Duemilanove
Hacked together luminance sensor

A quick check on Aliexpress turned up a TLS2561 digital luminance sensor for the princely sum of $1 (or $5 for 5). Throw in a tiny battery or power supply and it’s easy to build a WiFi-connected IoT thingy for well under ten bucks!

I’m still waiting on the ESP8266 board, but in about 30 minutes I’ve thrown together a proof of concept using an ancient Arduino Duemilanove. I’m using a little SSD1306 OLED screen for output. These things are outrageously expensive at four bucks!

 

If you’re interested, here’s the code I threw together using Platform.io and a couple of Adafruit Libraries:

#include "Arduino.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
/**************************************************************************/
/*
Configures the gain and integration time for the TSL2561
*/
/**************************************************************************/
void configureSensor(void)
{
/* You can also manually set the gain or enable auto-gain support */
// tsl.setGain(TSL2561_GAIN_1X); /* No gain … use in bright light to avoid sensor saturation */
// tsl.setGain(TSL2561_GAIN_16X); /* 16x gain … use in low light to boost sensitivity */
tsl.enableAutoRange(true); /* Auto-gain … switches automatically between 1x and 16x */
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */
/* Update these values depending on what you've set above! */
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("———————");
display.print ("Gain: "); display.println("Auto");
display.print ("Timing: "); display.println("101 ms");
display.println("———————");
display.display();
}
void setup() {
Serial.begin(9600);
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3D (for the 128×64)
tsl.begin();
display.display();
delay(2000);
display.clearDisplay();
configureSensor();
}
void loop() {
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
// erase previous display
display.fillRect(0, 40, display.width(), 20, 0);
display.setCursor(0,40);
display.setTextSize(2);
/* Display the results (light is measured in lux) */
display.print(event.light); display.print(" lux");
display.display();
delay(200);
}

view raw
main.cpp
hosted with ❤ by GitHub

Leave a comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.