code.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. // First, checks if it isn't implemented yet.
  2. if (!String.prototype.format) {
  3. String.prototype.format = function() {
  4. var args = arguments;
  5. return this.replace(/{(\d+)}/g, function(match, number) {
  6. return typeof args[number] != 'undefined'
  7. ? args[number]
  8. : match
  9. ;
  10. });
  11. };
  12. }
  13. var releaseURL = 'https://api.github.com/repos/sle118/squeezelite-esp32/releases';
  14. var recovery = false;
  15. var enableAPTimer = true;
  16. var enableStatusTimer = true;
  17. var commandHeader = 'squeezelite -b 500:2000 -d all=info ';
  18. var pname, ver, otapct, otadsc;
  19. var blockAjax = false;
  20. var blockFlashButton = false;
  21. var lastMsg = '';
  22. var apList = null;
  23. var selectedSSID = "";
  24. var refreshAPInterval = null;
  25. var checkStatusInterval = null;
  26. var StatusIntervalActive = false;
  27. var RefreshAPIIntervalActive = false;
  28. var LastRecoveryState=null;
  29. var output = '';
  30. function stopCheckStatusInterval(){
  31. if(checkStatusInterval != null){
  32. clearTimeout(checkStatusInterval);
  33. checkStatusInterval = null;
  34. }
  35. StatusIntervalActive = false;
  36. }
  37. function stopRefreshAPInterval(){
  38. if(refreshAPInterval != null){
  39. clearTimeout(refreshAPInterval);
  40. refreshAPInterval = null;
  41. }
  42. RefreshAPIIntervalActive = false;
  43. }
  44. function startCheckStatusInterval(){
  45. StatusIntervalActive = true;
  46. checkStatusInterval = setTimeout(checkStatus, 3000);
  47. }
  48. function startRefreshAPInterval(){
  49. RefreshAPIIntervalActive = true;
  50. refreshAPInterval = setTimeout(refreshAP(false), 4500); // leave enough time for the initial scan
  51. }
  52. function RepeatCheckStatusInterval(){
  53. if(StatusIntervalActive)
  54. startCheckStatusInterval();
  55. }
  56. function RepeatRefreshAPInterval(){
  57. if(RefreshAPIIntervalActive)
  58. startRefreshAPInterval();
  59. }
  60. $(document).ready(function(){
  61. $("#wifi-status").on("click", ".ape", function() {
  62. $( "#wifi" ).slideUp( "fast", function() {});
  63. $( "#connect-details" ).slideDown( "fast", function() {});
  64. });
  65. $("#manual_add").on("click", ".ape", function() {
  66. selectedSSID = $(this).text();
  67. $( "#ssid-pwd" ).text(selectedSSID);
  68. $( "#wifi" ).slideUp( "fast", function() {});
  69. $( "#connect_manual" ).slideDown( "fast", function() {});
  70. $( "#connect" ).slideUp( "fast", function() {});
  71. //update wait screen
  72. $( "#loading" ).show();
  73. $( "#connect-success" ).hide();
  74. $( "#connect-fail" ).hide();
  75. });
  76. $("#wifi-list").on("click", ".ape", function() {
  77. selectedSSID = $(this).text();
  78. $( "#ssid-pwd" ).text(selectedSSID);
  79. $( "#wifi" ).slideUp( "fast", function() {});
  80. $( "#connect_manual" ).slideUp( "fast", function() {});
  81. $( "#connect" ).slideDown( "fast", function() {});
  82. //update wait screen
  83. $( "#loading" ).show();
  84. $( "#connect-success" ).hide();
  85. $( "#connect-fail" ).hide();
  86. });
  87. $("#cancel").on("click", function() {
  88. selectedSSID = "";
  89. $( "#connect" ).slideUp( "fast", function() {});
  90. $( "#connect_manual" ).slideUp( "fast", function() {});
  91. $( "#wifi" ).slideDown( "fast", function() {});
  92. });
  93. $("#manual_cancel").on("click", function() {
  94. selectedSSID = "";
  95. $( "#connect" ).slideUp( "fast", function() {});
  96. $( "#connect_manual" ).slideUp( "fast", function() {});
  97. $( "#wifi" ).slideDown( "fast", function() {});
  98. });
  99. $("#join").on("click", function() {
  100. performConnect();
  101. });
  102. $("#manual_join").on("click", function() {
  103. performConnect($(this).data('connect'));
  104. });
  105. $("#ok-details").on("click", function() {
  106. $( "#connect-details" ).slideUp( "fast", function() {});
  107. $( "#wifi" ).slideDown( "fast", function() {});
  108. });
  109. $("#ok-credits").on("click", function() {
  110. $( "#credits" ).slideUp( "fast", function() {});
  111. $( "#app" ).slideDown( "fast", function() {});
  112. });
  113. $("#acredits").on("click", function(event) {
  114. event.preventDefault();
  115. $( "#app" ).slideUp( "fast", function() {});
  116. $( "#credits" ).slideDown( "fast", function() {});
  117. });
  118. $("#ok-connect").on("click", function() {
  119. $( "#connect-wait" ).slideUp( "fast", function() {});
  120. $( "#wifi" ).slideDown( "fast", function() {});
  121. });
  122. $("#disconnect").on("click", function() {
  123. $( "#connect-details-wrap" ).addClass('blur');
  124. $( "#diag-disconnect" ).slideDown( "fast", function() {});
  125. });
  126. $("#no-disconnect").on("click", function() {
  127. $( "#diag-disconnect" ).slideUp( "fast", function() {});
  128. $( "#connect-details-wrap" ).removeClass('blur');
  129. });
  130. $("#yes-disconnect").on("click", function() {
  131. stopCheckStatusInterval();
  132. selectedSSID = "";
  133. $( "#diag-disconnect" ).slideUp( "fast", function() {});
  134. $( "#connect-details-wrap" ).removeClass('blur');
  135. $.ajax({
  136. url: '/connect.json',
  137. dataType: 'text',
  138. method: 'DELETE',
  139. cache: false,
  140. contentType: 'application/json; charset=utf-8',
  141. data: JSON.stringify({ 'timestamp': Date.now()})
  142. });
  143. startCheckStatusInterval();
  144. $( "#connect-details" ).slideUp( "fast", function() {});
  145. $( "#wifi" ).slideDown( "fast", function() {})
  146. });
  147. $("input#show-nvs").on("click", function() {
  148. this.checked=this.checked?1:0;
  149. if(this.checked){
  150. $('a[href^="#tab-nvs"]').show();
  151. } else {
  152. $('a[href^="#tab-nvs"]').hide();
  153. }
  154. });
  155. $("input#autoexec-cb").on("click", function() {
  156. var data = { 'timestamp': Date.now() };
  157. autoexec = (this.checked)?1:0;
  158. data['autoexec'] = autoexec;
  159. showMessage('please wait for the ESP32 to reboot', 'WARNING');
  160. $.ajax({
  161. url: '/config.json',
  162. dataType: 'text',
  163. method: 'POST',
  164. cache: false,
  165. headers: { "X-Custom-autoexec": autoexec },
  166. contentType: 'application/json; charset=utf-8',
  167. data: JSON.stringify(data),
  168. error: function (xhr, ajaxOptions, thrownError) {
  169. console.log(xhr.status);
  170. console.log(thrownError);
  171. if (thrownError != '') showMessage(thrownError, 'ERROR');
  172. },
  173. complete: function(response) {
  174. //var returnedResponse = JSON.parse(response.responseText);
  175. console.log(response.responseText);
  176. console.log('sent config JSON with headers:', autoexec);
  177. console.log('now triggering reboot');
  178. $.ajax({
  179. url: '/reboot_ota.json',
  180. dataType: 'text',
  181. method: 'POST',
  182. cache: false,
  183. contentType: 'application/json; charset=utf-8',
  184. data: JSON.stringify({ 'timestamp': Date.now()}),
  185. error: function (xhr, ajaxOptions, thrownError) {
  186. console.log(xhr.status);
  187. console.log(thrownError);
  188. if (thrownError != '') showMessage(thrownError, 'ERROR');
  189. },
  190. complete: function(response) {
  191. console.log('reboot call completed');
  192. }
  193. });
  194. }
  195. });
  196. });
  197. $("input#save-autoexec1").on("click", function() {
  198. var data = { 'timestamp': Date.now() };
  199. autoexec1 = $("#autoexec1").val();
  200. data['autoexec1'] = autoexec1;
  201. $.ajax({
  202. url: '/config.json',
  203. dataType: 'text',
  204. method: 'POST',
  205. cache: false,
  206. headers: { "X-Custom-autoexec1": autoexec1 },
  207. contentType: 'application/json; charset=utf-8',
  208. data: JSON.stringify(data),
  209. error: function (xhr, ajaxOptions, thrownError) {
  210. console.log(xhr.status);
  211. console.log(thrownError);
  212. if (thrownError != '') showMessage(thrownError, 'ERROR');
  213. }
  214. });
  215. console.log('sent config JSON with headers:', autoexec1);
  216. console.log('sent data:', JSON.stringify(data));
  217. });
  218. $("input#save-gpio").on("click", function() {
  219. var data = { 'timestamp': Date.now() };
  220. var headers = {};
  221. $("input.gpio").each(function() {
  222. var id = $(this)[0].id;
  223. var pin = $(this).val();
  224. if (pin != '') {
  225. headers["X-Custom-"+id] = pin;
  226. data[id] = pin;
  227. }
  228. });
  229. $.ajax({
  230. url: '/config.json',
  231. dataType: 'text',
  232. method: 'POST',
  233. cache: false,
  234. headers: headers,
  235. contentType: 'application/json; charset=utf-8',
  236. data: JSON.stringify(data),
  237. error: function (xhr, ajaxOptions, thrownError) {
  238. console.log(xhr.status);
  239. console.log(thrownError);
  240. if (thrownError != '') showMessage(thrownError, 'ERROR');
  241. }
  242. });
  243. console.log('sent config JSON with headers:', JSON.stringify(headers));
  244. console.log('sent config JSON with data:', JSON.stringify(data));
  245. });
  246. $("#save-nvs").on("click", function() {
  247. var headers = {};
  248. var data = { 'timestamp': Date.now() };
  249. $("input.nvs").each(function() {
  250. var key = $(this)[0].id;
  251. var val = $(this).val();
  252. if (key != '') {
  253. headers["X-Custom-"+key] = val;
  254. data[key] = val;
  255. }
  256. });
  257. var key = $("#nvs-new-key").val();
  258. var val = $("#nvs-new-value").val();
  259. if (key != '') {
  260. headers["X-Custom-"+key] = val;
  261. data[key] = val;
  262. }
  263. $.ajax({
  264. url: '/config.json',
  265. dataType: 'text',
  266. method: 'POST',
  267. cache: false,
  268. headers: headers,
  269. contentType: 'application/json; charset=utf-8',
  270. data: JSON.stringify(data),
  271. error: function (xhr, ajaxOptions, thrownError) {
  272. console.log(xhr.status);
  273. console.log(thrownError);
  274. if (thrownError != '') showMessage(thrownError, 'ERROR');
  275. }
  276. });
  277. console.log('sent config JSON with headers:', JSON.stringify(headers));
  278. console.log('sent config JSON with data:', JSON.stringify(data));
  279. });
  280. $("#flash").on("click", function() {
  281. var data = { 'timestamp': Date.now() };
  282. if (blockFlashButton) return;
  283. blockFlashButton = true;
  284. var url = $("#fwurl").val();
  285. data['fwurl'] = url;
  286. $.ajax({
  287. url: '/config.json',
  288. dataType: 'text',
  289. method: 'POST',
  290. cache: false,
  291. headers: { "X-Custom-fwurl": url },
  292. contentType: 'application/json; charset=utf-8',
  293. data: JSON.stringify(data),
  294. error: function (xhr, ajaxOptions, thrownError) {
  295. console.log(xhr.status);
  296. console.log(thrownError);
  297. if (thrownError != '') showMessage(thrownError, 'ERROR');
  298. }
  299. });
  300. enableStatusTimer = true;
  301. });
  302. $("#generate-command").on("click", function() {
  303. var commandLine = commandHeader + '-n ' + $("#player").val();
  304. if (output == 'bt') {
  305. commandLine += ' -o "BT -n \'' + $("#btsink").val() + '\'" -R -Z 192000 -r "44100-44100"';
  306. } else if (output == 'spdif') {
  307. commandLine += ' -o SPDIF -R -Z 192000';
  308. } else {
  309. commandLine += ' -o I2S';
  310. }
  311. if ($("#optional").val() != '') {
  312. commandLine += ' ' + $("#optional").val();
  313. }
  314. $("#autoexec1").val(commandLine);
  315. });
  316. $('[name=audio]').on("click", function(){
  317. if (this.id == 'bt') {
  318. $("#btsinkdiv").show(200);
  319. output = 'bt';
  320. } else if (this.id == 'spdif') {
  321. $("#btsinkdiv").hide(200);
  322. output = 'spdif';
  323. } else {
  324. $("#btsinkdiv").hide(200);
  325. output = 'i2s';
  326. }
  327. });
  328. $('#fwcheck').on("click", function(){
  329. $("#releaseTable").html("");
  330. $.getJSON(releaseURL, function(data) {
  331. var i=0;
  332. data.forEach(function(release) {
  333. var url = '';
  334. release.assets.forEach(function(asset) {
  335. if (asset.name.match(/\.bin$/)) {
  336. url = asset.browser_download_url;
  337. }
  338. });
  339. var [ver, idf, cfg, branch] = release.name.split('#');
  340. var body = release.body;
  341. body = body.replace(/\'/ig, "\"");
  342. body = body.replace(/[\s\S]+(### Revision Log[\s\S]+)### ESP-IDF Version Used[\s\S]+/, "$1");
  343. body = body.replace(/- \(.+?\) /g, "- ");
  344. var [date, time] = release.created_at.split('T');
  345. var trclass = (i++ > 6)?' hide':'';
  346. $("#releaseTable").append(
  347. "<tr class='release"+trclass+"'>"+
  348. "<td data-toggle='tooltip' title='"+body+"'>"+ver+"</td>"+
  349. "<td>"+date+"</td>"+
  350. "<td>"+cfg+"</td>"+
  351. "<td>"+idf+"</td>"+
  352. "<td>"+branch+"</td>"+
  353. "<td><input id='generate-command' type='button' class='btn btn-success' value='Select' data-url='"+url+"' onclick='setURL(this);' /></td>"+
  354. "</tr>"
  355. );
  356. });
  357. if (i > 7) {
  358. $("#releaseTable").append(
  359. "<tr id='showall'>"+
  360. "<td colspan='6'>"+
  361. "<input type='button' id='showallbutton' class='btn btn-info' value='Show older releases' />"+
  362. "</td>"+
  363. "</tr>"
  364. );
  365. $('#showallbutton').on("click", function(){
  366. $("tr.hide").removeClass("hide");
  367. $("tr#showall").addClass("hide");
  368. });
  369. }
  370. $("#searchfw").css("display", "inline");
  371. })
  372. .fail(function() {
  373. alert("failed to fetch release history!");
  374. });
  375. });
  376. $('input#searchinput').on("input", function(){
  377. var s = $('input#searchinput').val();
  378. var re = new RegExp(s, "gi");
  379. if (s.length == 0) {
  380. $("tr.release").removeClass("hide");
  381. } else if (s.length < 3) {
  382. $("tr.release").addClass("hide");
  383. } else {
  384. $("tr.release").addClass("hide");
  385. $("tr.release").each(function(tr){
  386. $(this).find('td').each (function() {
  387. if ($(this).html().match(re)) {
  388. $(this).parent().removeClass('hide');
  389. }
  390. });
  391. });
  392. }
  393. });
  394. $('#boot-button').on("click", function(){
  395. enableStatusTimer = true;
  396. });
  397. $('#reboot-button').on("click", function(){
  398. enableStatusTimer = true;
  399. });
  400. $('#updateAP').on("click", function(){
  401. refreshAP(true);
  402. console.log("refresh AP");
  403. });
  404. //first time the page loads: attempt to get the connection status and start the wifi scan
  405. refreshAP(false);
  406. getConfig();
  407. //start timers
  408. startCheckStatusInterval();
  409. startRefreshAPInterval();
  410. $('[data-toggle="tooltip"]').tooltip({
  411. html: true,
  412. placement : 'right',
  413. });
  414. });
  415. function setURL(button) {
  416. var url = button.dataset.url;
  417. $("#fwurl").val(url);
  418. $('[data-url^="http"]').addClass("btn-success").removeClass("btn-danger");
  419. $('[data-url="'+url+'"]').addClass("btn-danger").removeClass("btn-success");
  420. }
  421. function performConnect(conntype){
  422. //stop the status refresh. This prevents a race condition where a status
  423. //request would be refreshed with wrong ip info from a previous connection
  424. //and the request would automatically shows as succesful.
  425. stopCheckStatusInterval();
  426. //stop refreshing wifi list
  427. stopRefreshAPInterval();
  428. var pwd;
  429. var dhcpname;
  430. if (conntype == 'manual') {
  431. //Grab the manual SSID and PWD
  432. selectedSSID=$('#manual_ssid').val();
  433. pwd = $("#manual_pwd").val();
  434. dhcpname= $("#dhcp-name2").val();;
  435. }else{
  436. pwd = $("#pwd").val();
  437. dhcpname= $("#dhcp-name1").val();;
  438. }
  439. //reset connection
  440. $( "#loading" ).show();
  441. $( "#connect-success" ).hide();
  442. $( "#connect-fail" ).hide();
  443. $( "#ok-connect" ).prop("disabled",true);
  444. $( "#ssid-wait" ).text(selectedSSID);
  445. $( "#connect" ).slideUp( "fast", function() {});
  446. $( "#connect_manual" ).slideUp( "fast", function() {});
  447. $( "#connect-wait" ).slideDown( "fast", function() {});
  448. $.ajax({
  449. url: '/connect.json',
  450. dataType: 'text',
  451. method: 'POST',
  452. cache: false,
  453. headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd, 'X-Custom-host_name': dhcpname },
  454. contentType: 'application/json; charset=utf-8',
  455. data: { 'timestamp': Date.now()},
  456. error: function (xhr, ajaxOptions, thrownError) {
  457. console.log(xhr.status);
  458. console.log(thrownError);
  459. if (thrownError != '') showMessage(thrownError, 'ERROR');
  460. }
  461. });
  462. //now we can re-set the intervals regardless of result
  463. startCheckStatusInterval();
  464. startRefreshAPInterval();
  465. }
  466. function rssiToIcon(rssi){
  467. if(rssi >= -60){
  468. return 'w0';
  469. }
  470. else if(rssi >= -67){
  471. return 'w1';
  472. }
  473. else if(rssi >= -75){
  474. return 'w2';
  475. }
  476. else{
  477. return 'w3';
  478. }
  479. }
  480. function refreshAP(force){
  481. if (!enableAPTimer && !force) return;
  482. $.getJSON( "/ap.json", function( data ) {
  483. if(data.length > 0){
  484. //sort by signal strength
  485. data.sort(function (a, b) {
  486. var x = a["rssi"]; var y = b["rssi"];
  487. return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  488. });
  489. apList = data;
  490. refreshAPHTML(apList);
  491. }
  492. });
  493. }
  494. function refreshAPHTML(data){
  495. var h = "";
  496. data.forEach(function(e, idx, array) {
  497. h += '<div class="ape{0}"><div class="{1}"><div class="{2}">{3}</div></div></div>'.format(idx === array.length - 1?'':' brdb', rssiToIcon(e.rssi), e.auth==0?'':'pw',e.ssid);
  498. h += "\n";
  499. });
  500. $( "#wifi-list" ).html(h)
  501. }
  502. function checkStatus(){
  503. RepeatCheckStatusInterval();
  504. if (!enableStatusTimer) return;
  505. if (blockAjax) return;
  506. blockAjax = true;
  507. $.getJSON( "/status.json", function( data ) {
  508. if (data.hasOwnProperty('ssid') && data['ssid'] != ""){
  509. if (data["ssid"] === selectedSSID){
  510. //that's a connection attempt
  511. if (data["urc"] === 0){
  512. //got connection
  513. $("#connected-to span").text(data["ssid"]);
  514. $("#connect-details h1").text(data["ssid"]);
  515. $("#ip").text(data["ip"]);
  516. $("#netmask").text(data["netmask"]);
  517. $("#gw").text(data["gw"]);
  518. $("#wifi-status").slideDown( "fast", function() {});
  519. $("span#foot-wifi").html(", SSID: <strong>"+data["ssid"]+"</strong>, IP: <strong>"+data["ip"]+"</strong>");
  520. //unlock the wait screen if needed
  521. $( "#ok-connect" ).prop("disabled",false);
  522. //update wait screen
  523. $( "#loading" ).hide();
  524. $( "#connect-success" ).text("Your IP address now is: " + data["ip"] );
  525. $( "#connect-success" ).show();
  526. $( "#connect-fail" ).hide();
  527. enableAPTimer = false;
  528. if (!recovery) enableStatusTimer = false;
  529. }
  530. else if (data["urc"] === 1){
  531. //failed attempt
  532. $("#connected-to span").text('');
  533. $("#connect-details h1").text('');
  534. $("#ip").text('0.0.0.0');
  535. $("#netmask").text('0.0.0.0');
  536. $("#gw").text('0.0.0.0');
  537. $("span#foot-wifi").html("");
  538. //don't show any connection
  539. $("#wifi-status").slideUp( "fast", function() {});
  540. //unlock the wait screen
  541. $( "#ok-connect" ).prop("disabled",false);
  542. //update wait screen
  543. $( "#loading" ).hide();
  544. $( "#connect-fail" ).show();
  545. $( "#connect-success" ).hide();
  546. enableAPTimer = true;
  547. enableStatusTimer = true;
  548. }
  549. }
  550. else if (data.hasOwnProperty('urc') && data['urc'] === 0){
  551. //ESP32 is already connected to a wifi without having the user do anything
  552. if( !($("#wifi-status").is(":visible")) ){
  553. $("#connected-to span").text(data["ssid"]);
  554. $("#connect-details h1").text(data["ssid"]);
  555. $("#ip").text(data["ip"]);
  556. $("#netmask").text(data["netmask"]);
  557. $("#gw").text(data["gw"]);
  558. $("#wifi-status").slideDown( "fast", function() {});
  559. $("span#foot-wifi").html(", SSID: <strong>"+data["ssid"]+"</strong>, IP: <strong>"+data["ip"]+"</strong>");
  560. }
  561. enableAPTimer = false;
  562. if (!recovery) enableStatusTimer = false;
  563. }
  564. }
  565. else if (data.hasOwnProperty('urc') && data['urc'] === 2){
  566. //that's a manual disconnect
  567. if($("#wifi-status").is(":visible")){
  568. $("#wifi-status").slideUp( "fast", function() {});
  569. $("span#foot-wifi").html("");
  570. }
  571. enableAPTimer = true;
  572. enableStatusTimer = true;
  573. }
  574. if (data.hasOwnProperty('recovery')) {
  575. if(LastRecoveryState != data["recovery"]){
  576. LastRecoveryState = data["recovery"];
  577. $("input#show-nvs")[0].checked=LastRecoveryState==1?true:false;
  578. }
  579. if($("input#show-nvs")[0].checked){
  580. $('a[href^="#tab-nvs"]').show();
  581. } else{
  582. $('a[href^="#tab-nvs"]').hide();
  583. }
  584. if (data["recovery"] === 1) {
  585. recovery = true;
  586. $("#otadiv").show();
  587. $('a[href^="#tab-audio"]').hide();
  588. $('a[href^="#tab-gpio"]').show();
  589. $("footer.footer").removeClass('sl');
  590. $("footer.footer").addClass('recovery');
  591. $("#boot-button").html('Reboot');
  592. $("#boot-form").attr('action', '/reboot_ota.json');
  593. enableStatusTimer = true;
  594. } else {
  595. recovery = false;
  596. $("#otadiv").hide();
  597. $('a[href^="#tab-audio"]').show();
  598. $('a[href^="#tab-gpio"]').hide();
  599. $("footer.footer").removeClass('recovery');
  600. $("footer.footer").addClass('sl');
  601. $("#boot-button").html('Recovery');
  602. $("#boot-form").attr('action', '/recovery.json');
  603. enableStatusTimer = false;
  604. }
  605. }
  606. if (data.hasOwnProperty('project_name') && data['project_name'] != ''){
  607. pname = data['project_name'];
  608. }
  609. if (data.hasOwnProperty('version') && data['version'] != ''){
  610. ver = data['version'];
  611. $("span#foot-fw").html("fw: <strong>"+ver+"</strong>, mode: <strong>"+pname+"</strong>");
  612. }
  613. if (data.hasOwnProperty('ota_pct') && data['ota_pct'] != 0){
  614. otapct = data['ota_pct'];
  615. $('.progress-bar').css('width', otapct+'%').attr('aria-valuenow', otapct);
  616. $('.progress-bar').html(otapct+'%');
  617. }
  618. if (data.hasOwnProperty('ota_dsc') && data['ota_dsc'] != ''){
  619. otadsc = data['ota_dsc'];
  620. $("span#flash-status").html(otadsc);
  621. if (otadsc.match(/Error:/) || otapct > 95) {
  622. blockFlashButton = false;
  623. enableStatusTimer = true;
  624. }
  625. } else {
  626. $("span#flash-status").html('');
  627. }
  628. if (data.hasOwnProperty('message') && data['message'] != ''){
  629. var msg = data['message'].text;
  630. var severity = data['message'].severity;
  631. if (msg != lastMsg) {
  632. showMessage(msg, severity);
  633. lastMsg = msg;
  634. }
  635. }
  636. blockAjax = false;
  637. })
  638. .fail(function(xhr, ajaxOptions, thrownError) {
  639. console.log(xhr.status);
  640. console.log(thrownError);
  641. if (thrownError != '') showMessage(thrownError, 'ERROR');
  642. blockAjax = false;
  643. });
  644. }
  645. function getConfig() {
  646. $.getJSON("/config.json", function(data) {
  647. Object.keys(data).sort().forEach(function(key, i) {
  648. if (data.hasOwnProperty(key)) {
  649. if (key == 'autoexec') {
  650. if (data["autoexec"] === "1") {
  651. $("#autoexec-cb")[0].checked=true;
  652. } else {
  653. $("#autoexec-cb")[0].checked=false;
  654. }
  655. } else if (key == 'autoexec1') {
  656. $("textarea#autoexec1").val(data[key]);
  657. } else if (key == 'host_name') {
  658. $("dhcp-name1").val(data[key]);
  659. $("dhcp-name2").val(data[key]);
  660. }
  661. $("tbody#nvsTable").append(
  662. "<tr>"+
  663. "<td>"+key+"</td>"+
  664. "<td class='value'>"+
  665. "<input type='text' class='form-control nvs' id='"+key+"'>"+
  666. "</td>"+
  667. "</tr>"
  668. );
  669. $("input#"+key).val(data[key]);
  670. }
  671. });
  672. $("tbody#nvsTable").append(
  673. "<tr>"+
  674. "<td>"+
  675. "<input type='text' class='form-control' id='nvs-new-key' placeholder='new key'>"+
  676. "</td>"+
  677. "<td>"+
  678. "<input type='text' class='form-control' id='nvs-new-value' placeholder='new value'>"+
  679. "</td>"+
  680. "</tr>"
  681. );
  682. })
  683. .fail(function(xhr, ajaxOptions, thrownError) {
  684. console.log(xhr.status);
  685. console.log(thrownError);
  686. if (thrownError != '') showMessage(thrownError, 'ERROR');
  687. blockAjax = false;
  688. });
  689. }
  690. function showMessage(message, severity) {
  691. if (severity == 'INFO') {
  692. $('#message').css('background', '#6af');
  693. } else if (severity == 'WARNING') {
  694. $('#message').css('background', '#ff0');
  695. } else {
  696. $('#message').css('background', '#f00');
  697. }
  698. $('#message').html(message);
  699. $("#content").fadeTo("slow", 0.3, function() {
  700. $("#message").show(500).delay(5000).hide(500, function() {
  701. $("#content").fadeTo("slow", 1.0);
  702. });
  703. });
  704. }