
// SimpleSQM - Based on opensource example program by Adafruit for their TSL2591 Sensor Module
/* TSL2591 Digital Light Sensor */
/* Dynamic Range: 600M:1 */
/* Maximum Lux: 88K */

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"

// connect SCL to analog 5
// connect SDA to analog 4
// connect Vin to 3.3-5V DC
// connect GROUND to common ground

Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)

/**************************************************************************/
/*
    Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
     //for an SQM we need the highest gain and longest integration time for maximum sensitivity.
     tsl.setGain(TSL2591_GAIN_MAX);   // 9876x gain
 
     tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)
}

// Variable definitaions moved out of library routine to make them global



// include LCD library code:
      
      #include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins

      LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// assign pin for control button

  int BUTTON = 6;

 // Measure actual dark readings for IR and Full and enter them here.
 // The datasheet suggest typically between 0 and 20, but I got readings between 0 and 1
 // Simple run the program with zero entered and note the IR and Full readings with the sensor completely blanked off.

  int DARK_IR = 0;
  int DARK_FULL = 0;

 //  And variables for IR, FULL and Lux so we can manipulate them

  unsigned long IR, FULL;
  float LUX;

 // This factor is used to calculate visual magnitude from Lux. Default is 1.00 which assumes
 // the sensor reads accurately in Lux, change it until magnitude readings scale correctly.
 // You can calculate the factor from an measures SQ value and the corect one with this formula:
   
 //  CORRECTION_FACTOR  = 10 ^ (measured SQ * -0.4) / (10 ^ (actual SQ * -0.4)
 
    float CORRECTION_FACTOR = 2.454L;

 // This factor is used to oversample the signal to get better resolution at lower light levels. It relies on the 
 // inherent 'dither' of readings due to inherent random noise in both the chip and low level signals.

  int OVERSAMPLE = 4;


 // For calculating visual magnitudes we need to use the Log10() function in teh maths libarary
   #include <math.h>


  // For lightmeter function
  byte LIGHTMETER = false;


/**************************************************************************/
/*
    Program entry point for the Arduino sketch
*/
/**************************************************************************/
void setup(void)
{
  //Check for button press
   if (digitalRead(BUTTON))
  {
    LIGHTMETER = !LIGHTMETER;
  }
  
  //Enable the serial monitor in the Arduino IDE and this section will send you basic diagnostics
  
  Serial.begin(9600);
  
  Serial.println("Starting Adafruit TSL2591 Test!");
  
  if (tsl.begin())
  {
    Serial.println("Found a TSL2591 sensor");
  }
  else
  {
    Serial.println("No sensor found ... check your wiring?");
    while (1);
  }
    
  /* Configure the sensor */
  configureSensor();

  //configure the button
  pinMode (BUTTON,INPUT_PULLUP);
 

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("PhragSoft Astro");
  lcd.setCursor(0,1);
  lcd.print("SQM Meter");
  delay(1500);
}


/**************************************************************************/
/*
   Read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
  // Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
  // That way you can do whatever math and comparisons you want!
  
  uint32_t lum = tsl.getFullLuminosity();
  uint16_t ir, full;

  
  ir = lum >> 16;
  full = lum & 0xFFFF;

  //add to global values (allow for oversampling)

  IR = IR + ir - DARK_IR;
  FULL = FULL + full - DARK_FULL;

  //This section will send raw readings to the serial monitor, useful for diagnostics
 
  Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
  Serial.print("IR: "); Serial.print(ir);  Serial.print("  ");
  Serial.print("Full: "); Serial.print(full); Serial.print("  ");
  Serial.print("Visible: "); Serial.print(full - ir); Serial.print("  ");
  Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir),6);

}

void displayResults(void)
{

  //This function displays the information on th2 LCD



    IR = 0;
  FULL = 0;
  for (int reads = OVERSAMPLE; reads>0; reads--) {
    advancedRead();
  }

  // Apply corrections and calculate LUX 

  LUX = tsl.calculateLux(FULL, IR) * CORRECTION_FACTOR / OVERSAMPLE;
     
     lcd.clear();
         
  // The original project used a normally closed pushbutton
  // for a normally open pushbotton replace the following line with: if (!digitalRead(BUTTON))

  if (digitalRead(BUTTON))
  {
    lcd.print("I ");
    lcd.print(IR/4);
    lcd.setCursor(8,0);
    lcd.print("V ");
    lcd.print((FULL-IR)/4);
    lcd.setCursor(0,1);
    lcd.print("F ");
    lcd.print(FULL/4);
    lcd.setCursor(8,1);
    lcd.print("LUX: ");
    lcd.print(LUX,4);
  }
  else {


    lcd.print("LUX: ");
    lcd.print(LUX,4);
    lcd.setCursor(0,1);
    lcd.print("SQM: ");
    lcd.print (log10(LUX/(108000))/-0.4);
    
     }
  
    

}


/**************************************************************************/
/*
    Arduino loop function,
*/
/**************************************************************************/
void loop(void)
{
  
  
  displayResults();

 // Change delay to change the refresh frequency;
 // Note that the sensor can't operate faster than the read period, so a delay of 0
 // gives an refresh rate of every OVERSAMPLE x 600ms
  
 delay(0);
}
