diff --git a/ampel-firmware/web_server.cpp b/ampel-firmware/web_server.cpp index 3441b0b0c24402b2e4dfae973a6059850c364a36..0e9c1346de27d26d614f747d62e84cd6381a39da 100644 --- a/ampel-firmware/web_server.cpp +++ b/ampel-firmware/web_server.cpp @@ -48,49 +48,49 @@ namespace web_server { // "<meta http-equiv='refresh' content='%d'>" "</head>" "<body>" - "<div class='pure-g'><div class='pure-u-1'><div class='pure-menu'><p class='pure-menu-heading'>HfT-Stuttgart CO<sub>2</sub> Ampel</p></div></div>" "<div class='pure-u-1'><ul class='pure-menu pure-menu-horizontal pure-menu-list'>" "<li class='pure-menu-item'><a href='/config' class='pure-menu-link'>Config</a></li>" "<li class='pure-menu-item'><a href='#table' class='pure-menu-link'>Info</a></li>" - "<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>" - "<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>" - "<li class='pure-menu-item'><a href='%s' class='pure-menu-link'>Download CSV</a></li>" - "<li class='pure-menu-item' id='led'>⬤</li>"// LED - "</ul></div></div>" - "<script>" - // Show a colored dot on the webpage, with a similar color than on LED Ring. - "hue=(1-(Math.min(Math.max(parseInt(document.title),500),1600)-500)/1100)*120;" - "document.getElementById('led').style.color=['hsl(',hue,',100%%,50%%)'].join('');" - "</script>" - "<div class='pure-g'>" - "<div class='pure-u-1' id='graph'></div>"// Graph placeholder - "</div>" - "<div class='pure-g'>" - "<table id='table' class='pure-table-striped pure-u-1 pure-u-md-1-2'>"); + "<li class='pure-menu-item'><a href='#graph' class='pure-menu-link'>Graph</a></li>"); - body1_template = PSTR("<tr><th colspan='2'>%s</th></tr>" + body1_template = PSTR("<li class='pure-menu-item'><a href='#log' class='pure-menu-link'>Log</a></li>" + "<li class='pure-menu-item'><a href='%s' class='pure-menu-link'>Download CSV</a></li>" + "<li class='pure-menu-item' id='led'>⬤</li>" // LED + "</ul></div></div>" + "<script>" + // Show a colored dot on the webpage, with a similar color than on LED Ring. + "hue=(1-(Math.min(Math.max(parseInt(document.title),500),1600)-500)/1100)*120;" + "document.getElementById('led').style.color=['hsl(',hue,',100%%,50%%)'].join('');" + "</script>" + "<div class='pure-g'>" + "<div class='pure-u-1' id='graph'></div>"// Graph placeholder + "</div>" + "<div class='pure-g'>" + "<table id='table' class='pure-table-striped pure-u-1 pure-u-md-1-2'>" + "<tr><th colspan='2'>%s</th></tr>" "<tr><td>CO<sub>2</sub></td><td>%5d ppm</td></tr>" "<tr><td>Temperature</td><td>%.1f℃</td></tr>" "<tr><td>Humidity</td><td>%.1f%%</td></tr>" "<tr><td>Last measurement</td><td>%s</td></tr>" "<tr><td>Timestep</td><td>%5d s</td></tr>" - "<tbody>" - "<tr><th colspan='2'>CSV</th></tr>" //TODO: Gray out if !config::csv_active + "<tbody %s>" + "<tr><th colspan='2'>CSV</th></tr>"//TODO: Gray out if !config::csv_active "<tr><td>Last write</td><td>%s</td></tr>" "<tr><td>Interval</td><td>%5d s</td></tr>" "<tr><td>Available space</td><td>%d kB</td></tr>" "</tbody>" - "<tbody>" + "<tbody %s>" "<tr><th colspan='2'>MQTT</th></tr>" "<tr><td>Connected?</td><td>%s</td></tr>" "<tr><td>Last publish</td><td>%s</td></tr>" "<tr><td>Interval</td><td>%5d s</td></tr>" "</tbody>"); + body2_template = PSTR( #if defined(ESP32) - "<tbody>" + "<tbody %s>" "<tr><th colspan='2'>LoRaWAN</th></tr>" "<tr><td>Connected?</td><td>%s</td></tr>" "<tr><td>Frequency</td><td>%s MHz</td></tr>" @@ -118,56 +118,54 @@ namespace web_server { "<form action='/delete_csv' method='POST' onsubmit=\"return confirm('Are you really sure you want to delete all data?') && (document.body.style.cursor = 'wait');\">" "<input type='submit' value='Delete CSV'/>" "</form>" - "</div>"); + "</div>" + "<a href='https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-firmware' target='_blank'>Source code</a> " + "<a href='https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-documentation' target='_blank'>Documentation</a>"); - script_template = - PSTR( - "<a href='https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-firmware' target='_blank'>Source code</a>" - "<a href='https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-documentation' target='_blank'>Documentation</a>" - "<script>" - "document.body.style.cursor = 'default';" - "fetch('%s',{credentials:'include'})" - ".then(response=>response.text())" - ".then(csvText=>csvToTable(csvText))" - ".then(htmlTable=>addLogTableToPage(htmlTable))" - ".then(_=>Plotly.newPlot('graph',data,layout,{displaylogo:false}))" - ".catch(e=>console.error(e));" - "xs=[];" - "data=[{x:xs,y:[],type:'scatter',name:'CO<sub>2</sub>',line:{color:'#2ca02c'}}," - "{x:xs,y:[],type:'scatter',name:'Temperature',yaxis:'y2',line:{color:'#ff7f0e',dash:'dot'}}," - "{x:xs,y:[],type:'scatter',name:'Humidity',yaxis:'y3',line:{color:'#1f77b4',dash:'dot'}}];" - "layout={height:600,title:'%s',legend:{xanchor:'right',x:0.2,y:1.0}," - "xaxis:{domain:[0.0,0.85]},yaxis:{ticksuffix:'ppm',range:[0,2000],dtick:200}," - "yaxis2:{overlaying:'y',side:'right',ticksuffix:'°C',position:0.9,anchor:'free',range:[0,30],dtick:3}," - "yaxis3:{overlaying:'y',side:'right',ticksuffix:'%%',position:0.95,anchor:'free',range:[0,100],dtick:10}" - "};" - "function csvToTable(csvText){" - "csvText=csvText.trim();" - "lines=csvText.split('\\n');" - "table=document.createElement('table');" - "table.className='pure-table-striped';" - "n=lines.length;" - "lines.forEach((line,i)=>{" - "fields=line.split(';');" - //Don't display points without time - "if (!fields[0].includes('1970-')){" - "xs.push(fields[0]);" - "data[0]['y'].push(fields[1]);" - "data[1]['y'].push(fields[2]);" - "data[2]['y'].push(fields[3]);" - "};" - "if(i>4 && i<n-12){if(i==5){fields=['...','...','...','...']}else{return;}}" - "row=document.createElement('tr');" - "fields.forEach((field,index)=>{" - "cell=document.createElement(i<2?'th':'td');" - "cell.appendChild(document.createTextNode(field));" - "row.appendChild(cell);});" - "table.appendChild(row);});" - "return table;}" - "function addLogTableToPage(table){document.getElementById('log').appendChild(table);}" - "</script>" - "</body>" - "</html>"); + script_template = PSTR("<script>" + "document.body.style.cursor = 'default';" + "fetch('%s',{credentials:'include'})" + ".then(response=>response.text())" + ".then(csvText=>csvToTable(csvText))" + ".then(htmlTable=>addLogTableToPage(htmlTable))" + ".then(_=>Plotly.newPlot('graph',data,layout,{displaylogo:false}))" + ".catch(e=>console.error(e));" + "xs=[];" + "data=[{x:xs,y:[],type:'scatter',name:'CO<sub>2</sub>',line:{color:'#2ca02c'}}," + "{x:xs,y:[],type:'scatter',name:'Temperature',yaxis:'y2',line:{color:'#ff7f0e',dash:'dot'}}," + "{x:xs,y:[],type:'scatter',name:'Humidity',yaxis:'y3',line:{color:'#1f77b4',dash:'dot'}}];" + "layout={height:600,title:'%s',legend:{xanchor:'right',x:0.2,y:1.0}," + "xaxis:{domain:[0.0,0.85]},yaxis:{ticksuffix:'ppm',range:[0,2000],dtick:200}," + "yaxis2:{overlaying:'y',side:'right',ticksuffix:'°C',position:0.9,anchor:'free',range:[0,30],dtick:3}," + "yaxis3:{overlaying:'y',side:'right',ticksuffix:'%%',position:0.95,anchor:'free',range:[0,100],dtick:10}" + "};" + "function csvToTable(csvText){" + "csvText=csvText.trim();" + "lines=csvText.split('\\n');" + "table=document.createElement('table');" + "table.className='pure-table-striped';" + "n=lines.length;" + "lines.forEach((line,i)=>{" + "fields=line.split(';');" + //Don't display points without time + "if (!fields[0].includes('1970-')){" + "xs.push(fields[0]);" + "data[0]['y'].push(fields[1]);" + "data[1]['y'].push(fields[2]);" + "data[2]['y'].push(fields[3]);" + "};" + "if(i>4 && i<n-12){if(i==5){fields=['...','...','...','...']}else{return;}}" + "row=document.createElement('tr');" + "fields.forEach((field,index)=>{" + "cell=document.createElement(i<2?'th':'td');" + "cell.appendChild(document.createTextNode(field));" + "row.appendChild(cell);});" + "table.appendChild(row);});" + "return table;}" + "function addLogTableToPage(table){document.getElementById('log').appendChild(table);}" + "</script>" + "</body>" + "</html>"); // Web-server web_config::http.on("/", handleWebServerRoot); @@ -202,10 +200,9 @@ namespace web_server { //NOTE: Splitting in multiple parts in order to use less RAM. Higher than 2000 apparently crashes the ESP8266 char content[2000]; // Current size (with Lorawan): - // INFO - Header size : 1826 - Body size : 2005 - Script size : 1904 + // INFO - Header size : 1685 - Body1 size : 843 - Body2 size : 1395 - Script size : 1918 - snprintf_P(content, sizeof(content), header_template, sensor::co2, config::ampel_name(), wifi::local_ip, - csv_writer::filename); + snprintf_P(content, sizeof(content), header_template, sensor::co2, config::ampel_name(), wifi::local_ip); Serial.print(F("INFO - Header size : ")); Serial.print(strlen(content)); @@ -213,10 +210,11 @@ namespace web_server { web_config::http.send_P(200, PSTR("text/html"), content); // Body - snprintf_P(content, sizeof(content), body1_template, config::ampel_name(), sensor::co2, sensor::temperature, - sensor::humidity, sensor::timestamp, config::measurement_timestep, csv_writer::last_successful_write, - config::csv_interval, csv_writer::getAvailableSpace() / 1024, mqtt::connected ? "Yes" : "No", - mqtt::last_successful_publish, config::mqtt_sending_interval); + snprintf_P(content, sizeof(content), body1_template, csv_writer::filename, config::ampel_name(), sensor::co2, + sensor::temperature, sensor::humidity, sensor::timestamp, config::measurement_timestep, + config::is_csv_active() ? "" : "hidden", csv_writer::last_successful_write, config::csv_interval, + csv_writer::getAvailableSpace() / 1024, config::is_mqtt_active() ? "" : "hidden", + mqtt::connected ? "Yes" : "No", mqtt::last_successful_publish, config::mqtt_sending_interval); Serial.print(F(" - Body1 size : ")); Serial.print(strlen(content)); @@ -224,8 +222,8 @@ namespace web_server { snprintf_P(content, sizeof(content), body2_template, #if defined(ESP32) - lorawan::connected ? "Yes" : "No", config::lorawan_frequency_plan, lorawan::last_transmission, - config::lorawan_sending_interval, + config::is_lorawan_active() ? "" : "hidden", lorawan::connected ? "Yes" : "No", config::lorawan_frequency_plan, + lorawan::last_transmission, config::lorawan_sending_interval, #endif config::temperature_offset, config::auto_calibrate_sensor ? "Yes" : "No", config::ampel_name(), config::ampel_name(), wifi::local_ip, wifi::local_ip, ampel.macAddress, ESP.getFreeHeap(),