/* This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details. */

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>
#include <SparkFun_SCD30_Arduino_Library.h>
#include <Wire.h>

String matrixausgabe_text  = " "; // Ausgabetext als globale Variable

volatile int matrixausgabe_index = 0;// aktuelle Position in Matrix

IPAddress myOwnIP; // ownIP for mDNS 

//-------------- definition mqtt-object ueber WiFi
WiFiClient   espClient; 
PubSubClient mqttclient(espClient);

//--------- list of mqtt callback functions 
#define MAX_MQTT_SUB 10 // maximal 10 subscriptions erlaubt
typedef void (*mqtthandle) (byte*,unsigned int);
typedef struct {       // Typdeklaration Callback
  String topic;        // mqtt-topic
  mqtthandle fun;      // callback function 
}
subscribe_type; 
subscribe_type mqtt_sub[MAX_MQTT_SUB];
int mqtt_sub_count=0;

String MQTT_Rx_Payload = "" ;
//--------- mqtt callback function 
void mqttcallback(char* to, byte* pay, unsigned int len) {
  String topic   = String(to);
  String payload = String((char*)pay);
  MQTT_Rx_Payload=payload.substring(0,len);
  Serial.println("\ncallback topic:" + topic + ", payload:" + MQTT_Rx_Payload);
  for (int i=0;i<mqtt_sub_count;i++) { // durchsuche alle subscriptions, bis topic passt 
    if (topic==mqtt_sub[i].topic) 
      mqtt_sub[i].fun(pay,len);         // Aufruf der richtigen callback-Funktion
  }
}

//------------ reconnect mqtt-client
void mqttreconnect() { // Loop until we're reconnected 
  if (!mqttclient.connected()) { 
    while (!mqttclient.connected()) { 
      Serial.print("Attempting MQTT connection...");
      if (mqttclient.connect("CO2Ampel" , "user", "passwort" )) {
        Serial.println("connected");
        for (int i=0;i<mqtt_sub_count;i++) { // subscribe topic
          mqttclient.subscribe(mqtt_sub[i].topic.c_str());
          Serial.println("\nsubscribe");
          Serial.print(mqtt_sub[i].topic);
        }
      } 
      else { 
        Serial.print("failed, rc=");
        Serial.print(mqttclient.state());
        Serial.println(" try again in 5 seconds");
        delay(5000);
      }
    }
  } 
  else { 
    mqttclient.loop(); 
  }
}

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(2,13,NEO_GRBW + NEO_KHZ800);
//Reading CO2, humidity and temperature from the SCD30 By: Nathan Seidle SparkFun Electronics 

//https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library

SCD30 airSensorSCD30; // Objekt SDC30 Umweltsensor
int co2 = 0 ;
int temp = 0 ;
int hum = 0 ;

void setup(){ // Einmalige Initialisierung
  Serial.begin(115200);
  //----------------------------------MQTT-Client 
  mqttclient.setServer("192.168.1.XX", 1883);
  mqttclient.setCallback(mqttcallback);

  pixels.begin();//-------------- Initialisierung Neopixel
  delay(1);
  pixels.show();
  pixels.setPixelColor(0,0,0,0,0); // alle aus
  pixels.setPixelColor(1,0,0,0,0);
  pixels.show();                 // und anzeigen

  Wire.begin(); // ---- Initialisiere den I2C-Bus 

  if (Wire.status() != I2C_OK) Serial.println("Something wrong with I2C");

  if (airSensorSCD30.begin() == false) {
    Serial.println("The SCD30 did not respond. Please check wiring."); 
    while(1) {
      yield(); 
      delay(1);
    } 
  }

  airSensorSCD30.setAutoSelfCalibration(false); // Sensirion no auto calibration

  airSensorSCD30.setMeasurementInterval(2);     // CO2-Messung alle 5 s

  //------------ WLAN initialisieren 
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  delay(100);
  Serial.print ("\nWLAN connect to:");
  Serial.print("WIFI");
  WiFi.begin("SSID","PASSWORD-XXX");
  while (WiFi.status() != WL_CONNECTED) { // Warte bis Verbindung steht 
    delay(500); 
    Serial.print(".");
  };
  Serial.println ("\nconnected, meine IP:"+ WiFi.localIP().toString());
  matrixausgabe_text = " Meine IP:" + WiFi.localIP().toString();
  myOwnIP = WiFi.localIP();
  matrixausgabe_index=0;


  pixels.setPixelColor(0,40,0,0,0);
  pixels.show();
  delay( 3000 );

  // Forced Calibration Sensirion SCD 30
  airSensorSCD30.setAltitudeCompensation(545); // Altitude in m ü NN 
  airSensorSCD30.setForcedRecalibrationFactor(400); // fresh air 

  delay( 3000 );

  Wire.setClock(100000L);            // 100 kHz SCD30 
  Wire.setClockStretchLimit(200000L);// CO2-SCD30
}

void loop() { // Kontinuierliche Wiederholung 
  co2 = airSensorSCD30.getCO2() ;
  temp = airSensorSCD30.getTemperature() ;
  hum = airSensorSCD30.getHumidity() ;
  if (( ( co2 ) < ( 700 ) ))
  {
    pixels.setPixelColor(0,0,30,0,0);
    pixels.show();
  }
  else
  {
    if (( ( co2 ) > ( 700 ) ))
    {
      pixels.setPixelColor(0,30,30,0,0);
      pixels.show();
      if (( ( co2 ) > ( 1000 ) ))
      {
        pixels.setPixelColor(0,40,0,0,0);
        pixels.show();
      }
    }
    else
    {
    }
  }
  delay( 1000 );
  mqttreconnect();
  {
    String pay=String(String(co2));
    mqttclient.publish("sensor/CO2",pay.c_str());
    Serial.print("\nmqtt publish: "); 
    Serial.print(pay);
  };
  mqttreconnect();
  {
    String pay=String(String(temp));
    mqttclient.publish("sensor/temp",pay.c_str());
    Serial.print("\nmqtt publish: "); 
    Serial.print(pay);
  };
  mqttreconnect();
  {
    String pay=String(String(hum));
    mqttclient.publish("sensor/hum",pay.c_str());
    Serial.print("\nmqtt publish: "); 
    Serial.print(pay);
  };
  delay( 6000 );
}
