Gerfried 4 年 前
コミット
9cca704c9f
1 ファイル変更814 行追加0 行削除
  1. 814 0
      aml_sensorbox_tmpNoise.ino

+ 814 - 0
aml_sensorbox_tmpNoise.ino

@@ -0,0 +1,814 @@
+/*
+ * AML TMP+NOISE
+ * 
+ * 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.  
+ *      
+ * 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
+ *      
+ *      
+ *      
+ *      
+ ************************************************      
+ *      
+ * 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
+ *  
+ *  
+ ************************************************  
+ *  
+ *  
+ * VERSION: 1.03
+ */
+
+ #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 002";
+ 
+ //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.eyJzdWIiOjE1LCJpYXQiOjE2MDA4NDY3MTl9.Jk1CXJXeB6cm4T0QARoj_1BtxvsZF3jl5UhvPRMEBvQ";
+ 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;
+ 
+//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);
+
+   //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 < 3470) && (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.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();
+      }
+}