WiFi Photometer
9 min read

WiFi Photometer

Code for a wifi enabled photometer
WiFi Photometer

const int led_farben_max = 3;
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
String sVersion = "Version 2.0";
String sVersion2 = " vom 22.02.2019";
const char* ssid = "PHOTOMETER-";
const char* password = "";
unsigned long ulReqcount;
int ledPin[] = {13, 12, 14};
const String farbkennung[] = {"Gr&uumlne LED &nbsp", "Rote LED &nbsp", "Blaue LED &nbsp", "Gr&uumlne, rote und blaue LED"};
const int sdaPin = 4;
const int sclPin = 5;
const int data_runs = 7;
float VIS_IRZEROdata[] = {0.0, 0.0, 0.0};
float IRZEROdata[]
        = {0.0, 0.0, 0.0};
float LUXZEROdata[]
        = {0.0, 0.0, 0.0};
float VIS_IRdata[]
        = {0.0, 0.0, 0.0};
float IRdata[]
        = {0.0, 0.0, 0.0};
float LUXdata[]
        = {0.0, 0.0, 0.0};
float E_LUX[]
        = {0.0, 0.0, 0.0};
float E_VIS_IR[]
        = {0.0, 0.0, 0.0};
float E_IR[]
        = {0.0, 0.0, 0.0};
int probenzeilenIndex
        = 0;
const int probenzeilenMax = 5;
float LUX_werte[3][probenzeilenMax];
float E_werte[3][probenzeilenMax];
String anzeige
        = "a";
bool download
        = false;
String datentabelle
        = "";
const String trennzeichen = "\t";
uint16_t broadband = 0;
uint16_t infrared = 0;
WiFiServer server(80);
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
void displaySensorDetails(void) {
        sensor_t sensor;
        tsl.getSensor(&sensor);
        Serial.println("------------------------------------");
        Serial.print ("Sensor: "); Serial.println(sensor.name);
        Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
        Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
        Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
        delay(500);
}
void configureSensor(void) {
        tsl.enableAutoRange(true);
        tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS);
        Serial.print ("Gain: "); Serial.println("Auto");
        Serial.print ("Timing: "); Serial.println("13 ms");
        Serial.println("------------------------------------");
}
bool readSensor(int color) {
        sensors_event_t event;
        int ok = 0;
        float LUX[data_runs + 1];
        float VIS_IR[data_runs + 1];
        float IR[data_runs + 1];
        float LUX_max = 0.0, LUX_min = 0.0;
        for (int j = 0; j <= data_runs; j++) {
                LUX[j]
                        = 0.0;
                VIS_IR[j]
                        = 0.0;
                IR[j]
                        = 0.0;
        }
        if (led_farben_max > 1) {
                digitalWrite(ledPin[color], HIGH);
        }
        else {
                digitalWrite(ledPin[1], HIGH);
        }
        for (int j = 0; j <= data_runs - 1; j++) {
                tsl.getEvent(&event);
                if (event.light) {
                        LUX[j] = (event.light * 1.0);
                        if (j == 0) {
                                LUX_max = LUX[j];
                                LUX_min = LUX[j];
                        }
                        if (LUX[j] > LUX_max) LUX_max = LUX[j];
                        if (LUX[j] < LUX_min) LUX_min = LUX[j];
                        tsl.getLuminosity (&broadband, &infrared);
                        VIS_IR[j] = (broadband * 1.0);
                        IR[j]  = (infrared * 1.0);
                        delay(25);
                        ok += 1;
                }
                else {
                        Serial.println("Der Sensor-Messwert ist unbrauchbar. -> Sensor fehler!");
                }
        }
        if (led_farben_max > 1) {
                digitalWrite(ledPin[color], LOW);
        }
        else {
                digitalWrite(ledPin[1], LOW);
        }
        if (ok >= data_runs) {
                for (int j = 0; j <= data_runs - 1; j++) {
                        LUX[data_runs]
                                += LUX[j];
                        VIS_IR[data_runs] += VIS_IR[j];
                        IR[data_runs]
                                += IR[j];
                }
                LUX[data_runs]
                        = (LUX[data_runs] - LUX_max - LUX_min)
                          / (data_runs * 1.0 - 2.0);
                VIS_IR[data_runs] = VIS_IR[data_runs] / (data_runs * 1.0);
                IR[data_runs]
                        = IR[data_runs]
                          / (data_runs * 1.0);
                LUXdata[color]
                        = LUX[data_runs];
                VIS_IRdata[color] = VIS_IR[data_runs];
                IRdata[color]
                        = IR[data_runs];
                return true;
        }
        else {
                return false;
        }
}
void cleardata() {
        Serial.println("Cleardata(RESET) aufgerufen!" );
        for (int zeilennummer = 0; zeilennummer < probenzeilenMax; zeilennummer++) {
                for (int ledfarbe = 0; ledfarbe < led_farben_max; ledfarbe++) {
                        LUX_werte[ledfarbe][zeilennummer] = 0.0;
                        E_werte[ledfarbe][zeilennummer]
                                = 0.0;
                        LUXZEROdata[ledfarbe]
                                = 0.0;
                        VIS_IRZEROdata[ledfarbe]
                                = 0.0;
                        IRZEROdata[ledfarbe]
                                = 0.0;
                }
        }
        probenzeilenIndex = 0;
}
void setup() {
        for (int led = 0; led < led_farben_max; led++) {
                if (led_farben_max == 1) pinMode(ledPin[1], OUTPUT);
                if (led_farben_max > 1) pinMode(ledPin[led], OUTPUT);
        }
        ulReqcount = 0;
        Serial.begin(9600);
        WiFi.mode(WIFI_AP);
        if (led_farben_max > 1) {
                for (int led = 0; led < led_farben_max; led++) {
                        digitalWrite(ledPin[led], HIGH);
                        delay(2000);
                        digitalWrite(ledPin[led], LOW);
                }
        }
        else {
                digitalWrite(ledPin[1], HIGH);
                delay(6000);
                digitalWrite(ledPin[1], LOW);
        }
        for (int zeilennummer = 0; zeilennummer < probenzeilenMax; zeilennummer++) {
                for (int ledfarbe = 0; ledfarbe < led_farben_max; ledfarbe++) {
                        LUX_werte[ledfarbe][zeilennummer] = 0.0;
                        E_werte[ledfarbe][zeilennummer]
                                = 0.0;
                }
        }
        Serial.println("");
        Serial.println(String(sVersion + String (led_farben_max) + sVersion2));
        uint8_t mac[WL_MAC_ADDR_LENGTH];
        WiFi.softAPmacAddress(mac);
        String macID = String((mac[WL_MAC_ADDR_LENGTH - 2] * 256 + mac[WL_MAC_ADDR_LENGTH - 1]), DEC);
        macID.toUpperCase();
        String AP_NameString = ssid + macID;
        char AP_NameChar[AP_NameString.length() + 1];
        memset(AP_NameChar, 0, AP_NameString.length() + 1);
        for (int i = 0; i < AP_NameString.length(); i++) AP_NameChar[i] = AP_NameString.charAt(i);
        WiFi.softAP(AP_NameChar, password);
        server.begin();
        Serial.print("WIFI Access Point gestartet. Name (SSID) : "); Serial.println(AP_NameChar);
        Serial.print("WEB-Server erreichbar unter der IP-Adresse): "); Serial.println(WiFi.softAPIP());
        Serial.println("");
        Wire.pins(sdaPin, sclPin);
        if (!tsl.begin()) {
                Serial.print("Ooops, es konnte kein TSL2561-Sensor erkannt werden ...! (Hardware Fehler) Programm Abbruch!!! Reset nötig!!!");
                while (1);
        }
        displaySensorDetails();
        configureSensor();
        Serial.println("");
}
void loop() {
        WiFiClient client = server.available();
        if (!client) return;
        Serial.println("Neuer WIFI-Client");
        unsigned long ultimeout = millis() + 250;
        while (!client.available() && (millis() < ultimeout)) delay(1);
        if (millis() > ultimeout) {
                Serial.println("WIFI-Client Fehler: Connection-Time-Out!");
                return;
        }
        String sRequest = client.readStringUntil('\r');
        client.flush();
        if (sRequest == "") {
                Serial.println("WIFI-Client Fehler: Leere Anfrage! -> WIFI-Client angehalten");
                client.stop();
                return;
        }
        String sPath = "", sParam = "", sCmd = "";
        String sGetstart = "GET ";
        int iStart, iEndSpace, iEndQuest;
        iStart = sRequest.indexOf(sGetstart);
        if (iStart >= 0) {
                iStart += +sGetstart.length();
                iEndSpace = sRequest.indexOf(" ", iStart);
                iEndQuest = sRequest.indexOf("?", iStart);
                if (iEndSpace > 0) {
                        if (iEndQuest > 0) {
                                sPath = sRequest.substring(iStart, iEndQuest);
                                sParam = sRequest.substring(iEndQuest, iEndSpace);
                        }
                        else {
                                sPath = sRequest.substring(iStart, iEndSpace);
                        }
                }
        }
        if (sParam.length() > 0) {
                int iEqu = sParam.indexOf("=");
                if (iEqu >= 0) {
                        sCmd = sParam.substring(iEqu + 1, sParam.length());
                        Serial.println(sCmd);
                }
        }
        String sResponse, sHeader;
        String sResponseStart = "";
        String sResponseTab
                = "";
        if (sPath != "/") {
                sResponse = "<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>Die angeforderte Webseite (URL) gibt es auf diesem Server nicht. Bitte zurück zu 192.168.4.1!</p></body></html>";
                sHeader = "HTTP/1.1 404 Not found\r\n";
                sHeader += "Content-Length: ";
                sHeader += sResponse.length();
                sHeader += "\r\n Content-Type: text/html\r\n Connection: close\r\n\r\n";
        }
        else {
                if (sCmd.length() > 0) {
                        Serial.print("Command: "); Serial.println(sCmd);
                        if (sCmd.indexOf("READZERO") >= 0) {
                                for (int color = 0; color < led_farben_max; color++) {
                                        if (!readSensor(color)) Serial.println("Sensor Fehler");
                                        else {
                                                LUXZEROdata[color]
                                                        = LUXdata[color];
                                                VIS_IRZEROdata[color] = VIS_IRdata[color];
                                                IRZEROdata[color]
                                                        = IRdata[color];
                                        }
                                }
                        }
                        if (sCmd.indexOf("READTSL") >= 0) {
                                for (int color = 0; color < led_farben_max; color++) {
                                        if (!readSensor(color)) Serial.println("Sensor Fehler");
                                        LUX_werte[color][probenzeilenIndex] = LUXdata[color];
                                        if (LUXdata[color] > 0.0 & LUXZEROdata[color] > 0.0) {
                                                E_LUX[color] = -log10((LUXdata[color] * 1.0) / (LUXZEROdata[color] * 1.0));
                                        }
                                        else {
                                                E_LUX[color] = 0.0;
                                        }
                                        if (VIS_IRdata[color] > 0.0 & VIS_IRZEROdata[color] > 0.0) {
                                                E_VIS_IR[color] = -log10((VIS_IRdata[color] * 1.0) / (VIS_IRZEROdata[color] * 1.0));
                                        }
                                        else {
                                                E_VIS_IR[color] = 0.0;
                                        }
                                        if (IRdata[color] > 0.0 & IRZEROdata[color] > 0.0) {
                                                E_IR[color] = -log10((IRdata[color] * 1.0) / (IRZEROdata[color] * 1.0));
                                        }
                                        else {
                                                E_IR[color] = 0.0;
                                        }
                                }
                                probenzeilenIndex += 1;
                                if (probenzeilenIndex >= probenzeilenMax) probenzeilenIndex = 0;
                        }
                        if (sCmd.indexOf("CLEARDATA") >= 0) {
                                cleardata()
                                ;
                        }
                        if (led_farben_max > 1) {
                                if (sCmd.indexOf("GR")
                                    >= 0) {
                                        anzeige = "g"
                                        ;
                                }
                                if (sCmd.indexOf("RT")
                                    >= 0) {
                                        anzeige = "r"
                                        ;
                                }
                                if (sCmd.indexOf("BL")
                                    >= 0) {
                                        anzeige = "b"
                                        ;
                                }
                                if (sCmd.indexOf("ALL")
                                    >= 0) {
                                        anzeige = "a"
                                        ;
                                }
                        }
                        if (sCmd.indexOf("DOWNLOAD") >= 0) {
                                download = true;
                        }
                }
                for (int color = 0; color < led_farben_max; color++) {
                        for (int zeilennummer = 0; zeilennummer < probenzeilenMax; zeilennummer++) {
                                if (LUX_werte[color][zeilennummer] > 0.0 & LUXZEROdata[color] > 0.0) {
                                        E_werte[color][zeilennummer] = -log10((LUX_werte[color][zeilennummer] * 1.0) / (LUXZEROdata[color] * 1.0));
                                }
                                else {
                                        E_werte[color][zeilennummer] = 0.0;
                                }
                        }
                }
                sResponseStart = "<html><head><title>Photometer</title></head><body>";
                sResponseStart += "<font color=\"#FFFFFF\"><body bgcolor=\"#003CA0\">";
                sResponseStart += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
                sResponseStart += "<p style=\"text-align: center; font-family: 'Helvetica', sans-serif; font-size: 27; font-weight:bold; \">Photometer &nbsp &nbsp";
                sResponseStart += "</p>";
                sResponseStart += "<p style='text-align: center'><a href=\"?pin=READZERO\"><button style='font-size:26px'>Leerprobe</button></a>";
                sResponseStart += String("&nbsp &nbsp &nbsp &nbsp <a href=\"?pin=READTSL\"> <button style='font-size:26px'>Probe &nbsp" + String(probenzeilenIndex + 1) + "</button></a></p>");
                sResponseStart += "<p style='text-align: center'><table border='0' style=\"font-family: 'Helvetica', sans-serif; color: white; margin-left: auto; margin-right: auto; font-size: 20 \">";
                for (int color = 0; color < led_farben_max; color++) {
                        if (led_farben_max > 1) {
                                sResponseStart += String("<tr><td>" + farbkennung[color] + "</td><td>:</td><td>" + String(LUXdata[color]) + " lx &nbsp</td><td>" + String(E_LUX[color], 4) + "</td></tr>");
                        }
                        else {
                                sResponseStart += String("<tr><td>" + String(LUXdata[color]) + " lx &nbsp</td><td>" + String(E_LUX[color], 4) + "</td></tr>");
                        }
                }
                sResponseStart += "</table></p>";
                sResponseStart += "<p style='text-align: center'>";
                sResponseStart += "Probentabelle anzeigen f&uumlr:<BR>";
                if (led_farben_max > 1) {
                        sResponseStart += String("<a href=\"?pin=GR\"><button>" + farbkennung[0] + "</button></a>");
                        sResponseStart += String("<a href=\"?pin=RT\"><button>" + farbkennung[1] + "</button></a>");
                        sResponseStart += String("<a href=\"?pin=BL\"><button>" + farbkennung[2] + "</button></a>");
                        sResponseStart += String("<a href=\"?pin=ALL\"><button>" + farbkennung[3] + "</button></a>");
                }
                sResponseStart += "</p>";
                if (led_farben_max > 1) {
                        datentabelle = String(" " + trennzeichen + "(g)" + trennzeichen + "(g)" + trennzeichen + "(r)" + trennzeichen + "(r)" + trennzeichen + "(b)" + trennzeichen + "(b)\r\n");
                        datentabelle += String(" " + trennzeichen + "M" + trennzeichen + "E" + trennzeichen + "M" + trennzeichen + "E" + trennzeichen + "M" + trennzeichen + "E\r\n");
                        datentabelle += String(" " + trennzeichen + "[lx]" + trennzeichen + "[-]" + trennzeichen + "[lx]" + trennzeichen + "[-]" + trennzeichen + "[lx]" + trennzeichen + "[-]\r\n");
                        datentabelle += String("Leerprobe" + trennzeichen + String(LUXZEROdata[0], 2) + trennzeichen + "-" + trennzeichen + String(LUXZEROdata[1], 2) + trennzeichen + "-" + trennzeichen + String(LUXZEROdata[2], 2) + trennzeichen + "-\r\n");
                        for (int i = 0; i < probenzeilenMax; i++) {
                                datentabelle += ("Probe " + String(i + 1));
                                datentabelle += (trennzeichen + (String(LUX_werte[0][i], 2)) + trennzeichen + (String(String(E_werte[0][i], 3))));
                                datentabelle += (trennzeichen + (String(LUX_werte[1][i], 2)) + trennzeichen + (String(String(E_werte[1][i], 3))));
                                datentabelle += (trennzeichen + (String(LUX_werte[2][i], 2)) + trennzeichen + (String(String(E_werte[2][i], 3))));
                                datentabelle += "\r\n";
                        }
                }
                else {
                        datentabelle = String(" " + trennzeichen + "M" + trennzeichen + "E\r\n");
                        datentabelle += String(" " + trennzeichen + "[lx]" + trennzeichen + "[-]\r\n");
                        datentabelle += String("Leerprobe" + trennzeichen + String(LUXZEROdata[0], 2) + trennzeichen + "-\r\n");
                        for (int i = 0; i < probenzeilenMax; i++) {
                                datentabelle += ("Probe " + String(i + 1));
                                datentabelle += (trennzeichen + (String(LUX_werte[0][i], 2)) + trennzeichen + (String(String(E_werte[0][i], 3))));
                                datentabelle += "\r\n";
                        }
                }
                Serial.println(datentabelle);
                if (led_farben_max == 1) {
                        anzeige = "g";
                }
                sResponseTab += "<table border='1' width='100%' style=\"font-family: 'Helvetica', sans-serif; color: white;\"><tr><th><a href=\"? pin=CLEARDATA\"> <button>Reset</button></a></th>";
                if (anzeige == "a" or anzeige == "g") sResponseTab += "<th>Messwert(g) [lx]</th> <th>Extinktion(g) [-]</th>";
                if (anzeige == "a" or anzeige == "r") sResponseTab += "<th>Messwert(r) [lx]</th> <th>Extinktion(r) [-]</th>";
                if (anzeige == "a" or anzeige == "b") sResponseTab += "<th>Messwert(b) [lx]</th> <th>Extinktion(b) [-]</th>";
                sResponseTab += "</tr>";
                sResponseTab += "<tr><td>Leerprobe</td>";
                if (anzeige == "a" or anzeige == "g") {
                        sResponseTab += String("<td style='text-align: center'>" + String(LUXZEROdata[0]) + "</td><td></td>");
                }
                if (anzeige == "a" or anzeige == "r") {
                        sResponseTab += String("<td style='text-align: center'>" + String(LUXZEROdata[1]) + "</td><td></td>");
                }
                if (anzeige == "a" or anzeige == "b") {
                        sResponseTab += String("<td style='text-align: center'>" + String(LUXZEROdata[2]) + "</td><td></td>");
                }
                sResponseTab += "</tr>";
                for (int i = 0; i < probenzeilenMax; i++) {
                        sResponseTab += "<tr>";
                        sResponseTab += String("<td>Probe " + String(i + 1) + "</td>");
                        if (anzeige == "a" or anzeige == "g") {
                                sResponseTab += String("<td style='text-align: center'>" + String(LUX_werte[0][i], 2) + "</td>");
                                sResponseTab += String("<td style='text-align: center'>" + String(E_werte[0][i], 3) + "</td>");
                        }
                        if (anzeige == "a" or anzeige == "r") {
                                sResponseTab += String("<td style='text-align: center'>" + String(LUX_werte[1][i], 2) + "</td>");
                                sResponseTab += String("<td style='text-align: center'>" + String(E_werte[1][i], 3) + "</td>");
                        }
                        if (anzeige == "a" or anzeige == "b") {
                                sResponseTab += String("<td style='text-align: center'>" + String(LUX_werte[2][i], 2) + "</td>");
                                sResponseTab += String("<td style='text-align: center'>" + String(E_werte[2][i], 3) + "</td>");
                        }
                        sResponseTab += "</tr>";
                }
                sResponseTab += "</table>";
                sResponseTab += "<p style='text-align: center'><a href=\"?pin=DOWNLOAD\"><button>Download</button></a></p><BR>";
                sResponse += "</body></html>";
                sHeader = "HTTP/1.1 200 OK\r\n Content-Length: ";
                sHeader += sResponse.length() + sResponseStart.length() + sResponseTab.length();
                sHeader += "\r\n Content-Type: text/html\r\n Connection: close\r\n\r\n";
        }
        if (download) {
                download = false;
                sResponse = "HTTP/1.1 200 OK\r\n";
                sResponse += "Content-Type: text/csv; charset=utf-8 \r\n";
                sResponse += "Content-Transfer-Encoding: binary \r\n";
                sResponse += "Content-Disposition: attachment; filename=\"photometer_daten.csv\" \r\n";
                sResponse += "Pragma: no-cache Expires: 0 \r\n";
                sResponse += "Content-Length:";
                sResponse += String(datentabelle.length());
                sResponse += " \r\n";
                sResponse += " Connection: close";
                sResponse += "\r\n\r\n";
                sResponse += datentabelle;
                client.print(sResponse);
                delay(1000);
        }
        else {
                client.print(sHeader);
                client.print(sResponseStart);
                client.print(sResponseTab);
                client.print(sResponse);
        }
        client.stop();
        Serial.println("WIFI-Client getrennt");
}