The recycled coffee jar contains a 3.3V regulator, the ESP8266 on an ESP-12E board (which contains flash memory and a PCB antenna, among other things), a TSL2561 light sensor, and on top of the coffee jar lid is an AM2302 temperature and humidity sensor.
The ESP8266 has been flashed with Nodemcu (http://www.nodemcu.com/index_en.html) which means it can be programmed with Lua scripts. Lua, it turns out, is horrible, but that's another story.
Every five minutes, the ESP wakes up, collects temperature, humidity and light level values from the sensors, connects to our guest wifi network, and uploads the values to a ThingSpeak channel (https://thingspeak.com/channels/40838). You can see some charts and dials that are linked to the recorded values here: http://www.noblesque.org.uk/greenhouse.html
The TSL2561 contains two sensors - one that measures visible plus infrared light, and another that measures infrared light only. The two levels are supposed to be combined using a calculation that approximates brightness seen by the human eye, but I don't care about that for the greenhouse, I just want to see the two values separately.
The TSL2561 measure the light levels and provides output as integer values over a serial interface. It has two parameters that affect the range - a 16x gain that can be switched on or off, and a variable integration time, with three preset durations of 402ms, 101ms or 13.7ms. (Integration time can also be controlled manually.)
Initially I used the default integration time (402ms) with the 16x gain turned on, but it quickly became apparent that the values were hitting the maximum end of the range:
So I turned off the 16x gain, but it's still hitting the ceiling sometimes:
The good news is that it's bright in the greenhouse (good for the plants), but I need to use a shorter integration time to extend the range of the sensor further.
Sampling by integrationSampling by integration is a bit like collecting rain in a glass and measuring the level. If you put the glass out in the rain for one hour and measure the water level, then empty the glass and put it back in the rain for 10 hours, if it's raining at the same rate throughout that time, the water level will be 10 times higher.
If the glass has straight parallel sides, you can work out the rainfall in mm per hour by dividing the water level measured by the number of hours the glass was outside, and that will tell you the average rate of rainfall during that time.
It's hard to measure a mm level of water precisely, but errors in the measurement will be less significant if the glass is fuller. In other words, if it's not raining very much, then leave the glass outside for a longer period of time to get a more accurate measurement of the average rainfall rate.
If you leave the glass outside for 10 hours and it rains a lot, the glass will overflow. In this case, the sampling period needs to be reduced, so that the measured value comes back within the available range.
Enough talk about rain, back to the TSL2561
The integration time of the TSL2561 can be adjusted, much like adjusting the time that the glass is out in the rain, and like the glass, the TSL2561 has a maximum value it can measure, which is 65535.
There is an additional complication - if the integration time is reduced, the maximum value that can be measured also reduces. The analogy with the glass breaks down a bit here - it's as if the glass is being constructed at the same time as the water is being collected, so if you only measure rain for one hour then you get a shorter glass to measure it in. If you measure for ten hours, you get a full-size glass. In fact, the glass is finished to its full height even before the ten hours is up.
With the TSL2561, if you select an integration time of 101ms, the maximum value that can be measured is 37177, and if you select 13.7ms, then it is 5047.
So which integration time option should be chosen, and should the 16x gain be switched on or off?
Switching off the gain and selecting the shortest integration time should provide the largest range of measurement values. However, because maximum value is limited by the shorter integration time, the range at 13.7ms is about the same as at 101ms.
It's hard to visualise so I made a chart:
(which gets cropped in this layout - click it to see the full image).
Input light level is on the X-axis, with a range from 0 to 1 (where 1 is the brightest that the TSL2561 can measure without overflow). The output values are on the Y-axis, and you can see that the 101ms and 13.7ms integration time options have a lower range of possible values than the 402ms option.
It's clear to see in the chart that the 13.7ms options provide about the same input range as the 101ms corresponding options, but with a lower range of output values. The only benefit of choosing 13.7ms is that you get the measurements quicker. This isn't useful for my greenhouse, so I won't use the 13.7ms setting.
The 101ms option with the 16x gain turned off provides the greatest input range. If I had to use just one combination, this would be it. However, at lower light levels, the granularity of output values is poor.
Therefore, at lower light levels, I can switch to one of the other options to get better granularity of output values.
The output values will need to be scaled according to the chosen settings, so that the values don't alter significantly when changing the integration time or switching on/off the gain.
So, given that it doesn't matter too much how long the measurement takes, I think what my greenhouse monitor needs to do is try the remaining four options (ignoring the two 13.7ms ones) in order of smallest range, smallest granularity first, and return the first result that doesn't overflow, scaled to normalise the output values across the set of possible settings.
Turn the above into code.
Hmm. For reasons I cannot fathom, when I set the integration time to 101ms and the light is bright, I cannot get a "full scale" reading of 37177 on both channels unless I wait about 250ms after powering up. I can't see any clues in the datasheet as to why that might be - it's supposed to begin integrating as soon as it powers up, then transfer the values to the data registers.
For now I've set it to wait 500ms in all cases before reading the values, to be sure.