_wwwServer.ino 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729
  1. // 1-channel LoRa Gateway for ESP8266
  2. // Copyright (c) 2016, 2017, 2018, 2019 Maarten Westenberg version for ESP8266
  3. //
  4. // based on work done by many people and making use of several libraries.
  5. //
  6. // All rights reserved. This program and the accompanying materials
  7. // are made available under the terms of the MIT License
  8. // which accompanies this distribution, and is available at
  9. // https://opensource.org/licenses/mit-license.php
  10. //
  11. // NO WARRANTY OF ANY KIND IS PROVIDED
  12. //
  13. // Author: Maarten Westenberg (mw12554@hotmail.com)
  14. //
  15. // This file contains the webserver code for the ESP Single Channel Gateway.
  16. // Note:
  17. // The ESP Webserver works with Strings to display HTML content.
  18. // Care must be taken that not all data is output to the webserver in one string
  19. // as this will use a LOT of memory and possibly kill the heap (cause system
  20. // crash or other unreliable behaviour.
  21. // Instead, output of the various tables on the webpage should be displayed in
  22. // chunks so that strings are limited in size.
  23. // Be aware that using no strings but only sendContent() calls has its own
  24. // disadvantage that these calls take a lot of time and cause the page to be
  25. // displayed like an old typewriter.
  26. // So, the trick is to make chucks that are sent to the website by using
  27. // a response String but not make those Strings too big.
  28. //
  29. // Also, selecting too many options for Statistics, display, Hopping channels
  30. // etc makes the gateway more sluggish and may impact the available memory and
  31. // thus its performance and reliability. It's up to the user to select wisely!
  32. //
  33. // --------------------------------------------------------------------------------
  34. // PRINT IP
  35. // Output the 4-byte IP address for easy printing.
  36. // As this function is also used by _otaServer.ino do not put in #define
  37. // --------------------------------------------------------------------------------
  38. static void printIP(IPAddress ipa, const char sep, String& response)
  39. {
  40. response+=(String)ipa[0]; response+=sep;
  41. response+=(String)ipa[1]; response+=sep;
  42. response+=(String)ipa[2]; response+=sep;
  43. response+=(String)ipa[3];
  44. }
  45. //
  46. // The remainder of the file ONLY works is A_SERVER=1 is set.
  47. //
  48. #if A_SERVER==1
  49. // ================================================================================
  50. // WEBSERVER DECLARATIONS
  51. // ================================================================================
  52. // None at the moment
  53. // ================================================================================
  54. // WEBSERVER FUNCTIONS
  55. // ================================================================================
  56. // --------------------------------------------------------------------------------
  57. // Used by all functions requiring user confirmation
  58. // Displays a menu by user and two buttons "OK" and "CANCEL"
  59. // The function returns true for OK and false for CANCEL
  60. // Usage: Call this function ONCE during startup to declare and init
  61. // the ynDialog JavaScript function, and call the function
  62. // from the program when needed.
  63. // Paramters of the JavaScript function:
  64. // s: Th strig contining the question to be answered
  65. // o: The OK tab for the webpage where to go to
  66. // c: The Cancel string (optional)
  67. // --------------------------------------------------------------------------------
  68. boolean YesNo()
  69. {
  70. boolean ret = false;
  71. String response = "";
  72. response += "<script>";
  73. response += "var ch = \"\"; "; // Init choice
  74. response += "function ynDialog(s,y) {";
  75. response += " try { adddlert(s); }";
  76. response += " catch(err) {";
  77. response += " ch = \" \" + s + \".\\n\\n\"; ";
  78. response += " ch += \"Click OK to continue,\\n\"; ";
  79. response += " ch += \"or Cancel\\n\\n\"; ";
  80. response += " if(!confirm(ch)) { ";
  81. response += " javascript:window.location.reload(true);";
  82. response += " } ";
  83. response += " else { ";
  84. response += " document.location.href = '/'+y; ";
  85. response += " } ";
  86. response += " }";
  87. response += "}";
  88. response += "</script>";
  89. server.sendContent(response);
  90. // Put something like this in the ESP program
  91. // response += "<input type=\"button\" value=\"YesNo\" onclick=\"ynDialog()\" />";
  92. return(ret);
  93. }
  94. // --------------------------------------------------------------------------------
  95. // WWWFILE
  96. // This function will open a pop-up in the browser and then
  97. // display the contents of a file in that window
  98. // Output is sent to server.sendContent()
  99. // Note: The output is not in a variable, its size would be too large
  100. // Parameters:
  101. // fn; String with filename
  102. // Returns:
  103. // <none>
  104. // --------------------------------------------------------------------------------
  105. void wwwFile(String fn) {
  106. if (!SPIFFS.exists(fn)) {
  107. # if _MONITOR>=1
  108. mPrint("wwwFile:: ERROR: SPIFFS file not found=");
  109. # endif
  110. return;
  111. } // _MONITOR
  112. # if _MONITOR>=1
  113. else if (debug>=2) {
  114. mPrint("wwwFile:: SPIFFS Filesystem existist= " + String(fn));
  115. }
  116. # endif //_MONITOR
  117. # if _MONITOR>=1
  118. File f = SPIFFS.open(fn, "r"); // Open the file for reading
  119. int j;
  120. for (j=0; j<LOGFILEREC; j++) {
  121. String s=f.readStringUntil('\n');
  122. if (s.length() == 0) {
  123. Serial.print(F("wwwFile:: String length 0"));
  124. break;
  125. }
  126. server.sendContent(s.substring(12)); // Skip the first 12 Gateway specific binary characters
  127. server.sendContent("\n");
  128. yield();
  129. }
  130. f.close();
  131. # endif //_MONITOR
  132. }
  133. // --------------------------------------------------------------------------------
  134. // Button function Docu, display the documentation pages.
  135. // This is a button on the top of the GUI screen.
  136. // --------------------------------------------------------------------------------
  137. void buttonDocu()
  138. {
  139. String response = "";
  140. response += "<script>";
  141. response += "var txt = \"\";";
  142. response += "function showDocu() {";
  143. response += " try { adddlert(\"Welcome,\"); }";
  144. response += " catch(err) {";
  145. response += " txt = \"Do you want the documentation page.\\n\\n\"; ";
  146. response += " txt += \"Click OK to continue viewing documentation,\\n\"; ";
  147. response += " txt += \"or Cancel to return to the home page.\\n\\n\"; ";
  148. response += " if(confirm(txt)) { ";
  149. response += " document.location.href = \"https://things4u.github.io/Projects/SingleChannelGateway/UserGuide/Introduction%206.html\"; ";
  150. response += " }";
  151. response += " }";
  152. response += "}";
  153. response += "</script>";
  154. server.sendContent(response);
  155. }
  156. // --------------------------------------------------------------------------------
  157. // Button function Log displays logfiles.
  158. // This is a button on the top of the GUI screen
  159. // --------------------------------------------------------------------------------
  160. void buttonLog()
  161. {
  162. // String response = "";
  163. String fn = "";
  164. int i = 0;
  165. while (i< LOGFILEMAX ) {
  166. fn = "/log-" + String(gwayConfig.logFileNo - i);
  167. wwwFile(fn); // Display the file contents in the browser
  168. i++;
  169. }
  170. // server.sendContent(response);
  171. }
  172. // --------------------------------------------------------------------------------
  173. // Navigate webpage by buttons. This method has some advantages:
  174. // - Less time/cpu usage
  175. // - Less memory usage <a href=\"SPEED=160\">
  176. // --------------------------------------------------------------------------------
  177. static void wwwButtons()
  178. {
  179. String response = "";
  180. String mode = (gwayConfig.expert ? "Basic Mode" : "Expert Mode");
  181. String moni = (gwayConfig.monitor ? "Hide Monitor" : "Monitor ON");
  182. String seen = (gwayConfig.seen ? "Seen OFF" : "Node last seen");
  183. YesNo(); // Init the Yes/No function
  184. buttonDocu();
  185. response += "<input type=\"button\" value=\"Documentation\" onclick=\"showDocu()\" >";
  186. response += "<a href=\"LOG\" download><button type=\"button\">Log Files</button></a>";
  187. response += "<a href=\"EXPERT\" download><button type=\"button\">" + mode + "</button></a>";
  188. # if _MONITOR>=1
  189. response += "<a href=\"MONITOR\" download><button type=\"button\">" +moni+ "</button></a>";
  190. # endif
  191. # if _SEENMAX>=1
  192. response += "<a href=\"SEEN\" download><button type=\"button\">" +seen+ "</button></a>";
  193. # endif
  194. server.sendContent(response); // Send to the screen
  195. }
  196. // --------------------------------------------------------------------------------
  197. // SET ESP8266/ESP32 WEB SERVER VARIABLES
  198. //
  199. // This funtion implements the WiFi Webserver (very simple one). The purpose
  200. // of this server is to receive simple admin commands, and execute these
  201. // results which are sent back to the web client.
  202. // Commands: DEBUG, ADDRESS, IP, CONFIG, GETTIME, SETTIME
  203. // The webpage is completely built response and then printed on screen.
  204. //
  205. // Parameters:
  206. // cmd: Contains a character array with the command to execute
  207. // arg: Contains the parameter value of that command
  208. // Returns:
  209. // <none>
  210. // --------------------------------------------------------------------------------
  211. static void setVariables(const char *cmd, const char *arg) {
  212. // DEBUG settings; These can be used as a single argument
  213. if (strcmp(cmd, "DEBUG")==0) { // Set debug level 0-2
  214. if (atoi(arg) == 1) {
  215. debug = (debug+1)%4;
  216. }
  217. else if (atoi(arg) == -1) {
  218. debug = (debug+3)%4;
  219. }
  220. writeGwayCfg(CONFIGFILE); // Save configuration to file
  221. }
  222. if (strcmp(cmd, "CAD")==0) { // Set -cad on=1 or off=0
  223. _cad=(bool)atoi(arg);
  224. writeGwayCfg(CONFIGFILE); // Save configuration to file
  225. }
  226. if (strcmp(cmd, "HOP")==0) { // Set -hop on=1 or off=0
  227. _hop=(bool)atoi(arg);
  228. if (! _hop) {
  229. ifreq=0;
  230. setFreq(freqs[ifreq].upFreq);
  231. rxLoraModem();
  232. sf = SF7;
  233. cadScanner();
  234. }
  235. writeGwayCfg(CONFIGFILE); // Save configuration to file
  236. }
  237. // DELAY, write txDelay for transmissions
  238. //
  239. if (strcmp(cmd, "DELAY")==0) { // Set delay usecs
  240. gwayConfig.txDelay+=atoi(arg)*1000;
  241. writeGwayCfg(CONFIGFILE); // Save configuration to file
  242. }
  243. // TRUSTED, write node trusted value
  244. //
  245. if (strcmp(cmd, "TRUSTED")==0) { // Set delay usecs
  246. gwayConfig.trusted=atoi(arg);
  247. if (atoi(arg) == 1) {
  248. gwayConfig.trusted = (gwayConfig.trusted +1)%4;
  249. }
  250. else if (atoi(arg) == -1) {
  251. gwayConfig.trusted = (gwayConfig.trusted -1)%4;
  252. }
  253. writeGwayCfg(CONFIGFILE); // Save configuration to file
  254. }
  255. // SF; Handle Spreading Factor Settings
  256. //
  257. if (strcmp(cmd, "SF")==0) {
  258. uint8_t sfi = sf;
  259. if (atoi(arg) == 1) {
  260. if (sf>=SF12) sf=SF7; else sf= (sf_t)((int)sf+1);
  261. }
  262. else if (atoi(arg) == -1) {
  263. if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
  264. }
  265. rxLoraModem(); // Reset the radio with the new spreading factor
  266. writeGwayCfg(CONFIGFILE); // Save configuration to file
  267. }
  268. // FREQ; Handle Frequency Settings
  269. //
  270. if (strcmp(cmd, "FREQ")==0) {
  271. uint8_t nf = sizeof(freqs)/ sizeof(freqs[0]); // Number of frequency elements in array
  272. // Compute frequency index
  273. if (atoi(arg) == 1) {
  274. if (ifreq==(nf-1)) ifreq=0; else ifreq++;
  275. }
  276. else if (atoi(arg) == -1) {
  277. Serial.println("down");
  278. if (ifreq==0) ifreq=(nf-1); else ifreq--;
  279. }
  280. setFreq(freqs[ifreq].upFreq);
  281. rxLoraModem(); // Reset the radio with the new frequency
  282. writeGwayCfg(CONFIGFILE); // Save configuration to file
  283. }
  284. //if (strcmp(cmd, "GETTIME")==0) { Serial.println(F("gettime tbd")); } // Get the local time
  285. //
  286. //if (strcmp(cmd, "SETTIME")==0) { Serial.println(F("settime tbd")); } // Set the local time
  287. //
  288. // Help
  289. //
  290. if (strcmp(cmd, "HELP")==0) { Serial.println(F("Display Help Topics")); }
  291. // Node
  292. //
  293. #if GATEWAYNODE==1
  294. if (strcmp(cmd, "NODE")==0) { // Set node on=1 or off=0
  295. gwayConfig.isNode =(bool)atoi(arg);
  296. writeGwayCfg(CONFIGFILE); // Save configuration to file
  297. }
  298. // File Counter//
  299. if (strcmp(cmd, "FCNT")==0) {
  300. frameCount=0;
  301. rxLoraModem(); // Reset the radio with the new frequency
  302. writeGwayCfg(CONFIGFILE);
  303. }
  304. #endif
  305. // WiFi Manager
  306. //
  307. #if _WIFIMANAGER==1
  308. if (strcmp(cmd, "NEWSSID")==0) {
  309. WiFiManager wifiManager;
  310. strcpy(wpa[0].login,"");
  311. strcpy(wpa[0].passw,"");
  312. WiFi.disconnect();
  313. wifiManager.autoConnect(AP_NAME, AP_PASSWD );
  314. }
  315. #endif
  316. // Update the software (from User Interface)
  317. #if A_OTA==1
  318. if (strcmp(cmd, "UPDATE")==0) {
  319. if (atoi(arg) == 1) {
  320. updateOtaa();
  321. writeGwayCfg(CONFIGFILE);
  322. }
  323. }
  324. #endif
  325. #if A_REFRESH==1
  326. if (strcmp(cmd, "REFR")==0) { // Set refresh on=1 or off=0
  327. gwayConfig.refresh =(bool)atoi(arg);
  328. writeGwayCfg(CONFIGFILE); // Save configuration to file
  329. }
  330. #endif
  331. }
  332. // --------------------------------------------------------------------------------
  333. // OPEN WEB PAGE
  334. // This is the init function for opening the webpage
  335. //
  336. // --------------------------------------------------------------------------------
  337. static void openWebPage()
  338. {
  339. ++gwayConfig.views; // increment number of views
  340. #if A_REFRESH==1
  341. //server.client().stop(); // Experimental, stop webserver in case something is still running!
  342. #endif
  343. String response="";
  344. server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
  345. server.sendHeader("Pragma", "no-cache");
  346. server.sendHeader("Expires", "-1");
  347. // init webserver, fill the webpage
  348. // NOTE: The page is renewed every _WWW_INTERVAL seconds, please adjust in configGway.h
  349. //
  350. server.setContentLength(CONTENT_LENGTH_UNKNOWN);
  351. server.send(200, "text/html", "");
  352. String tt=""; printIP((IPAddress)WiFi.localIP(),'.',tt); // Time with separator
  353. #if A_REFRESH==1
  354. if (gwayConfig.refresh) {
  355. response += String() + "<!DOCTYPE HTML><HTML><HEAD><meta http-equiv='refresh' content='"+_WWW_INTERVAL+";http://";
  356. response += tt;
  357. response += "'><TITLE>1ch Gateway " + String(tt) + "</TITLE>";
  358. }
  359. else {
  360. response += String("<!DOCTYPE HTML><HTML><HEAD><TITLE>1ch Gateway " + String(tt) + "</TITLE>");
  361. }
  362. #else
  363. response += String("<!DOCTYPE HTML><HTML><HEAD><TITLE>1ch Gateway " + String(tt) + "</TITLE>");
  364. #endif
  365. response += "<META HTTP-EQUIV='CONTENT-TYPE' CONTENT='text/html; charset=UTF-8'>";
  366. response += "<META NAME='AUTHOR' CONTENT='M. Westenberg (mw1554@hotmail.com)'>";
  367. response += "<style>.thead {background-color:green; color:white;} ";
  368. response += ".cell {border: 1px solid black;}";
  369. response += ".config_table {max_width:100%; min-width:400px; width:98%; border:1px solid black; border-collapse:collapse;}";
  370. response += "</style></HEAD><BODY>";
  371. response +="<h1>ESP Gateway Config</h1>";
  372. response +="<p style='font-size:10px;'>";
  373. response +="Version: "; response+=VERSION;
  374. response +="<br>ESP alive since "; // STARTED ON
  375. stringTime(startTime, response);
  376. response +=", Uptime: "; // UPTIME
  377. uint32_t secs = millis()/1000;
  378. uint16_t days = secs / 86400; // Determine number of days
  379. uint8_t _hour = hour(secs);
  380. uint8_t _minute = minute(secs);
  381. uint8_t _second = second(secs);
  382. response += String(days) + "-";
  383. if (_hour < 10) response += "0"; response += String(_hour) + ":";
  384. if (_minute < 10) response += "0"; response += String(_minute) + ":";
  385. if (_second < 10) response += "0"; response += String(_second);
  386. response +="<br>Current time "; // CURRENT TIME
  387. stringTime(now(), response);
  388. response +="<br>";
  389. response +="</p>";
  390. server.sendContent(response);
  391. }
  392. // --------------------------------------------------------------------------------
  393. // H2 Gateway Settings
  394. //
  395. // Display the configuration and settings data. This is an interactive setting
  396. // allowing the user to set CAD, HOP, Debug and several other operating parameters
  397. //
  398. // --------------------------------------------------------------------------------
  399. static void gatewaySettings()
  400. {
  401. String response="";
  402. String bg="";
  403. response +="<h2>Gateway Settings</h2>";
  404. response +="<table class=\"config_table\">";
  405. response +="<tr>";
  406. response +="<th class=\"thead\">Setting</th>";
  407. response +="<th colspan=\"2\" style=\"background-color: green; color: white; width:120px;\">Value</th>";
  408. response +="<th colspan=\"4\" style=\"background-color: green; color: white; width:100px;\">Set</th>";
  409. response +="</tr>";
  410. bg = " background-color: ";
  411. bg += ( _cad ? "LightGreen" : "orange" );
  412. response +="<tr><td class=\"cell\">CAD</td>";
  413. response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
  414. response += ( _cad ? "ON" : "OFF" );
  415. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=1\"><button>ON</button></a></td>";
  416. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"CAD=0\"><button>OFF</button></a></td>";
  417. response +="</tr>";
  418. bg = " background-color: ";
  419. bg += ( _hop ? "LightGreen" : "orange" );
  420. response +="<tr><td class=\"cell\">HOP</td>";
  421. response +="<td colspan=\"2\" style=\"border: 1px solid black;"; response += bg; response += "\">";
  422. response += ( _hop ? "ON" : "OFF" );
  423. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=1\"><button>ON</button></a></td>";
  424. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"HOP=0\"><button>OFF</button></a></td>";
  425. response +="</tr>";
  426. response +="<tr><td class=\"cell\">SF Setting</td><td class=\"cell\" colspan=\"2\">";
  427. if (_cad) {
  428. response += "AUTO</td>";
  429. }
  430. else {
  431. response += sf;
  432. response +="<td class=\"cell\"><a href=\"SF=-1\"><button>-</button></a></td>";
  433. response +="<td class=\"cell\"><a href=\"SF=1\"><button>+</button></a></td>";
  434. }
  435. response +="</tr>";
  436. // Channel
  437. response +="<tr><td class=\"cell\">Channel</td>";
  438. response +="<td class=\"cell\" colspan=\"2\">";
  439. if (_hop) {
  440. response += "AUTO</td>";
  441. }
  442. else {
  443. response += String(ifreq);
  444. response +="</td>";
  445. response +="<td class=\"cell\"><a href=\"FREQ=-1\"><button>-</button></a></td>";
  446. response +="<td class=\"cell\"><a href=\"FREQ=1\"><button>+</button></a></td>";
  447. }
  448. response +="</tr>";
  449. // Trusted options, when TRUSTED_NODE is set
  450. #ifdef _TRUSTED_NODES
  451. response +="<tr><td class=\"cell\">Trusted Nodes</td><td class=\"cell\" colspan=\"2\">";
  452. response +=gwayConfig.trusted;
  453. response +="</td>";
  454. response +="<td class=\"cell\"><a href=\"TRUSTED=-1\"><button>-</button></a></td>";
  455. response +="<td class=\"cell\"><a href=\"TRUSTED=1\"><button>+</button></a></td>";
  456. response +="</tr>";
  457. #endif
  458. // Debugging options, only when _DUSB of _MONITOR is set, otherwise no
  459. // serial or minotoring activity
  460. #if _DUSB>=1 || _MONITOR>=1
  461. response +="<tr><td class=\"cell\">Debug Level</td><td class=\"cell\" colspan=\"2\">";
  462. response +=debug;
  463. response +="</td>";
  464. response +="<td class=\"cell\"><a href=\"DEBUG=-1\"><button>-</button></a></td>";
  465. response +="<td class=\"cell\"><a href=\"DEBUG=1\"><button>+</button></a></td>";
  466. response +="</tr>";
  467. // Debug Pattern
  468. response +="<tr><td class=\"cell\">Debug pattern</td>";
  469. bg = ( (pdebug & P_SCAN) ? "LightGreen" : "orange" );
  470. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  471. response += bg; response += "\">";
  472. response +="<a href=\"PDEBUG=SCAN\">";
  473. response +="<button>SCN</button></a></td>";
  474. bg = ( (pdebug & P_CAD) ? "LightGreen" : "orange" );
  475. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  476. response += bg; response += "\">";
  477. response +="<a href=\"PDEBUG=CAD\">";
  478. response +="<button>CAD</button></a></td>";
  479. bg = ( (pdebug & P_RX) ? "LightGreen" : "orange" );
  480. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  481. response += bg; response += "\">";
  482. response +="<a href=\"PDEBUG=RX\">";
  483. response +="<button>RX</button></a></td>";
  484. bg = ( (pdebug & P_TX) ? "LightGreen" : "orange" );
  485. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  486. response += bg; response += "\">";
  487. response +="<a href=\"PDEBUG=TX\">";
  488. response +="<button>TX</button></a></td>";
  489. response += "</tr>";
  490. // Use a second Line
  491. response +="<tr><td class=\"cell\"></td>";
  492. bg = ( (pdebug & P_PRE) ? "LightGreen" : "orange" );
  493. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  494. response += bg; response += "\">";
  495. response +="<a href=\"PDEBUG=PRE\">";
  496. response +="<button>PRE</button></a></td>";
  497. bg = ( (pdebug & P_MAIN) ? "LightGreen" : "orange" );
  498. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  499. response += bg; response += "\">";
  500. response +="<a href=\"PDEBUG=MAIN\">";
  501. response +="<button>MAI</button></a></td>";
  502. bg = ( (pdebug & P_GUI) ? "LightGreen" : "orange" );
  503. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  504. response += bg; response += "\">";
  505. response +="<a href=\"PDEBUG=GUI\">";
  506. response +="<button>GUI</button></a></td>";
  507. bg = ( (pdebug & P_RADIO) ? "LightGreen" : "orange" );
  508. response +="<td class=\"cell\" style=\"border: 1px solid black; width:20px; background-color: ";
  509. response += bg; response += "\">";
  510. response +="<a href=\"PDEBUG=RADIO\">";
  511. response +="<button>RDIO</button></a></td>";
  512. response +="</tr>";
  513. #endif
  514. // USB Debug, Serial Debugging
  515. response +="<tr><td class=\"cell\">Usb Debug</td><td class=\"cell\" colspan=\"2\">";
  516. response += _DUSB;
  517. response +="</td>";
  518. //response +="<td class=\"cell\"> </td>";
  519. //response +="<td class=\"cell\"> </td>";
  520. response +="</tr>";
  521. #if GATEWAYNODE==1
  522. response +="<tr><td class=\"cell\">Framecounter Internal Sensor</td>";
  523. response +="<td class=\"cell\" colspan=\"2\">";
  524. response +=frameCount;
  525. response +="</td><td colspan=\"2\" style=\"border: 1px solid black;\">";
  526. response +="<button><a href=\"/FCNT\">RESET</a></button></td>";
  527. response +="</tr>";
  528. bg = " background-color: ";
  529. bg += ( (gwayConfig.isNode == 1) ? "LightGreen" : "orange" );
  530. response +="<tr><td class=\"cell\">Gateway Node</td>";
  531. response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black;" + bg + "\">";
  532. response += ( (gwayConfig.isNode == true) ? "ON" : "OFF" );
  533. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"NODE=1\"><button>ON</button></a></td>";
  534. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"NODE=0\"><button>OFF</button></a></td>";
  535. response +="</tr>";
  536. #endif
  537. /// WWW Refresh
  538. #if A_REFRESH==1
  539. bg = " background-color: ";
  540. bg += ( (gwayConfig.refresh == 1) ? "LightGreen" : "orange" );
  541. response +="<tr><td class=\"cell\">WWW Refresh</td>";
  542. response +="<td class=\"cell\" colspan=\"2\" style=\"border: 1px solid black; " + bg + "\">";
  543. response += ( (gwayConfig.refresh == 1) ? "ON" : "OFF" );
  544. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=1\"><button>ON</button></a></td>";
  545. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"REFR=0\"><button>OFF</button></a></td>";
  546. response +="</tr>";
  547. #endif
  548. // Time Correction DELAY
  549. if (gwayConfig.expert) {
  550. response +="<tr><td class=\"cell\">Time Correction (uSec)</td><td class=\"cell\" colspan=\"2\">";
  551. response += gwayConfig.txDelay;
  552. response +="</td>";
  553. response +="<td class=\"cell\"><a href=\"DELAY=-1\"><button>-</button></a></td>";
  554. response +="<td class=\"cell\"><a href=\"DELAY=1\"><button>+</button></a></td>";
  555. response +="</tr>";
  556. }
  557. // Reset Accesspoint
  558. #if _WIFIMANAGER==1
  559. response +="<tr><td><tr><td>";
  560. response +="Click <a href=\"/NEWSSID\">here</a> to reset accesspoint<br>";
  561. response +="</td><td></td></tr>";
  562. #endif
  563. // Update Firmware all statistics
  564. response +="<tr><td class=\"cell\">Update Firmware</td><td colspan=\"2\"></td>";
  565. response +="<td class=\"cell\" colspan=\"2\" class=\"cell\"><a href=\"/UPDATE=1\"><button>UPDATE</button></a></td></tr>";
  566. // Format the Filesystem
  567. response +="<tr><td class=\"cell\">Format SPIFFS</td>";
  568. response +=String() + "<td class=\"cell\" colspan=\"2\" >"+""+"</td>";
  569. response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"FORMAT\" onclick=\"ynDialog(\'Do you really want to format?\',\'FORMAT\')\" /></td></tr>";
  570. // Reset all statistics
  571. #if _STATISTICS >= 1
  572. response +="<tr><td class=\"cell\">Statistics</td>";
  573. response +=String() + "<td class=\"cell\" colspan=\"2\" >"+statc.resets+"</td>";
  574. response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"RESET\" onclick=\"ynDialog(\'Do you really want to reset statistics?\',\'RESET\')\" /></td></tr>";
  575. // Reset
  576. response +="<tr><td class=\"cell\">Boots and Resets</td>";
  577. response +=String() + "<td class=\"cell\" colspan=\"2\" >"+gwayConfig.boots+"</td>";
  578. response +="<td colspan=\"2\" class=\"cell\"><input type=\"button\" value=\"RESET\" onclick=\"ynDialog(\'Do you want to reset boots?\',\'BOOT\')\" /></td></tr>";
  579. #endif
  580. response +="</table>";
  581. server.sendContent(response);
  582. }
  583. // --------------------------------------------------------------------------------
  584. // H2 Package Statistics
  585. //
  586. // This section display a matrix on the screen where everay channel and spreading
  587. // factor is displayed.
  588. // --------------------------------------------------------------------------------
  589. static void statisticsData()
  590. {
  591. String response="";
  592. // Header
  593. response +="<h2>Package Statistics</h2>";
  594. response +="<table class=\"config_table\">";
  595. response +="<tr><th class=\"thead\">Counter</th>";
  596. # if _STATISTICS == 3
  597. response +="<th class=\"thead\">C 0</th>";
  598. response +="<th class=\"thead\">C 1</th>";
  599. response +="<th class=\"thead\">C 2</th>";
  600. # endif //_STATISTICS==3
  601. response +="<th class=\"thead\">Pkgs</th>";
  602. response +="<th class=\"thead\">Pkgs/hr</th>";
  603. response +="</tr>";
  604. //
  605. // Table rows
  606. //
  607. response +="<tr><td class=\"cell\">Packages Downlink</td>";
  608. # if _STATISTICS == 3
  609. response +="<td class=\"cell\">" + String(statc.msg_down_0) + "</td>";
  610. response +="<td class=\"cell\">" + String(statc.msg_down_1) + "</td>";
  611. response +="<td class=\"cell\">" + String(statc.msg_down_2) + "</td>";
  612. # endif
  613. response += "<td class=\"cell\">" + String(statc.msg_down) + "</td>";
  614. response +="<td class=\"cell\"></td></tr>";
  615. response +="<tr><td class=\"cell\">Packages Uplink Total</td>";
  616. # if _STATISTICS == 3
  617. response +="<td class=\"cell\">" + String(statc.msg_ttl_0) + "</td>";
  618. response +="<td class=\"cell\">" + String(statc.msg_ttl_1) + "</td>";
  619. response +="<td class=\"cell\">" + String(statc.msg_ttl_2) + "</td>";
  620. # endif //_STATISTICS==3
  621. response +="<td class=\"cell\">" + String(statc.msg_ttl) + "</td>";
  622. response +="<td class=\"cell\">" + String((statc.msg_ttl*3600)/(now() - startTime)) + "</td></tr>";
  623. response +="<tr><td class=\"cell\">Packages Uplink OK </td>";
  624. #if _STATISTICS == 3
  625. response +="<td class=\"cell\">" + String(statc.msg_ok_0) + "</td>";
  626. response +="<td class=\"cell\">" + String(statc.msg_ok_1) + "</td>";
  627. response +="<td class=\"cell\">" + String(statc.msg_ok_2) + "</td>";
  628. # endif //_STATISTICS==3
  629. response +="<td class=\"cell\">" + String(statc.msg_ok) + "</td>";
  630. response +="<td class=\"cell\"></td></tr>";
  631. // Provide a table with all the SF data including percentage of messsages
  632. #if _STATISTICS == 2
  633. response +="<tr><td class=\"cell\">SF7 rcvd</td>";
  634. response +="<td class=\"cell\">"; response +=statc.sf7;
  635. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf7/statc.msg_ttl : 0)+" %";
  636. response +="</td></tr>";
  637. response +="<tr><td class=\"cell\">SF8 rcvd</td>";
  638. response +="<td class=\"cell\">"; response +=statc.sf8;
  639. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf8/statc.msg_ttl : 0)+" %";
  640. response +="</td></tr>";
  641. response +="<tr><td class=\"cell\">SF9 rcvd</td>";
  642. response +="<td class=\"cell\">"; response +=statc.sf9;
  643. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf9/statc.msg_ttl : 0)+" %";
  644. response +="</td></tr>";
  645. response +="<tr><td class=\"cell\">SF10 rcvd</td>";
  646. response +="<td class=\"cell\">"; response +=statc.sf10;
  647. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf10/statc.msg_ttl : 0)+" %";
  648. response +="</td></tr>";
  649. response +="<tr><td class=\"cell\">SF11 rcvd</td>";
  650. response +="<td class=\"cell\">"; response +=statc.sf11;
  651. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf11/statc.msg_ttl : 0)+" %";
  652. response +="</td></tr>";
  653. response +="<tr><td class=\"cell\">SF12 rcvd</td>";
  654. response +="<td class=\"cell\">"; response +=statc.sf12;
  655. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %";
  656. response +="</td></tr>";
  657. # endif //_STATISTICS==2
  658. # if _STATISTICS == 3
  659. response +="<tr><td class=\"cell\">SF7 rcvd</td>";
  660. response +="<td class=\"cell\">"; response +=statc.sf7_0;
  661. response +="<td class=\"cell\">"; response +=statc.sf7_1;
  662. response +="<td class=\"cell\">"; response +=statc.sf7_2;
  663. response +="<td class=\"cell\">"; response +=statc.sf7;
  664. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf7/statc.msg_ttl : 0)+" %";
  665. response +="</td></tr>";
  666. response +="<tr><td class=\"cell\">SF8 rcvd</td>";
  667. response +="<td class=\"cell\">"; response +=statc.sf8_0;
  668. response +="<td class=\"cell\">"; response +=statc.sf8_1;
  669. response +="<td class=\"cell\">"; response +=statc.sf8_2;
  670. response +="<td class=\"cell\">"; response +=statc.sf8;
  671. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf8/statc.msg_ttl : 0)+" %";
  672. response +="</td></tr>";
  673. response +="<tr><td class=\"cell\">SF9 rcvd</td>";
  674. response +="<td class=\"cell\">"; response +=statc.sf9_0;
  675. response +="<td class=\"cell\">"; response +=statc.sf9_1;
  676. response +="<td class=\"cell\">"; response +=statc.sf9_2;
  677. response +="<td class=\"cell\">"; response +=statc.sf9;
  678. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf9/statc.msg_ttl : 0)+" %";
  679. response +="</td></tr>";
  680. response +="<tr><td class=\"cell\">SF10 rcvd</td>";
  681. response +="<td class=\"cell\">"; response +=statc.sf10_0;
  682. response +="<td class=\"cell\">"; response +=statc.sf10_1;
  683. response +="<td class=\"cell\">"; response +=statc.sf10_2;
  684. response +="<td class=\"cell\">"; response +=statc.sf10;
  685. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf10/statc.msg_ttl : 0)+" %";
  686. response +="</td></tr>";
  687. response +="<tr><td class=\"cell\">SF11 rcvd</td>";
  688. response +="<td class=\"cell\">"; response +=statc.sf11_0;
  689. response +="<td class=\"cell\">"; response +=statc.sf11_1;
  690. response +="<td class=\"cell\">"; response +=statc.sf11_2;
  691. response +="<td class=\"cell\">"; response +=statc.sf11;
  692. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf11/statc.msg_ttl : 0)+" %";
  693. response +="</td></tr>";
  694. response +="<tr><td class=\"cell\">SF12 rcvd</td>";
  695. response +="<td class=\"cell\">"; response +=statc.sf12_0;
  696. response +="<td class=\"cell\">"; response +=statc.sf12_1;
  697. response +="<td class=\"cell\">"; response +=statc.sf12_1;
  698. response +="<td class=\"cell\">"; response +=statc.sf12;
  699. response +="<td class=\"cell\">"; response += String(statc.msg_ttl>0 ? 100*statc.sf12/statc.msg_ttl : 0)+" %";
  700. response +="</td></tr>";
  701. # endif //_STATISTICS==3
  702. response +="</table>";
  703. server.sendContent(response);
  704. }
  705. // --------------------------------------------------------------------------------
  706. // Message History
  707. // If enabled, display the sensor messageHistory on the current webserver Page.
  708. // In this GUI section a number of statr[x] records are displayed such as:
  709. //
  710. // Time, The time the sensor message was received
  711. // Node, the DevAddr or even Node name for Trusted nodes,
  712. // Data (Localserver), when _LOCALSERVER is enabled contains decoded data
  713. // C, Channel frequency on which the sensor was received
  714. // Freq, The frequency of the channel
  715. // SF, Spreading Factor
  716. // pRSSI, Packet RSSI
  717. //
  718. // Parameters:
  719. // - <none>
  720. // Returns:
  721. // - <none>
  722. //
  723. // As we make the TRUSTED_NODE a dynamic parameter, it can be set/unset in the user
  724. // interface. It will allow the user to only see known nodes (with a name) in the
  725. // list or also nodes with only an address (Unknown nodes).
  726. // As a result, the size of the list will NOT be as large when only known nodes are
  727. // selected, as in can be deselcted in the GUI and we have only so much space on
  728. // th screen.
  729. // --------------------------------------------------------------------------------
  730. static void messageHistory()
  731. {
  732. #if _STATISTICS >= 1
  733. String response="";
  734. // PRINT HEADERS
  735. response += "<h2>Message History</h2>";
  736. response += "<table class=\"config_table\">";
  737. response += "<tr>";
  738. response += "<th class=\"thead\">Time</th>";
  739. response += "<th class=\"thead\">Node</th>";
  740. #if _LOCALSERVER==1
  741. response += "<th class=\"thead\">Data</th>";
  742. #endif
  743. response += "<th class=\"thead\" style=\"width: 20px;\">C</th>";
  744. response += "<th class=\"thead\">Freq</th>";
  745. response += "<th class=\"thead\" style=\"width: 40px;\">SF</th>";
  746. response += "<th class=\"thead\" style=\"width: 50px;\">pRSSI</th>";
  747. #if RSSI==1
  748. if (debug > 1) {
  749. response += "<th class=\"thead\" style=\"width: 50px;\">RSSI</th>";
  750. }
  751. #endif
  752. response += "</tr>";
  753. server.sendContent(response);
  754. // PRINT NODE CONTENT
  755. for (int i=0; i<MAX_STAT; i++) { // For every Node in the list
  756. if (statr[i].sf == 0) break;
  757. response = "";
  758. response += String() + "<tr><td class=\"cell\">"; // Tmst
  759. stringTime((statr[i].tmst), response); // XXX Change tmst not to be millis() dependent
  760. response += "</td>";
  761. response += String() + "<td class=\"cell\">"; // Node
  762. #ifdef _TRUSTED_NODES // DO nothing with TRUSTED NODES
  763. switch (gwayConfig.trusted) {
  764. case 0: printHEX((char *)(& (statr[i].node)),' ',response);
  765. break;
  766. case 1: if (SerialName((char *)(& (statr[i].node)), response) < 0) {
  767. printHEX((char *)(& (statr[i].node)),' ',response);
  768. };
  769. break;
  770. case 2: if (SerialName((char *)(& (statr[i].node)), response) < 0) {
  771. continue;
  772. };
  773. break;
  774. case 3: // Value and we do not print unless also defined for LOCAL_SERVER
  775. default:
  776. # if _MONITOR>=1
  777. mPrint("Unknow value for gwayConfig.trusted");
  778. # endif //_MONITOR
  779. break;
  780. }
  781. #else // _TRUSTED_NODES
  782. printHEX((char *)(& (statr[i].node)),' ',response);
  783. #endif // _TRUSTED_NODES
  784. response += "</td>";
  785. #if _LOCALSERVER==1
  786. response += String() + "<td class=\"cell\">"; // Data
  787. for (int j=0; j<statr[i].datal; j++) {
  788. if (statr[i].data[j] <0x10) response+= "0";
  789. response += String(statr[i].data[j],HEX) + " ";
  790. }
  791. response += "</td>";
  792. #endif
  793. response += String() + "<td class=\"cell\">" + statr[i].ch + "</td>";
  794. response += String() + "<td class=\"cell\">" + freqs[statr[i].ch].upFreq + "</td>";
  795. response += String() + "<td class=\"cell\">" + statr[i].sf + "</td>";
  796. response += String() + "<td class=\"cell\">" + statr[i].prssi + "</td>";
  797. #if RSSI==1
  798. if (debug >= 2) {
  799. response += String() + "<td class=\"cell\">" + statr[i].rssi + "</td>";
  800. }
  801. #endif
  802. response += "</tr>";
  803. server.sendContent(response);
  804. }
  805. server.sendContent("</table>");
  806. #endif
  807. }
  808. // --------------------------------------------------------------------------------
  809. // H2 NODE SEEN HISTORY
  810. // If enabled, display the sensor last Seen history.
  811. // This setting ,pves togetjer with the "expert" mode.
  812. // If that mode is enabled than the node seen intory is displayed
  813. //
  814. // Parameters:
  815. // - <none>
  816. // Returns:
  817. // - <none>
  818. // --------------------------------------------------------------------------------
  819. static void nodeHistory()
  820. {
  821. #if _SEENMAX >= 1
  822. if (gwayConfig.seen) {
  823. // First draw the headers
  824. String response="";
  825. response += "<h2>Node Last Seen History</h2>";
  826. response += "<table class=\"config_table\">";
  827. response += "<tr>";
  828. response += "<th class=\"thead\" style=\"width: 220px;\">Time</th>";
  829. response += "<th class=\"thead\">Node</th>";
  830. response += "<th class=\"thead\">Pkgs</th>";
  831. //#if _LOCALSERVER==1
  832. // response += "<th class=\"thead\">Data</th>";
  833. //#endif
  834. response += "<th class=\"thead\" style=\"width: 20px;\">C</th>";
  835. response += "<th class=\"thead\" style=\"width: 40px;\">SF</th>";
  836. response += "</tr>";
  837. server.sendContent(response);
  838. // Now start the contents
  839. int i;
  840. for (i=0; i<_SEENMAX; i++) {
  841. if (listSeen[i].idSeen == 0) break;
  842. response = "";
  843. response += String() + "<tr><td class=\"cell\">"; // Tmst
  844. stringTime((listSeen[i].timSeen), response);
  845. response += "</td>";
  846. response += String() + "<td class=\"cell\">"; // Node
  847. #ifdef _TRUSTED_NODES // DO nothing with TRUSTED NODES
  848. switch (gwayConfig.trusted) {
  849. case 0: printHEX((char *)(& (listSeen[i].idSeen)),' ',response);
  850. break;
  851. case 1: if (SerialName((char *)(& (listSeen[i].idSeen)), response) < 0) {
  852. printHEX((char *)(& (listSeen[i].idSeen)),' ',response);
  853. };
  854. break;
  855. case 2: if (SerialName((char *)(& (listSeen[i].idSeen)), response) < 0) {
  856. continue;
  857. };
  858. break;
  859. case 3: // Value 3 and we do not print unless also defined for LOCAL_SERVER
  860. default:
  861. # if _MONITOR>=1
  862. mPrint("Unknow value for gwayConfig.trusted");
  863. # endif //_MONITOR
  864. break;
  865. }
  866. #else
  867. printHEX((char *)(& (listSeen[i].idSeen)),' ',response);
  868. #endif // _TRUSTED_NODES
  869. response += "</td>";
  870. response += String() + "<td class=\"cell\">" + listSeen[i].cntSeen + "</td>"; // Counter
  871. response += String() + "<td class=\"cell\">" + listSeen[i].chnSeen + "</td>"; // Channel
  872. response += String() + "<td class=\"cell\">" + listSeen[i].sfSeen + "</td>"; // SF
  873. server.sendContent(response);
  874. }
  875. server.sendContent("</table>");
  876. }
  877. #endif //_SEENMAX
  878. } // nodeHistory()
  879. // --------------------------------------------------------------------------------
  880. // MONITOR DATA
  881. // This function will print monitor data for the gateway based on the settings in
  882. // _MONITOR in file configGway.h
  883. // Only when the _MONITOR is positive then the function will be executed.
  884. // If less then nothing will be displayed.
  885. // XXX We have to make the function such that when printed, the webpage refreshes.
  886. // --------------------------------------------------------------------------------
  887. int monitorData()
  888. {
  889. # if _MONITOR>=1
  890. if (gwayConfig.monitor) {
  891. String response="";
  892. response +="<h2>Monitoring Console</h2>";
  893. response +="<table class=\"config_table\">";
  894. response +="<tr>";
  895. response +="<th class=\"thead\">Monitor Console</th>";
  896. response +="</tr>";
  897. for (int i=0; i<_MONITOR; i++) {
  898. if (monitor[i].txt == "") {
  899. break;
  900. }
  901. // DISPLAY line
  902. response +="<tr><td class=\"cell\">" ;
  903. response += String(monitor[i].txt);
  904. response += "</td></tr>";
  905. }
  906. response +="</table>";
  907. server.sendContent(response);
  908. }
  909. # endif
  910. }
  911. // --------------------------------------------------------------------------------
  912. // WIFI CONFIG
  913. // wifiConfig() displays the most important Wifi parameters gathered
  914. //
  915. // --------------------------------------------------------------------------------
  916. static void wifiConfig()
  917. {
  918. if (gwayConfig.expert) {
  919. String response="";
  920. response +="<h2>WiFi Config</h2>";
  921. response +="<table class=\"config_table\">";
  922. response +="<tr><th class=\"thead\">Parameter</th><th class=\"thead\">Value</th></tr>";
  923. response +="<tr><td class=\"cell\">WiFi host</td><td class=\"cell\">";
  924. #if ESP32_ARCH==1
  925. response +=WiFi.getHostname(); response+="</tr>";
  926. #else
  927. response +=wifi_station_get_hostname(); response+="</tr>";
  928. #endif
  929. response +="<tr><td class=\"cell\">WiFi SSID</td><td class=\"cell\">";
  930. response +=WiFi.SSID(); response+="</tr>";
  931. response +="<tr><td class=\"cell\">IP Address</td><td class=\"cell\">";
  932. printIP((IPAddress)WiFi.localIP(),'.',response);
  933. response +="</tr>";
  934. response +="<tr><td class=\"cell\">IP Gateway</td><td class=\"cell\">";
  935. printIP((IPAddress)WiFi.gatewayIP(),'.',response);
  936. response +="</tr>";
  937. response +="<tr><td class=\"cell\">NTP Server</td><td class=\"cell\">"; response+=NTP_TIMESERVER; response+="</tr>";
  938. response +="<tr><td class=\"cell\">LoRa Router</td><td class=\"cell\">"; response+=_TTNSERVER; response+="</tr>";
  939. response +="<tr><td class=\"cell\">LoRa Router IP</td><td class=\"cell\">";
  940. printIP((IPAddress)ttnServer,'.',response);
  941. response +="</tr>";
  942. #ifdef _THINGSERVER
  943. response +="<tr><td class=\"cell\">LoRa Router 2</td><td class=\"cell\">"; response+=_THINGSERVER;
  944. response += String() + ":" + _THINGPORT + "</tr>";
  945. response +="<tr><td class=\"cell\">LoRa Router 2 IP</td><td class=\"cell\">";
  946. printIP((IPAddress)thingServer,'.',response);
  947. response +="</tr>";
  948. #endif
  949. response +="</table>";
  950. server.sendContent(response);
  951. } // gwayConfig.expert
  952. } // wifiConfig
  953. // --------------------------------------------------------------------------------
  954. // H2 systemStatus
  955. // systemStatus is additional and only available in the expert mode.
  956. // It provides a number of system specific data such as heap size etc.
  957. // --------------------------------------------------------------------------------
  958. static void systemStatus()
  959. {
  960. if (gwayConfig.expert) {
  961. String response="";
  962. response +="<h2>System Status</h2>";
  963. response +="<table class=\"config_table\">";
  964. response +="<tr>";
  965. response +="<th class=\"thead\">Parameter</th>";
  966. response +="<th class=\"thead\">Value</th>";
  967. response +="<th colspan=\"2\" class=\"thead\">Set</th>";
  968. response +="</tr>";
  969. response +="<tr><td style=\"border: 1px solid black; width:120px;\">Gateway ID</td>";
  970. response +="<td class=\"cell\">";
  971. if (MAC_array[0]< 0x10) response +='0'; response +=String(MAC_array[0],HEX); // The MAC array is always returned in lowercase
  972. if (MAC_array[1]< 0x10) response +='0'; response +=String(MAC_array[1],HEX);
  973. if (MAC_array[2]< 0x10) response +='0'; response +=String(MAC_array[2],HEX);
  974. response +="FFFF";
  975. if (MAC_array[3]< 0x10) response +='0'; response +=String(MAC_array[3],HEX);
  976. if (MAC_array[4]< 0x10) response +='0'; response +=String(MAC_array[4],HEX);
  977. if (MAC_array[5]< 0x10) response +='0'; response +=String(MAC_array[5],HEX);
  978. response+="</tr>";
  979. response +="<tr><td class=\"cell\">Free heap</td><td class=\"cell\">"; response+=ESP.getFreeHeap(); response+="</tr>";
  980. // XXX We Shoudl find an ESP32 alternative
  981. #if !defined ESP32_ARCH
  982. response +="<tr><td class=\"cell\">ESP speed</td><td class=\"cell\">"; response+=ESP.getCpuFreqMHz();
  983. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=80\"><button>80</button></a></td>";
  984. response +="<td style=\"border: 1px solid black; width:40px;\"><a href=\"SPEED=160\"><button>160</button></a></td>";
  985. response+="</tr>";
  986. response +="<tr><td class=\"cell\">ESP Chip ID</td><td class=\"cell\">"; response+=ESP.getChipId(); response+="</tr>";
  987. #endif
  988. response +="<tr><td class=\"cell\">OLED</td><td class=\"cell\">"; response+=OLED; response+="</tr>";
  989. #if _STATISTICS >= 1
  990. response +="<tr><td class=\"cell\">WiFi Setups</td><td class=\"cell\">"; response+=gwayConfig.wifis; response+="</tr>";
  991. response +="<tr><td class=\"cell\">WWW Views</td><td class=\"cell\">"; response+=gwayConfig.views; response+="</tr>";
  992. #endif
  993. response +="</table>";
  994. server.sendContent(response);
  995. } // gwayConfig.expert
  996. } // systemStatus
  997. // --------------------------------------------------------------------------------
  998. // H2 System State and Interrupt
  999. // Display interrupt data, but only for debug >= 2
  1000. //
  1001. // --------------------------------------------------------------------------------
  1002. static void interruptData()
  1003. {
  1004. if (gwayConfig.expert) {
  1005. uint8_t flags = readRegister(REG_IRQ_FLAGS);
  1006. uint8_t mask = readRegister(REG_IRQ_FLAGS_MASK);
  1007. String response="";
  1008. response +="<h2>System State and Interrupt</h2>";
  1009. response +="<table class=\"config_table\">";
  1010. response +="<tr>";
  1011. response +="<th class=\"thead\">Parameter</th>";
  1012. response +="<th class=\"thead\">Value</th>";
  1013. response +="<th colspan=\"2\" class=\"thead\">Set</th>";
  1014. response +="</tr>";
  1015. response +="<tr><td class=\"cell\">_state</td>";
  1016. response +="<td class=\"cell\">";
  1017. switch (_state) { // See loraModem.h
  1018. case S_INIT: response +="INIT"; break;
  1019. case S_SCAN: response +="SCAN"; break;
  1020. case S_CAD: response +="CAD"; break;
  1021. case S_RX: response +="RX"; break;
  1022. case S_TX: response +="TX"; break;
  1023. default: response +="unknown"; break;
  1024. }
  1025. response +="</td></tr>";
  1026. response +="<tr><td class=\"cell\">_STRICT_1CH</td>";
  1027. response +="<td class=\"cell\">" ;
  1028. response += String() + _STRICT_1CH;
  1029. response +="</td></tr>";
  1030. response +="<tr><td class=\"cell\">flags (8 bits)</td>";
  1031. response +="<td class=\"cell\">0x";
  1032. if (flags <16) response += "0";
  1033. response +=String(flags,HEX); response+="</td></tr>";
  1034. response +="<tr><td class=\"cell\">mask (8 bits)</td>";
  1035. response +="<td class=\"cell\">0x";
  1036. if (mask <16) response += "0";
  1037. response +=String(mask,HEX); response+="</td></tr>";
  1038. response +="<tr><td class=\"cell\">Re-entrant cntr</td>";
  1039. response +="<td class=\"cell\">";
  1040. response += String() + gwayConfig.reents;
  1041. response +="</td></tr>";
  1042. response +="<tr><td class=\"cell\">ntp call cntr</td>";
  1043. response +="<td class=\"cell\">";
  1044. response += String() + gwayConfig.ntps;
  1045. response+="</td></tr>";
  1046. response +="<tr><td class=\"cell\">ntpErr cntr</td>";
  1047. response +="<td class=\"cell\">";
  1048. response += String() + gwayConfig.ntpErr;
  1049. response +="</td>";
  1050. response +="<td colspan=\"2\" style=\"border: 1px solid black;\">";
  1051. stringTime(gwayConfig.ntpErrTime, response);
  1052. response +="</td>";
  1053. response +="</tr>";
  1054. response +="</table>";
  1055. server.sendContent(response);
  1056. }// if gwayConfig.expert
  1057. } // interruptData
  1058. // --------------------------------------------------------------------------------
  1059. // setupWWW is the main function for webserver functions/
  1060. // SetupWWW function called by main setup() program to setup webserver
  1061. // It does actually not much more than installing all the callback handlers
  1062. // for messages sent to the webserver
  1063. //
  1064. // Implemented is an interface like:
  1065. // http://<server>/<Variable>=<value>
  1066. //
  1067. // --------------------------------------------------------------------------------
  1068. void setupWWW()
  1069. {
  1070. server.begin(); // Start the webserver
  1071. // -----------------
  1072. // BUTTONS, define what should happen with the buttons we press on the homepage
  1073. server.on("/", []() {
  1074. sendWebPage("",""); // Send the webPage string
  1075. server.sendHeader("Location", String("/"), true);
  1076. server.send ( 302, "text/plain", "");
  1077. });
  1078. server.on("/HELP", []() {
  1079. sendWebPage("HELP",""); // Send the webPage string
  1080. server.sendHeader("Location", String("/"), true);
  1081. server.send ( 302, "text/plain", "");
  1082. });
  1083. // Format the filesystem
  1084. server.on("/FORMAT", []() {
  1085. Serial.print(F("FORMAT ..."));
  1086. SPIFFS.format(); // Normally disabled. Enable only when SPIFFS corrupt
  1087. initConfig(&gwayConfig);
  1088. writeConfig( CONFIGFILE, &gwayConfig);
  1089. writeSeen( _SEENFILE, listSeen); // Write the last time record is seen
  1090. # if _MONITOR>=1
  1091. if ((debug>=1) && (pdebug & P_GUI )) {
  1092. mPrint("Format DONE");
  1093. }
  1094. # endif //_MONITOR
  1095. server.sendHeader("Location", String("/"), true);
  1096. server.send ( 302, "text/plain", "");
  1097. });
  1098. // Reset the statistics
  1099. server.on("/RESET", []() {
  1100. Serial.println(F("RESET"));
  1101. startTime= now() - 1; // Reset all timers too
  1102. statc.msg_ttl = 0; // Reset package statistics
  1103. statc.msg_ok = 0;
  1104. statc.msg_down = 0;
  1105. #if _STATISTICS >= 3
  1106. statc.msg_ttl_0 = 0;
  1107. statc.msg_ttl_1 = 0;
  1108. statc.msg_ttl_2 = 0;
  1109. statc.msg_ok_0 = 0;
  1110. statc.msg_ok_1 = 0;
  1111. statc.msg_ok_2 = 0;
  1112. statc.msg_down_0 = 0;
  1113. statc.msg_down_1 = 0;
  1114. statc.msg_down_2 = 0;
  1115. #endif
  1116. #if _STATISTICS >= 1
  1117. for (int i=0; i<MAX_STAT; i++) { statr[i].sf = 0; }
  1118. #if _STATISTICS >= 2
  1119. statc.sf7 = 0;
  1120. statc.sf8 = 0;
  1121. statc.sf9 = 0;
  1122. statc.sf10= 0;
  1123. statc.sf11= 0;
  1124. statc.sf12= 0;
  1125. statc.resets= 0;
  1126. writeGwayCfg(CONFIGFILE);
  1127. #if _STATISTICS >= 3
  1128. statc.sf7_0 = 0; statc.sf7_1 = 0; statc.sf7_2 = 0;
  1129. statc.sf8_0 = 0; statc.sf8_1 = 0; statc.sf8_2 = 0;
  1130. statc.sf9_0 = 0; statc.sf9_1 = 0; statc.sf9_2 = 0;
  1131. statc.sf10_0= 0; statc.sf10_1= 0; statc.sf10_2= 0;
  1132. statc.sf11_0= 0; statc.sf11_1= 0; statc.sf11_2= 0;
  1133. statc.sf12_0= 0; statc.sf12_1= 0; statc.sf12_2= 0;
  1134. #endif
  1135. #endif
  1136. #endif
  1137. server.sendHeader("Location", String("/"), true);
  1138. server.send ( 302, "text/plain", "");
  1139. });
  1140. // Reset the boot counter
  1141. server.on("/BOOT", []() {
  1142. #if _STATISTICS >= 2
  1143. gwayConfig.boots = 0;
  1144. gwayConfig.wifis = 0;
  1145. gwayConfig.views = 0;
  1146. gwayConfig.ntpErr = 0; // NTP errors
  1147. gwayConfig.ntpErrTime = 0; // NTP last error time
  1148. gwayConfig.ntps = 0; // Number of NTP calls
  1149. #endif
  1150. gwayConfig.reents = 0; // Re-entrance
  1151. writeGwayCfg(CONFIGFILE);
  1152. #if _MONITOR>=1
  1153. if ((debug>=2) && (pdebug & P_MAIN)) {
  1154. mPrint("BOOT, config written");
  1155. }
  1156. #endif
  1157. server.sendHeader("Location", String("/"), true);
  1158. server.send ( 302, "text/plain", "");
  1159. });
  1160. // Reboot the Gateway
  1161. // NOTE: There is no button for this code yet
  1162. server.on("/REBOOT", []() {
  1163. sendWebPage("",""); // Send the webPage string
  1164. server.sendHeader("Location", String("/"), true);
  1165. server.send ( 302, "text/plain", "");
  1166. ESP.restart();
  1167. });
  1168. server.on("/NEWSSID", []() {
  1169. sendWebPage("NEWSSID",""); // Send the webPage string
  1170. server.sendHeader("Location", String("/"), true);
  1171. server.send ( 302, "text/plain", "");
  1172. });
  1173. // Set debug parameter
  1174. server.on("/DEBUG=-1", []() { // Set debug level 0-2. Note: +3 is same as -1
  1175. debug = (debug+3)%4;
  1176. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1177. # if _DUSB>=1 || _MONITOR>=1
  1178. if ((debug>=1) && (pdebug & P_MAIN)) {
  1179. mPrint("DEBUG -1: config written");
  1180. }
  1181. # endif // _DUSB _MONITOR
  1182. server.sendHeader("Location", String("/"), true);
  1183. server.send ( 302, "text/plain", "");
  1184. });
  1185. server.on("/DEBUG=1", []() {
  1186. debug = (debug+1)%4;
  1187. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1188. # if _DUSB>=1 || _MONITOR>=1
  1189. if ((debug>=1) && (pdebug & P_MAIN)) {
  1190. mPrint("DEBUG +1: config written");
  1191. }
  1192. # endif // _DUSB _MONITOR
  1193. server.sendHeader("Location", String("/"), true);
  1194. server.send ( 302, "text/plain", "");
  1195. });
  1196. // Set PDEBUG parameter
  1197. //
  1198. server.on("/PDEBUG=SCAN", []() { // Set debug level 0x01
  1199. pdebug ^= P_SCAN;
  1200. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1201. server.sendHeader("Location", String("/"), true);
  1202. server.send ( 302, "text/plain", "");
  1203. });
  1204. server.on("/PDEBUG=CAD", []() { // Set debug level 0x02
  1205. pdebug ^= P_CAD;
  1206. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1207. server.sendHeader("Location", String("/"), true);
  1208. server.send ( 302, "text/plain", "");
  1209. });
  1210. server.on("/PDEBUG=RX", []() { // Set debug level 0x04
  1211. pdebug ^= P_RX;
  1212. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1213. server.sendHeader("Location", String("/"), true);
  1214. server.send ( 302, "text/plain", "");
  1215. });
  1216. server.on("/PDEBUG=TX", []() { // Set debug level 0x08
  1217. pdebug ^= P_TX;
  1218. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1219. server.sendHeader("Location", String("/"), true);
  1220. server.send ( 302, "text/plain", "");
  1221. });
  1222. server.on("/PDEBUG=PRE", []() { // Set debug level 0-2
  1223. pdebug ^= P_PRE;
  1224. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1225. server.sendHeader("Location", String("/"), true);
  1226. server.send ( 302, "text/plain", "");
  1227. });
  1228. server.on("/PDEBUG=MAIN", []() { // Set debug level 0-2
  1229. pdebug ^= P_MAIN;
  1230. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1231. server.sendHeader("Location", String("/"), true);
  1232. server.send ( 302, "text/plain", "");
  1233. });
  1234. server.on("/PDEBUG=GUI", []() { // Set debug level 0-2
  1235. pdebug ^= P_GUI;
  1236. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1237. server.sendHeader("Location", String("/"), true);
  1238. server.send ( 302, "text/plain", "");
  1239. });
  1240. server.on("/PDEBUG=RADIO", []() { // Set debug level 0-2
  1241. pdebug ^= P_RADIO;
  1242. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1243. server.sendHeader("Location", String("/"), true);
  1244. server.send ( 302, "text/plain", "");
  1245. });
  1246. // Set delay in microseconds
  1247. server.on("/DELAY=1", []() {
  1248. gwayConfig.txDelay+=5000;
  1249. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1250. # if _MONITOR>=1
  1251. if ((debug>=1) && (pdebug & P_MAIN)) {
  1252. mPrint("DELAY +, config written");
  1253. }
  1254. # endif
  1255. server.sendHeader("Location", String("/"), true);
  1256. server.send ( 302, "text/plain", "");
  1257. });
  1258. server.on("/DELAY=-1", []() {
  1259. gwayConfig.txDelay-=5000;
  1260. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1261. # if _MONITOR>=1
  1262. if ((debug>=1) && (pdebug & P_MAIN)) {
  1263. mPrint("DELAY -, config written");
  1264. }
  1265. # endif
  1266. server.sendHeader("Location", String("/"), true);
  1267. server.send ( 302, "text/plain", "");
  1268. });
  1269. // Set Trusted Node Parameter
  1270. server.on("/TRUSTED=1", []() {
  1271. gwayConfig.trusted = (gwayConfig.trusted +1)%4;
  1272. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1273. # if _MONITOR>=2
  1274. mPrint("TRUSTED +, config written");
  1275. # endif //_MONITOR
  1276. server.sendHeader("Location", String("/"), true);
  1277. server.send ( 302, "text/plain", "");
  1278. });
  1279. server.on("/TRUSTED=-1", []() {
  1280. gwayConfig.trusted = (gwayConfig.trusted -1)%4;
  1281. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1282. #if _DUSB>=2
  1283. Serial.println(F("TRUSTED +, config written"));
  1284. #endif
  1285. server.sendHeader("Location", String("/"), true);
  1286. server.send ( 302, "text/plain", "");
  1287. });
  1288. // Spreading Factor setting
  1289. server.on("/SF=1", []() {
  1290. if (sf>=SF12) sf=SF7; else sf= (sf_t)((int)sf+1);
  1291. server.sendHeader("Location", String("/"), true);
  1292. server.send ( 302, "text/plain", "");
  1293. });
  1294. server.on("/SF=-1", []() {
  1295. if (sf<=SF7) sf=SF12; else sf= (sf_t)((int)sf-1);
  1296. server.sendHeader("Location", String("/"), true);
  1297. server.send ( 302, "text/plain", "");
  1298. });
  1299. // Set Frequency of the GateWay node
  1300. server.on("/FREQ=1", []() {
  1301. uint8_t nf = sizeof(freqs)/sizeof(freqs[0]); // Number of elements in array
  1302. #if _DUSB>=2
  1303. Serial.print("FREQ==1:: For freq[0] sizeof vector=");
  1304. Serial.print(sizeof(freqs[0]));
  1305. Serial.println();
  1306. #endif
  1307. if (ifreq==(nf-1)) ifreq=0; else ifreq++;
  1308. server.sendHeader("Location", String("/"), true);
  1309. server.send ( 302, "text/plain", "");
  1310. });
  1311. server.on("/FREQ=-1", []() {
  1312. uint8_t nf = sizeof(freqs)/sizeof(freqs[0]); // Number of elements in array
  1313. if (ifreq==0) ifreq=(nf-1); else ifreq--;
  1314. server.sendHeader("Location", String("/"), true);
  1315. server.send ( 302, "text/plain", "");
  1316. });
  1317. // Set CAD function off/on
  1318. server.on("/CAD=1", []() {
  1319. _cad=(bool)1;
  1320. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1321. server.sendHeader("Location", String("/"), true);
  1322. server.send ( 302, "text/plain", "");
  1323. });
  1324. server.on("/CAD=0", []() {
  1325. _cad=(bool)0;
  1326. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1327. server.sendHeader("Location", String("/"), true);
  1328. server.send ( 302, "text/plain", "");
  1329. });
  1330. // GatewayNode
  1331. server.on("/NODE=1", []() {
  1332. #if GATEWAYNODE==1
  1333. gwayConfig.isNode =(bool)1;
  1334. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1335. #endif
  1336. server.sendHeader("Location", String("/"), true);
  1337. server.send ( 302, "text/plain", "");
  1338. });
  1339. server.on("/NODE=0", []() {
  1340. #if GATEWAYNODE==1
  1341. gwayConfig.isNode =(bool)0;
  1342. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1343. #endif
  1344. server.sendHeader("Location", String("/"), true);
  1345. server.send ( 302, "text/plain", "");
  1346. });
  1347. #if GATEWAYNODE==1
  1348. // Framecounter of the Gateway node
  1349. server.on("/FCNT", []() {
  1350. frameCount=0;
  1351. rxLoraModem(); // Reset the radio with the new frequency
  1352. writeGwayCfg(CONFIGFILE);
  1353. //sendWebPage("",""); // Send the webPage string
  1354. server.sendHeader("Location", String("/"), true);
  1355. server.send ( 302, "text/plain", "");
  1356. });
  1357. #endif
  1358. // WWW Page refresh function
  1359. server.on("/REFR=1", []() { // WWW page auto refresh ON
  1360. #if A_REFRESH==1
  1361. gwayConfig.refresh =1;
  1362. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1363. #endif
  1364. server.sendHeader("Location", String("/"), true);
  1365. server.send ( 302, "text/plain", "");
  1366. });
  1367. server.on("/REFR=0", []() { // WWW page auto refresh OFF
  1368. #if A_REFRESH==1
  1369. gwayConfig.refresh =0;
  1370. writeGwayCfg(CONFIGFILE); // Save configuration to file
  1371. #endif
  1372. server.sendHeader("Location", String("/"), true);
  1373. server.send ( 302, "text/plain", "");
  1374. });
  1375. // Switch off/on the HOP functions
  1376. server.on("/HOP=1", []() {
  1377. _hop=true;
  1378. server.sendHeader("Location", String("/"), true);
  1379. server.send ( 302, "text/plain", "");
  1380. });
  1381. server.on("/HOP=0", []() {
  1382. _hop=false;
  1383. ifreq=0;
  1384. setFreq(freqs[ifreq].upFreq);
  1385. rxLoraModem();
  1386. server.sendHeader("Location", String("/"), true);
  1387. server.send ( 302, "text/plain", "");
  1388. });
  1389. #if !defined ESP32_ARCH
  1390. // Change speed to 160 MHz
  1391. server.on("/SPEED=80", []() {
  1392. system_update_cpu_freq(80);
  1393. server.sendHeader("Location", String("/"), true);
  1394. server.send ( 302, "text/plain", "");
  1395. });
  1396. server.on("/SPEED=160", []() {
  1397. system_update_cpu_freq(160);
  1398. server.sendHeader("Location", String("/"), true);
  1399. server.send ( 302, "text/plain", "");
  1400. });
  1401. #endif
  1402. // Display Documentation pages
  1403. server.on("/DOCU", []() {
  1404. server.sendHeader("Location", String("/"), true);
  1405. buttonDocu();
  1406. server.send ( 302, "text/plain", "");
  1407. });
  1408. // Display LOGging information
  1409. server.on("/LOG", []() {
  1410. server.sendHeader("Location", String("/"), true);
  1411. #if _DUSB>=2
  1412. Serial.println(F("LOG button"));
  1413. #endif
  1414. buttonLog();
  1415. server.send ( 302, "text/plain", "");
  1416. });
  1417. // Display Expert mode or Simple mode
  1418. server.on("/EXPERT", []() {
  1419. server.sendHeader("Location", String("/"), true);
  1420. gwayConfig.expert = bool(1 - (int) gwayConfig.expert) ;
  1421. server.send ( 302, "text/plain", "");
  1422. });
  1423. #if _MONITOR>=1
  1424. // Display Monitor Console or not
  1425. server.on("/MONITOR", []() {
  1426. server.sendHeader("Location", String("/"), true);
  1427. gwayConfig.monitor = bool(1 - (int) gwayConfig.monitor) ;
  1428. server.send ( 302, "text/plain", "");
  1429. });
  1430. #endif
  1431. // Display the SEEN statistics
  1432. server.on("/SEEN", []() {
  1433. server.sendHeader("Location", String("/"), true);
  1434. gwayConfig.seen = bool(1 - (int) gwayConfig.seen) ;
  1435. server.send ( 302, "text/plain", "");
  1436. });
  1437. // Update the sketch. Not yet implemented
  1438. server.on("/UPDATE=1", []() {
  1439. #if A_OTA==1
  1440. updateOtaa();
  1441. #endif
  1442. server.sendHeader("Location", String("/"), true);
  1443. server.send ( 302, "text/plain", "");
  1444. });
  1445. // -----------
  1446. // This section from version 4.0.7 defines what PART of the
  1447. // webpage is shown based on the buttons pressed by the user
  1448. // Maybe not all information should be put on the screen since it
  1449. // may take too much time to serve all information before a next
  1450. // package interrupt arrives at the gateway
  1451. # if _DUSB>=1
  1452. Serial.print(F("WWW Server started on port "));
  1453. Serial.println(A_SERVERPORT);
  1454. # endif //_DUSB
  1455. return;
  1456. } // setupWWW
  1457. // --------------------------------------------------------------------------------
  1458. // SEND WEB PAGE()
  1459. // Call the webserver and send the standard content and the content that is
  1460. // passed by the parameter. Each time a variable is changed, this function is
  1461. // called to display the webpage again/
  1462. //
  1463. // NOTE: This is the only place where yield() or delay() calls are used.
  1464. //
  1465. // --------------------------------------------------------------------------------
  1466. void sendWebPage(const char *cmd, const char *arg)
  1467. {
  1468. openWebPage(); yield(); // Do the initial website setup
  1469. wwwButtons(); // Display buttons such as Documentation, Mode, Logfiles
  1470. setVariables(cmd,arg); yield(); // Read Webserver commands from line
  1471. statisticsData(); yield(); // Node statistics
  1472. messageHistory(); yield(); // Display the sensor history, message statistics
  1473. nodeHistory(); yield(); // Display the lastSeen array
  1474. monitorData(); yield(); // Console
  1475. gatewaySettings(); yield(); // Display web configuration
  1476. wifiConfig(); yield(); // WiFi specific parameters
  1477. systemStatus(); yield(); // System statistics such as heap etc.
  1478. interruptData(); yield(); // Display interrupts only when debug >= 2
  1479. websiteFooter(); yield();
  1480. server.client().stop();
  1481. }
  1482. // --------------------------------------------------------------------------------
  1483. // websiteFooter
  1484. //
  1485. // Thi function displays the last messages without header on the webpage and then
  1486. // closes the webpage.
  1487. // --------------------------------------------------------------------------------
  1488. static void websiteFooter()
  1489. {
  1490. // Close the client connection to server
  1491. server.sendContent(String() + "<br><br /><p style='font-size:10px'>Click <a href=\"/HELP\">here</a> to explain Help and REST options</p><br>");
  1492. server.sendContent(String() + "</BODY></HTML>");
  1493. server.sendContent(""); yield();
  1494. }
  1495. #endif // A_SERVER==1