code.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. var recovery = 0;
  2. var enableTimers = true;
  3. var commandHeader = 'squeezelite -b 500:2000 -d all=info ';
  4. // First, checks if it isn't implemented yet.
  5. if (!String.prototype.format) {
  6. String.prototype.format = function() {
  7. var args = arguments;
  8. return this.replace(/{(\d+)}/g, function(match, number) {
  9. return typeof args[number] != 'undefined'
  10. ? args[number]
  11. : match
  12. ;
  13. });
  14. };
  15. }
  16. var apList = null;
  17. var selectedSSID = "";
  18. var refreshAPInterval = null;
  19. var checkStatusInterval = null;
  20. var StatusIntervalActive = false;
  21. var ConfigIntervalActive = false;
  22. var RefreshAPIIntervalActive = false;
  23. function stopCheckStatusInterval(){
  24. if(checkStatusInterval != null){
  25. clearTimeout(checkStatusInterval);
  26. checkStatusInterval = null;
  27. }
  28. StatusIntervalActive = false;
  29. }
  30. function stopRefreshAPInterval(){
  31. if(refreshAPInterval != null){
  32. clearTimeout(refreshAPInterval);
  33. refreshAPInterval = null;
  34. }
  35. RefreshAPIIntervalActive = false;
  36. }
  37. function startCheckStatusInterval(){
  38. StatusIntervalActive = true;
  39. checkStatusInterval = setTimeout(checkStatus, 950);
  40. }
  41. function startRefreshAPInterval(){
  42. RefreshAPIIntervalActive = true;
  43. refreshAPInterval = setTimeout(refreshAP, 2800);
  44. }
  45. function RepeatCheckStatusInterval(){
  46. if(StatusIntervalActive)
  47. startCheckStatusInterval();
  48. }
  49. function RepeatCheckConfigInterval(){
  50. if(ConfigIntervalActive)
  51. startCheckConfigInterval();
  52. }
  53. function RepeatRefreshAPInterval(){
  54. if(RefreshAPIIntervalActive)
  55. startRefreshAPInterval()
  56. }
  57. $(document).ready(function(){
  58. $("#wifi-status").on("click", ".ape", function() {
  59. $( "#wifi" ).slideUp( "fast", function() {});
  60. $( "#connect-details" ).slideDown( "fast", function() {});
  61. });
  62. $("#manual_add").on("click", ".ape", function() {
  63. selectedSSID = $(this).text();
  64. $( "#ssid-pwd" ).text(selectedSSID);
  65. $( "#wifi" ).slideUp( "fast", function() {});
  66. $( "#connect_manual" ).slideDown( "fast", function() {});
  67. $( "#connect" ).slideUp( "fast", function() {});
  68. //update wait screen
  69. $( "#loading" ).show();
  70. $( "#connect-success" ).hide();
  71. $( "#connect-fail" ).hide();
  72. });
  73. $("#wifi-list").on("click", ".ape", function() {
  74. selectedSSID = $(this).text();
  75. $( "#ssid-pwd" ).text(selectedSSID);
  76. $( "#wifi" ).slideUp( "fast", function() {});
  77. $( "#connect_manual" ).slideUp( "fast", function() {});
  78. $( "#connect" ).slideDown( "fast", function() {});
  79. //update wait screen
  80. $( "#loading" ).show();
  81. $( "#connect-success" ).hide();
  82. $( "#connect-fail" ).hide();
  83. });
  84. $("#cancel").on("click", function() {
  85. selectedSSID = "";
  86. $( "#connect" ).slideUp( "fast", function() {});
  87. $( "#connect_manual" ).slideUp( "fast", function() {});
  88. $( "#wifi" ).slideDown( "fast", function() {});
  89. });
  90. $("#manual_cancel").on("click", function() {
  91. selectedSSID = "";
  92. $( "#connect" ).slideUp( "fast", function() {});
  93. $( "#connect_manual" ).slideUp( "fast", function() {});
  94. $( "#wifi" ).slideDown( "fast", function() {});
  95. });
  96. $("#join").on("click", function() {
  97. performConnect();
  98. });
  99. $("#manual_join").on("click", function() {
  100. performConnect($(this).data('connect'));
  101. });
  102. $("#ok-details").on("click", function() {
  103. $( "#connect-details" ).slideUp( "fast", function() {});
  104. $( "#wifi" ).slideDown( "fast", function() {});
  105. });
  106. $("#ok-credits").on("click", function() {
  107. $( "#credits" ).slideUp( "fast", function() {});
  108. $( "#app" ).slideDown( "fast", function() {});
  109. });
  110. $("#acredits").on("click", function(event) {
  111. event.preventDefault();
  112. $( "#app" ).slideUp( "fast", function() {});
  113. $( "#credits" ).slideDown( "fast", function() {});
  114. });
  115. $("#ok-connect").on("click", function() {
  116. $( "#connect-wait" ).slideUp( "fast", function() {});
  117. $( "#wifi" ).slideDown( "fast", function() {});
  118. });
  119. $("#disconnect").on("click", function() {
  120. $( "#connect-details-wrap" ).addClass('blur');
  121. $( "#diag-disconnect" ).slideDown( "fast", function() {});
  122. });
  123. $("#no-disconnect").on("click", function() {
  124. $( "#diag-disconnect" ).slideUp( "fast", function() {});
  125. $( "#connect-details-wrap" ).removeClass('blur');
  126. });
  127. $("#yes-disconnect").on("click", function() {
  128. stopCheckStatusInterval();
  129. selectedSSID = "";
  130. $( "#diag-disconnect" ).slideUp( "fast", function() {});
  131. $( "#connect-details-wrap" ).removeClass('blur');
  132. $.ajax({
  133. url: '/connect.json',
  134. dataType: 'json',
  135. method: 'DELETE',
  136. cache: false,
  137. data: { 'timestamp': Date.now()}
  138. });
  139. startCheckStatusInterval();
  140. $( "#connect-details" ).slideUp( "fast", function() {});
  141. $( "#wifi" ).slideDown( "fast", function() {})
  142. });
  143. $("#update-command").click(function() {
  144. updateAutoexec();
  145. });
  146. $("#generate-command").click(function() {
  147. generateCommand();
  148. });
  149. $('[name=audio]').click(function(){
  150. selectOutput(this);
  151. });
  152. if (recovery) {
  153. $("#recoverydiv").hide();
  154. $("#otadiv").show();
  155. $("#command_line").hide();
  156. $("#wifi").hide();
  157. } else {
  158. $("#recoverydiv").show();
  159. $("#otadiv").hide();
  160. }
  161. //first time the page loads: attempt to get the connection status and start the wifi scan
  162. refreshAP();
  163. getConfig();
  164. //start timers
  165. startCheckStatusInterval();
  166. startRefreshAPInterval();
  167. });
  168. function performConnect(conntype){
  169. //stop the status refresh. This prevents a race condition where a status
  170. //request would be refreshed with wrong ip info from a previous connection
  171. //and the request would automatically shows as succesful.
  172. stopCheckStatusInterval();
  173. //stop refreshing wifi list
  174. stopRefreshAPInterval();
  175. var pwd;
  176. if (conntype == 'manual') {
  177. //Grab the manual SSID and PWD
  178. selectedSSID=$('#manual_ssid').val();
  179. pwd = $("#manual_pwd").val();
  180. }else{
  181. pwd = $("#pwd").val();
  182. }
  183. //reset connection
  184. $( "#loading" ).show();
  185. $( "#connect-success" ).hide();
  186. $( "#connect-fail" ).hide();
  187. $( "#ok-connect" ).prop("disabled",true);
  188. $( "#ssid-wait" ).text(selectedSSID);
  189. $( "#connect" ).slideUp( "fast", function() {});
  190. $( "#connect_manual" ).slideUp( "fast", function() {});
  191. $( "#connect-wait" ).slideDown( "fast", function() {});
  192. $.ajax({
  193. url: '/connect.json',
  194. dataType: 'json',
  195. method: 'POST',
  196. cache: false,
  197. headers: { 'X-Custom-ssid': selectedSSID, 'X-Custom-pwd': pwd },
  198. data: { 'timestamp': Date.now()}
  199. });
  200. //now we can re-set the intervals regardless of result
  201. startCheckStatusInterval();
  202. startRefreshAPInterval();
  203. }
  204. function rssiToIcon(rssi){
  205. if(rssi >= -60){
  206. return 'w0';
  207. }
  208. else if(rssi >= -67){
  209. return 'w1';
  210. }
  211. else if(rssi >= -75){
  212. return 'w2';
  213. }
  214. else{
  215. return 'w3';
  216. }
  217. }
  218. function refreshAP(){
  219. if (!enableTimers) return;
  220. $.getJSON( "/ap.json", function( data ) {
  221. if(data.length > 0){
  222. //sort by signal strength
  223. data.sort(function (a, b) {
  224. var x = a["rssi"]; var y = b["rssi"];
  225. return ((x < y) ? 1 : ((x > y) ? -1 : 0));
  226. });
  227. apList = data;
  228. refreshAPHTML(apList);
  229. }
  230. });
  231. }
  232. function refreshAPHTML(data){
  233. var h = "";
  234. data.forEach(function(e, idx, array) {
  235. 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);
  236. h += "\n";
  237. });
  238. $( "#wifi-list" ).html(h)
  239. }
  240. function checkStatus(){
  241. if (!enableTimers) return;
  242. $.getJSON( "/status.json", function( data ) {
  243. if(data.hasOwnProperty('ssid') && data['ssid'] != ""){
  244. if(data["ssid"] === selectedSSID){
  245. //that's a connection attempt
  246. if(data["urc"] === 0){
  247. //got connection
  248. $("#connected-to span").text(data["ssid"]);
  249. $("#connect-details h1").text(data["ssid"]);
  250. $("#ip").text(data["ip"]);
  251. $("#netmask").text(data["netmask"]);
  252. $("#gw").text(data["gw"]);
  253. $("#wifi-status").slideDown( "fast", function() {});
  254. //unlock the wait screen if needed
  255. $( "#ok-connect" ).prop("disabled",false);
  256. //update wait screen
  257. $( "#loading" ).hide();
  258. $( "#connect-success" ).append("<p>Your IP address now is: " + text(data["ip"]) + "</p>");
  259. $( "#connect-success" ).show();
  260. $( "#connect-fail" ).hide();
  261. enableTimers = false;
  262. }
  263. else if(data["urc"] === 1){
  264. //failed attempt
  265. $("#connected-to span").text('');
  266. $("#connect-details h1").text('');
  267. $("#ip").text('0.0.0.0');
  268. $("#netmask").text('0.0.0.0');
  269. $("#gw").text('0.0.0.0');
  270. //don't show any connection
  271. $("#wifi-status").slideUp( "fast", function() {});
  272. //unlock the wait screen
  273. $( "#ok-connect" ).prop("disabled",false);
  274. //update wait screen
  275. $( "#loading" ).hide();
  276. $( "#connect-fail" ).show();
  277. $( "#connect-success" ).hide();
  278. enableTimers = true;
  279. }
  280. }
  281. else if(data.hasOwnProperty('urc') && data['urc'] === 0){
  282. //ESP32 is already connected to a wifi without having the user do anything
  283. if( !($("#wifi-status").is(":visible")) ){
  284. $("#connected-to span").text(data["ssid"]);
  285. $("#connect-details h1").text(data["ssid"]);
  286. $("#ip").text(data["ip"]);
  287. $("#netmask").text(data["netmask"]);
  288. $("#gw").text(data["gw"]);
  289. $("#wifi-status").slideDown( "fast", function() {});
  290. }
  291. enableTimers = false;
  292. }
  293. }
  294. else if(data.hasOwnProperty('urc') && data['urc'] === 2){
  295. //that's a manual disconnect
  296. if($("#wifi-status").is(":visible")){
  297. $("#wifi-status").slideUp( "fast", function() {});
  298. }
  299. enableTimers = true;
  300. }
  301. })
  302. .fail(function() {
  303. //don't do anything, the server might be down while esp32 recalibrates radio
  304. });
  305. RepeatCheckStatusInterval();
  306. }
  307. function getConfig() {
  308. $.getJSON("/config.json", function(data) {
  309. if (data.hasOwnProperty('autoexec')) {
  310. if (data["autoexec"] === 1) {
  311. console.log('turn on autoexec');
  312. $("#autoexec-cb")[0].checked=true;
  313. } else {
  314. console.log('turn off autoexec');
  315. $("#autoexec-cb")[0].checked=false;
  316. $("#autoexec-command").hide(200);
  317. }
  318. }
  319. if (data.hasOwnProperty('list')) {
  320. data.list.forEach(function(line) {
  321. let key = Object.keys(line)[0];
  322. let val = Object.values(line)[0];
  323. console.log(key, val);
  324. if (key == 'autoexec1') {
  325. $("#autoexec1").val(val);
  326. }
  327. });
  328. }
  329. })
  330. .fail(function() {
  331. console.log("failed to fetch config!");
  332. });
  333. }
  334. function updateAutoexec(){
  335. autoexec = ($("#autoexec-cb")[0].checked)?1:0;
  336. autoexec1 = $("#autoexec1").val();
  337. $.ajax({
  338. url: '/config.json',
  339. dataType: 'json',
  340. method: 'POST',
  341. cache: false,
  342. headers: { "X-Custom-autoexec": autoexec, "X-Custom-autoexec1": autoexec1 },
  343. data: { 'timestamp': Date.now() }
  344. });
  345. console.log('sent config JSON with headers:', autoexec, autoexec1);
  346. }
  347. function performFactory(){
  348. // $( "#ok-connect" ).prop("disabled",true);
  349. // $( "#ssid-wait" ).text(selectedSSID);
  350. // $( "#connect" ).slideUp( "fast", function() {});
  351. // $( "#connect_manual" ).slideUp( "fast", function() {});
  352. // $( "#connect-wait" ).slideDown( "fast", function() {});
  353. // // todo: should we update the UI here?
  354. $.ajax({
  355. url: '/factory.json',
  356. dataType: 'json',
  357. method: 'POST',
  358. cache: false,
  359. data: { 'timestamp': Date.now()}
  360. });
  361. }
  362. var output = '';
  363. function selectOutput(el) {
  364. if ($(el).attr('id') == 'bt') {
  365. $("#btsinkdiv").show(200);
  366. output = 'bt';
  367. } else if ($(el).attr('id') == 'spdif') {
  368. $("#btsinkdiv").hide(200);
  369. output = 'spdif';
  370. } else {
  371. $("#btsinkdiv").hide(200);
  372. output = 'i2s';
  373. }
  374. }
  375. function generateCommand() {
  376. var commandLine = commandHeader + '-n ' + $("#player").val();
  377. if (output == 'bt') {
  378. commandLine += ' -o "BT -n \'' + $("#btsink").val() + '\'" -R -Z 192000';
  379. } else if (output == 'spdif') {
  380. commandLine += ' -o SPDIF -R -Z 192000';
  381. } else {
  382. commandLine += ' -o I2S';
  383. }
  384. if ($("#optional").val() != '') {
  385. commandLine += ' ' + $("#optional").val();
  386. }
  387. $("#autoexec1").val(commandLine);
  388. }