
#include <WiFi.h>
#include <PubSubClient.h>
#include "SSD1306.h" // alias for `#include "SSD1306Wire.h"

// jfs Wemos lolin32
// jfs Heltec WiFi kit 32 (weisses Board)
#define HELTEC
//#define DEBUG
#define _NTC
#define _ADS1115
#define _SHT3x

// Initialize the OLED display using Wire library
#ifdef HELTEC
SSD1306  display(0x3c, 4, 15);
#else
SSD1306  display(0x3c, 5, 4);
#endif

#ifdef _NTC
  #include "ntc_support.h"
#endif
#ifdef _SHT3x
#include <SHT3x.h>
  SHT3x Sensor(0x44); 
#endif    
#ifdef _ADS1115
  // 0x48 addr to gnd
  // 0x49 addr to vdd
  // 0x4A addr to sda
  // 0x4B addr to scl
  #include <Adafruit_ADS1015.h>
  Adafruit_ADS1115 ads(0x48);
  float Voltage = 0.0;
  ads.setGain(ADS1015_REG_CONFIG_PGA_1_024V);
#endif

const char* mqttServer = "192.168.2.71";
const int mqttPort = 1883;
const char* clientID = "esp_32_ad_wandler_1";
const char* channelName = "/ESP32_LAB1/CMD/#";

long interval = 1000;       // Sende-Intervall in ms


WiFiClient MQTTclient;
PubSubClient client(MQTTclient);

void callback(char* topic, byte* payload, unsigned int length) {
  //String payload_buff;
  //for (int i=0;i<length;i++) {
    //payload_buff = payload_buff+String((char)payload[i]);
  //}
  //Serial.println(payload_buff); // Print out messages.
  String line0;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  line0=topic;
  int x = 0;
  int y = 0;
 
  if (line0.endsWith("interval")) {   
   for (int i=0;i<length;i++) {
    if (i==0) {
      x = payload[i]-'0';
    }
    if (i==1) {
      y = payload[i]-'0';
      x = x*10 + y;
    }
    if (i==2) {
      y = payload[i]-'0';
      x = x*10 + y;
    }
    if (i==3){
      x = 1000;
    }
   }
   interval = x * 10;
   Serial.println(interval);
  }
}
long lastReconnectAttempt = 0;

boolean reconnect() {
  if (client.connect(clientID)) {
    client.subscribe(channelName); // Subscribe to channel.
  }
  return client.connected();
}



//unsigned long previousMillis = 0; // Letzter Update-Zeitstempel
//long interval = 1000;       // Sende-Intervall in ms

//// WIFI
const int mxSize=4;
String ssids[mxSize] ={"GAST","pipanet","FRITZ!Box Gastzugang","WLAN-DE8245"};
String ssidp[mxSize] = {"passatvr6","passatvr6","praxis123","4955065570896956"};
boolean conok =false;

void netfound(int i){
     display.clear();
     display.setColor(BLACK);
     display.fillRect(0, 0, 128, 10);
     display.setColor(WHITE);
     display.drawString(0,0,String(i));
     display.drawString(20,0,"networks found");
     display.display(); 
}

boolean init_wifi(){
    boolean ok = false;
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
    int n = WiFi.scanNetworks();
    Serial.println("scan done");
    if (n == 0) {
        Serial.println("no networks found");
        netfound(0);
    } else {
        Serial.print(n);
        Serial.println(" networks found");
        netfound(n);        
        for (int i = 0; i < n; ++i) {
            for (int p=0;p<mxSize;p++){
              if (WiFi.SSID(i).equals(ssids[p])){
                String pp = ssidp[p];
                String ss = WiFi.SSID(i);
                WiFi.begin(ss.c_str(), pp.c_str());
                i=n;
                ok = true;
              }
            }
            delay(10);
        }
    }     
    return ok;
}  
///// WIFI


void setup() {
  // put your setup code here, to run once:
#ifdef HELTEC
  pinMode(16,OUTPUT); digitalWrite(16, LOW); delay(50); digitalWrite(16, HIGH);
#endif 
#ifdef _NTC
    ThermistorPin = 34;
    adcMax = 4095.0; // ADC resolution 12-bit (0-4095)
    Vs = 3.3;        // supply voltage
#endif
  Serial.begin(115200); 
  display.init();
  display.flipScreenVertically();
  display.clear();
  display.drawString(0, 0, "Starting...");
  display.display();
  while (!init_wifi()){
    delay(200);  
  }
  display.drawString(0, 10, "Connecting to WiFi...");
  display.display();
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  display.drawString(0, 20, "\nWiFi connected, IP address: "); 
  display.drawString(0, 30, WiFi.localIP().toString());
  client.setServer(mqttServer, mqttPort); // Connect to PubNub.
  client.setCallback(callback);
  lastReconnectAttempt = 0;
  display.display();
  //display.init();
  #ifdef DEBUG  
    i2c_scanner();
    delay(2000);
  #endif 
  #ifdef _ADS1115
    ads.begin();
  #endif 
  }

void loop() {
    if (!client.connected()) {
    long now = millis();
    if (now - lastReconnectAttempt > 5000) { // Try to reconnect.
      lastReconnectAttempt = now;
      if (reconnect()) { // Attempt to reconnect.
        lastReconnectAttempt = 0;
      }
    }
  } else { // Connected.
    client.loop();
    publishit(); // Publish message.
    delay(interval);
  }
}

void publishit() {
  char buffer[10];
  display.clear();
  display.drawString(0,0," ip: "+WiFi.localIP().toString());
  #ifdef _NTC
    double Vout, Rt = 0;
    double T, Tc, Tf = 0;
    double adc = 0;
    adc = analogRead(ThermistorPin);
    adc = ADC_LUT[(int)adc];
    Vout = adc * Vs/adcMax;
    Rt = R1 * Vout / (Vs - Vout);
    T = 1/(1/To + log(Rt/Ro)/Beta);    // Temperature in Kelvin
    Tc = T - 273.15;                   // Celsius
    Tf = Tc * 9 / 5 + 32;              // Fahrenheit
    #ifdef DEBUG
      Serial.println(Tc);
    #endif
    dtostrf(Tc, 6, 2, buffer);
    client.publish("/ESP32_LAB1/NTC",buffer); // Publish message.
    display.drawString(0,10," NTC "+String(Tc));
 #endif
 #ifdef _ADS1115
  int16_t adc0;
  int16_t adc1;
  int16_t adc2;
  int16_t adc3;  
  adc0 = ads.readADC_SingleEnded(0);
  Voltage = (adc0 * 0.1875)/1000;
  dtostrf(Voltage, 3, 5, buffer);
  client.publish("/ESP32_LAB1/V0",buffer); // Publish message.
  display.drawString(0,20," "+String(Voltage));
  #ifdef DEBUG
    Serial.print("AIN0: "); 
    Serial.print(adc0);
    Serial.print("\tVoltage: ");
    Serial.println(Voltage, 7); 
  #endif
  adc1 = ads.readADC_SingleEnded(1);
  Voltage = (adc1 * 0.1875)/1000;
  dtostrf(Voltage, 3, 5, buffer);
  client.publish("/ESP32_LAB1/V1",buffer); // Publish message.
  display.drawString(30,20," "+String(Voltage));
  #ifdef DEBUG
    Serial.print("AIN1: "); 
    Serial.print(adc1);
    Serial.print("\tVoltage: ");
    Serial.println(Voltage, 7); 
  #endif
  adc2 = ads.readADC_SingleEnded(2);
  Voltage = (adc2 * 0.1875)/1000;
  dtostrf(Voltage, 3, 5, buffer);
  client.publish("/ESP32_LAB1/V2",buffer); // Publish message.
  display.drawString(60,20," "+String(Voltage));
  #ifdef DEBUG
    Serial.print("AIN2: "); 
    Serial.print(adc2);
    Serial.print("\tVoltage: ");
    Serial.println(Voltage, 7);
  #endif 
  adc3 = ads.readADC_SingleEnded(3);
  Voltage = (adc3 * 0.1875)/1000;
  dtostrf(Voltage, 3, 5, buffer);
  client.publish("/ESP32_LAB1/V3",buffer); // Publish message.
  display.drawString(90,20," "+String(Voltage));
  #ifdef DEBUG
    Serial.print("AIN3: "); 
    Serial.print(adc3);
    Serial.print("\tVoltage: ");
    Serial.println(Voltage, 7);
  #endif 
#endif 
#ifdef _SHT3x
  double adx;
  Sensor.UpdateData();
  #ifdef DEBUG
    Serial.print(Sensor.GetTemperature()); //Celsius
    Serial.write("\xC2\xB0"); //The Degree symbol
    Serial.print("C");
    Serial.print(" | ");  
    Serial.print(Sensor.GetRelHumidity());
    Serial.print("%");
    Serial.print(" | ");  
    Serial.print(Sensor.GetAbsHumidity(SHT3x::Pa)); //Torr by default
    Serial.println(" Pa");    
  #endif 
  adx = Sensor.GetTemperature();
  dtostrf(adx, 6,2, buffer);
  client.publish("/ESP32_LAB1/T1",buffer); // Publish message.
  display.drawString(0,30," "+String(adx)+"C");
  adx = Sensor.GetRelHumidity();
  dtostrf(adx, 6,2, buffer);
  client.publish("/ESP32_LAB1/H1",buffer); // Publish message.
  display.drawString(40,30," "+String(adx)+"%");
  adx = Sensor.GetAbsHumidity(SHT3x::psi);
  dtostrf(adx, 6,2, buffer);
  client.publish("/ESP32_LAB1/P1",buffer); // Publish message.
  display.drawString(80,30," "+String(adx)+"psi");
#endif
 display.drawString(0,40," Interval "+String(interval));
 display.display();
}

void i2c_scanner(){
   byte error, address;
   int nDevices;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      nDevices++;
      Serial.print("Device found @ 0x");
      if (address<16) Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
      }
    else if (error==4) 
    {
      Serial.print("Unknow error @ 0x");
      if (address<16) Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");    
    #if OLED_DISPLAY
        display.drawString(0, 23 , "No I2C devices found");
        display.display();
    #endif
  } else {
    Serial.println("done\n");
  }
}  
