/*
 * AML TMP+NOISE
 * 
 * VERSION: 1.11
 * 
 * 
 * The Sensorbox measures Temperature and Noise-Level and sends this information with the GPS-position to a webservice.
 * 
 * ************************************************        
 * GENERAL INFO AND COMPONENTS 
 * 
 * Measuring Battery: https://learn.adafruit.com/adafruit-feather-32u4-fona/power-management
 * Gettin Noise: http://arduinolearning.com/code/arduino-and-max4466-electret-module-example.php
 * Getting GSM Location: https://www.instructables.com/id/How-to-make-a-Mobile-Cellular-Location-Logger-with/
 * 
 * Tiny GPS++ Library: http://arduiniana.org/libraries/tinygpsplus/
 * 
 * 
 * Battery saving:
 * 
 * GPS Board:   - Use EN Pin to turn of the board when not needed (https://learn.adafruit.com/adafruit-ultimate-gps/overview)
 *              - EN soll laut der Quelle auf GND gesetzt werden. Es dauert dann aber länger bis wieder ein Fix gefunden wurde.
 *              
 * 
 * Feather FONA:  - Cut the key trac on the bottom of the board (https://learn.adafruit.com/adafruit-feather-32u4-fona/power-management)
 *                - If you want to depower the cell module, cut the KEY trace on the bottom of the board, wire KEY to an unused pad, 
 *                  and toggle the pin low for 100ms to completely turn on/off the module.
 *                - https://arduino.stackexchange.com/questions/54001/adafruit-feather-32u4-fona-key-pin
 *                  cut the trace and wire it to a micro controller pin
 *                - Key - this is by default tied to ground, cut the trace on the bottom and wire to a microcontroller pin to manually turn the module on and off. 
 *                  (Pulse low for a few seconds to change from on to off) This is the only way to truly disable the cellular module.
 *                
 *************************************************      
 * TODOS & BUGS:               
 *      - Die Ladeanzeige über die LED funktioniert nicht immer korrekt. Besonders gelbes Blinken (Aufladen) ist davon betroffen.  
 *      - GPS fix ist noch valide obwohl die Box offline ist. Wenn der Akku aus ist, sollte ein NO-FIX gesendet werden.
 *      
 ************************************************      
 *      
 * IMPORTANT INFO: 
 *  - Be sure to use the correct Token and device number before uplading the code
 *  - For A1 Sim-Cards the APN needs to be set in initFONA(). Uncomment the line if other SIM-Card is used or set the correct APN
 *  
 * 
 *  
 *  
 ************************************************  
 *  
 */

#include <Adafruit_NeoPixel.h>
#include "Adafruit_FONA.h"
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
#include <AES.h>

#define LEDPIN 13
#define ANALOG_TEMP_PIN A0
#define ANALOG_NOISE_PIN A1
#define KEYPIN 12
#define GPSENABLE 11


#define FONA_RX 9
#define FONA_TX 8
#define FONA_RST 4
#define FONA_RI 7

#define aref_voltage 3.3

Adafruit_NeoPixel pixel(1, LEDPIN, NEO_GRB + NEO_KHZ800);


//GSM
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
uint8_t type;

//This is: Box 5
char URL[] = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlhdCI6MTYwMDg0NjY2NH0.d5xvkTVDcHJl-K6KkohIWcUC5XcYNRZ_wzSLMvqAyvw";
//char URL2[] = "http://www.mobillab.wien/sensorbox/write/";
char URL3[] = "http://aml.media.tuwien.ac.at:11312/api/sensorstatus/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlhdCI6MTYwMDg0NjY2NH0.d5xvkTVDcHJl-K6KkohIWcUC5XcYNRZ_wzSLMvqAyvw";
unsigned long ATtimeOut = 10000;  // How long we will give an AT command to complete
boolean initFONAagain = false;

//Limits
int offlineMv = 3520;  //Lowest Millivolts before box shuts down
int onlineMv = 3570;   //Millivolts to go online again

//GPS
static const uint32_t GPSBaud = 9600;
TinyGPSPlus gps;
boolean encodeGPSAgain = false;

//Timing
unsigned long currentMillis = 0;

unsigned long singleBlinkDuration = 500;  //Duration for 1 Blink
unsigned long lastSingleBlinkStart = 0;
unsigned long blinkSequenceDuration = 4200;  //Duration for an blink sequence (not sure if needed)
unsigned long lastBlinkSequenceStart = 0;
unsigned long blinkPauseDuration = 200;  //Duration for blink pause
unsigned long lastBlinkPauseStart = 0;
unsigned long blinkInterval = 10000;  //Interval to blink

unsigned long checkBatInterval = 15000;  //Interval for Checking the Battery -> long interval: every 10 Minutes (if everthing is ok) 600000; short interval: every 15 seconds (150000)
unsigned long lastBatCheck = 0;

unsigned long sendToWebInterval = 1200000;  //20 min = 1200000;   5min = 300000;         //Interval for sending data to webservice
unsigned long lastSendToWeb = 0;

unsigned long pullLowDuration = 2000;  //3 seconds for pulling KEYPIN low to turn off/on Fona

unsigned long GPSUpdateInterval = 21600000;  // 6hrs
unsigned long lastGPSupdate = 0;
unsigned long GPSUpdateTimeout = 180000;  //Time for trying to find a fix! If over, then no fix found (indoor).

unsigned long noiseSameplingInterval = 2000;  //Start sampling
unsigned long lastNoiseSampling = 0;


//Temp
byte tempPin = A0;
float temperature;

//Noise
const int sampleWindow = 500;  // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;
int noiseAVG = 0;

const int numReadings = 20;  // change for higher smoothing
int readings[numReadings];   // the readings from the analog input
int readIndex = 0;           // the index of the current reading
int total = 0;               // the running total

double boxDB = 115;

//Status Flags
byte statusInfo[] = {
  1,  //Value = 1 - status everything ok (white)
  0,  //Value = 1 - no Position   (blue)
  0,  //Value = 1 - no connection to server (GSM) (pink)
  0,  //Value = 1 - low battery (red)
  0,  //Value = 1 - is charging   (yellow)
  0,  //Value = 1 - battery fully charged (green)
};

uint16_t lastBatteryLevel = 0;
uint16_t lastMilliVolts = 0;
boolean lastMessageSent = true;


//encryption
//AES aes;
//byte *key = (unsigned char*)"0123491889010123";


void setup() {


  //while (!Serial);
  Serial.begin(115200);
  Serial1.begin(GPSBaud);

  //Init LED and turn on pixel
  pixel.begin();
  pixel.setBrightness(30);
  pixel.setPixelColor(0, pixel.Color(255, 255, 255));  //light up while startup
  pixel.show();

  analogReference(EXTERNAL);  //sets analog reference voltage to AREF pin

  // initialize the readings for Noise to 0:
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }

  //Pins to turn on and off gsm and gps
  pinMode(KEYPIN, OUTPUT);
  digitalWrite(KEYPIN, HIGH);
  pinMode(GPSENABLE, OUTPUT);
  digitalWrite(GPSENABLE, LOW);

  encodeGPSAgain = true;

  delay(900000);  //15minutes to charge the battery before anything else is done 900000

  //Turn off pixel
  pixel.setPixelColor(0, pixel.Color(0, 0, 0));
  pixel.show();

  
}

void loop() {

  

  if (!lastMessageSent) {  //Turn off everything thats not needed

    blinkStatus();

    if (encodeGPSAgain) encodeGPS();  //Encoding again if no valid or updated signal found; no rekursion here
    /*if(initFONAagain) {              //NOT NEEDED?????
      initFONA();      //Init FONA again if FONA was off while first attempt
      Serial.println("INFO: Init Fona again before noise sampling; Line 211");
     }*/

    //Sampling Noise in a specific interval.
    currentMillis = millis();
    if (currentMillis - lastNoiseSampling >= noiseSameplingInterval) {
      lastNoiseSampling = currentMillis;
      noiseAVG = getNoise();
      //Serial.println("Info: Noise: " + String(noiseAVG) + "dB");
    }

    //Getting GPS data in a specific interval.
    currentMillis = millis();
    if (currentMillis - lastGPSupdate >= GPSUpdateInterval) {
      //Serial.println("Checking GPS");
      lastGPSupdate = currentMillis;
      encodeGPS();
    }
  }



  //Send to Web in a specific interval
  currentMillis = millis();

  

  if ((currentMillis - lastSendToWeb >= sendToWebInterval)) {
    //Serial.println("foo");

    

    lastSendToWeb = currentMillis;

    switchFONA();
    //Serial.println(" INFO: Switching FONA (in begin of sendtoweb); Line 239");
    initFONA();
    if (initFONAagain) {
      initFONA();
      //Serial.println(" Init FONA again (in begin of sendtoweb); Line 243");
    }


    //Send to Webservice, if battery is good enough and GPS was once valid
    //INFO: Checking for valid GPS Signal only makes sense for static use on one place.
    //      For dynamic use with changing places the check should use gps.location.isUpdated()
    if (gps.location.isValid() && (lastMilliVolts >= offlineMv) && !lastMessageSent) {

      lastMilliVolts = getBatteryVoltage();
      lastBatteryLevel = getBatteryLevel();
      //delay(10000);
      //Serial.println("INFO: Sending Data!");
      sendToWebService(getGeoJSONDataString(), URL);
      //delay(10000);
      //Serial.println("INFO: Sending Status!");
      sendToWebService("{\"battery\": " + String(getBatteryLevel()) + ", \"millivolt\": " + String(getBatteryVoltage()) + ", \"gps_fix\": 1, \"online\": 1}", URL3);

    } else {  //Check Battery

      lastMilliVolts = getBatteryVoltage();
      lastBatteryLevel = getBatteryLevel();
    }


    //SERVICE MESSAGES
    //Power too low, but last message not yet sent -> send last message; BUT make sure, that mV is plausible -> >500
    byte gpsFix = 1;
    if (statusInfo[1] == 1) {  //Statusinfo is 1 in case of error -> no gps
      gpsFix = 0;
    }

    if ((lastMilliVolts < offlineMv) && (lastMilliVolts > 500) && !lastMessageSent) {

      //Serial.println("INFO: Sending last message to DATAHUB");
      //Tell the server that there is no GPS Fix (although there might still be one).
      //TODO: Clear the tinyGPS object (so that there is actually no fix)
      sendToWebService("{\"battery\": " + String(getBatteryLevel()) + ", \"millivolt\": " + getBatteryVoltage() + ", \"gps_fix\": 0" + ", \"online\": 0}", URL3);
      lastMessageSent = true;  //set to false; needed if battery is charging and sensor is sending again


    } else if ((lastMilliVolts > onlineMv) && lastMessageSent) {  //Power sufficient again (after charging) -> back to work msg (just a service msg) (3520mV to avoid pending between last msg and back to work msg)

      //Serial.println("INFO: Sending Back to Work message to DATAHUB");
      sendToWebService("{\"battery\": " + String(getBatteryLevel()) + ", \"millivolt\": " + getBatteryVoltage() + ", \"gps_fix\": " + gpsFix + ", \"online\": 1}", URL3);
      lastMessageSent = false;  //set to false; needed if battery is charging and sensor is sending again
    }

    //Try to get a valid GPS location
    if (!gps.location.isValid() && (lastMilliVolts >= onlineMv) && !lastMessageSent) {

      //Serial.println("INFO: Sending NO GPS Message to DATAHUB");
      sendToWebService("{\"battery\": " + String(getBatteryLevel()) + ", \"millivolt\": " + getBatteryVoltage() + ", \"gps_fix\": 0" + ", \"online\": 1}", URL3);

      GPSUpdateInterval = sendToWebInterval;
    }

    switchFONA();
    //Serial.println("INFO: Switching FONA after sending; Line 300");
  }
}


void initFONA() {

  //Serial.println("INFO: Starting FONA init");

  fonaSerial->begin(4800);
  if (!fona.begin(*fonaSerial)) {
    //Serial.println(F("INIT - Couldn't find FONA"));
    switchFONA();  //In case Phona is turned off (happens wenn battery runs completely out and is charged up again.
    //Serial.println("INFO: Switching FONA in initFONA; Line 314");
    initFONAagain = true;  //after switching ON try to init again
    //Serial.println("ERROR: init FONA again; FONA not found");


    statusInfo[2] = 1;
    // Try to turn it on
    //turnOn();
    if (!fona.begin(*fonaSerial)) {
      while (1)
        ;
    }
  } else {
    statusInfo[2] = 0;
    initFONAagain = false;
  }

  type = fona.type();

  // Set APN (needed for A1 Sim cards) -> Uncomment if other SIM-Cards are in use
  fona.setGPRSNetworkSettings(F("A1.net"), F("ppp@a1plus.at"), F("ppp"));

  // turn GPRS on
  delay(10000);

  if (!fona.enableGPRS(true)) {
    //Serial.println(F("INIT - Failed to turn on GPRS"));
    statusInfo[2] = 1;
    //Serial.println("ERROR: init FONA again; no GPRS");
    initFONAagain = true;  //Try to init FONA again in the next loop
  } else {
    statusInfo[2] = 0;
    initFONAagain = false;
  }

  /* NOT  WORKING: Sending timestamp couses HTTP POST ERROR
      // enable NTP time sync 
      fona.enableNTPTimeSync(true, F("pool.ntp.org"));
          //Serial.println(F("INFO: Failed to enable NTP time sync"));
      */


  //turnOnOffFona();
}

void switchFONA() {

  //Switching FONA on and off through pulling the KEYPIN LOW for a while
  //Each pull to LOW switches the FONA, either on or off (depending on the current state)

  //Serial.println("INFO: Switching FONA");
  unsigned long startMillis = millis();

  while (millis() - startMillis < pullLowDuration) {

    digitalWrite(KEYPIN, LOW);
  }

  digitalWrite(KEYPIN, HIGH);
}


void sendToWebService(String message, char URL[]) {


  //Serial.println("INFO - Start sending to Webservice");

  uint16_t statuscode;
  int16_t length;
  //String datastring = getGeoJSON();
  //String datastring = getSimpleDataString();      //For readable output on Server
  String datastring = message;


  //******with encryption start******
  /*
      byte *key = (unsigned char*)"0123491889010123"; //needs to be randomized!!!!
      unsigned long long int my_iv = 36712162; //needs to be randomized!!!!

      byte plain[datastring.length()];
      datastring.getBytes(plain, datastring.length());

      int plainLength = sizeof(plain)-1;  // don't count the trailing /0 of the string !
      int padedLength = plainLength + N_BLOCK - plainLength % N_BLOCK;

      aes.iv_inc();
      byte iv [N_BLOCK] ;
      byte plain_p[padedLength];
      byte cipher [padedLength] ;
      aes.set_IV(my_iv);
      aes.get_IV(iv);
      aes.do_aes_encrypt(plain,plainLength,cipher,key,128,iv);

      flushSerial();
      bool success = true;
      if (!fona.HTTP_POST_start(URL, F("text/plain"), (uint8_t *) plain, strlen(plain), &statuscode, (uint16_t *)&length)) {
         //Serial.println("HTTP POST FAILED!");
          statusInfo[2] = 1;
      } else {
          statusInfo[2] = 0;
      }
      
      */
  //******with encryption end******

  //******without encryption start******

  unsigned int len = datastring.length() + 1;
  char data[len];
  datastring.toCharArray(data, len);

  flushSerial();

  //char myData[] = "{\"simple\":\"json\"}";
  bool success = true;
  String test = "fona";
  unsigned int lenToken = test.length() + 1;
  char tokenData[lenToken];
  test.toCharArray(tokenData, lenToken);


  if (!fona.HTTP_POST_start(URL, F("text/plain"), (uint8_t *)data, strlen(data), &statuscode, (uint16_t *)&length)) {
    statusInfo[2] = 1;  //HTTP Post failed
    //Serial.println("ERROR: HTTP post failed");
    //pixel.setPixelColor(0, pixel.Color(255 ,255, 255));     //white, just for testing
    //pixel.show();

  } else {
    statusInfo[2] = 0;
  }

  //******without encryption end******

  fona.HTTP_POST_end();

  //Serial.println("INFO - End sending to Webservice");
}

String getGeoJSONDataString() {


  /* GeoJSON should look like this:
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [100.0, 0.0]
      },
      "properties": {
        "Temperature": [24.5, "°C"],
        "Noise": [100.0, "dB"],
        "timestamp": "123456723495",
      }
    }
  */


  String json = "{\"type\":\"Feature\",\"geometry\":{\"type\": \"Point\", \"coordinates\":[" + floatToString(gps.location.lng()) + ", " + floatToString(gps.location.lat()) + "]}, \"properties\": {\"Temperature\":[" + String(getTemperature()) + ", \"°C\"], \"Noise\":[" + String(noiseAVG) + ", \"dB\"], \"timestamp\":\"" + getTimeString() + "\"}}";


  return json;
}


String getTimeString() {

  /* NOT  WORKING: Sending timestamp couses HTTP POST ERROR
   *  
   *  
  // read the time
  char timeBuffer[23];
  fona.getTime(timeBuffer, 23);  // make sure replybuffer is at least 23 bytes!

  //Format timebuffer: YY/MM/DD,HH:MM+00
  
  //Serial.println("INFO: Time: " + String(timeBuffer));
  String timestamp = timeBuffer;
  */
  return "";
}

/* JUST USED FOR TESTING
String getSimpleDataString() {
  
 
  return ("GPS: " + floatToString(gps.location.lng()) + ", " + floatToString(gps.location.lat()) + 
                      "; Temperature: " + String(getTemperature())  + " C; Noise: " + String(noiseAVG) + " DB; Battery: " + String(getBatteryLevel()) + " %; Voltage: " + String(getBatteryVoltage()) +" mV; " + boxID);
      

}
*/

String floatToString(float val) {

  int i;
  char buff[10];
  String valueString = "";

  dtostrf(val, 4, 6, buff);  //4 is mininum width, 6 is precision
  valueString += buff;

  return valueString;
}

////////////  Get Sensor Data ///////////////////


void encodeGPS() {
  //Serial.println("INFO: Turning on GPS module");
  digitalWrite(GPSENABLE, HIGH);

  unsigned long start = millis();
  // For one second we parse GPS data and report some key values
  for (start; millis() - start < 1000;) {
    while (Serial1.available()) {
      char c = Serial1.read();
      //Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      gps.encode(c);  // Did a new valid sentence come in?
    }
  }
  //Serial.println();


  // DEBUGGING: Re-encoding for a certain time
  if (millis() - lastGPSupdate <= GPSUpdateTimeout) {

    //if we haven't seen lots of data in 5 seconds, something's wrong.
    if (start > 5000 && gps.charsProcessed() < 10) {
      //Serial.println("ERROR: Not getting any GPS data! Encoding again");
      encodeGPSAgain = true;

      //TODO: Turning Module OFF here?
    } else if (!gps.location.isValid()) {  //also add timer for circumstances when there is definately no signal to find
      //Serial.println("ERROR: GPS Data not valid! Encoding again");
      encodeGPSAgain = true;
      GPSUpdateInterval = sendToWebInterval;  //SendToWebinterval is usually shorter.
    } else if (!gps.location.isUpdated()) {
      //Serial.println("ERROR: GPS Data not updated! Encoding again");
      encodeGPSAgain = true;
    } else {
      //Serial.println("INFO: GPS: " + floatToString(gps.location.lat()) + ", " + floatToString(gps.location.lng()));
      //Serial.println("INFO: Turning off GPS-Module");
      digitalWrite(GPSENABLE, LOW);  //turn gps module off
      encodeGPSAgain = false;
      GPSUpdateInterval = 21600000;
      statusInfo[1] = 0;
    }

  } else {
    //Serial.println("ERROR: Timeout - No GPS-Data");
    statusInfo[1] = 1;
    //TODO: Send Error Message to Server
    digitalWrite(GPSENABLE, LOW);  //turn gps module off
    encodeGPSAgain = false;
    GPSUpdateInterval = sendToWebInterval;
  }
}



float getTemperature() {

  int pinReading = analogRead(ANALOG_TEMP_PIN);

  float voltage = pinReading * aref_voltage;
  voltage /= 1024.0;

  float temp = (voltage - 0.5) * 100;

  //Serial.println("Temperature: " + String(temp));

  //(((analogRead(ANALOG_TEMP_PIN) * 3.3)/1024.0) - 0.5) * 100;

  return temp;
}

//source: http://arduinolearning.com/code/arduino-and-max4466-electret-module-example.php
float getNoiseReading() {
  unsigned long startMillis = millis();  // Start of sample window
  unsigned int peakToPeak = 0;           // peak-to-peak level
  unsigned int signalMax = 0;
  unsigned int signalMin = 1024;
  while (millis() - startMillis < sampleWindow) {
    sample = analogRead(ANALOG_NOISE_PIN);
    if (sample < 1024) {  // toss out spurious readings
      if (sample > signalMax) {
        signalMax = sample;  // save just the max levels
      } else if (sample < signalMin) {
        signalMin = sample;  // save just the min levels
      }
    }
  }
  peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
  return peakToPeak;                   //* 3.3) / 1024;  // convert to volts
}



int getNoise() {
  // subtract the last reading:
  total = total - readings[readIndex];
  double noiseReading = getNoiseReading();
  // read from the sensor:
  // https://forum.arduino.cc/index.php?topic=318908.0
  // 80 = db on SPL-Meter, 120 = Noise from Noise Sensor at 80 db on the SPL-Meter

  //How to calibrate:
  //take the SPL-Meter and the Sensorbox
  //uncomment this:
  //Serial.println("Noise:");
  //Serial.println(noiseReading);
  //Serial.println("");
  //uncomment the seria println before the return
  //play a sound to reach 80 db on the SPL Meter
  // change boxDB on top to Value which is showing for the Sensorbox

  readings[readIndex] = (20 * log(noiseReading / boxDB) + 80);
  // add the reading to the total:
  total = total + readings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }

  // calculate the average:

  //for calibration of Noise
  //Serial.println(total / numReadings);

  return (total / numReadings);
  // send it to the computer as ASCII digits
}


uint16_t getBatteryLevel() {

  uint16_t vbat;

  fona.getBattPercent(&vbat);

  lastBatteryLevel = vbat;
  //Serial.println("Battery Level: " + String(vbat));
  return vbat;
}

uint16_t getBatteryVoltage() {
  uint16_t vbat;
  //uint16_t batStat;            //NOT WORKING
  fona.getBattVoltage(&vbat);

  //ATTENTION: This function doesn NOT work with public FONA Library.!!!!
  //Status: 0 = not charging; 1 = charging; 2 = finished charging
  //More Info in SIM800 Series AT Command Manual
  //NOT WORKING: getBattStatus always returns 0
  //fona.getBattStatus(&batStat);
  //Serial.println("Battery Status: " + String(batStat));

  //Serial.println("MilliVolts: " + String(vbat));

  //Clear false readings with too high (unrealistic) values
  if (vbat > 4700) vbat = 0;


  //Battery low
  if (vbat <= 3600 && vbat != 0) statusInfo[3] = 1;
  else statusInfo[3] = 0;

  //Battery charging
  if (vbat > lastMilliVolts && vbat != 0) statusInfo[4] = 1;
  else statusInfo[4] = 0;

  //Battery fully charged
  if (vbat > 4170 && vbat != 0) {
    statusInfo[5] = 1;
    statusInfo[4] = 0;
  } else {
    statusInfo[5] = 0;
  }


  return vbat;
}



////////////  Helpers & Output ///////////////////



void blinkStatus() {

  //get number of statusInfo
  boolean blinkSequenceActive = false;

  currentMillis = millis();

  if (currentMillis - lastBlinkSequenceStart >= blinkInterval) {  //start blinking
    blinkSequenceActive = true;
    lastBlinkSequenceStart = currentMillis;
  }


  if (blinkSequenceActive) {  //do the blink sequence

    lastSingleBlinkStart = currentMillis;

    for (int i = 0; i < sizeof(statusInfo);) {

      switch (i) {
        case 0:
          pixel.setPixelColor(0, pixel.Color(255, 255, 255));  //white -> status blink
          break;
        case 1:
          pixel.setPixelColor(0, pixel.Color(0, 200, 255));  //blue -> no GPS
          break;
        case 2:
          pixel.setPixelColor(0, pixel.Color(255, 0, 255));  //pink -> no GSM
          break;
        case 3:
          pixel.setPixelColor(0, pixel.Color(255, 0, 0));  //red -> low Battery
          break;
        case 4:
          pixel.setPixelColor(0, pixel.Color(255, 188, 0));  //orange -> bat charging
          break;
        case 5:
          pixel.setPixelColor(0, pixel.Color(0, 255, 0));  //green -> bat fully charged
          break;
      }

      if (statusInfo[i] != 0) pixel.show();

      currentMillis = millis();
      if (currentMillis - lastSingleBlinkStart >= singleBlinkDuration) {
        i++;  //increase counter to get to the next info
        lastSingleBlinkStart = currentMillis;
        pixel.setPixelColor(0, pixel.Color(0, 0, 0));  //green -> bat fully charged
        pixel.show();
      }
    }
  }

  if (currentMillis - lastBlinkSequenceStart >= blinkSequenceDuration) {  //turn off again

    pixel.setPixelColor(0, pixel.Color(0, 0, 0));
    pixel.show();
    blinkSequenceActive = false;
  }
}

/*
void printSensorData(){
  Serial.println("SensorData:");
  Serial.print("\nTemperature: "); Serial.println(getTemperature());
  Serial.print("\nNoise: "); Serial.println(getNoise());
  Serial.print("\nBattery: "); Serial.print(getBatteryLevel()); Serial.println(" %");
  Serial.print("\nLocation: "); Serial.print(gps.location.lat(), 6); Serial.print(", "); Serial.println(gps.location.lng(), 6); 
  Serial.println("---------------------------------------");
}

String sensorDataToString() {
  String data = "Sensordata: Temperature: " + String(getTemperature()) + " Noise: " + String(getNoise()) + " Battery: " + String(getBatteryLevel()) + "% Location: " + String(gps.location.lat()) + ", " + String(gps.location.lng());
  return data;
}
*/
void flushSerial() {
  while (Serial.available()) {
    Serial.read();
  }
}
