diff --git a/base.php b/base.php
index c0458cf..e31c847 100644
--- a/base.php
+++ b/base.php
@@ -97,7 +97,11 @@ function je($s)
function tr($key)
{
global $_messages;
- return isset($_messages[$key]) ? $_messages[$key] : ('??' . $key . '??');
+ if (isset($_messages[$key])) return $_messages[$key];
+ else {
+ ob_end_clean();
+ die('??' . $key . '??');
+ }
}
/** Like eval, but allows */
diff --git a/compile_html.php b/compile_html.php
index 5bc4f15..c8698fc 100755
--- a/compile_html.php
+++ b/compile_html.php
@@ -22,9 +22,22 @@ ob_start();
foreach($_pages as $_k => $p) {
if ($p->bodyclass == 'api') {
if (ESP_DEMO) {
- $target = 'term.html';
- echo "Generating: ~$_k.html -> $target\n";
- $s = "";
+ echo "Generating: ~$_k.html (bounce)\n";
+
+ if ($_k=='index') {
+ $s = "";
+ }
+ else {
+ $s = "
+ ";
+ }
+
+
} else {
continue;
}
diff --git a/js/appcommon.js b/js/appcommon.js
index 26f8733..0f103df 100644
--- a/js/appcommon.js
+++ b/js/appcommon.js
@@ -33,7 +33,11 @@ $.ready(function () {
let h = x.querySelector('h2')
let hdl = function () {
- $(x).toggleClass('expanded')
+ if ($(x).hasClass('d-expanded')) {
+ $(x).removeClass('d-expanded')
+ } else {
+ $(x).toggleClass('expanded')
+ }
}
$(h).on('click', hdl).on('keypress', cr(hdl))
})
@@ -90,24 +94,39 @@ $.ready(function () {
// (a way to pass errors back from server via redirect)
let errAt = window.location.search.indexOf('err=')
if (errAt !== -1 && qs('.Box.errors')) {
- let errs = window.location.search.substr(errAt + 4).split(',')
+ let errs = decodeURIComponent(window.location.search.substr(errAt + 4)).split(',')
let humanReadableErrors = []
errs.forEach(function (er) {
let lbls = qsa('label[for="' + er + '"]')
- for (let i = 0; i < lbls.length; i++) {
- let lbl = lbls[i]
- lbl.classList.add('error')
- if (i === 0) humanReadableErrors.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''))
+ if (lbls) {
+ for (let i = 0; i < lbls.length; i++) {
+ let lbl = lbls[i]
+ lbl.classList.add('error')
+ if (i === 0) humanReadableErrors.push(lbl.childNodes[0].textContent.trim().replace(/: ?$/, ''))
+ }
+ } else {
+ humanReadableErrors.push(er)
}
- // else {
- // hres.push(er)
- // }
})
qs('.Box.errors .list').innerHTML = humanReadableErrors.join(', ')
qs('.Box.errors').classList.remove('hidden')
}
+ let msgAt = window.location.search.indexOf('msg=')
+ if (msgAt !== -1 && qs('.Box.message')) {
+ let msg = decodeURIComponent(window.location.search.substr(msgAt + 4))
+ let box = qs('.Box.message')
+ box.innerHTML = msg
+ box.classList.remove('hidden')
+ setTimeout(() => {
+ box.classList.add('hiding')
+ setTimeout(() => {
+ box.classList.add('hidden')
+ }, 1000)
+ }, 2000)
+ }
+
modal.init()
notify.init()
diff --git a/js/term/connection.js b/js/term/connection.js
index 7b799ca..8e8f7be 100644
--- a/js/term/connection.js
+++ b/js/term/connection.js
@@ -19,12 +19,18 @@ module.exports = class TermConnection extends EventEmitter {
this.pageShown = false
+ this.disconnectTimeout = null
+
document.addEventListener('visibilitychange', () => {
if (document.hidden === true) {
console.info('Window lost focus, freeing socket')
- this.closeSocket()
- clearTimeout(this.heartbeatTimeout)
+ // Delayed, avoid disconnecting if the background time is short
+ this.disconnectTimeout = setTimeout(() => {
+ this.closeSocket()
+ clearTimeout(this.heartbeatTimeout)
+ }, 1000)
} else {
+ clearTimeout(this.disconnectTimeout)
console.info('Window got focus, re-connecting')
this.init()
}
@@ -80,7 +86,6 @@ module.exports = class TermConnection extends EventEmitter {
break
default:
- this.emit('load')
this.screen.load(evt.data)
if (!this.pageShown) {
window.showPage()
@@ -118,7 +123,7 @@ module.exports = class TermConnection extends EventEmitter {
console.error('Socket not ready')
return false
}
- if (typeof message != 'string') {
+ if (typeof message !== 'string') {
message = JSON.stringify(message)
}
this.ws.send(message)
@@ -161,7 +166,7 @@ module.exports = class TermConnection extends EventEmitter {
heartbeat () {
clearTimeout(this.heartbeatTimeout)
- this.heartbeatTimeout = setTimeout(() => this.onHeartbeatFail(), 2000)
+ this.heartbeatTimeout = setTimeout(() => this.onHeartbeatFail(), 2500)
}
onHeartbeatFail () {
diff --git a/js/term/index.js b/js/term/index.js
index 3a7a6c1..41593ac 100644
--- a/js/term/index.js
+++ b/js/term/index.js
@@ -14,33 +14,47 @@ module.exports = function (opts) {
const input = TermInput(conn, screen)
const termUpload = TermUpload(conn, input, screen)
screen.input = input
+ screen.conn = conn
input.termUpload = termUpload
- // we delay the display of "connecting" to avoid flash when changing tabs with the terminal open
- let showConnectingTimeout = -1
+ let showSplashTimeout = null
+ let showSplash = (obj, delay = 250) => {
+ clearTimeout(showSplashTimeout)
+ showSplashTimeout = setTimeout(() => {
+ screen.window.statusScreen = obj
+ }, delay)
+ }
+
conn.on('open', () => {
- showConnectingTimeout = setTimeout(() => {
- screen.window.statusScreen = { title: 'Connecting', loading: true }
- }, 250)
+ // console.log('*open')
+ showSplash({ title: 'Connecting', loading: true })
})
conn.on('connect', () => {
- clearTimeout(showConnectingTimeout)
- screen.window.statusScreen = { title: 'Waiting for content', loading: true }
+ // console.log('*connect')
+ showSplash({ title: 'Waiting for content', loading: true })
})
conn.on('load', () => {
+ // console.log('*load')
+ clearTimeout(showSplashTimeout)
if (screen.window.statusScreen) screen.window.statusScreen = null
})
conn.on('disconnect', () => {
- clearTimeout(showConnectingTimeout)
- screen.window.statusScreen = { title: 'Disconnected' }
+ // console.log('*disconnect')
+ showSplash({ title: 'Disconnected' })
screen.screen = []
screen.screenFG = []
screen.screenBG = []
screen.screenAttrs = []
})
- conn.on('silence', () => { screen.window.statusScreen = { title: 'Waiting for server', loading: true } })
+ conn.on('silence', () => {
+ // console.log('*silence')
+ showSplash({ title: 'Waiting for server', loading: true }, 0)
+ })
// conn.on('ping-fail', () => { screen.window.statusScreen = { title: 'Disconnected' } })
- conn.on('ping-success', () => { screen.window.statusScreen = { title: 'Re-connecting', loading: true } })
+ conn.on('ping-success', () => {
+ // console.log('*ping-success')
+ showSplash({ title: 'Re-connecting', loading: true }, 0)
+ })
conn.init()
input.init(opts)
diff --git a/js/term/screen.js b/js/term/screen.js
index e71a7e3..b24ce98 100644
--- a/js/term/screen.js
+++ b/js/term/screen.js
@@ -30,6 +30,15 @@ module.exports = class TermScreen extends EventEmitter {
return () => console.warn('TermScreen#input not set!')
}
})
+ // dummy. Handle for Conn
+ this.conn = new Proxy({}, {
+ get () {
+ return () => console.warn('TermScreen#conn not set!')
+ },
+ set (a, b) {
+ return () => console.warn('TermScreen#conn not set!')
+ }
+ })
this.cursor = {
x: 0,
diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js
index 9e83e12..c210e00 100644
--- a/js/term/screen_parser.js
+++ b/js/term/screen_parser.js
@@ -199,7 +199,7 @@ module.exports = class ScreenParser {
if (this.screen.window.debug) console.log(`Blinky cells: ${this.screen.blinkingCellCount}`)
this.screen.renderer.scheduleDraw('load', 16)
- this.screen.emit('load')
+ this.screen.conn.emit('load')
}
/**
diff --git a/js/wifi.js b/js/wifi.js
index 40d8020..9728a6f 100644
--- a/js/wifi.js
+++ b/js/wifi.js
@@ -7,8 +7,8 @@ const tr = require('./lang')
let curSSID
// Get XX % for a slider input
- function rangePt (inp) {
- return Math.round(((inp.value / inp.max) * 100)) + '%'
+ function calc_dBm (inp) {
+ return `+${(inp.value * 0.25).toFixed(2)} dBm`
}
// Display selected STA SSID etc
@@ -142,11 +142,11 @@ const tr = require('./lang')
let inp = x.querySelector('input')
let disp1 = x.querySelector('.x-disp1')
let disp2 = x.querySelector('.x-disp2')
- let t = rangePt(inp)
+ let t = calc_dBm(inp)
$(disp1).html(t)
$(disp2).html(t)
$(inp).on('input', function () {
- t = rangePt(inp)
+ t = calc_dBm(inp)
$(disp1).html(t)
$(disp2).html(t)
})
diff --git a/lang/en.php b/lang/en.php
index 9b29c99..9333add 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -12,10 +12,24 @@ return [
'menu.term' => 'Back to Terminal',
'menu.cfg_system' => 'System Settings',
'menu.cfg_wifi_conn' => 'Connecting to Network',
-
'menu.settings' => 'Settings',
- 'title.term' => 'Terminal',
+ // not used - api etc. Added to suppress warnings
+ 'menu.term_set' => '',
+ 'menu.wifi_connstatus' => '',
+ 'menu.wifi_set' => '',
+ 'menu.wifi_scan' => '',
+ 'menu.network_set' => '',
+ 'menu.system_set' => '',
+ 'menu.write_defaults' => '',
+ 'menu.restore_defaults' => '',
+ 'menu.restore_hard' => '',
+ 'menu.reset_screen' => '',
+ 'menu.index' => '',
+
+ // Terminal page
+
+ 'title.term' => 'Terminal', // page title of the terminal page
'term_nav.config' => 'Config',
'term_nav.wifi' => 'WiFi',
@@ -26,18 +40,14 @@ return [
'term_nav.keybd' => 'Keyboard',
'term_nav.paste_prompt' => 'Paste text to send:',
- 'net.ap' => 'DHCP Server (AP)',
- 'net.sta' => 'DHCP Client (Station)',
- 'net.sta_mac' => 'Station MAC',
- 'net.ap_mac' => 'AP MAC',
- 'net.details' => 'MAC addresses',
+ // Terminal settings page
'term.defaults' => 'Initial Settings',
'term.expert' => 'Expert Options',
'term.explain_initials' => '
- Those are the initial settings used after ESPTerm powers on or when the screen
- reset command is received. Some options can be changed by the application via escape sequences,
- those changes won\'t be saved in Flash.
+ Those are the initial settings used after ESPTerm powers on, or when the screen
+ reset command is received (\ec
). They can be changed by the
+ terminal application using escape sequences.
',
'term.explain_expert' => '
Those are advanced config options that usually don\'t need to be changed.
@@ -58,7 +68,7 @@ return [
'term.term_width' => 'Width',
'term.term_height' => 'Height',
'term.buttons' => 'Button labels',
- 'term.theme' => 'Color scheme',
+ 'term.theme' => 'Color palette',
'term.cursor_shape' => 'Cursor style',
'term.parser_tout_ms' => 'Parser timeout',
'term.display_tout_ms' => 'Redraw delay',
@@ -66,14 +76,14 @@ return [
'term.fn_alt_mode' => 'SS3 Fn keys',
'term.show_config_links' => 'Show nav links',
'term.show_buttons' => 'Show buttons',
- 'term.loopback' => 'Local Echo',
- 'term.crlf_mode' => 'Enter sends CR+LF',
+ 'term.loopback' => 'Local Echo (SRM)',
+ 'term.crlf_mode' => 'Enter = CR+LF (LNM)',
'term.want_all_fn' => 'Capture all keys
(F5, F11, F12…)',
'term.button_msgs' => 'Button codes
(ASCII, dec, CSV)',
'term.color_fg' => 'Default fg.',
'term.color_bg' => 'Default bg.',
- 'term.color_fg_prev' => 'Fg. colors',
- 'term.color_bg_prev' => 'Bg. colors',
+ 'term.color_fg_prev' => 'Foreground',
+ 'term.color_bg_prev' => 'Background',
'term.colors_preview' => 'Defaults',
'cursor.block_blink' => 'Block, blinking',
@@ -83,23 +93,7 @@ return [
'cursor.bar_blink' => 'I-bar, blinking',
'cursor.bar_steady' => 'I-bar, steady',
-// // terminal color labels
-// 'color.0' => 'Black',
-// 'color.1' => 'Red',
-// 'color.2' => 'Green',
-// 'color.3' => 'Yellow',
-// 'color.4' => 'Blue',
-// 'color.5' => 'Purple',
-// 'color.6' => 'Cyan',
-// 'color.7' => 'Silver',
-// 'color.8' => 'Gray',
-// 'color.9' => 'Light Red',
-// 'color.10' => 'Light Green',
-// 'color.11' => 'Light Yellow',
-// 'color.12' => 'Light Blue',
-// 'color.13' => 'Light Purple',
-// 'color.14' => 'Light Cyan',
-// 'color.15' => 'White',
+ // Network config page
'net.explain_sta' => '
Switch off Dynamic IP to configure the static IP address.',
@@ -118,6 +112,14 @@ return [
'net.sta_addr_mask' => 'Subnet mask',
'net.sta_addr_gw' => 'Gateway IP',
+ 'net.ap' => 'DHCP Server (AP)',
+ 'net.sta' => 'DHCP Client (Station)',
+ 'net.sta_mac' => 'Station MAC',
+ 'net.ap_mac' => 'AP MAC',
+ 'net.details' => 'MAC addresses',
+
+ // Wifi config page
+
'wifi.ap' => 'Built-in Access Point',
'wifi.sta' => 'Join Existing Network',
@@ -143,76 +145,89 @@ return [
'wifi.enter_passwd' => 'Enter password for ":ssid:"',
'wifi.sta_explain' => 'After selecting a network, press Apply to connect.',
- 'wifi.conn.status' => 'Status:',
- 'wifi.conn.back_to_config' => 'Back to WiFi config',
- 'wifi.conn.telemetry_lost' => 'Telemetry lost; something went wrong, or your device disconnected.',
- 'wifi.conn.explain_android_sucks' => '
+ // Wifi connecting status page
+
+ 'wificonn.status' => 'Status:',
+ 'wificonn.back_to_config' => 'Back to WiFi config',
+ 'wificonn.telemetry_lost' => 'Telemetry lost; something went wrong, or your device disconnected.',
+ 'wificonn.explain_android_sucks' => '
If you\'re configuring ESPTerm via a smartphone, or were connected
from another external network, your device may lose connection and this
progress indicator won\'t work. Please wait a while (~ 15 seconds),
then check if the connection succeeded.',
- 'wifi.conn.explain_reset' => '
+ 'wificonn.explain_reset' => '
To force enable the built-in AP, hold the BOOT
button until the blue LED starts flashing. Hold the button longer (until the LED
flashes rapidly) for a "factory reset".',
- 'wifi.conn.disabled' =>"Station mode is disabled.",
- 'wifi.conn.idle' =>"Idle, not connected and has no IP.",
- 'wifi.conn.success' => "Connected! Received IP ",
- 'wifi.conn.working' => "Connecting to selected AP",
- 'wifi.conn.fail' => "Connection failed, check settings & try again. Cause: ",
+ 'wificonn.disabled' =>"Station mode is disabled.",
+ 'wificonn.idle' =>"Idle, not connected and has no IP.",
+ 'wificonn.success' => "Connected! Received IP ",
+ 'wificonn.working' => "Connecting to selected AP",
+ 'wificonn.fail' => "Connection failed, check settings & try again. Cause: ",
- 'system.save_restore' => 'Save & Restore',
- 'system.confirm_restore' => 'Restore all settings to their default values?',
- 'system.confirm_restore_hard' =>
- 'Restore to firmware default settings? This will reset ' .
- 'all active settings and switch to AP mode with the default SSID.',
- 'system.confirm_store_defaults' =>
- 'Enter admin password to confirm you want to overwrite the default settings.',
- 'system.password' => 'Admin password:',
- 'system.restore_defaults' => 'Reset to saved defaults',
- 'system.write_defaults' => 'Save active settings as defaults',
- 'system.restore_hard' => 'Reset active settings to firmware defaults',
- 'system.explain_persist' => '
- ESPTerm saves all settings in Flash. The active settings can be copied to
- the "defaults area" and restored later using the blue button below.
- ',
- 'system.uart' => 'Serial Port',
- 'system.explain_uart' => '
- This form controls the primary, communication UART. The debug UART is fixed
- at 115.200 baud, one stop-bit and no parity.
- ',
+ // Access restrictions form
- 'system.security' => 'Access Restrictions',
- 'system.explain_security' => '
+ 'pwlock.title' => 'Access Restrictions',
+ 'pwlock.explain' => '
Some parts, or all of the web interface can be protected by a password prompt.
- Leave the new password fields empty if you do not wish to change it.
+ Leave the new password fields empty if you do not wish to change it.
+ The default password is "%def_access_pw%".
',
- 'system.pwlock' => 'Protected pages',
- 'system.pwlock.none' => 'None, all open',
- 'system.pwlock.settings_noterm' => 'WiFi, Net & System settings',
- 'system.pwlock.settings' => 'All settings pages',
- 'system.pwlock.menus' => 'This entire menu section',
- 'system.pwlock.all' => 'Everything, even terminal',
- 'system.new_access_pw' => 'New password',
- 'system.new_access_pw2' => 'New pass., repeat',
- 'system.admin_pw' => 'Admin password',
- 'system.access_name' => 'Username',
-
- 'system.change_adminpw' => 'Change Admin Password',
- 'system.explain_adminpw' =>
+ 'pwlock.region' => 'Protected pages',
+ 'pwlock.region.none' => 'None, all open',
+ 'pwlock.region.settings_noterm' => 'WiFi, Net & System settings',
+ 'pwlock.region.settings' => 'All settings pages',
+ 'pwlock.region.menus' => 'This entire menu section',
+ 'pwlock.region.all' => 'Everything, even terminal',
+ 'pwlock.new_access_pw' => 'New password',
+ 'pwlock.new_access_pw2' => 'Repeat',
+ 'pwlock.admin_pw' => 'Admin password',
+ 'pwlock.access_name' => 'Username',
+
+ // Setting admin password
+
+ 'adminpw.title' => 'Change Admin Password',
+ 'adminpw.explain' =>
'
The "admin password" is used to manipulate the stored default settings
and to change access restrictions. This password is not saved as part
of the main config, i.e. using save / restore does not affect this
password. When the admin password is forgotten, the easiest way to
- re-gain access is to wipe and re-flash the chip.
+ re-gain access is to wipe and re-flash the chip.
+ The default admin password is "%def_admin_pw%".
+ ',
+ 'adminpw.new_admin_pw' => 'New admin password',
+ 'adminpw.new_admin_pw2' => 'Repeat',
+ 'adminpw.old_admin_pw' => 'Old admin password',
+
+ // Persist form
+
+ 'persist.title' => 'Save & Restore',
+ 'persist.explain' => '
+ ESPTerm saves all settings in Flash. The active settings can be copied to
+ the "defaults area" and restored later using the blue button below.
',
- 'system.new_admin_pw' => 'New admin pass.',
- 'system.new_admin_pw2' => 'New pass., repeat',
- 'system.old_admin_pw' => 'Old admin pass.',
+ 'persist.confirm_restore' => 'Restore all settings to their default values?',
+ 'persist.confirm_restore_hard' =>
+ 'Restore to firmware default settings? This will reset ' .
+ 'all active settings and switch to AP mode with the default SSID.',
+ 'persist.confirm_store_defaults' =>
+ 'Enter admin password to confirm you want to overwrite the default settings.',
+ 'persist.password' => 'Admin password:',
+ 'persist.restore_defaults' => 'Reset to saved defaults',
+ 'persist.write_defaults' => 'Save active settings as defaults',
+ 'persist.restore_hard' => 'Reset active settings to factory defaults',
+ 'persist.restore_hard_explain' => '(This clears the WiFi config! Does not affect saved defaults or admin password.)',
+ // UART settings form
+
+ 'uart.title' => 'Serial Port Parameters',
+ 'uart.explain' => '
+ This form controls the communication UART. The debug UART is fixed
+ at 115.200 baud, one stop-bit and no parity.
+ ',
'uart.baud' => 'Baud rate',
'uart.parity' => 'Parity',
'uart.parity.none' => 'None',
@@ -223,6 +238,19 @@ return [
'uart.stop_bits.one_and_half' => 'One and half',
'uart.stop_bits.two' => 'Two',
+ // HW tuning form
+
+ 'hwtuning.title' => 'Hardware Tuning',
+ 'hwtuning.explain' => '
+ ESP8266 can be overclocked from 80 MHz to 160 MHz.
+ This will make it more responsive and allow faster screen updates
+ at the expense of slightly higher power consumption. This can also make
+ it more susceptible to interference. Use with care.
+ ',
+ 'hwtuning.overclock' => 'Overclock to 160MHz',
+
+ // Generic button / dialog labels
+
'apply' => 'Apply!',
'enabled' => 'Enabled',
'disabled' => 'Disabled',
diff --git a/pages/_head.php b/pages/_head.php
index 9466a12..af974b9 100644
--- a/pages/_head.php
+++ b/pages/_head.php
@@ -32,4 +32,6 @@ if (strpos($_GET['BODYCLASS'], 'cfg') !== false) {
= tr('form_errors') ?>
+