#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>
#include <base64.h>

const int     SMTP_PORT            = 465;
const char*   SMTP_SERVER          = "smtp.gmail.com";
String        error_message = "";
String        Response;

/****************************
 * 
 * This sketch is based on the ESP-01 being turned
 * on by the PIR or Radar Sensor after each trigger
 * event. Once triggered, this program will determine
 * how long to remain on even if the trigger goes LOW.
 * 
 * So all activity can occur in the setup and the loop
 * method just keeps the LED flashing to indicate
 * trigger activity
 *  
 */
 
/*
 * to use gmail with the esp8266 devices you need to
 * set Less Secure App Access to ON
 * from the security settings of your gmail account
 * without this setting, email through gmail will NOT WORK!
 */
 
const char* ssid     = "xxxxxxxx";  // Your WiFi SSID
const char* password = "xxxxxxx";   // Your WiFi Password

String Senders_Login    = "xxxxxxx@gmail.com";  // YOUR gmail account
String Senders_Password = "xxxxxx";  // your gmail password
String From;

String To, Subject, Message, Login_base64, Passwrd_base64;

// Uncomment & update if you want to use a Static IP 
// (Static IP connection is much faster than DHCP)
//#define IP
//IPAddress ip(192, 168, 1, 6);
//IPAddress gateway(192, 168, 1, 254);
//IPAddress subnet(255, 255, 255, 0);

int LED = LED_BUILTIN;                                        // Choose the pin for the LED 
String chipID;

// for ESP-01 we will use the TX pin (Pin 1) IF this doesn't work, then RX which is Pin 3
const int powerLatch = 3;

WiFiClientSecure client;

// Blink the LED 
// Provides a visual display of activity

void blink() {
  // a simple blink routine for the ESP-01 led
  
  for (int j=1; j<=3; j++) {
    // ON
    digitalWrite(LED, LOW);
    delay(100); 
    
    //OFF
    digitalWrite(LED, HIGH);
    delay(1000);
  }

}

void setup() {
  // Set the latch pin to keep power on
  pinMode(powerLatch, OUTPUT); 
  digitalWrite(powerLatch, HIGH);

  // prepare LED
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);  
  delay(1000);
  client.setInsecure();
 
  // in the circuit diagram for this sketch, the PIR output pin 
  // connects to the MOSFET Gate and this turns on the MOSFET
  // which then turns on the complete circuit
  // The advantage with this is that the Gate voltage can
  // be greater than 3.3v which is the limit for the ESP8266 input
  // While the PIR has an output of 3.3v, the radar sensors output
  // a voltage similar to their input voltage.
  
  // Enter your own data for who you are sending the emails to 
  To      = "xxxxxxx@gmail.com";  // set the to email address
  From    = "xxxxxxx@gmail.com";  // set the from email address
  Subject = "ESP-01 Solar Powered Motion Sensor Triggered";
  
  // We start by connecting to a WiFi network

  // Set Static IP, if defined above
  #if defined(IP)
      WiFi.config(ip, gateway, subnet);
  #endif

  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }

  chipID = String(ESP.getChipId(), HEX);

  Message = "ESP-01 Solar Powered Sensor has been triggered<br />ESP Chip ID:" + chipID; 

  SendMail(From, To, Subject, Message);

  // if you have configured an ESP-01 driven buzzer
  // you can initiate a buzzer sound with this bit of code
  // now send the beep signal
  HTTPClient http;
  
  //http.begin("http://192.168.1.17/buzz2"); //HTTP
  //int httpCode = http.GET();
  //http.end();  

  // to add a variable buzzer sound for different locations
  http.begin("http://192.168.1.17/buzz?times=2&on=300&off=500"); // buzzer with variable settings
  int httpCode = http.GET();
  http.end();  

}


void loop() {
      // quick blink
      blink();

      // now delay for one minute
      // if the trigger is no longer active
      // the ESP-01 will turn the circuit off when the latch pin goes low
      // at the end

      delay(60000); // 60 seconds change this value to suit
      
      blink(); // quick flash before sleeping
  
      digitalWrite(powerLatch, LOW);
      
      
}

void SendMail(String From, String To, String Subject, String Message) {
  
  if (!client.connect(SMTP_SERVER, SMTP_PORT)) {
    error_message = "SMTP could not connect to the mail server";
    return;
  }
  if (ErrorWhileWaitingForSMTP_Response("220", 500)) {
    error_message = "SMTP Connection Error";
    return;
  }
  client.println("HELO server");
  if (ErrorWhileWaitingForSMTP_Response("250", 500)) {
    error_message = "SMTP Identification error";
    return;
  }
  client.println("AUTH LOGIN");
  WaitSMTPResponse(Response, 500);
  client.println(base64::encode(Senders_Login));
  
  WaitSMTPResponse(Response, 500);
  client.println(base64::encode(Senders_Password));

  if (ErrorWhileWaitingForSMTP_Response("235", 500)) {
    error_message = "SMTP Authorisation error";
    return;
  }

  // Note that mailFrom and recipient (To) do not support
  // multiple email addresses in the string. The sending of the
  // message will fail.
  
  String mailFrom = "MAIL FROM: <" + From + '>';
  client.println(mailFrom);
  WaitSMTPResponse(Response, 500);
  
  String recipient = "RCPT TO: <" + To + '>';
  client.println(recipient);
  WaitSMTPResponse(Response, 500);
  client.println("DATA");
  
  if (ErrorWhileWaitingForSMTP_Response("354", 500)) {
    error_message = "SMTP DATA error";
    return;
  }
  
  client.println("From: <" + String(From) + '>');
  client.println("To: <" + String(To) + '>');
  client.print("Subject: ");
  client.println(String(Subject));
  client.println("Mime-Version: 1.0");
  client.println("Content-Type: text/html; charset=\"UTF-8\"");
  client.println("Content-Transfer-Encoding: 7bit");
  client.println();
  
  String body = "<!DOCTYPE html><html lang=\"en\">" + Message + "</html>";
  client.println(body);
  client.println(".");
  
  if (ErrorWhileWaitingForSMTP_Response("250", 1000)) {
    error_message = "SMTP Message error";
    return;
  }
  
  client.println("QUIT");
  if (ErrorWhileWaitingForSMTP_Response("221", 1000)) {
    error_message = "SMTP QUIT error";
    return;
  }
  
  client.stop();
}

bool ErrorWhileWaitingForSMTP_Response(String Error_Code, int TimeOut) {
  int timer = millis();
  
  while (!client.available()) {
    
    if (millis() > (timer + TimeOut)) {
      error_message = "SMTP Timeout";
      return true;
    }
  }
  
  Response = client.readStringUntil('\n');
  
  if (Response.indexOf(Error_Code) == -1) return true;
  return false;
}

bool WaitSMTPResponse(String Error_Code, int TimeOut) {
  int timer = millis();
  
  while (!client.available()) {
    
    if (millis() > (timer + TimeOut)) {
      error_message = "SMTP Timeout";
      return false;
    }
  }
  Response = client.readStringUntil('\n');
  
  if (Response.indexOf(Error_Code) == -1) return false;
  return true;
}
