| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817 | /* * AML TMP+NOISE *  * VERSION: 1.03 *  * 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.   *       ************************************************       *       * 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 *   * SOURCE TOKENS: *      BOX 1: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjcsImlhdCI6MTYwMDg0NjI2MH0.YKzbg-8_hFuw1-W0Hqa5eLZAncfqlqT2rf2c95Abi7k *      BOX 2: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE1LCJpYXQiOjE2MDA4NDY3MTl9.Jk1CXJXeB6cm4T0QARoj_1BtxvsZF3jl5UhvPRMEBvQ *      BOX 3: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEwLCJpYXQiOjE2MDA4NDYyMDZ9.rrA8lZ18SThb4L8mf18Krz7dK5ioCwqWd10BstT9GnE *      BOX 4: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE0LCJpYXQiOjE2MDA4NDY0MDR9.0BPUK7NVTlqi7i9QFx9kcVY55jsn0qskPWDL1PKyKec *      BOX 5: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlhdCI6MTYwMDg0NjY2NH0.d5xvkTVDcHJl-K6KkohIWcUC5XcYNRZ_wzSLMvqAyvw *      BOX 6: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjMsImlhdCI6MTYwMDg0NTg4M30.OjsoqjcAMhCh9WLkBpBtXyOlOL25mBXSxT1Uy3tM01M *      BOX 7: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjUsImlhdCI6MTYwMDg0NjUwMH0.XqBhCwt9V6YTNE8fwfxrXahBxGGNHgLkXgO3XaqDcwI *      BOX 8: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjExLCJpYXQiOjE2MDA4NDYxMjd9.uJPST-APKEpsS-CIimNh3ePNce2PaabuX5c3HNnVsfo *      BOX 9: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE2LCJpYXQiOjE2MTA3MTg5MjF9.2lk9xY4Gy0CR65V9giXPHrDR7Eei-O3R5sS1oD6hzsM *   *   ************************************************   *   */ #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); //Name of this Box String boxID = "BOX 009";  //GSM SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); SoftwareSerial *fonaSerial = &fonaSS; Adafruit_FONA fona = Adafruit_FONA(FONA_RST); uint8_t type; //char URL[] = "http://airquality.media.tuwien.ac.at:10005/measurements"; char URL[] = "http://aml.media.tuwien.ac.at:11312/api/sensordata/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjE2LCJpYXQiOjE2MTA3MTg5MjF9.2lk9xY4Gy0CR65V9giXPHrDR7Eei-O3R5sS1oD6hzsM"; char URL2[] = "http://www.mobillab.wien/sensorbox/write/"; //char URL[] = "www.kunstmedienkultur.com/sensorbox/"; unsigned long ATtimeOut = 10000; // How long we will give an AT command to complete boolean initFONAagain = false;//GPS static const uint32_t GPSBaud = 9600; TinyGPSPlus gps; boolean encodeGPSAgain = false; //Timingunsigned long currentMillis =0;unsigned long singleBlinkDuration = 500;            //Duration for 1 Blinkunsigned 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 blinkunsigned 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 webserviceunsigned long lastSendToWeb = 0;unsigned long pullLowDuration = 2000;            //3 seconds for pulling KEYPIN low to turn off/on Fonaunsigned 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;//Tempbyte tempPin = A0;float temperature;//Noiseconst int sampleWindow = 500; // Sample window width in mS (50 mS = 20Hz)unsigned int sample;int noiseAVG = 0;const int numReadings = 20;     // change for higher smoothingint readings[numReadings];      // the readings from the analog inputint readIndex = 0;              // the index of the current readingint total = 0;                  // the running totaldouble boxDB = 115;//Status Flagsbyte 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;//encryptionAES aes;byte *key = (unsigned char*)"0123491889010123";void setup() {   //while (!Serial);   Serial.begin(115200);   Serial1.begin(GPSBaud);   //Inbit 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;   /*   //Get initial position   lastGPSupdate = millis();   encodeGPS();   //Switch FONA on to initially check battery status   initFONA();   if(initFONAagain) initFONA();        //Try again. In case FONA was turned off in 1st attempt   lastMilliVolts = getBatteryVoltage();   switchFONA();    */   delay(900000); //15minutes to charge the battery before anything else is done      //Turn off pixel   pixel.setPixelColor(0, pixel.Color(0, 0, 0));   pixel.show();      }void loop() {       blinkStatus();    //After the last message led is constantly red   if(!lastMessageSent) { //Turn off everything thats not needed        if(encodeGPSAgain) encodeGPS();    //Encoding again if no valid or updated signal found; no rekursion here     if(initFONAagain) initFONA();      //Init FONA again if FONA was off while first attempt          //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)) {    lastSendToWeb = currentMillis;        //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 >= 3500) && !lastMessageSent) {      switchFONA();      initFONA();      lastMilliVolts = getBatteryVoltage();       //Serial.println("INFO: Sending to URL");      sendToWebService(getGeoJSONDataString(), URL);      //(Serial.println("INFO: Sending to URL2");      //sendToWebService(getGeoJSONDataString(), URL2);      switchFONA();    } else {      //Check Battery      switchFONA();      initFONA();      lastMilliVolts = getBatteryVoltage();       switchFONA();    }    //SERVICE MESSAGES    //Power too low, but last message not yet sent -> send last message; BUT make sure, that mV is plausible -> >500    if ((lastMilliVolts < 3480) && (lastMilliVolts > 500) && !lastMessageSent) {       switchFONA();      initFONA();      //sendToWebService(getServiceJSONDataString(" LAST MESSAGE - NO BATTERY"));      sendToWebService(boxID + "Bat: " + lastMilliVolts + "mV ------- LAST MESSAGE - NO BATTERY", URL2);      lastMessageSent = true;            //set to false; needed if battery is charging and sensor is sending again      switchFONA();    } else if((lastMilliVolts > 3550) && 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)      switchFONA();      initFONA();      sendToWebService(boxID + "Bat: " + lastMilliVolts + "mV ------- BACK TO WORK", URL2);        //sendToWebService(getGeoJSONDataString(), URL);      lastMessageSent = false;            //set to false; needed if battery is charging and sensor is sending again      switchFONA();    }        //Try to get a valid GPS location    if(!gps.location.isValid() && (lastMilliVolts >= 3550) && !lastMessageSent) {      switchFONA();      initFONA();      sendToWebService(boxID + "Bat: " + lastMilliVolts + "mV ------- NO GPS", URL2); //TODO: Change to service message      //sendToWebService(getGeoJSONDataString(), URL);      switchFONA();            GPSUpdateInterval = sendToWebInterval;      //Serial.println("INFO: NO GPS (sendtowebservice; 258)");    }    }   } 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.        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 getServiceJSONDataString(uint16_t batLevel, String message) {  /* Service JSON should Look like this    {      "battery": 17.4,      "status_message": "failed to get GPS fix"    }    */        String json =   "{\"battery\": " + String(batLevel) +                     ", \"status_message\": \"" + message + "\"}";    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 "";}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.phpfloat 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();      }}
 |