#include <SolarCalculator.h>
#include <Arduino.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_GPS.h>
#include <Adafruit_HMC5883_U.h>
#include <Stepper.h>
#include <Servo.h>

//GPS Config
#define GPSSerial Serial1

char noread;
bool GPSlock;

Adafruit_GPS GPS(&GPSSerial);

//Compass Config
int devangle, turndeg, pastturndeg, pastheaddeg, totaldeg, numsat;
double sunAZ, sunELE, AZangle;
const int utc = 2;
float headrad, headdeg, lon, lat;

Adafruit_HMC5883_Unified Compass = Adafruit_HMC5883_Unified(12345);

//Stepper Config
const int stepsrev = 32;
const int gearred = 64;
int difhead, difAZ;
double pastsunAZ;

Stepper Stepper(stepsrev, 6, 8, 7, 9 ); //1-3-2-4 Pins

//Servo Config
Servo servo;
const int servoPin = 5;

//Sunrise + Sunset
int sunriseint, sunsetint;
float sunrisefloat, sunsetfloat;
double sunrise, sunset, transit, timenow, sunriseclock, sunsetclock;



void setup() {
  Serial.begin(9600);
  
  //GPS + Compass Setup
  GPSSerial.begin(9600);
  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
  GPSlock = false;
  
  sensor_t sensor;
  Compass.getSensor(&sensor);
  Compass.begin();

  //Stepper Setup
  devangle = 0.069;
  totaldeg = 0;
  pastturndeg = 0;
  pastheaddeg = 0;
  pastsunAZ = 0;
  
  //Servo Setup
  servo.attach(servoPin);
  servo.write(90);
}

void loop() {
  //Compass Loop
  sensors_event_t event;
  Compass.getEvent(&event);
  
  headrad = atan2(event.magnetic.y, event.magnetic.x);
  headrad += decangle;
  
  if(headrad < 0) {
    headrad += 2*PI;
  }
  if(headrad > 2*PI) {
    headrad -= 2*PI;
  }
  
  headdeg = headrad * 180/M_PI

  //GPS Loop
  clearGPS(); 
  
  while(!GPS.newNMEAreceived()){
    noread = GPS.read();
  }

  GPS.parse(GPS.lastNMEA());
  
  numsat = GPS.satellites;
  
  if(GPS.fix) {
    lat = GPS.latitude/100;
    lon = GPS.longitude/100;
  
    GPSlock = true;
  }
  
  if(GPSlock == true) {
    //Solar Calculator
    calcHorizontalCoordinates(GPS.year, GPS.month, GPS.day, GPS.hour, GPS.minute, GPS.seconds, lat, lon, sunAZ, sunELE);
    
    //Sunrise + Sunset
    calcCivilDawnDusk(GPS.year, GPS.month, GPS.day, lat, lon, transit, sunrise, sunset); 
    
    sunriseint = sunrise;
    sunrisefloat = (sunrise - sunriseint)*0.6;
    sunriseclock = sunriseint + sunrisefloat + utc;

    sunsetint = sunset;
    sunsetfloat = (sunset - sunsetint)*0.6;
    sunsetclock = sunsetint + sunsetfloat + utc;
    
    timenow = (GPS.hour + utc) + (GPS.minute/60);
    
    //Servo Loop
    servo.write(180 - sunELE);

    //Stepper Loop
    AZangle = sunAZ-headdeg;

    difhead = (headdeg-pastheaddeg);
    difAZ = (sunAZ-pastsunAZ);

    AZangle = (difAZ-difhead); //headdeg

    if(AZangle >= 180) {
      AZangle = AZangle - 360;
    }
    if(AZangle <= -180) {
      AZangle = AZangle + 360;
    }
    
    AZangle = AZangle*5,688;

    Stepper.setSpeed(300);
    Stepper.step(round(AZangle));

    pastheaddeg = headdeg;
    pastsunAZ = sunAZ;
    
    if(sunELE<= 0){
      sunNOSEE = true;
      sunSEE = false;
    }
    else {
      sunNOSEE = false;
      sunSEE = true;
    }
  }

  Serial.println("Heading in degrees: ");
  Serial.print(headdeg);
  Serial.println("GPS-lock: ");
  Serial.print(GPSlock);
  Serial.println("Elevation of the sun: ");
  Serial.print(sunELE);
  Serial.println("Azimuth of the sun");
  Serial.print(sunAZ);
}

void clearGPS() {
  while(!GPS.newNMEAreceived()) {
    noread = GPS.read();
  }

  while(!GPS.newNMEAreceived()) {
    noread = GPS.read();
  }

  GPS.parse(GPS.lastNMEA());
}

//Code made by @NotADesigner