Introduction: Portable Weather Station for Night Sky Observers
Light pollution is one of many problems in world. For solve that problem, we need to know how much is night sky polluted with artificial light. Many students with teachers in world try to measure light pollution with expensive sensors. I decided to change my portable luxmeter (for more check previous instructables project Portable Luxmeter ) to weather station with TSL2591 sensor. This sensor is sensitive enough for measure night pollution. Also, I add HTU21D for temperature and humidity measure.
Step 1: What Is Night Pollution and How It Measure
Night pollution is light from lamps, cars, houses, huge lcd panels in city and every light made by human. That light call artificial. For observers, artificial light is main problem to see stars from city, and they must go outside city. For human, high light pollution is harmful. And also for trees, grass and animals.
For checking light pollution of your place, you can see here lightpollutionmap
It is only model, and real values can vary. That's why I created that luxmeter.
For measure light pollution, I measure only lux and calculate magnitude/ arsec2.
I can calculate from lux to candela per suqare meters :
1 cd/m2 = 1 lux
Magnitude per square arcsecond (mag/arcsec2) describe night sky background (it calls surface brightness).
More on wiki: Surface brightness
For calculating cd/m2 to mag/arcsec2 is formula:
[value in mag/arcsec2] = Log10([value in cd/m2]/108000)/-0.4
Step 2: BOM
1. WEMOS D1 Mini or any microcontroller
(I use wemos, because it is smallest one, with usb port, you can try Arduino Nano)
WEMOS D1 MINI (Yanwen Economic Air Mail)
WEMOS D1 MINI (AliExpress Standard Shipping)
WEMOS D1 MINI 10 pcs (China Post Registered Air Mail - free Shiping)
usb cable for programming and uploading code to wemos
2. TSL2591 Sensor
TSL2591 (Yanwen Economic Air Mail)
TSL2591 (China Post Registered Air Mail)
TSL2591 (China Post Registered Air Mail)
3. HTU21D temperature and humidity sensor
HTU21D (Cainiao Super Economy)
HTU21D (Yanwen Economic Air Mail - free shipping)
4. OLED display 0.96 (128 x 64)
5. 18650 battery
6. TP4056 charging module
7. switch buttons or dip jumper
8. breadboard and dupont cables
9. case, I create from wood + tape
Step 3: Circuit
Circuit is pretty simple:
Connect all i2c modules (TSL2591, OLED, HTU21D) to SCL and SDA pins on wemos (SDA -> D2, SCL -> D1).
Power them with 3.3 V from wemos.
Connect plus terminal of battery to 5V pin on wemos and battery + pin on tp4056 charging module to plus terminal on battery.
Connect all grounds together.
Step 4: HTU21D Sensor
I buy new temperature sensor, which measure with accuracy 0.3 °C !
Things you should know about this sensor ( from sparkfun):
- Uses the I2C interface
- Typical humidity accuracy of ±2%
- Typical temperature accuracy of ±0.3 °C
- Operates from 0 to 100% humidity but this sensor isn’t recommended for harsh environments where it could come in contact with water (such as rain).
- 3.3V sensor - use inline logic level converters or 10k resistors to limit 5V signals
- Only one HTU21D sensor can reside on the I2C bus at a time
My summary: it is good sensor, because it measure with accuracy 0.3 °C and both - temperature and humidity. Pros is I2C interference and cons 3.3V, but it doesn't matter in my case.
Step 5: TSL2591
This sensor is good for measure night sky pollution because of it sensitivity (to 188 micro lux!).
1. are diodes with possible ir and full measure. I don't use it.
2. voltage regulator from 5V to 3.3 V
Chip specifications (from adafruit):
- Approximates Human eye Response
- Extremely wide dynamic range 1 to 600,000,000 Counts
- Lux Range: 188 uLux sensitivity, up to 88,000 Lux input measurements.
- Temperature range: -30 to 80 *C
- Voltage range: 3.3-5V into on board regulator
- Interface: I2C
- This board/chip uses I2C 7-bit address 0x29 (fixed)
- Dimensions: 19mm x 16mm x 1mm / .75" x .63" x .04"Weight: 1.1g
- 2 diodes for measure both - IR and Full spectrum
Summary:
188 uLux is perferct, also I2C communication is simple. Maybe problem can be fixed I2C adress (0x29). Also on board regulator is good and possible to use sensor during winter (frost).
Step 6: Code
You need these libraries (I add them to one zip file):
- Adafruit-GFX-Library-master
- adafruit_gfx_library_master
- Adafruit_HTU21DF_Library-master
- Adafruit_Sensor-master
- Adafruit_TSL2591_Library-master
Code : you can use mine, or create own. Don't forget to set maximal integration time (600 MS) and gain to max (GAIN_MAX) for night sky measure.
If you try to use my code, please download ino file. When I copy from instructable my code, something wrong with libraries.
I use loading image of moon just for fun. You can use any, just use this page for get array:
http://javl.github.io/image2cpp/
//https://lastminuteengineers.com/oled-display-arduino-tutorial/<br>//http://javl.github.io/image2cpp/ // mcd to magnitude <a href="http://unihedron.com/projects/darksky/magconv.php?ACTION=SOLVEMAGS&txtCDM2=0.1" rel="nofollow"> http://unihedron.com/projects/darksky/magconv.php...</a> // The HD44780 is a controller for character-based liquid crystal displays (LCDs). <a href="https://www.quinapalus.com/hd44780udg.html" rel="nofollow"> http://unihedron.com/projects/darksky/magconv.php...</a> #include <Wire.h><p>#include <Fonts/FreeSerif9pt7b.h></p>#include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #include "Adafruit_HTU21DF.h" #include "Adafruit_TSL2591.h" int counter; // OLED display TWI address #define OLED_ADDR 0x3C Adafruit_SSD1306 display(-1); // - 1 for restart display with restart button on arduino board Adafruit_HTU21DF htu = Adafruit_HTU21DF(); Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later) uint32_t lum; uint16_t ir, full; int ulux; float lux; float temp; float rel_hum; float mag_arcsec2; // visual mags/arcsecond² [value in mag/arcsec2] = Log10([value in cd/m2]/108000)/-0.4 // symbols // degree for Celsius const unsigned char degree [] PROGMEM = { 0xe,0x11,0x11,0x11,0xe,0x0,0x0,0x0 }; // exponent 2 const unsigned char exponent [] PROGMEM = { 0xe,0x1b,0x3,0x6,0xc,0x18,0x1f,0x0 }; // 'moon_logo', 128x64px const unsigned char intro [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x07, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0x77, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xbe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xcc, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xc0, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xc0, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x60, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x18, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x38, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x48, 0x7f, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x80, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xc4, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x60, 0x0f, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x43, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x4f, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x5f, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xb7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0x0f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x01, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; void setup() { // htu21d htu.begin(); // tsl2591 sensor_t sensor; tsl.getSensor(&sensor); tsl.setGain(TSL2591_GAIN_MAX); // MAX, HIGH MED,LOW, tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS); // 100MS, 200 MS, 300MS, 400MS,500MS, 600MS // setup for oled display display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR); display.clearDisplay(); display.display(); display.drawBitmap(0, 0, intro, 128, 64, WHITE); display.display(); delay(1000); display.setTextSize(1); display.setTextColor(WHITE); display.setFont(&FreeSerif9pt7b); display.clearDisplay(); } void loop() { lux = 0; ulux =0; mag_arcsec2=0; temp=0; rel_hum=0; delay(100); lum = tsl.getFullLuminosity(); ir = lum >> 16; full = lum & 0xFFFF; delay(100); lux = tsl.calculateLux(full, ir); // light intensiti in microlux ulux= lux*1000000; if (ulux<0) { ulux=0; } mag_arcsec2 = log10(lux/108000)/-0.4; //(log((ulux/108000) ) /(-0.4) temp = htu.readTemperature(); rel_hum = htu.readHumidity(); display_values(); } void display_values() { //display.drawPixel(120, 50, WHITE); display.clearDisplay(); display.setCursor(1, 15); display.print(temp); display.drawBitmap(42, 2, degree, 8,5 , WHITE); display.setCursor(50, 15); display.print("C"); display.setCursor(70, 15); display.print(rel_hum); display.setCursor(114, 15); display.print("%"); display.drawLine(1, 20, 127, 20, WHITE); display.drawLine(67, 1, 67, 20, WHITE); display.setCursor(1, 35); display.print("ulux ="); display.setCursor(50, 35); display.print(ulux); display.setCursor(1, 55); display.print("mag/arsec"); display.drawBitmap(70, 45, exponent, 8,8 , WHITE); display.setCursor(83, 55); display.print(mag_arcsec2); display.display(); }
Step 7: Inside
I create own case and I use breadboard with dupont cables as you can see.
I use TP4056 for charging battery with usb cable (need swtich dip jumper).
For turn on/off I use dip jumper.
For daylight, TSL2591 shows 0 and mag/arcsec2 is nan.
For night sky should TSL2591 show from 0 to 1000 000 microlux (ulux) and corresponding mag/arcsec2
(cca . 14 to 22 mag/arsec2).
For fullMoon I measured 50k ulux which is 0.05 lux.