#include "DHTesp.h"
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "WiFi.h"
#include "certs.h"

// Define DHT sensor pin and type
#define DHTPIN 15
#define DHTTYPE DHTesp::DHT22

// Define AWS IoT topics
#define AWS_IOT_PUBLISH_TOPIC  "esp32/pub"
#define AWS_IOT_SUBSCRIBE_TOPIC "esp32/sub"

// Variables to store humidity and temperature
float h;
float t;

// Create a DHT sensor object
DHTesp dhtSensor;

// Create WiFiClientSecure and PubSubClient objects
WiFiClientSecure net = WiFiClientSecure();
PubSubClient client(net);

// Function to connect to AWS IoT
void connectAWS()
{
  // Connect to Wi-Fi
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD, 6);
  Serial.println("Connecting to Wi-Fi");

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }

  // Configure WiFiClientSecure with AWS IoT device credentials
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);

  // Connect to the MQTT broker on the AWS endpoint
  client.setServer(AWS_IOT_ENDPOINT, 8883);

  // Set up a message handler
  client.setCallback(messageHandler);

  Serial.println("Connecting to AWS IOT");

  // Keep trying to connect until successful
  while (!client.connect(THINGNAME))
  {
    Serial.print(".");
    delay(100);
  }

  // If not connected after a certain timeout, print an error message
  if (!client.connected())
  {
    Serial.println("AWS IoT Timeout!");
    return;
  }

  // Subscribe to a topic
  client.subscribe(AWS_IOT_SUBSCRIBE_TOPIC);

  Serial.println("AWS IoT Connected!");
}

// Function to publish sensor data to AWS IoT
void publishMessage()
{
  // Create a JSON document
  StaticJsonDocument<200> doc;
  doc["humidity"] = h;
  doc["temperature"] = t;
  char jsonBuffer[512];
  
  // Serialize JSON document to a string
  serializeJson(doc, jsonBuffer);
  
  // Publish the JSON string to the specified topic
  client.publish(AWS_IOT_PUBLISH_TOPIC, jsonBuffer);
}

// Callback function to handle incoming MQTT messages
void messageHandler(char* topic, byte* payload, unsigned int length)
{
  Serial.print("incoming: ");
  Serial.println(topic);

  // Deserialize JSON payload
  StaticJsonDocument<200> doc;
  deserializeJson(doc, payload);
  
  // Extract and print the "message" field from the JSON payload
  const char* message = doc["message"];
  Serial.println(message);
}

void setup() {
  // Start serial communication
  Serial.begin(115200);

  // Connect to AWS IoT
  connectAWS();

  // Initialize DHT sensor
  dhtSensor.setup(DHTPIN, DHTTYPE);
}

void loop() {
  // Read temperature and humidity from DHT sensor
  TempAndHumidity data = dhtSensor.getTempAndHumidity();

  // Check if the sensor reading is valid
  if (isnan(data.temperature) || isnan(data.humidity)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Update global variables with sensor data
  h = data.humidity;
  t = data.temperature;

  // Print sensor data to serial monitor
  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.println(F("°C "));

  // Publish sensor data to AWS IoT
  publishMessage();

  // Handle MQTT messages
  client.loop();

  // Delay before the next sensor reading
  delay(1000);
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND