#include <DHT.h>
#include <Wire.h>
#include <MPU6050.h>
#include <RTClib.h>
#include <SD.h>
#include <SPI.h>

#define DHT_PIN 2 // Data pin for DHT22
#define SD_CHIP_SELECT_PIN 10 // SD's CS pin
#define DHTTYPE DHT22 // Type of current DHT sensor

const String data_base_file_name = "db.txt";
const int MPU6050_ADDRESS = 0x69;

// objects of classes
DHT dht(DHT_PIN, DHTTYPE); // temperature and humdidity sensor
MPU6050 mpu; // gyroscope
RTC_DS1307 rtc; // Real Time Clock 

// data varuables
int16_t accelerationX, accelerationY, accelerationZ;
int16_t gyroX, gyroY, gyroZ;

float accelerationAngleX;
float accelerationAngleY;
float accelerationAngleZ;

float DHT22_Temperature;
float DHT22_Humidity;

void setup() {
  Serial.begin(9600);
  Wire.begin(); // initializing I2C 
  //Setting new address to the MPU6050
  Wire.beginTransmission(MPU6050_ADDRESS);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
  mpu.initialize(); // initializing gyroscope
  // checking gyroscore (mpu) for connection
  if (mpu.testConnection()) {
    Serial.println("MPU6050 is connected.");
  } else {
    Serial.println("MPU6050 Error: Connection failed.");
  }
  // checking RTC_DS1307 for connection
  if (!rtc.begin()) {
    Serial.println("RTC_DS1307 Error: Connection failed.");
  }
  if (!rtc.isrunning()) {
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // setting up the time
  }
  // checking SD for connection
  if (!SD.begin(SD_CHIP_SELECT_PIN)) {
    Serial.println("SD Error: Connection failed.");
  }
  if (SD.exists(data_base_file_name)) {
    SD.remove(data_base_file_name);
    Serial.print("SD Info: deleted "); Serial.println(data_base_file_name);
  }
  // creating FILE if not exists
  File data_base_file = SD.open(data_base_file_name, FILE_WRITE);
  if (data_base_file) {
    data_base_file.println("New information!");
    data_base_file.close();
    Serial.println("SD Info: The data has been added.");
  } else {
    Serial.println("SD Error: Failed to open the file "); Serial.println(data_base_file_name);
  }
  data_base_file = SD.open(data_base_file_name, FILE_READ);
  while (data_base_file.available()) {
    char c = data_base_file.read();
    Serial.print(c);
  } data_base_file.close();
}

void loop() {
  DHT22_Temperature = dht.readTemperature();
  DHT22_Humidity = dht.readHumidity();
  // receiving acceleration data
  accelerationX = mpu.getAccelerationX();
  accelerationY = mpu.getAccelerationY();
  accelerationZ = mpu.getAccelerationZ();
  // receiving rotation data
  gyroX = mpu.getRotationX();
  gyroY = mpu.getRotationY();
  gyroZ = mpu.getRotationZ();

  float denomX = sqrt(accelerationY * accelerationY + accelerationZ * accelerationZ);
  float denomY = sqrt(accelerationX * accelerationX + accelerationZ * accelerationZ);
  float denomZ = sqrt(accelerationY * accelerationY + accelerationX * accelerationX);

  denomX ? accelerationAngleX = atan(accelerationX / denomX) * 180.0 / M_PI : accelerationAngleX = 1;
  denomY ? accelerationAngleY = atan(accelerationY / denomY) * 180.0 / M_PI : accelerationAngleY = 0;
  denomZ ? accelerationAngleZ = atan(accelerationZ / denomZ) * 180.0 / M_PI : accelerationAngleZ = 0;

  // checking if all the data is available on MPU6050 and display the data
    Serial.print("Angle X: "); Serial.println(accelerationAngleX);
    Serial.print("Angle Y: "); Serial.println(accelerationAngleY);
    Serial.print("Angle Z: "); Serial.println(accelerationAngleZ);

    Serial.print("Gyro X: "); Serial.println(gyroX);
    Serial.print("Gyro Y: "); Serial.println(gyroY);
    Serial.print("Gyro Z: "); Serial.println(gyroZ);

  Serial.println("\n"); // space between each updated data output
  // checking for nan data of DHT22
  if (isnan(DHT22_Temperature) || isnan(DHT22_Humidity)) {
    Serial.print("DHT Error: Cannot read data from pin ");
    Serial.println(DHT_PIN);
  } else {
    // displaying data to the Serial Monitor from DHT22
    // Reading temperature 
    Serial.print("Temperature in C: "); Serial.println(DHT22_Temperature);
    // Reading Humidity 
    Serial.print("Humidity: "); Serial.println(DHT22_Humidity);
  }
  // receiving data from RTC_DS1307
  DateTime currentTime = rtc.now();
  Serial.print("Time: ");
  Serial.print(currentTime.hour());
  Serial.print(".");
  Serial.print(currentTime.minute());
  Serial.print(".");
  Serial.println(currentTime.second());
  delay(3000); // wait for 3 seconds after each iteration
}

GND5VSDASCLSQWRTCDS1307+