Arduino Core 3 (#407)
* Add and remove libs and components for Arduino Core 3 * Arduino Core 3 * Add back Solo1 * Change ESP32-S3 to 4MB build * Update README.md * Fix retain and number of retries * Fix rolling log * Fix defaults * Fix BleScanner on Solo1 * Export settings * Import settings * Fix HA Battery voltage * Change submodule * Update espMqttClient and AsyncTCP * Webserial and MQTT/Network reconnecting * Update nuki_ble --------- Co-authored-by: iranl <iranl@github.com>
This commit is contained in:
364
lib/WebSerialLite/frontend/index.html
Normal file
364
lib/WebSerialLite/frontend/index.html
Normal file
@@ -0,0 +1,364 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Web Console</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<style type="text/css">
|
||||
div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
margin: 0.4rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
*,
|
||||
::after,
|
||||
::before {
|
||||
-webkit-box-sizing: inherit;
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI",
|
||||
Roboto, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.gray {
|
||||
color: #667189;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
filter: drop-shadow(0 4px 3px rgb(0 0 0 / 0.07)) drop-shadow(0 2px 2px rgb(0 0 0 / 0.06));
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.justify-items-end {
|
||||
justify-items: end;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
box-sizing: border-box;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.main {
|
||||
/* padding-top: 3rem; */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
.main .pannel {
|
||||
position: relative;
|
||||
border: #fff;
|
||||
border-style: solid;
|
||||
border-width: 0.5rem;
|
||||
border-radius: 1rem;
|
||||
background-color: #fff;
|
||||
width: calc(100% - 1rem);
|
||||
font-size: medium;
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
|
||||
.pannel button {
|
||||
cursor: pointer;
|
||||
padding: 8px 10px 8px;
|
||||
font-size: medium;
|
||||
outline-style: none;
|
||||
border: 0px;
|
||||
color: #fff;
|
||||
background-color: #0067f4;
|
||||
}
|
||||
|
||||
.pannel button:disabled {
|
||||
background-color: #5a6169;
|
||||
}
|
||||
|
||||
.pannel #record {
|
||||
min-height: 3.25rem;
|
||||
padding: 0.5rem;
|
||||
resize: vertical;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
#control-button {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
}
|
||||
|
||||
#control-button button {
|
||||
background-color: #5a6169;
|
||||
}
|
||||
|
||||
.alert span {
|
||||
user-select: none;
|
||||
background: #ffe14d;
|
||||
padding: 2px 10px;
|
||||
display: block;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 1rem 0.5rem;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.float-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.float-right {
|
||||
float: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="section main text-center">
|
||||
<h1 id="title" style="display: none;">Web Console</h1>
|
||||
<a href="/">
|
||||
<img id="logo" src="/logo" onerror="removeLogo();" />
|
||||
</a>
|
||||
|
||||
<div class="pannel shadow grid gap-2">
|
||||
<div id="control-button">
|
||||
<button class="rounded shadow" onclick="terminalClean()">
|
||||
<svg viewBox="64 64 896 896" focusable="false" data-icon="delete" width="1em" height="1em"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path
|
||||
d="M864 256H736v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zm-200 0H360v-72h304v72z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="rounded shadow" onclick="enableFlowLock=!enableFlowLock">
|
||||
<svg viewBox="64 64 896 896" focusable="false" data-icon="lock" width="1em" height="1em"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path
|
||||
d="M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="rounded shadow" onclick="enableTimestamp=!enableTimestamp">
|
||||
<svg viewBox="64 64 896 896" focusable="false" data-icon="clock-circle" width="1em" height="1em"
|
||||
fill="currentColor" aria-hidden="true">
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z">
|
||||
</path>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z">
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<textarea class="w-full rounded" title="record" id="record" cols="30" rows="40" disabled></textarea>
|
||||
<div class="flex w-full grid gap-2" id="terminal">
|
||||
<input type="text" name="cmd" id="command-text" class="grow rounded" /><button
|
||||
class="grid justify-items-end rounded shadow" id="command-button">
|
||||
SEND
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h1 />
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
let gateway = `ws://${window.location.host + window.location.pathname}ws`;
|
||||
let websocket;
|
||||
let textArea = document.getElementById("record");
|
||||
let enableFlowLock = false;
|
||||
let enableTimestamp = false;
|
||||
let pingTimeout;
|
||||
let connectTimeout;
|
||||
let commandHistory = [];
|
||||
let commandHistoryIdx = 0;
|
||||
|
||||
function removeLogo() {
|
||||
document.getElementById("logo").remove();
|
||||
document.getElementById("title").style.display = "block";
|
||||
}
|
||||
|
||||
function initWebPage() {
|
||||
document.getElementById("command-button").disabled = true;
|
||||
document.getElementById("command-text").disabled = true;
|
||||
initCommandHistory();
|
||||
initWebSocket();
|
||||
initButton();
|
||||
trapKeyPress();
|
||||
}
|
||||
|
||||
function initCommandHistory() {
|
||||
const json = localStorage.history;
|
||||
commandHistory = json ? JSON.parse(json) : [];
|
||||
commandHistoryIdx = commandHistory.length;
|
||||
}
|
||||
|
||||
function initWebSocket() {
|
||||
clearTimeout(connectTimeout);
|
||||
clearTimeout(pingTimeout);
|
||||
pingTimeout = false;
|
||||
connectTimeout = setTimeout(() => {
|
||||
terminalWrite("[WebSerial] Connect timeout.");
|
||||
websocket.close();
|
||||
initWebSocket();
|
||||
}, 3000);
|
||||
terminalWrite("[WebSerial] Connecting...");
|
||||
websocket = new WebSocket(gateway);
|
||||
websocket.onopen = onOpen;
|
||||
websocket.onclose = onClose;
|
||||
websocket.onmessage = onMessage;
|
||||
websocket.onerror = onError;
|
||||
}
|
||||
|
||||
function initButton() {
|
||||
document.getElementById("command-button").addEventListener("click", sendCommand);
|
||||
}
|
||||
|
||||
function trapKeyPress() {
|
||||
document.getElementById("command-text").addEventListener("keypress", (event) => {
|
||||
if (event.code === "Enter") {
|
||||
event.preventDefault();
|
||||
document.getElementById("command-button").click();
|
||||
}
|
||||
});
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (document.activeElement && document.activeElement.id === 'command-text') {
|
||||
if (event.code === "ArrowUp") {
|
||||
commandHistoryIdx--;
|
||||
if (commandHistoryIdx < 0)
|
||||
commandHistoryIdx = commandHistory.length > 0 ? commandHistory.length - 1 : 0;
|
||||
if (commandHistoryIdx >= 0 && commandHistoryIdx < commandHistory.length)
|
||||
document.getElementById("command-text").value = commandHistory[commandHistoryIdx];
|
||||
|
||||
} else if (event.code === "ArrowDown") {
|
||||
commandHistoryIdx++;
|
||||
if (commandHistoryIdx >= commandHistory.length)
|
||||
commandHistoryIdx = 0;
|
||||
if (commandHistoryIdx >= 0 && commandHistoryIdx < commandHistory.length)
|
||||
document.getElementById("command-text").value = commandHistory[commandHistoryIdx];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onOpen(event) {
|
||||
clearTimeout(connectTimeout);
|
||||
terminalWrite("[WebSerial] Connected...");
|
||||
document.getElementById("command-button").disabled = false;
|
||||
document.getElementById("command-text").disabled = false;
|
||||
}
|
||||
|
||||
function onError(e) {
|
||||
console.log("[WebSerial] Error!", e);
|
||||
websocket.close();
|
||||
}
|
||||
|
||||
function onClose(e) {
|
||||
console.log("[WebSerial] Connection closed.", e);
|
||||
}
|
||||
|
||||
function onMessage(event) {
|
||||
if (event.data == 'pong') {
|
||||
clearTimeout(pingTimeout);
|
||||
pingTimeout = false;
|
||||
} else {
|
||||
terminalWrite(event.data);
|
||||
}
|
||||
}
|
||||
|
||||
function terminalWrite(raw) {
|
||||
if (enableTimestamp) {
|
||||
let now = new Date();
|
||||
raw = "[" + now.toLocaleTimeString() + "] " + raw + "\n";
|
||||
}
|
||||
textArea.value += raw + "\n";
|
||||
if (!enableFlowLock) {
|
||||
textArea.scrollTop = textArea.scrollHeight;
|
||||
}
|
||||
}
|
||||
|
||||
function terminalClean() {
|
||||
textArea.value = "";
|
||||
textArea.scrollTop = textArea.scrollHeight;
|
||||
}
|
||||
|
||||
function sendCommand() {
|
||||
let cmd = document.getElementById("command-text").value;
|
||||
console.log('send command: ', cmd);
|
||||
websocket.send(cmd);
|
||||
commandHistory.push(cmd);
|
||||
console.log('history size: ', commandHistory.length);
|
||||
if (commandHistory.length > 20) {
|
||||
console.log('history cleanup');
|
||||
commandHistory.splice(0, commandHistory.length - 20);
|
||||
console.log('history size: ', commandHistory.length);
|
||||
}
|
||||
commandHistoryIdx = commandHistory.length;
|
||||
document.getElementById("command-text").value = "";
|
||||
localStorage.history = JSON.stringify(commandHistory);
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
if (!pingTimeout && websocket.readyState == WebSocket.OPEN) {
|
||||
pingTimeout = setTimeout(() => {
|
||||
terminalWrite("[WebSerial] Ping timeout.");
|
||||
websocket.close();
|
||||
initWebSocket();
|
||||
}, 3000);
|
||||
websocket.send("ping");
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
window.addEventListener("DOMContentLoaded", function () {
|
||||
initWebPage();
|
||||
}, false);
|
||||
</script>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user