#define SW_VERSION " ThinkSpeak.com" // SW version will appears at innitial LCD Display
#define TINY_GSM_MODEM_SIM900
#include <TinyGsmClient.h>
#define SerialAT Serial
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
/* ESP12-E & Thinkspeak*/
const char apn[]  = "xxxxx";
const char user[] = "";
const char pass[] = "";
const char server[] = "api.thingspeak.com";
const int  port = 80;
const char* TS_SERVER = "api.thingspeak.com";
String TS_API_KEY ="xxxxx";
int sent = 0;
/* TIMER */
#include <SimpleTimer.h>
SimpleTimer timer;
/* OLED */
#include <ACROBOTIC_SSD1306.h> // library for OLED: SCL ==> D1; SDA ==> D2
#include <SPI.h>
#include <Wire.h>
/* DHT22*/
#include "DHT.h"
#define DHTPIN D3  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);
float hum = 0;
float temp = 0;
/* Soil Moister */
#define soilMoisterPin A0
#define soilMoisterVcc D4 //not used. LM393 VCC connect to 3.3V
int soilMoister = 0;
/* DS18B20 Temperature Sensor */
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 14 // DS18B20 on NodeMCU pin D5 corresponds to GPIO 014 on Arduino
float soilTemp;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
void setup() 
{
    Serial.begin(115200);
    delay(10);
    Serial.println(".... Starting Setup");
    
    SerialAT.begin(115200);
    delay(3000);
  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  Serial.println("Initializing modem...");
  modem.init();
  
  pinMode(soilMoisterVcc, OUTPUT);
  Serial.begin(115200);
  delay(10);
  oledStart();
  dht.begin();
  DS18B20.begin();
  
 
  timer.setInterval(2000L, getDhtData);
  timer.setInterval(7000L, getSoilMoisterData);
  timer.setInterval(9000L, getSoilTempData);
  timer.setInterval(19000L, sendDataTS);
  digitalWrite (soilMoisterVcc, LOW);
}
void loop() 
{
  displayData();
  timer.run(); // Initiates SimpleTimer
}
/***************************************************
 * Start OLED
 **************************************************/
void oledStart(void)
{
  Wire.begin();  
  oled.init();                      // Initialze SSD1306 OLED display
  clearOledDisplay();
  oled.clearDisplay();              // Clear screen
  oled.setTextXY(0,0);              
  oled.putString(" ");
}
/***************************************************
 * Get DHT data
 **************************************************/
void getDhtData(void)
{
  float tempIni = temp;
  float humIni = hum;
  temp = dht.readTemperature();
  hum = dht.readHumidity();
  if (isnan(hum) || isnan(temp))   // Check if any reads failed and exit early (to try again).
  {
    Serial.println("Failed to read from DHT sensor!");
    temp = tempIni;
    hum = humIni;
    return;
  }
}
/***************************************************
 * Get Soil Moister Sensor data
 **************************************************/
void getSoilMoisterData(void)
{
  soilMoister = 0;
  digitalWrite (soilMoisterVcc, HIGH);
  delay (500);
  int N = 3;
  for(int i = 0; i < N; i++) // read sensor "N" times and get the average
  {
    soilMoister += analogRead(soilMoisterPin);   
    delay(150);
  }
  digitalWrite (soilMoisterVcc, LOW);
  soilMoister = soilMoister/N; 
  Serial.println(soilMoister);
  soilMoister = map(soilMoister, 689, 274, 0, 100); 
}
/***************************************************
 * Get SoilTemp sensor data
 **************************************************/
void getSoilTempData()
{
  DS18B20.requestTemperatures(); 
  soilTemp = DS18B20.getTempCByIndex(0);
  int newData = ((soilTemp + 0.05) * 10); //fix soilTemp value to 1 decimal place.
  soilTemp = (newData / 10.0);
}
  
/***************************************************
 * Display data at Serial Monitora & OLED Display
 **************************************************/
void displayData(void)
{
  Serial.print(" Temperature: ");
  Serial.print(temp);
  Serial.print("oC   Humidity: ");
  Serial.print(hum);
  Serial.println("%");
  Serial.print("SoilTemp: ");
  Serial.print(soilTemp);
  Serial.print("oC");
  
  
  oled.setTextXY(1,0);              // Set cursor position, start of line 2
  oled.putString("TEMP: " + String(temp) + " oC");
  oled.setTextXY(3,0);              // Set cursor position, start of line 2
  oled.putString("HUM : " + String(hum) + " %");
  oled.setTextXY(5,0);              // Set cursor position, start of line 2
  oled.putString("Tsoil:" + String(soilTemp) + " oC");
   oled.setTextXY(7,0);              // Set cursor position, start of line 2
  oled.putString("Hsoil: " + String(soilMoister) + " %");
}
/***************************************************
 * Clear OLED Display
 **************************************************/
void clearOledDisplay()
{
  oled.setFont(font8x8);
  oled.setTextXY(0,0); oled.putString("                ");
  oled.setTextXY(1,0); oled.putString("                ");
  oled.setTextXY(2,0); oled.putString("                ");
  oled.setTextXY(3,0); oled.putString("                ");
  oled.setTextXY(4,0); oled.putString("                ");
  oled.setTextXY(5,0); oled.putString("                ");
  oled.setTextXY(6,0); oled.putString("                ");
  oled.setTextXY(7,0); oled.putString("                ");
  oled.setTextXY(0,0); oled.putString("                ");              
}
/***************************************************
 * Sending Data to Thinkspeak Channel
 **************************************************/
void sendDataTS(void)
{
   if (client.connect(TS_SERVER, 80)) 
   { 
     String postStr = TS_API_KEY;
     postStr += "&field1=";
     postStr += String(temp);
     postStr += "&field2=";
     postStr += String(hum);
     postStr += "&field3=";
     postStr += String(soilMoister);
     postStr += "&field4=";
     postStr += String(soilTemp);
     postStr += "\r\n\r\n";
   
     client.print("POST /update HTTP/1.1\n");
     client.print("Host: api.thingspeak.com\n");
     client.print("Connection: close\n");
     client.print("X-THINGSPEAKAPIKEY: " + TS_API_KEY + "\n");
     client.print("Content-Type: application/x-www-form-urlencoded\n");
     client.print("Content-Length: ");
     client.print(postStr.length());
     client.print("\n\n");
     client.print(postStr);
     delay(1000); 
   }
   sent++;
   client.stop();
}