Portable Weather Station for Night Sky Observers

1,579

13

6

About: I study Teaching physics and geography, I enjoy with laws of nature :D Be happy and fun with science.

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.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

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

unihedron.com/projects/darksky/magconv.php



Step 2: BOM

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.

Sensors Contest

Participated in the
Sensors Contest

Be the First to Share

    Recommendations

    • CNC Contest

      CNC Contest
    • Make it Move

      Make it Move
    • Teacher Contest

      Teacher Contest

    6 Discussions

    0
    None
    Tond11

    4 weeks ago

    Hay,

    I made it and it is a great project to learn from, for me it has certainly sense to made project like you did.
    BTW i live in the Netherlands (Rotterdam) and it is unbelieveble how much artificial light we have unfortunate.
    Thanks again and keep making "simple "projects.
    Regards Tobo.

    1 reply
    0
    None
    Michal ChomaTond11

    Reply 4 weeks ago

    Appreciate! Do you want make some measurements together? Contact me. I measure Moon light, cca 100 000 microlux. My group on FB: https://www.facebook.com/groups/1829154687394948/?multi_permalinks=2248302092146870%2C2246812522295827¬if_id=1565703432258256¬if_t=group_activity

    0
    None
    Michal ChomaJJ Slabbert

    Reply 7 weeks ago

    Appreciate! I don't know, if it has sense to make projects like that. Sometimes people say me, it looks bad. I make simple projects, with minimum code.

    0
    None
    ArtSuzhou

    8 weeks ago on Step 7

    Great project. How did you manage to embed the graphics inside the article?

    1 reply
    0
    None
    Michal ChomaArtSuzhou

    Reply 8 weeks ago

    I just add picture to every step. Hmmm, I think it is normally or?