// include header file into code
#include <headerFile.h>

// setup function
void setup() {
  // make serial connection at 115200 baud
  Serial.begin(115200);

  // tell display what settings to use
  display.begin(i2c_adress, true);
  display.clearDisplay();

  // tell sensors to start reading
  dht.begin();
  sgp.begin();

  pinMode(MICPIN, INPUT);
  pinMode(DHTPIN, INPUT);
  
  websocketSetup();
  resetValues();
}

// loop function
void loop() {
  // loop the websocket connection so it stays alive
  webSocket.loop();

  // update when interval is met
  if (currentMillis - lastMillis >= interval){
    lastMillis = millis();
    update();
  }

  // update the counter
  currentMillis = millis();
}

// hexdump function for websockets binary handler
void hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {
	const uint8_t* src = (const uint8_t*) mem;
	USE_SERIAL.printf("\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)", (ptrdiff_t)src, len, len);
	for(uint32_t i = 0; i < len; i++) {
		if(i % cols == 0) {
			USE_SERIAL.printf("\n[0x%08X] 0x%08X: ", (ptrdiff_t)src, i);
		}
		USE_SERIAL.printf("%02X ", *src);
		src++;
	}
	USE_SERIAL.printf("\n");
}

// handler for websocket events 
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
	switch(type) {
		case WStype_DISCONNECTED:
			USE_SERIAL.printf("[WSc] Disconnected!\n");
			break;
		case WStype_CONNECTED:
			USE_SERIAL.printf("[WSc] Connected to url: %s\n", payload);

			// send message to server when Connected
			webSocket.sendTXT("{\"message\": \"Connected\"}");
			break;
		case WStype_TEXT:
			// USE_SERIAL.printf("[WSc] get text: %s\n", payload);

			// send message to server
			// webSocket.sendTXT("message here");
			break;
		case WStype_BIN:
			// USE_SERIAL.printf("[WSc] get binary length: %u\n", length);
			hexdump(payload, length);

			// send data to server
			// webSocket.sendBIN(payload, length);
			break;
		case WStype_ERROR:			
		case WStype_FRAGMENT_TEXT_START:
		case WStype_FRAGMENT_BIN_START:
		case WStype_FRAGMENT:
		case WStype_FRAGMENT_FIN:
			break;
	}
}

// special function to setup websocket
void websocketSetup(){
	WiFiMulti.addAP("iotroam", "vbK9gbDBIB");
  WiFiMulti.addAP("LansanKPN-boven", "19sander71vlieland14");

	while(WiFiMulti.run() != WL_CONNECTED) {
		delay(100);
	}

	// server address, port and URL
	webSocket.begin("145.92.8.114", 80, "/ws");

	// event handler
	webSocket.onEvent(webSocketEvent);

	// try ever 500 again if connection has failed
	webSocket.setReconnectInterval(500);
}

// function to reset the values if needed
void resetValues() {
  TVOC_base;
  eCO2_base;
  counter = 0;
  temperature = 0;
  humidity = 0;
  eCO2 = 0;
  TVOC = 0;
  noise = false;
  lastMillis = 0;
  currentMillis = 0;
}

// function to check for errors in sensors
bool checkForError(){
  if (!sgp.IAQmeasure()) {
    Serial.println("SGP30: BAD");
    errorSGP30 = true;
  } else {
    Serial.println("SGP30: OK");
    errorSGP30 = false;
  }

  if (isnan(temperature) || isnan(humidity)){
    Serial.println("DHT11: BAD");
    errorDHT11 = true;
  } else {
    Serial.println("DHT11: OK");
    errorDHT11 = false;
  }

  return false;
}

// function to update when interval is met (see intervalCounter variable)
void update(){
  // display sensordata on oled screen
  displayData();
  
  // webSocket.sendTXT("{\"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp.eCO2) + "\",\"TVOC\":\"" + String(sgp.TVOC) + "\"}");
  webSocket.sendTXT("{\"node\": \"" + String(WiFi.macAddress()) + "\", \"Temp\":\"" + String(temperature) + "\",\"Humi\":\"" + String(humidity) + "\",\"eCO2\":\"" + String(sgp.eCO2) + "\",\"TVOC\":\"" + String(sgp.TVOC) + "\"}");

  sgp.getIAQBaseline(&eCO2_base, &TVOC_base);

  // read dht11 sensor
  temperature = float(dht.readTemperature());
  humidity = float(dht.readHumidity());

  // check if any errors occured when reading sensors
  checkForError();
}

// function to display data on oled screen
void displayData() {
  // clear display for new info
  display.clearDisplay();

  // set custom text properties
  display.setTextSize(2);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 0);

  // display info on oled screen
  display.println((String) "Temp: " + int(temperature) + "C" + '\n'
    + "Humi: " + int(humidity) + "%" + '\n'
    + "eCO2: " + int(sgp.eCO2) + '\n'
    + "TVOC: " + int(sgp.TVOC));

  // display the screen                
  display.display();
}