// Sketch 1 of 2
// Arduino Uno
  // Data is collected by this device and transmitted to the MKR 1400 via serial

// The DHT22 Sensor Requires 2 libraries, but only one is called in the code.  
//     (1): DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library 
//     (2): Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor 

#include <SPI.h>
#include <Wire.h>
#include <DS3231.h>   // RTC module
#include <DHT.h>      // DHT22
#include "U8glib.h"   // Velleman 128 x 64 OLED SPI Display 
                      // Note: Another standard U8glib library did not work when I attempted to use it for this display. It did work when I used the library recommended by the manufacturer. 
                      // Library: https://www.velleman.eu/support/downloads/?code=VMA437 
                      // Syntax: https://github.com/olikraus/u8glib/wiki/userreference & https://github.com/olikraus/u8glib/wiki/thelloworld
//#include <SD.h>     // Option to save to SD card in Ethernet Shield for Arduino Uno

RTClib RTC;

#define DHTPIN 11     // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
DHT dht(DHTPIN, DHTTYPE);

U8GLIB_SH1106_128X64 u8g(3, 4, 6, 7); // (CLK/SCK: 3, MOSI: 4, CS: 6, DC(A0): 7) // u8g(sck, mosi, cs, a0 [, reset]) 

int y_pos = 0;  // global variable

//const int chipSelect = 10; // Option to save to SD card in Ethernet Shield for Arduino Uno
//float fileSizeSD = 0.0;    // Option to save to SD card in Ethernet Shield for Arduino Uno

int i = 0; // Count # of readings taken by the Uno (same as # loops in program) 

const int ledPin = 9;     // transmit indicator (flashes when a data transmission occurs)
const int ledPin2 = 8;    // push transmit indicator (pushed high by manual button on breadboard or output from MKR 1400 activated from the cloud)
const int buttonPin = A1;

int buttonState = 0;

int transmitFrequency = 30;  // Frequency of Serial Print dataString for sending data to the second device (minutes)
String pTransmitDateTime = "";
int transmitCounter = 0;
int pTransmitMinute = 0;
int ptriggerTransmitAlertIndicator;

float cRuntimeAtTriggerStart = 0.0;
float dtLastTrigger = 0.0;
int triggerCounter = 0.0;
int triggerTransmitAlertCounter = 0;

// Input Variables to Control Trigger
float lowTrigger = 20.0;
float highTrigger = 40.0;
float dtLastTriggerLimit = 2.0; // If the condition is met for this length of time, an alert will be generated

void setup (void) {
    Serial.begin(9600);
    Wire.begin();
    dht.begin();
    pinMode(ledPin, OUTPUT);
    pinMode(ledPin2, OUTPUT);
    pinMode(buttonPin, INPUT);
    u8g.setRot180();  // flip screen, if required (add/remove comments on this line to rotate)

    // Option to save to SD card in Ethernet Shield for Arduino Uno
        //    Serial.print("Initializing SD card...");
        //    if (!SD.begin(chipSelect))     // see if the card is present and can be initialized
        //    {
        //      Serial.println("Card failed, or not present");
        //      while (1);     // don't do anything more
        //    }
        //    Serial.println("card initialized.");
}

void loop (void) {
    delay(5000);
    DateTime now = RTC.now();
    float cRuntime = millis()/60000;
    float p = getPressure();
//    Serial.println(p);

    buttonState = digitalRead(buttonPin);
//    Serial.print("Button: ");
//    Serial.println(buttonState);
    if(buttonState == 1)
    {
      digitalWrite(ledPin2, HIGH);
      delay(30000); // delay to allow MKR1400 to get ready to recieve data if Uno:buttonPin is pushed HIGH by MKR1400:pingPin
    }
    else
    {
      digitalWrite(ledPin2, LOW);
    }
    
    float h = dht.readHumidity();
    float t = dht.readTemperature(true);  // t = dht.readTemperature(true) --> temp if degrees F & t = dht.readTemperature() --> temp if degrees C 
    
    int transmitIndicator = 0;
    if(now.minute() % transmitFrequency == 0 && now.minute() != pTransmitMinute)
    {
      transmitIndicator = 1;
      pTransmitMinute = now.minute();
      pTransmitDateTime = String(now.hour())+String(":")+String(now.minute())+String(":")+String(now.second());
    }

    int triggerStatus = 0;
    if(p <= lowTrigger || p >= highTrigger)  
    {
 // Note: the variable referenced in the condition for this if statement is evaulated against high & low setpoints
 //    It is quick to change which variable is evaluated - this is the only location where the variable is specified

      triggerStatus = 1;
      triggerCounter++;
    }
    else
    {
      triggerCounter = 0;
    }
    
    if(triggerStatus == 1 && triggerCounter == 1)
    {
      cRuntimeAtTriggerStart = cRuntime;
    }
    
    dtLastTrigger = cRuntime - cRuntimeAtTriggerStart;
    
    int triggerTransmitAlertIndicator = 0;
    if((dtLastTrigger > dtLastTriggerLimit) && triggerStatus == 1)
    {
      triggerTransmitAlertIndicator = 1;
      triggerTransmitAlertCounter++;
    }
    else
    {
      triggerTransmitAlertCounter = 0;
    }

    if(triggerTransmitAlertCounter > 0 && triggerTransmitAlertCounter % 10 == 0)
    {
      flashLED(2,500);
    }

    int triggerPushTransmitAlertIndicator = 0;
    if((triggerTransmitAlertIndicator == 1 && triggerTransmitAlertCounter == 1) || ptriggerTransmitAlertIndicator != triggerTransmitAlertIndicator) 
    // if(TriggerStatus existed for min specified time for Alert & Count = 1 meaining that this is the first loop where the time exceeded the min specified time 
    //       OR the triggerAlert status changes -- this will generate a push Alert if the TriggerStatus goes back to 0 meaning the Trigger conditions are no longer met.)
    {
      triggerPushTransmitAlertIndicator = 1;
      flashLED(5,500);
      delay(5000);
    }

    ptriggerTransmitAlertIndicator = triggerTransmitAlertIndicator; // current indicator stored to previous indicator. On the next loop the value transferred here will be compared to the value generated based on new values.

    // Create strings
    String dataString = "";
    String cDateTime = "";
    String cHumTemp = "";
    String cP = "";
   
    dataString += "<"+String(i)+","+String(triggerTransmitAlertIndicator)+","+String(dtLastTrigger,0)+","+String(buttonState)+", "+String(now.month())+","+String(now.day())+","+String(now.year())+", "+String(now.hour())+","+String(now.minute())+","+String(now.second())+", "+String(h)+","+String(t)+","+String(p)+">";
    cDateTime += String(now.month())+"/"+String(now.day())+"/"+String(now.year())+" "+String(now.hour())+":"+String(now.minute())+":"+String(now.second());
    cHumTemp += "H:"+String(h)+"% T:"+String(t)+"degF";
    cP += "P:"+String(p)+"psi";

    if(transmitIndicator == 1 || triggerPushTransmitAlertIndicator == 1 || buttonState == 1)
    {
      char dataArray[100];
      dataString.toCharArray(dataArray, 100);
      Serial.println(dataArray);
      flashLED(10,500);
      transmitCounter++;
    }
   
//    Serial.print("T:");
//    Serial.println(triggerStatus);
   
    delay(100);     // wait a bit for the entire message to arrive
    // picture loop
    u8g.firstPage();  
    do 
    {
    draw(cDateTime,cHumTemp, cP,i,transmitCounter,now.minute(),transmitFrequency,pTransmitMinute);
    } 
    while(u8g.nextPage());
    delay(1000);
    // writeToSD(dataString);  // Option to save to SD card in Ethernet Shield for Arduino Uno   
    i++;
}

void draw(String DcDateTime,String DcHumTemp, String DcP, int Di, int DtransmitCounter,int DnowMinute,int DtransmitFrequency, int DpTransmitMinute) 
{
    u8g.begin();
    u8g.setFont(u8g_font_5x7);  //u8g_font_micro //u8g_font_5x7  //u8g_font_5x8  //u8g_font_6x10
    u8g.setFontPosTop();
    u8g.setPrintPos(0,0);
    u8g.print(DcDateTime);
    u8g.setPrintPos(0,8);
    u8g.print(2);
    u8g.setPrintPos(10,8);
    u8g.print(DcHumTemp);
    u8g.setPrintPos(0,16);
    u8g.print("3 #:");
    u8g.setPrintPos(30,16);
    u8g.print(Di);
    u8g.setPrintPos(50,16);
    u8g.print(DcP);
    u8g.setPrintPos(0,24);
    u8g.print("4 #t:");
    u8g.setPrintPos(30,24);
    u8g.print(DtransmitCounter);
    u8g.setPrintPos(50,24);
    u8g.print("tFreq: ");
    u8g.setPrintPos(83,24);
    u8g.print(DtransmitFrequency);
    u8g.setPrintPos(0,32);
    u8g.print(5);
    u8g.setPrintPos(10,32);
    u8g.print("nowMinute:");
    u8g.setPrintPos(70,32);
    u8g.print(DnowMinute);
    u8g.setPrintPos(0,40);
    u8g.print(6);
    u8g.setPrintPos(10,40);
    u8g.print("pTransmitMinute:");
    u8g.setPrintPos(95,40);
    u8g.print(DpTransmitMinute);
    u8g.setPrintPos(0,48);
    u8g.print(7);
    u8g.setPrintPos(10,48);
    u8g.print("Remainder:");
    u8g.setPrintPos(70,48);
    u8g.print(DnowMinute % DtransmitFrequency);
}

float getPressure()
{
  int sensorVal=analogRead(A2);
//    Serial.print("Sensor Value: ");
//    Serial.print(sensorVal);
  float voltage = (sensorVal*5.0)/1023.0;
//    Serial.print(" Volts: "); 
//    Serial.print(voltage);
  // When Pressure = 0, Analog Input = 100
  // Conversion of Analog Input to Voltage: Analog Input = 100 -> Voltage = 100*(5/1023) = 0.4889
  float m = ((150-0)/(4.5-0.4889));
  float b = 150 - (m*4.5);
//    Serial.print(" m = ");
//    Serial.print(m);
//    Serial.print(" b = ");
//    Serial.print(b);
  float pressure_psi = ((m*voltage)+ b);
//    Serial.print(" Pressure = ");
//    Serial.print(pressure_psi);
//    Serial.println(" psi");    
//    delay(200);
  return pressure_psi;
}

void flashLED(int num, int t)
{
  for (int z = 1; z <= num; z++)
  {
      digitalWrite(ledPin, HIGH);
      delay(t);
      digitalWrite(ledPin, LOW);
      delay(t);
  }
}


// Option to save to SD card in Ethernet Shield for Arduino Uno   
    //void writeToSD(String dataToWrite)
    //{    
    //    // open the file. note that only one file can be open at a time,
    //    // so you have to close this one before opening another.
    //    File dataFile = SD.open("datalog4.txt", FILE_WRITE);
    //    fileSizeSD = dataFile.size();  // Reurns file size in bytes
    //    fileSizeSD = fileSizeSD / 1000000 ;  // Converts bytes to MB. 1 MB = 1e6 bytes
    //    // if the file is available, write to it:
    //    if (dataFile) 
    //    {
    //      dataFile.println(dataToWrite);
    //      dataFile.close();
    //      // print to the serial port too:
    //      // Serial.println(dataToWrite);
    //    }
    //    // if the file isn't open, pop up an error:
    //    else 
    //    {
    //      Serial.println("error opening datalog1.txt");
    //    }   
    //}
