Advertisement
Guest User

Untitled

a guest
Jan 29th, 2020
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 17.68 KB | None | 0 0
  1. /*---------------------------------------------------
  2. HTTP 1.1 Temperature & Humidity Webserver for ESP8266
  3. for ESP8266 adapted Arduino IDE
  4.  
  5. by Stefan Thesen 05/2015 - free for anyone
  6.  
  7. Connect DHT21 / AMS2301 at GPIO2
  8. ---------------------------------------------------*/
  9.  
  10. #include <ESP8266WiFi.h>
  11. #include <WiFiUdp.h>
  12. #include "time_ntp.h"
  13. #include "DHT.h"
  14.  
  15. // WiFi connection
  16. const char* ssid = "WIFI-NAME-HERE";
  17. const char* password = "WIFI-PASSWORD-HERE";
  18.  
  19. // ntp timestamp
  20. unsigned long ulSecs2000_timer=0;
  21.  
  22. // storage for Measurements; keep some mem free; allocate remainder
  23. #define KEEP_MEM_FREE 10240
  24. #define MEAS_SPAN_H 168
  25. unsigned long ulMeasCount=0;    // values already measured
  26. unsigned long ulNoMeasValues=0; // size of array
  27. unsigned long ulMeasDelta_ms;   // distance to next meas time
  28. unsigned long ulNextMeas_ms;    // next meas time
  29. unsigned long *pulTime;         // array for time points of measurements
  30. float *pfTemp,*pfHum;           // array for temperature and humidity measurements
  31.  
  32. unsigned long ulReqcount;       // how often has a valid page been requested
  33. unsigned long ulReconncount;    // how often did we connect to WiFi
  34.  
  35. // Create an instance of the server on Port 80
  36. WiFiServer server(80);
  37.  
  38. //////////////////////////////
  39. // DHT21 / AMS2301 is at GPIO2
  40. //////////////////////////////
  41. #define DHTPIN 2
  42.  
  43. // Uncomment whatever type you're using!
  44. //#define DHTTYPE DHT11   // DHT 11
  45. //#define DHTTYPE DHT22   // DHT 22  (AM2302)
  46. #define DHTTYPE DHT21   // DHT 21 (AM2301)
  47.  
  48. // init DHT; 3rd parameter = 16 works for ESP8266@80MHz
  49. DHT dht(DHTPIN, DHTTYPE,16);
  50.  
  51. // needed to avoid link error on ram check
  52. extern "C"
  53. {
  54. #include "user_interface.h"
  55. }
  56.  
  57. /////////////////////
  58. // the setup routine
  59. /////////////////////
  60. void setup()
  61. {
  62.   // setup globals
  63.   ulReqcount=0;
  64.   ulReconncount=0;
  65.    
  66.   // start serial
  67.   Serial.begin(9600);
  68.   Serial.println("WLAN Temperatur und Feuchtigkeitslogger - S. Thesen 05/2015");
  69.  
  70.   // inital connect
  71.   WiFi.mode(WIFI_STA);
  72.   WiFi.hostname("temphum");
  73.   WiFiStart();
  74.  
  75.   // allocate ram for data storage
  76.   uint32_t free=system_get_free_heap_size() - KEEP_MEM_FREE;
  77.   ulNoMeasValues = free / (sizeof(float)*2+sizeof(unsigned long));  // humidity & temp --> 2 + time
  78.   pulTime = new unsigned long[ulNoMeasValues];
  79.   pfTemp = new float[ulNoMeasValues];
  80.   pfHum = new float[ulNoMeasValues];
  81.  
  82.   if (pulTime==NULL || pfTemp==NULL || pfHum==NULL)
  83.   {
  84.     ulNoMeasValues=0;
  85.     Serial.println("Error in memory allocation!");
  86.   }
  87.   else
  88.   {
  89.     Serial.print("Allocated storage for ");
  90.     Serial.print(ulNoMeasValues);
  91.     Serial.println(" data points.");
  92.    
  93.     float fMeasDelta_sec = MEAS_SPAN_H*3600./ulNoMeasValues;
  94.     ulMeasDelta_ms = ( (unsigned long)(fMeasDelta_sec+0.5) ) * 1000;  // round to full sec
  95.     Serial.print("Measurements will happen each ");
  96.     Serial.print(ulMeasDelta_ms);
  97.     Serial.println(" ms.");
  98.    
  99.     ulNextMeas_ms = millis()+ulMeasDelta_ms;
  100.   }
  101. }
  102.  
  103.  
  104. ///////////////////
  105. // (re-)start WiFi
  106. ///////////////////
  107. void WiFiStart()
  108. {
  109.   ulReconncount++;
  110.  
  111.   // Connect to WiFi network
  112.   Serial.println();
  113.   Serial.println();
  114.   Serial.print("Connecting to ");
  115.   Serial.println(ssid);
  116.  
  117.   WiFi.begin(ssid, password);
  118.  
  119.   while (WiFi.status() != WL_CONNECTED)
  120.   {
  121.     delay(500);
  122.     Serial.print(".");
  123.   }
  124.   Serial.println("");
  125.   Serial.println("WiFi connected");
  126.  
  127.   // Start the server
  128.   server.begin();
  129.   Serial.println("Server started");
  130.  
  131.   // Print the IP address
  132.   Serial.println(WiFi.localIP());
  133.  
  134.   ///////////////////////////////
  135.   // connect to NTP and get time
  136.   ///////////////////////////////
  137.   ulSecs2000_timer=getNTPTimestamp();
  138.   Serial.print("Current Time UTC from NTP server: " );
  139.   Serial.println(epoch_to_string(ulSecs2000_timer).c_str());
  140.  
  141.   ulSecs2000_timer -= millis()/1000;  // keep distance to millis() counter
  142. }
  143.  
  144.  
  145. /////////////////////////////////////
  146. // make html table for measured data
  147. /////////////////////////////////////
  148. unsigned long MakeTable (WiFiClient *pclient, bool bStream)
  149. {
  150.   unsigned long ulLength=0;
  151.  
  152.   // here we build a big table.
  153.   // we cannot store this in a string as this will blow the memory  
  154.   // thus we count first to get the number of bytes and later on
  155.   // we stream this out
  156.   if (ulMeasCount==0)
  157.   {
  158.     String sTable = "Noch keine Daten verf&uuml;gbar.<BR>";
  159.     if (bStream)
  160.     {
  161.       pclient->print(sTable);
  162.     }
  163.     ulLength+=sTable.length();
  164.   }
  165.   else
  166.   {
  167.     unsigned long ulEnd;
  168.     if (ulMeasCount>ulNoMeasValues)
  169.     {
  170.       ulEnd=ulMeasCount-ulNoMeasValues;
  171.     }
  172.     else
  173.     {
  174.       ulEnd=0;
  175.     }
  176.    
  177.     String sTable;
  178.     sTable = "<table style=\"width:100%\"><tr><th>Zeit / UTC</th><th>T &deg;C</th><th>Hum &#037;</th></tr>";
  179.     sTable += "<style>table, th, td {border: 2px solid black; border-collapse: collapse;} th, td {padding: 5px;} th {text-align: left;}</style>";
  180.     for (unsigned long li=ulMeasCount;li>ulEnd;li--)
  181.     {
  182.       unsigned long ulIndex=(li-1)%ulNoMeasValues;
  183.       sTable += "<tr><td>";
  184.       sTable += epoch_to_string(pulTime[ulIndex]).c_str();
  185.       sTable += "</td><td>";
  186.       sTable += pfTemp[ulIndex];
  187.       sTable += "</td><td>";
  188.       sTable += pfHum[ulIndex];
  189.       sTable += "</td></tr>";
  190.  
  191.       // play out in chunks of 1k
  192.       if(sTable.length()>1024)
  193.       {
  194.         if(bStream)
  195.         {
  196.           pclient->print(sTable);
  197.           //pclient->write(sTable.c_str(),sTable.length());
  198.         }
  199.         ulLength+=sTable.length();
  200.         sTable="";
  201.       }
  202.     }
  203.    
  204.     // remaining chunk
  205.     sTable+="</table>";
  206.     ulLength+=sTable.length();
  207.     if(bStream)
  208.     {
  209.       pclient->print(sTable);
  210.       //pclient->write(sTable.c_str(),sTable.length());
  211.     }  
  212.   }
  213.  
  214.   return(ulLength);
  215. }
  216.  
  217.  
  218. ////////////////////////////////////////////////////
  219. // make google chart object table for measured data
  220. ////////////////////////////////////////////////////
  221. unsigned long MakeList (WiFiClient *pclient, bool bStream)
  222. {
  223.   unsigned long ulLength=0;
  224.  
  225.   // here we build a big list.
  226.   // we cannot store this in a string as this will blow the memory  
  227.   // thus we count first to get the number of bytes and later on
  228.   // we stream this out
  229.   if (ulMeasCount>0)
  230.   {
  231.     unsigned long ulBegin;
  232.     if (ulMeasCount>ulNoMeasValues)
  233.     {
  234.       ulBegin=ulMeasCount-ulNoMeasValues;
  235.     }
  236.     else
  237.     {
  238.       ulBegin=0;
  239.     }
  240.    
  241.     String sTable="";
  242.     for (unsigned long li=ulBegin;li<ulMeasCount;li++)
  243.     {
  244.       // result shall be ['18:24:08 - 21.5.2015',21.10,49.00],
  245.       unsigned long ulIndex=li%ulNoMeasValues;
  246.       sTable += "['";
  247.       sTable += epoch_to_string(pulTime[ulIndex]).c_str();
  248.       sTable += "',";
  249.       sTable += pfTemp[ulIndex];
  250.       sTable += ",";
  251.       sTable += pfHum[ulIndex];
  252.       sTable += "],\n";
  253.  
  254.       // play out in chunks of 1k
  255.       if(sTable.length()>1024)
  256.       {
  257.         if(bStream)
  258.         {
  259.           pclient->print(sTable);
  260.           //pclient->write(sTable.c_str(),sTable.length());
  261.         }
  262.         ulLength+=sTable.length();
  263.         sTable="";
  264.       }
  265.     }
  266.    
  267.     // remaining chunk
  268.     if(bStream)
  269.     {
  270.       pclient->print(sTable);
  271.       //pclient->write(sTable.c_str(),sTable.length());
  272.     }
  273.     ulLength+=sTable.length();  
  274.   }
  275.  
  276.   return(ulLength);
  277. }
  278.  
  279.  
  280. //////////////////////////
  281. // create HTTP 1.1 header
  282. //////////////////////////
  283. String MakeHTTPHeader(unsigned long ulLength)
  284. {
  285.   String sHeader;
  286.  
  287.   sHeader  = F("HTTP/1.1 200 OK\r\nContent-Length: ");
  288.   sHeader += ulLength;
  289.   sHeader += F("\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n");
  290.  
  291.   return(sHeader);
  292. }
  293.  
  294.  
  295. ////////////////////
  296. // make html footer
  297. ////////////////////
  298. String MakeHTTPFooter()
  299. {
  300.   String sResponse;
  301.  
  302.   sResponse  = F("<FONT SIZE=-2><BR>Aufrufz&auml;hler=");
  303.   sResponse += ulReqcount;
  304.   sResponse += F(" - Verbindungsz&auml;hler=");
  305.   sResponse += ulReconncount;
  306.   sResponse += F(" - Freies RAM=");
  307.   sResponse += (uint32_t)system_get_free_heap_size();
  308.   sResponse += F(" - Max. Datenpunkte=");
  309.   sResponse += ulNoMeasValues;
  310.   sResponse += F("<BR>Stefan Thesen 05/2015<BR></body></html>");
  311.  
  312.   return(sResponse);
  313. }
  314.  
  315.  
  316. /////////////
  317. // main look
  318. /////////////
  319. void loop()
  320. {
  321.   ///////////////////
  322.   // do data logging
  323.   ///////////////////
  324.   if (millis()>=ulNextMeas_ms)
  325.   {
  326.     ulNextMeas_ms = millis()+ulMeasDelta_ms;
  327.  
  328.     pfHum[ulMeasCount%ulNoMeasValues] = dht.readHumidity();
  329.     pfTemp[ulMeasCount%ulNoMeasValues] = dht.readTemperature();
  330.     pulTime[ulMeasCount%ulNoMeasValues] = millis()/1000+ulSecs2000_timer;
  331.    
  332.     Serial.print("Logging Temperature: ");
  333.     Serial.print(pfTemp[ulMeasCount%ulNoMeasValues]);
  334.     Serial.print(" deg Celsius - Humidity: ");
  335.     Serial.print(pfHum[ulMeasCount%ulNoMeasValues]);
  336.     Serial.print("% - Time: ");
  337.     Serial.println(pulTime[ulMeasCount%ulNoMeasValues]);
  338.    
  339.     ulMeasCount++;
  340.   }
  341.  
  342.   //////////////////////////////
  343.   // check if WLAN is connected
  344.   //////////////////////////////
  345.   if (WiFi.status() != WL_CONNECTED)
  346.   {
  347.     WiFiStart();
  348.   }
  349.  
  350.   ///////////////////////////////////
  351.   // Check if a client has connected
  352.   ///////////////////////////////////
  353.   WiFiClient client = server.available();
  354.   if (!client)
  355.   {
  356.     return;
  357.   }
  358.  
  359.   // Wait until the client sends some data
  360.   Serial.println("new client");
  361.   unsigned long ultimeout = millis()+250;
  362.   while(!client.available() && (millis()<ultimeout) )
  363.   {
  364.     delay(1);
  365.   }
  366.   if(millis()>ultimeout)
  367.   {
  368.     Serial.println("client connection time-out!");
  369.     return;
  370.   }
  371.  
  372.   /////////////////////////////////////
  373.   // Read the first line of the request
  374.   /////////////////////////////////////
  375.   String sRequest = client.readStringUntil('\r');
  376.   //Serial.println(sRequest);
  377.   client.flush();
  378.  
  379.   // stop client, if request is empty
  380.   if(sRequest=="")
  381.   {
  382.     Serial.println("empty request! - stopping client");
  383.     client.stop();
  384.     return;
  385.   }
  386.  
  387.   // get path; end of path is either space or ?
  388.   // Syntax is e.g. GET /?show=1234 HTTP/1.1
  389.   String sPath="",sParam="", sCmd="";
  390.   String sGetstart="GET ";
  391.   int iStart,iEndSpace,iEndQuest;
  392.   iStart = sRequest.indexOf(sGetstart);
  393.   if (iStart>=0)
  394.   {
  395.     iStart+=+sGetstart.length();
  396.     iEndSpace = sRequest.indexOf(" ",iStart);
  397.     iEndQuest = sRequest.indexOf("?",iStart);
  398.    
  399.     // are there parameters?
  400.     if(iEndSpace>0)
  401.     {
  402.       if(iEndQuest>0)
  403.       {
  404.         // there are parameters
  405.         sPath  = sRequest.substring(iStart,iEndQuest);
  406.         sParam = sRequest.substring(iEndQuest,iEndSpace);
  407.       }
  408.       else
  409.       {
  410.         // NO parameters
  411.         sPath  = sRequest.substring(iStart,iEndSpace);
  412.       }
  413.     }
  414.   }
  415.    
  416.  
  417.   ///////////////////////////
  418.   // format the html response
  419.   ///////////////////////////
  420.   String sResponse,sResponse2,sHeader;
  421.  
  422.   /////////////////////////////
  423.   // format the html page for /
  424.   /////////////////////////////
  425.   if(sPath=="/")
  426.   {
  427.     ulReqcount++;
  428.     int iIndex= (ulMeasCount-1)%ulNoMeasValues;
  429.     sResponse  = F("<html>\n<head>\n<title>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</title>\n<script type=\"text/javascript\" src=\"https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['gauge']}]}\"></script>\n<script type=\"text/javascript\">\nvar temp=");
  430.     sResponse += pfTemp[iIndex];
  431.     sResponse += F(",hum=");
  432.     sResponse += pfHum[iIndex];
  433.     sResponse += F(";\ngoogle.load('visualization', '1', {packages: ['gauge']});google.setOnLoadCallback(drawgaugetemp);google.setOnLoadCallback(drawgaugehum);\nvar gaugetempOptions = {min: -20, max: 50, yellowFrom: -20, yellowTo: 0,redFrom: 30, redTo: 50, minorTicks: 10, majorTicks: ['-20','-10','0','10','20','30','40','50']};\n");
  434.     sResponse += F("var gaugehumOptions = {min: 0, max: 100, yellowFrom: 0, yellowTo: 25, redFrom: 75, redTo: 100, minorTicks: 10, majorTicks: ['0','10','20','30','40','50','60','70','80','90','100']};\nvar gaugetemp,gaugehum;\n\nfunction drawgaugetemp() {\ngaugetempData = new google.visualization.DataTable();\n");
  435.     sResponse += F("gaugetempData.addColumn('number', '\260C');\ngaugetempData.addRows(1);\ngaugetempData.setCell(0, 0, temp);\ngaugetemp = new google.visualization.Gauge(document.getElementById('gaugetemp_div'));\ngaugetemp.draw(gaugetempData, gaugetempOptions);\n}\n\n");
  436.     sResponse += F("function drawgaugehum() {\ngaugehumData = new google.visualization.DataTable();\ngaugehumData.addColumn('number', '%');\ngaugehumData.addRows(1);\ngaugehumData.setCell(0, 0, hum);\ngaugehum = new google.visualization.Gauge(document.getElementById('gaugehum_div'));\ngaugehum.draw(gaugehumData, gaugehumOptions);\n}\n");
  437.     sResponse += F("</script>\n</head>\n<body>\n<font color=\"#000000\"><body bgcolor=\"#d0d0f0\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\"><h1>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</h1>AMS2301 / DHT21 an ESP8266 <BR><BR><FONT SIZE=+1>Letzte Messung um ");
  438.     sResponse += epoch_to_string(pulTime[iIndex]).c_str();
  439.     sResponse += F(" UTC<BR>\n<div id=\"gaugetemp_div\" style=\"float:left; width:160px; height: 160px;\"></div> \n<div id=\"gaugehum_div\" style=\"float:left; width:160px; height: 160px;\"></div>\n<div style=\"clear:both;\"></div>");
  440.    
  441.     sResponse2 = F("<p>Temperatur & Feuchtigkeitsverlauf - Seiten laden l&auml;nger:<BR><a href=\"/grafik\">Grafik</a>     <a href=\"/tabelle\">Tabelle</a></p>");
  442.     sResponse2 += MakeHTTPFooter().c_str();
  443.    
  444.     // Send the response to the client
  445.     client.print(MakeHTTPHeader(sResponse.length()+sResponse2.length()).c_str());
  446.     client.print(sResponse);
  447.     client.print(sResponse2);
  448.   }
  449.   else if(sPath=="/tabelle")
  450.   ////////////////////////////////////
  451.   // format the html page for /tabelle
  452.   ////////////////////////////////////
  453.   {
  454.     ulReqcount++;
  455.     unsigned long ulSizeList = MakeTable(&client,false); // get size of table first
  456.    
  457.     sResponse  = F("<html><head><title>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</title></head><body>");
  458.     sResponse += F("<font color=\"#000000\"><body bgcolor=\"#d0d0f0\">");
  459.     sResponse += F("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">");
  460.     sResponse += F("<h1>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</h1>");
  461.     sResponse += F("<FONT SIZE=+1>");
  462.     sResponse += F("<a href=\"/\">Startseite</a><BR><BR>Letzte Messungen im Abstand von ");
  463.     sResponse += ulMeasDelta_ms;
  464.     sResponse += F("ms<BR>");
  465.     // here the big table will follow later - but let us prepare the end first
  466.      
  467.     // part 2 of response - after the big table
  468.     sResponse2 = MakeHTTPFooter().c_str();
  469.    
  470.     // Send the response to the client - delete strings after use to keep mem low
  471.     client.print(MakeHTTPHeader(sResponse.length()+sResponse2.length()+ulSizeList).c_str());
  472.     client.print(sResponse); sResponse="";
  473.     MakeTable(&client,true);
  474.     client.print(sResponse2);
  475.   }
  476.   else if(sPath=="/grafik")
  477.   ///////////////////////////////////
  478.   // format the html page for /grafik
  479.   ///////////////////////////////////
  480.   {
  481.     ulReqcount++;
  482.     unsigned long ulSizeList = MakeList(&client,false); // get size of list first
  483.  
  484.     sResponse  = F("<html>\n<head>\n<title>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</title>\n<script type=\"text/javascript\" src=\"https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['corechart']}]}\"></script>\n");
  485.     sResponse += F("<script type=\"text/javascript\"> google.setOnLoadCallback(drawChart);\nfunction drawChart() {var data = google.visualization.arrayToDataTable([\n['Zeit / UTC', 'Temperatur', 'Feuchtigkeit'],\n");    
  486.     // here the big list will follow later - but let us prepare the end first
  487.      
  488.     // part 2 of response - after the big list
  489.     sResponse2  = F("]);\nvar options = {title: 'Verlauf',vAxes:{0:{viewWindowMode:'explicit',gridlines:{color:'black'},format:\"##.##\260C\"},1: {gridlines:{color:'transparent'},format:\"##,##%\"},},series:{0:{targetAxisIndex:0},1:{targetAxisIndex:1},},curveType:'none',legend:{ position: 'bottom'}};");
  490.     sResponse2 += F("var chart = new google.visualization.LineChart(document.getElementById('curve_chart'));chart.draw(data, options);}\n</script>\n</head>\n");
  491.     sResponse2 += F("<body>\n<font color=\"#000000\"><body bgcolor=\"#d0d0f0\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\"><h1>WLAN Logger f&uuml;r Lufttemperatur und Feuchtigkeit</h1><a href=\"/\">Startseite</a><BR>");
  492.     sResponse2 += F("<BR>\n<div id=\"curve_chart\" style=\"width: 600px; height: 400px\"></div>");
  493.     sResponse2 += MakeHTTPFooter().c_str();
  494.    
  495.     // Send the response to the client - delete strings after use to keep mem low
  496.     client.print(MakeHTTPHeader(sResponse.length()+sResponse2.length()+ulSizeList).c_str());
  497.     client.print(sResponse); sResponse="";
  498.     MakeList(&client,true);
  499.     client.print(sResponse2);
  500.   }
  501.   else
  502.   ////////////////////////////
  503.   // 404 for non-matching path
  504.   ////////////////////////////
  505.   {
  506.     sResponse="<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";
  507.    
  508.     sHeader  = F("HTTP/1.1 404 Not found\r\nContent-Length: ");
  509.     sHeader += sResponse.length();
  510.     sHeader += F("\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n");
  511.    
  512.     // Send the response to the client
  513.     client.print(sHeader);
  514.     client.print(sResponse);
  515.   }
  516.  
  517.   // and stop the client
  518.   client.stop();
  519.   Serial.println("Client disconnected");
  520. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement