WiFi Photometer
Code for a wifi enabled 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üne LED  ", "Rote LED  ", "Blaue LED  ", "Grüne, 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    ";
sResponseStart += "</p>";
sResponseStart += "<p style='text-align: center'><a href=\"?pin=READZERO\"><button style='font-size:26px'>Leerprobe</button></a>";
sResponseStart += String("        <a href=\"?pin=READTSL\"> <button style='font-size:26px'>Probe  " + 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  </td><td>" + String(E_LUX[color], 4) + "</td></tr>");
}
else {
sResponseStart += String("<tr><td>" + String(LUXdata[color]) + " lx  </td><td>" + String(E_LUX[color], 4) + "</td></tr>");
}
}
sResponseStart += "</table></p>";
sResponseStart += "<p style='text-align: center'>";
sResponseStart += "Probentabelle anzeigen für:<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");
}