import he from 'he';
import { Promise } from 'es6-promise';
if (!String.prototype.format) {
Object.assign(String.prototype, {
format() {
const args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] !== 'undefined' ? args[number] : match;
});
},
});
}
if (!String.prototype.encodeHTML) {
Object.assign(String.prototype, {
encodeHTML() {
return he.encode(this).replace(/\n/g, '
')
},
});
}
Object.assign(Date.prototype, {
toLocalShort() {
const opt = { dateStyle: 'short', timeStyle: 'short' };
return this.toLocaleString(undefined, opt);
},
});
const nvsTypes = {
NVS_TYPE_U8: 0x01,
/*! < Type uint8_t */
NVS_TYPE_I8: 0x11,
/*! < Type int8_t */
NVS_TYPE_U16: 0x02,
/*! < Type uint16_t */
NVS_TYPE_I16: 0x12,
/*! < Type int16_t */
NVS_TYPE_U32: 0x04,
/*! < Type uint32_t */
NVS_TYPE_I32: 0x14,
/*! < Type int32_t */
NVS_TYPE_U64: 0x08,
/*! < Type uint64_t */
NVS_TYPE_I64: 0x18,
/*! < Type int64_t */
NVS_TYPE_STR: 0x21,
/*! < Type string */
NVS_TYPE_BLOB: 0x42,
/*! < Type blob */
NVS_TYPE_ANY: 0xff /*! < Must be last */,
};
const btIcons = {
bt_playing: 'play-circle-fill',
bt_disconnected: 'bluetooth-fill',
bt_neutral: '',
bt_connected: 'bluetooth-connect-fill',
bt_disabled: '',
play_arrow: 'play-circle-fill',
pause: 'pause-circle-fill',
stop: 'stop-circle-fill',
'': '',
};
const btStateIcons = [
{ desc: 'Idle', sub: ['bt_neutral'] },
{ desc: 'Discovering', sub: ['bt_disconnected'] },
{ desc: 'Discovered', sub: ['bt_disconnected'] },
{ desc: 'Unconnected', sub: ['bt_disconnected'] },
{ desc: 'Connecting', sub: ['bt_disconnected'] },
{
desc: 'Connected',
sub: ['bt_connected', 'play_arrow', 'bt_playing', 'pause', 'stop'],
},
{ desc: 'Disconnecting', sub: ['bt_disconnected'] },
];
const pillcolors = {
MESSAGING_INFO: 'badge-success',
MESSAGING_WARNING: 'badge-warning',
MESSAGING_ERROR: 'badge-danger',
};
const connectReturnCode = {
UPDATE_CONNECTION_OK : 0,
UPDATE_FAILED_ATTEMPT : 1,
UPDATE_USER_DISCONNECT : 2,
UPDATE_LOST_CONNECTION : 3,
UPDATE_FAILED_ATTEMPT_AND_RESTORE : 4
}
const taskStates = {
0: 'eRunning',
/*! < A task is querying the state of itself, so must be running. */
1: 'eReady',
/*! < The task being queried is in a read or pending ready list. */
2: 'eBlocked',
/*! < The task being queried is in the Blocked state. */
3: 'eSuspended',
/*! < The task being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */
4: 'eDeleted',
};
const flash_status_codes = {
NONE : 0,
REBOOT_TO_RECOVERY: 2,
SET_FWURL: 5,
FLASHING: 6,
DONE: 7,
UPLOADING: 8,
ERROR: 9
};
let flash_state=flash_status_codes.FLASH_NONE;
let flash_ota_dsc='';
let flash_ota_pct=0;
let older_recovery=false;
function isFlashExecuting(data){
return (flash_state!=flash_status_codes.UPLOADING ) && (data.ota_dsc!='' || data.ota_pct>0);
}
function post_config(data){
let confPayload={
timestamp: Date.now(),
config : data
};
$.ajax({
url: '/config.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(confPayload),
error: handleExceptionResponse,
});
}
function process_ota_event(data){
if(data.ota_dsc){
flash_ota_dsc=data.ota_dsc;
}
if( data.ota_pct != undefined){
flash_ota_pct=data.ota_pct;
}
if(flash_state==flash_status_codes.ERROR){
return;
}
else if(isFlashExecuting(data)){
flash_state=flash_status_codes.FLASHING;
}
else if(flash_state==flash_status_codes.FLASHING ){
if(flash_ota_pct ==100){
// we were processing OTA, and we've reached 100%
flash_state=flash_status_codes.DONE;
$('#flashfilename').val('');
}
else if(flash_ota_pct<0 && older_recovery){
// we were processing OTA on an older recovery and we missed the
// end of flashing.
console.log('End of flashing from older recovery');
if(data.ota_dsc==''){
flash_ota_dsc = 'OTA Process Completed';
}
flash_state=flash_status_codes.DONE;
}
}
else if(flash_state ==flash_status_codes.UPLOADING){
if(flash_ota_pct ==100){
// we were processing OTA, and we've reached 100%
// reset the progress bar
flash_ota_pct = 0;
flash_state=flash_status_codes.FLASHING;
}
}
}
function set_ota_error(message){
flash_state=flash_status_codes.ERROR;
handle_flash_state({
ota_pct: 0,
ota_dsc: message,
event: flash_events.SET_ERROR
});
}
function show_update_dialog(){
$('#otadiv').modal();
if (flash_ota_pct >= 0) {
update_progress();
}
if (flash_ota_dsc !== '') {
$('span#flash-status').html(flash_ota_dsc);
}
}
const flash_events={
SET_ERROR: function(data){
if(data.ota_dsc){
flash_ota_dsc=data.ota_dsc;
}
else {
flash_ota_dsc = 'Error';
}
flash_ota_pct=data.ota_pct??0;
$('#fwProgressLabel').parent().addClass('bg-danger');
update_progress();
show_update_dialog();
},
START_OTA : function() {
if (flash_state == flash_status_codes.NONE || flash_state == flash_status_codes.ERROR || flash_state == undefined) {
$('#fwProgressLabel').parent().removeClass('bg-danger');
flash_state=flash_status_codes.REBOOT_TO_RECOVERY;
if(!recovery){
flash_ota_dsc = 'Starting recovery mode...';
// Reboot system to recovery mode
const data = {
timestamp: Date.now(),
};
$.ajax({
url: '/recovery.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
error: function(xhr, _ajaxOptions, thrownError){
set_ota_error(`Unexpected error while trying to restart to recovery. (status=${xhr.status??''}, error=${thrownError??''} ) `);
},
complete: function(response) {
console.log(response.responseText);
},
});
}
else {
flash_ota_dsc='Starting Update';
}
show_update_dialog();
}
else {
console.warn('Unexpected status while starting flashing');
}
},
FOUND_RECOVERY: function(data) {
console.log(JSON.stringify(data));
const url=$('#fw-url-input').val();
if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){
const fileInput = $('#flashfilename')[0].files;
if (fileInput.length > 0) {
flash_ota_dsc = 'Sending file to device.';
flash_state= flash_status_codes.UPLOADING;
const uploadPath = '/flash.json';
const xhttp = new XMLHttpRequest();
// xhrObj.upload.addEventListener("loadstart", loadStartFunction, false);
xhttp.upload.addEventListener("progress", progressFunction, false);
//xhrObj.upload.addEventListener("load", transferCompleteFunction, false);
xhttp.onreadystatechange = function() {
if (xhttp.readyState === 4) {
if(xhttp.status === 0 || xhttp.status === 404) {
set_ota_error(`Upload Failed. Recovery version might not support uploading. Please use web update instead.`);
$('#flashfilename').val('');
}
}
};
xhttp.open('POST', uploadPath, true);
xhttp.send(fileInput[0] );
}
else if(url==''){
flash_state= flash_status_codes.NONE;
}
else {
flash_ota_dsc = 'Saving firmware URL location.';
flash_state= flash_status_codes.SET_FWURL;
let confData= { fwurl: {
value: $('#fw-url-input').val(),
type: 33,
}
};
post_config(confData);
}
show_update_dialog();
}
},
PROCESS_OTA_UPLOAD: function(data){
flash_state= flash_status_codes.UPLOADING;
process_ota_event(data);
show_update_dialog();
},
PROCESS_OTA_STATUS: function(data){
if(data.ota_pct>0){
older_recovery = true;
}
if(flash_state == flash_status_codes.REBOOT_TO_RECOVERY){
data.event = flash_events.FOUND_RECOVERY;
handle_flash_state(data);
}
else if(flash_state==flash_status_codes.DONE && !recovery){
flash_state=flash_status_codes.NONE;
$('#rTable tr.release').removeClass('table-success table-warning');
$('#fw-url-input').val('');
}
else {
process_ota_event(data);
if(flash_state && (flash_state >flash_status_codes.NONE && flash_ota_pct>=0) ) {
show_update_dialog();
}
}
},
PROCESS_OTA: function(data) {
process_ota_event(data);
if(flash_state && (flash_state >flash_status_codes.NONE && flash_ota_pct>=0) ) {
show_update_dialog();
}
}
};
window.hideSurrounding = function(obj){
$(obj).parent().parent().hide();
}
function update_progress(){
$('.progress-bar')
.css('width', flash_ota_pct + '%')
.attr('aria-valuenow', flash_ota_pct)
.text(flash_ota_pct+'%')
$('.progress-bar').html((flash_state==flash_status_codes.DONE?100:flash_ota_pct) + '%');
}
function handle_flash_state(data) {
if(data.event) {
data.event(data);
}
else {
console.error('Unexpected error while processing handle_flash_state');
return;
}
}
window.hFlash = function(){
// reset file upload selection if any;
$('#flashfilename').val('');
handle_flash_state({ event: flash_events.START_OTA, url: $('#fw-url-input').val() });
}
window.handleReboot = function(link){
if(link=='reboot_ota'){
$('#reboot_ota_nav').removeClass('active').prop("disabled",true); delayReboot(500,'', 'reboot_ota');
}
else {
$('#reboot_nav').removeClass('active'); delayReboot(500,'',link);
}
}
function progressFunction(evt){
// if (evt.lengthComputable) {
// progressBar.max = evt.total;
// progressBar.value = evt.loaded;
// percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";
// }
handle_flash_state({
ota_pct: ( Math.round(evt.loaded / evt.total * 100)),
ota_dsc: ('Uploading file to device'),
event: flash_events.PROCESS_OTA_UPLOAD
});
}
function handlebtstate(data) {
let icon = '';
let tt = '';
if (data.bt_status !== undefined && data.bt_sub_status !== undefined) {
const iconsvg = btStateIcons[data.bt_status].sub[data.bt_sub_status];
if (iconsvg) {
icon = `#${btIcons[iconsvg]}`;
tt = btStateIcons[data.bt_status].desc;
} else {
icon = `#${btIcons.bt_connected}`;
tt = 'Output status';
}
}
$('#o_type').title = tt;
$('#o_bt').attr('xlink:href',icon);
}
function handleTemplateTypeRadio(outtype) {
if (outtype === 'bt') {
$('#bt').prop('checked', true);
$('#o_bt').attr('display', 'inline');
$('#o_spdif').attr('display', 'none');
$('#o_i2s').attr('display', 'none');
output = 'bt';
} else if (outtype === 'spdif') {
$('#spdif').prop('checked', true);
$('#o_bt').attr('display', 'none');
$('#o_spdif').attr('display', 'inline');
$('#o_i2s').attr('display', 'none');
output = 'spdif';
} else {
$('#i2s').prop('checked', true);
$('#o_bt').attr('display', 'none');
$('#o_spdif').attr('display', 'none');
$('#o_i2s').attr('display', 'inline');
output = 'i2s';
}
}
function handleExceptionResponse(xhr, _ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
if (thrownError !== '') {
showLocalMessage(thrownError, 'MESSAGING_ERROR');
}
}
function HideCmdMessage(cmdname) {
$('#toast_' + cmdname).css('display', 'none');
$('#toast_' + cmdname)
.removeClass('table-success')
.removeClass('table-warning')
.removeClass('table-danger')
.addClass('table-success');
$('#msg_' + cmdname).html('');
}
function showCmdMessage(cmdname, msgtype, msgtext, append = false) {
let color = 'table-success';
if (msgtype === 'MESSAGING_WARNING') {
color = 'table-warning';
} else if (msgtype === 'MESSAGING_ERROR') {
color = 'table-danger';
}
$('#toast_' + cmdname).css('display', 'block');
$('#toast_' + cmdname)
.removeClass('table-success')
.removeClass('table-warning')
.removeClass('table-danger')
.addClass(color);
let escapedtext = msgtext
.substring(0, msgtext.length - 1)
.encodeHTML()
.replace(/\n/g, '
');
escapedtext =
($('#msg_' + cmdname).html().length > 0 && append
? $('#msg_' + cmdname).html() + '
'
: '') + escapedtext;
$('#msg_' + cmdname).html(escapedtext);
}
let releaseURL =
'https://api.github.com/repos/sle118/squeezelite-esp32/releases';
let recovery = false;
const commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W';
let blockAjax = false;
//let blockFlashButton = false;
let apList = null;
//let selectedSSID = '';
//let checkStatusInterval = null;
let messagecount = 0;
let messageseverity = 'MESSAGING_INFO';
let StatusIntervalActive = false;
let LastRecoveryState = null;
let SystemConfig={};
let LastCommandsState = null;
var output = '';
let hostName = '';
let versionName='Squeezelite-ESP32';
let prevmessage='';
let project_name=versionName;
let platform_name=versionName;
let btSinkNamesOptSel='#cfg-audio-bt_source-sink_name';
let ConnectedToSSID={};
let ConnectingToSSID={};
let lmsBaseUrl;
let prevLMSIP='';
const ConnectingToActions = {
'CONN' : 0,'MAN' : 1,'STS' : 2,
}
Promise.prototype.delay = function(duration) {
return this.then(
function(value) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(value);
}, duration);
});
},
function(reason) {
return new Promise(function(_resolve, reject) {
setTimeout(function() {
reject(reason);
}, duration);
});
}
);
};
function startCheckStatusInterval() {
StatusIntervalActive = true;
setTimeout(checkStatus, 3000);
}
function RepeatCheckStatusInterval() {
if (StatusIntervalActive) {
startCheckStatusInterval();
}
}
function getConfigJson(slimMode) {
const config = {};
$('input.nvs').each(function(_index, entry) {
if (!slimMode) {
const nvsType = parseInt(entry.attributes.nvs_type.value, 10);
if (entry.id !== '') {
config[entry.id] = {};
if (
nvsType === nvsTypes.NVS_TYPE_U8 ||
nvsType === nvsTypes.NVS_TYPE_I8 ||
nvsType === nvsTypes.NVS_TYPE_U16 ||
nvsType === nvsTypes.NVS_TYPE_I16 ||
nvsType === nvsTypes.NVS_TYPE_U32 ||
nvsType === nvsTypes.NVS_TYPE_I32 ||
nvsType === nvsTypes.NVS_TYPE_U64 ||
nvsType === nvsTypes.NVS_TYPE_I64
) {
config[entry.id].value = parseInt(entry.value);
} else {
config[entry.id].value = entry.value;
}
config[entry.id].type = nvsType;
}
} else {
config[entry.id] = entry.value;
}
});
const key = $('#nvs-new-key').val();
const val = $('#nvs-new-value').val();
if (key !== '') {
if (!slimMode) {
config[key] = {};
config[key].value = val;
config[key].type = 33;
} else {
config[key] = val;
}
}
return config;
}
// eslint-disable-next-line no-unused-vars
function onFileLoad(elementId, event) {
let data = {};
try {
data = JSON.parse(elementId.srcElement.result);
} catch (e) {
alert('Parsing failed!\r\n ' + e);
}
$('input.nvs').each(function(_index, entry) {
if (data[entry.id]) {
if (data[entry.id] !== entry.value) {
console.log(
'Changed ' + entry.id + ' ' + entry.value + '==>' + data[entry.id]
);
$(this).val(data[entry.id]);
}
}
});
}
// eslint-disable-next-line no-unused-vars
function onChooseFile(event, onLoadFileHandler) {
if (typeof window.FileReader !== 'function') {
throw "The file API isn't supported on this browser.";
}
const input = event.target;
if (!input) {
throw 'The browser does not properly implement the event object';
}
if (!input.files) {
throw 'This browser does not support the `files` property of the file input.';
}
if (!input.files[0]) {
return undefined;
}
const file = input.files[0];
let fr = new FileReader();
fr.onload = onLoadFileHandler;
fr.readAsText(file);
input.value = '';
}
function delayReboot(duration, cmdname, ota = 'reboot') {
const url = '/'+ota+'.json';
$('tbody#tasks').empty();
$('#tasks_sect').css('visibility', 'collapse');
Promise.resolve({ cmdname: cmdname, url: url })
.delay(duration)
.then(function(data) {
if (data.cmdname.length > 0) {
showCmdMessage(
data.cmdname,
'MESSAGING_WARNING',
'System is rebooting.\n',
true
);
} else {
showLocalMessage('System is rebooting.\n', 'MESSAGING_WARNING');
}
console.log('now triggering reboot');
$("button[onclick*='handleReboot']").addClass('rebooting');
$.ajax({
url: data.url,
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
timestamp: Date.now(),
}),
error: handleExceptionResponse,
complete: function() {
console.log('reboot call completed');
Promise.resolve(data)
.delay(6000)
.then(function(rdata) {
if (rdata.cmdname.length > 0) {
HideCmdMessage(rdata.cmdname);
}
getCommands();
getConfig();
});
},
});
});
}
// eslint-disable-next-line no-unused-vars
window.saveAutoexec1 = function(apply) {
showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Saving.\n', false);
let commandLine = commandHeader + ' -n "' + $('#player').val() + '"';
if (output === 'bt') {
commandLine += ' -o "BT" -R -Z 192000';
showCmdMessage(
'cfg-audio-tmpl',
'MESSAGING_INFO',
'Remember to configure the Bluetooth audio device name.\n',
true
);
} else if (output === 'spdif') {
commandLine += ' -o SPDIF -Z 192000';
} else {
commandLine += ' -o I2S';
}
if ($('#optional').val() !== '') {
commandLine += ' ' + $('#optional').val();
}
const data = {
timestamp: Date.now(),
};
data.config = {
autoexec1: { value: commandLine, type: 33 },
autoexec: {
value: $('#disable-squeezelite').prop('checked') ? '0' : '1',
type: 33,
},
};
$.ajax({
url: '/config.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
error: handleExceptionResponse,
complete: function(response) {
if (
response.responseText.result &&
JSON.parse(response.responseText).result === 'OK'
) {
showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Done.\n', true);
if (apply) {
delayReboot(1500, 'cfg-audio-tmpl');
}
} else if (response.responseText.result) {
showCmdMessage(
'cfg-audio-tmpl',
'MESSAGING_WARNING',
JSON.parse(response.responseText).Result + '\n',
true
);
} else {
showCmdMessage(
'cfg-audio-tmpl',
'MESSAGING_ERROR',
response.statusText + '\n'
);
}
console.log(response.responseText);
},
});
console.log('sent data:', JSON.stringify(data));
}
window.handleDisconnect = function(){
$.ajax({
url: '/connect.json',
dataType: 'text',
method: 'DELETE',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
timestamp: Date.now(),
}),
});
}
function setPlatformFilter(val){
if($('.upf').filter(function(){ return $(this).text().toUpperCase()===val.toUpperCase()}).length>0){
$('#splf').val(val).trigger('input');
return true;
}
return false;
}
window.handleConnect = function(){
ConnectingToSSID.ssid = $('#manual_ssid').val();
ConnectingToSSID.pwd = $('#manual_pwd').val();
ConnectingToSSID.dhcpname = $('#dhcp-name2').val();
$("*[class*='connecting']").hide();
$('#ssid-wait').text(ConnectingToSSID.ssid);
$('.connecting').show();
$.ajax({
url: '/connect.json',
dataType: 'text',
method: 'POST',
cache: false,
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
timestamp: Date.now(),
ssid: ConnectingToSSID.ssid,
pwd: ConnectingToSSID.pwd
}),
error: handleExceptionResponse,
});
// now we can re-set the intervals regardless of result
startCheckStatusInterval();
}
$(document).ready(function() {
$('#wifiTable').on('click','tr', function() {
});
$('#fw-url-input').on('input', function() {
if($(this).val().length>8 && ($(this).val().startsWith('http://') || $(this).val().startsWith('https://'))){
$('#start-flash').show();
}
else {
$('#start-flash').hide();
}
});
$('.upSrch').on('input', function() {
const val = this.value;
$("#rTable tr").removeClass(this.id+'_hide');
if(val.length>0) {
$(`#rTable td:nth-child(${$(this).parent().index()+1})`).filter(function(){
return !$(this).text().toUpperCase().includes(val.toUpperCase());
}).parent().addClass(this.id+'_hide');
}
$('[class*="_hide"]').hide();
$('#rTable tr').not('[class*="_hide"]').show()
});
setTimeout(refreshAP,1500);
$('#otadiv').on('hidden.bs.modal', function () {
// reset flash status. This should stop the state machine from
// executing steps up to flashing itself.
flash_state=flash_status_codes.NONE;
});
$('#WifiConnectDialog').on('shown.bs.modal', function () {
$("*[class*='connecting']").hide();
if(ConnectingToSSID.Action!==ConnectingToActions.STS){
$('.connecting-init').show();
$('#manual_ssid').trigger('focus');
}
else {
handleWifiDialog();
}
})
$('#WifiConnectDialog').on('hidden.bs.modal', function () {
$('#WifiConnectDialog input').val('');
})
$('#uCnfrm').on('shown.bs.modal', function () {
$('#selectedFWURL').text($('#fw-url-input').val());
})
$('input#show-commands')[0].checked = LastCommandsState === 1;
$('a[href^="#tab-commands"]').hide();
$('#load-nvs').on('click', function() {
$('#nvsfilename').trigger('click');
});
$('#clear-syslog').on('click', function() {
messagecount = 0;
messageseverity = 'MESSAGING_INFO';
$('#msgcnt').text('');
$('#syslogTable').html('');
});
$('#wifiTable').on('click','tr', function() {
ConnectingToSSID.Action=ConnectingToActions.CONN;
if($(this).children('td:eq(1)').text() == ConnectedToSSID.ssid){
ConnectingToSSID.Action=ConnectingToActions.STS;
return;
}
if(!$(this).is(':last-child')){
ConnectingToSSID.ssid=$(this).children('td:eq(1)').text();
$('#manual_ssid').val(ConnectingToSSID.ssid);
}
else {
ConnectingToSSID.Action=ConnectingToActions.MAN;
ConnectingToSSID.ssid='';
$('#manual_ssid').val(ConnectingToSSID.ssid);
}
});
$('#ok-credits').on('click', function() {
$('#credits').slideUp('fast', function() {});
$('#app').slideDown('fast', function() {});
});
$('#acredits').on('click', function(event) {
event.preventDefault();
$('#app').slideUp('fast', function() {});
$('#credits').slideDown('fast', function() {});
});
$('input#show-commands').on('click', function() {
this.checked = this.checked ? 1 : 0;
if (this.checked) {
$('a[href^="#tab-commands"]').show();
LastCommandsState = 1;
} else {
LastCommandsState = 0;
$('a[href^="#tab-commands"]').hide();
}
});
$('input#show-nvs').on('click', function() {
this.checked = this.checked ? 1 : 0;
if (this.checked) {
$('*[href*="-nvs"]').show();
} else {
$('*[href*="-nvs"]').hide();
}
});
$('#save-as-nvs').on('click', function() {
const config = getConfigJson(true);
const a = document.createElement('a');
a.href = URL.createObjectURL(
new Blob([JSON.stringify(config, null, 2)], {
type: 'text/plain',
})
);
a.setAttribute(
'download',
'nvs_config_' + hostName + '_' + Date.now() + 'json'
);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
$('#save-nvs').on('click', function() {
post_config(getConfigJson(false));
});
$('#fwUpload').on('click', function() {
const fileInput = document.getElementById('flashfilename').files;
if (fileInput.length === 0) {
alert('No file selected!');
} else {
handle_flash_state({ event: flash_events.START_OTA, file: fileInput[0] });
}
});
$('[name=output-tmpl]').on('click', function() {
handleTemplateTypeRadio(this.id);
});
$('#chkUpdates').on('click', function() {
$('#rTable').html('');
$.getJSON(releaseURL, function(data) {
let i = 0;
const branches = [];
data.forEach(function(release) {
const namecomponents = release.name.split('#');
const branch = namecomponents[3];
if (!branches.includes(branch)) {
branches.push(branch);
}
});
let fwb='';
branches.forEach(function(branch) {
fwb += '';
});
$('#fwbranch').append(fwb);
data.forEach(function(release) {
let url = '';
release.assets.forEach(function(asset) {
if (asset.name.match(/\.bin$/)) {
url = asset.browser_download_url;
}
});
const namecomponents = release.name.split('#');
const ver = namecomponents[0];
const cfg = namecomponents[2];
const branch = namecomponents[3];
var bits = ver.substr(ver.lastIndexOf('-')+1);
bits = (bits =='32' || bits == '16')?bits:'';
let body = release.body;
body = body.replace(/'/gi, '"');
body = body.replace(
/[\s\S]+(### Revision Log[\s\S]+)### ESP-IDF Version Used[\s\S]+/,
'$1'
);
body = body.replace(/- \(.+?\) /g, '- ');
$('#rTable').append(`