DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
web_assets.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3//
4// GENERATED by src/web/wizard/build_assets.py - DO NOT EDIT BY HAND.
5// Edit the source documents under src/web/input/ and re-run the generator.
6
8
9// ---- html ----
11 "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=devic"
12 "e-width, initial-scale=1\" /><title>Dashboard</title> <style>*{box-sizing:border-box;}body{margin:0;font-famil"
13 "y:system-ui,\"Segoe UI\",Roboto,sans-serif;background:#0e1116;color:#e6edf3;}header{display:flex;align-items:c"
14 "enter;gap:10px;padding:14px 20px;font-size:18px;font-weight:600;border-bottom:1px solid #30363d;}#dot{width:10"
15 "px;height:10px;border-radius:50%;background:#f85149;}#dot.live{background:#3fb950;}#status{font-size:13px;font"
16 "-weight:400;color:#8b949e;}#grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14"
17 "px;padding:18px;}.card{background:#1b2230;border:1px solid #30363d;border-radius:10px;padding:14px;}.card .lab"
18 "el{margin-bottom:8px;font-size:13px;color:#8b949e;}.card .num{font-size:30px;font-weight:600;font-variant-nume"
19 "ric:tabular-nums;}.card .unit{margin-left:4px;font-size:14px;color:#8b949e;}svg{display:block;width:100%;heigh"
20 "t:auto;}svg text{fill:#e6edf3;font-family:inherit;}canvas{display:block;width:100%;height:auto;}.btn{padding:8"
21 "px 14px;font:inherit;color:#fff;background:#238636;border:0;border-radius:6px;cursor:pointer;}.btn:active{back"
22 "ground:#2ea043;}input[type=\"range\"]{width:100%;accent-color:#3fb950;}.sw{width:42px;height:22px;cursor:point"
23 "er;accent-color:#3fb950;}</style> </head><body><header><span id=\"dot\"></span> Dashboard <span id=\"status\">"
24 "</span></header><div id=\"grid\"></div> <script>(function () {\nvar NS = \"http://www.w3.org/2000/svg\";\nvar "
25 "base = location.pathname.replace(/\\/+$/, \"\");\nvar grid = document.getElementById(\"grid\");\nvar dot = doc"
26 "ument.getElementById(\"dot\");\nvar status = document.getElementById(\"status\");\nvar widgets = {};\nvar ws ="
27 " null;\nfunction sendCtrl(k, v) {\nif (ws && ws.readyState === 1)\nws.send(JSON.stringify({ k: k, v: v }));\n}"
28 "\nfunction clamp(f) {\nreturn f < 0 ? 0 : f > 1 ? 1 : f;\n}\nfunction frac(v, mn, mx) {\nreturn mx > mn ? clam"
29 "p((v - mn) / (mx - mn)) : 0;\n}\nfunction fmt(v) {\nreturn Math.abs(v) >= 100 ? v.toFixed(0) : v.toFixed(1);\n"
30 "}\nfunction el(tag, attrs) {\nvar e = document.createElementNS(NS, tag);\nfor (var k in attrs) e.setAttribute("
31 "k, attrs[k]);\nreturn e;\n}\nfunction polar(cx, cy, r, deg) {\nvar a = (deg * Math.PI) / 180;\nreturn [cx + r "
32 "* Math.cos(a), cy - r * Math.sin(a)];\n}\nfunction arc(cx, cy, r, f) {\nvar s = polar(cx, cy, r, 180),\ne = po"
33 "lar(cx, cy, r, 180 - 180 * f);\nreturn (\n\"M\" +\ns[0] +\n\" \" +\ns[1] +\n\" A\" +\nr +\n\" \" +\nr +\n\" 0 "
34 "0 1 \" +\ne[0] +\n\" \" +\ne[1]\n);\n}\nfunction card(w) {\nvar c = document.createElement(\"div\");\nc.classN"
35 "ame = \"card\";\nvar lab = document.createElement(\"div\");\nlab.className = \"label\";\nlab.textContent = w.l"
36 "abel;\nc.appendChild(lab);\nvar upd;\nif (w.type === \"gauge\") {\nvar g = el(\"svg\", { viewBox: \"0 0 120 72"
37 "\" });\ng.appendChild(\nel(\"path\", {\nd: arc(60, 62, 50, 1),\nfill: \"none\",\nstroke: \"#30363d\",\n\"strok"
38 "e-width\": 10,\n\"stroke-linecap\": \"round\",\n}),\n);\nvar gv = el(\"path\", {\nd: arc(60, 62, 50, 0),\nfill"
39 ": \"none\",\nstroke: \"#3fb950\",\n\"stroke-width\": 10,\n\"stroke-linecap\": \"round\",\n});\ng.appendChild(g"
40 "v);\nvar gt = el(\"text\", {\nx: 60,\ny: 58,\n\"text-anchor\": \"middle\",\n\"font-size\": 16,\n\"font-weight"
41 "\": 600,\n});\ngt.textContent = \"-\";\ng.appendChild(gt);\nc.appendChild(g);\nupd = function (v) {\ngv.setAtt"
42 "ribute(\n\"d\",\narc(60, 62, 50, frac(v, w.min, w.max)),\n);\ngt.textContent = fmt(v) + w.unit;\n};\n} else if"
43 " (w.type === \"bar\") {\nvar b = el(\"svg\", { viewBox: \"0 0 200 40\" });\nb.appendChild(\nel(\"rect\", {\nx:"
44 " 0,\ny: 16,\nwidth: 200,\nheight: 12,\nrx: 6,\nfill: \"#30363d\",\n}),\n);\nvar bf = el(\"rect\", {\nx: 0,\ny:"
45 " 16,\nwidth: 0,\nheight: 12,\nrx: 6,\nfill: \"#3fb950\",\n});\nb.appendChild(bf);\nvar bt = el(\"text\", { x: "
46 "0, y: 11, \"font-size\": 12 });\nbt.textContent = \"-\";\nb.appendChild(bt);\nc.appendChild(b);\nupd = functio"
47 "n (v) {\nbf.setAttribute(\n\"width\",\n200 * frac(v, w.min, w.max),\n);\nbt.textContent = fmt(v) + w.unit;\n};"
48 "\n} else if (w.type === \"sparkline\") {\nvar s = el(\"svg\", { viewBox: \"0 0 200 50\" });\nvar pl = el(\"pol"
49 "yline\", {\nfill: \"none\",\nstroke: \"#3fb950\",\n\"stroke-width\": 2,\npoints: \"\",\n});\ns.appendChild(pl)"
50 ";\nc.appendChild(s);\nvar sn = document.createElement(\"div\");\nsn.className = \"num\";\nsn.textContent = \"-"
51 "\";\nc.appendChild(sn);\nvar hist = [];\nupd = function (v) {\nhist.push(v);\nif (hist.length > 40) hist.shift"
52 "();\nvar pts = hist\n.map(function (y, i) {\nreturn (\n(200 * i) / 39 +\n\",\" +\n(50 - 50 * frac(y, w.min, w."
53 "max))\n);\n})\n.join(\" \");\npl.setAttribute(\"points\", pts);\nsn.textContent = fmt(v) + \" \" + w.unit;\n};"
54 "\n} else if (w.type === \"chart\") {\nvar cv = document.createElement(\"canvas\");\ncv.width = 240;\ncv.height"
55 " = 64;\nc.appendChild(cv);\nvar cn = document.createElement(\"div\");\ncn.className = \"num\";\ncn.textContent"
56 " = \"-\";\nc.appendChild(cn);\nvar ctx = cv.getContext(\"2d\");\nvar ch = [];\nupd = function (v) {\nch.push(v"
57 ");\nif (ch.length > cv.width) ch.shift();\nctx.clearRect(0, 0, cv.width, cv.height);\nctx.strokeStyle = \"#3fb"
58 "950\";\nctx.lineWidth = 2;\nctx.beginPath();\nfor (var i = 0; i < ch.length; i++) {\nvar x = (cv.width * i) / "
59 "(cv.width - 1);\nvar y =\ncv.height -\ncv.height * frac(ch[i], w.min, w.max);\nif (i === 0) ctx.moveTo(x, y);"
60 "\nelse ctx.lineTo(x, y);\n}\nctx.stroke();\ncn.textContent = fmt(v) + \" \" + w.unit;\n};\n} else if (w.type ="
61 "== \"button\") {\nvar btn = document.createElement(\"button\");\nbtn.className = \"btn\";\nbtn.textContent = "
62 "\"Press\";\nbtn.onclick = function () {\nsendCtrl(w.key, 1);\n};\nc.appendChild(btn);\nupd = function () {};\n"
63 "} else if (w.type === \"toggle\") {\nvar tg = document.createElement(\"input\");\ntg.type = \"checkbox\";\ntg."
64 "className = \"sw\";\ntg.onchange = function () {\nsendCtrl(w.key, tg.checked ? 1 : 0);\n};\nc.appendChild(tg);"
65 "\nupd = function (v) {\ntg.checked = v >= 0.5;\n};\n} else if (w.type === \"slider\") {\nvar sl = document.cre"
66 "ateElement(\"input\");\nsl.type = \"range\";\nsl.min = w.min;\nsl.max = w.max;\nsl.value = w.min;\nvar sv = do"
67 "cument.createElement(\"span\");\nsv.className = \"unit\";\nsv.textContent = fmt(w.min) + w.unit;\nsl.oninput ="
68 " function () {\nsv.textContent = fmt(+sl.value) + w.unit;\n};\nsl.onchange = function () {\nsendCtrl(w.key, +s"
69 "l.value);\n};\nc.appendChild(sl);\nc.appendChild(sv);\nupd = function () {};\n} else {\nvar n = document.creat"
70 "eElement(\"div\");\nn.className = \"num\";\nvar tn = document.createTextNode(\"-\");\nn.appendChild(tn);\nvar "
71 "u = document.createElement(\"span\");\nu.className = \"unit\";\nu.textContent = w.unit;\nn.appendChild(u);\nc."
72 "appendChild(n);\nupd = function (v) {\ntn.nodeValue = fmt(v);\n};\n}\ngrid.appendChild(c);\nreturn upd;\n}\nfe"
73 "tch(base + \"/layout\")\n.then(function (r) {\nreturn r.json();\n})\n.then(function (list) {\nlist.forEach(fun"
74 "ction (w) {\nwidgets[w.key] = card(w);\n});\nif (\nlist.some(function (w) {\nreturn (\nw.type === \"button\" |"
75 "|\nw.type === \"toggle\" ||\nw.type === \"slider\"\n);\n})\n) {\nvar proto =\nlocation.protocol === \"https:\""
76 "\n? \"wss://\"\n: \"ws://\";\nws = new WebSocket(\nproto + location.host + base + \"/ws\",\n);\n}\nvar es = ne"
77 "w EventSource(base + \"/stream\");\nes.onopen = function () {\ndot.className = \"live\";\nstatus.textContent ="
78 " \"live\";\n};\nes.onerror = function () {\ndot.className = \"\";\nstatus.textContent = \"reconnecting...\";\n"
79 "};\nes.onmessage = function (ev) {\ntry {\nvar d = JSON.parse(ev.data);\nfor (var k in d)\nif (widgets[k]) wid"
80 "gets[k](d[k]);\n} catch (e) {}\n};\n});\n})();</script> </body></html>";
81
82const char DETWS_PROV_FORM[] =
83 "<!doctype html><html><head><meta name=\"viewport\" content=\"width=device-width\" /><title>WiFi setup</title><"
84 "/head><body><h2>WiFi setup</h2><form method=\"POST\" action=\"/save\"> SSID:<br /><input name=\"ssid\" maxleng"
85 "th=\"32\" /><br /> Password:<br /><input name=\"psk\" type=\"password\" maxlength=\"63\" /><br /><br /><input "
86 "type=\"submit\" value=\"Save\" /></form></body></html>";
87
88const char DETWS_PROV_SAVED_HTML[] = "<html><body> Saved. Rebooting... </body></html>";
89
90const char DETWS_TERMINAL_PAGE[] =
91 "<!doctype html><html><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width,init"
92 "ial-scale=1\" /><title>DetWS Terminal</title> <style>:root{--g:#2bb35a;--g2:#00c000;--bg:#080c08;}*{box-sizing"
93 ":border-box;}html,body{margin:0;height:100%;background:var(--bg);color:var(--g);font:14px/1.45 \"Consolas\",\""
94 "DejaVu Sans Mono\",monospace;}#wrap{display:flex;flex-direction:column;height:100%;position:relative;}#out{fle"
95 "x:1;overflow:auto;padding:10px;white-space:pre-wrap;word-break:break-word;text-shadow:0 0 4px rgba(43,179,90,0"
96 ".55);}#bar{display:flex;border-top:1px solid #14401f;background:#0a0f0a;}#ps{padding:8px 4px 8px 10px;color:va"
97 "r(--g2);}#in{flex:1;background:transparent;border:0;color:var(--g);font:inherit;padding:8px;outline:none;}#st{"
98 "padding:4px 10px;font-size:11px;color:#1c6e38;border-top:1px solid #14401f;}#crt{position:absolute;inset:0;poi"
99 "nter-events:none;z-index:9;background:repeating-linear-gradient( rgba(0,0,0,0) 0 2px,rgba(0,0,0,0.18) 3px );bo"
100 "x-shadow:inset 0 0 120px rgba(0,0,0,0.6);}.e{color:#d2553a;}</style> </head><body><div id=\"wrap\"><div id=\"o"
101 "ut\"></div><div id=\"bar\"><span id=\"ps\">&gt;</span ><input id=\"in\" autocomplete=\"off\" autofocus /></div"
102 "><div id=\"st\">connecting…</div><div id=\"crt\"></div></div> <script>var out = document.getElementById(\"out"
103 "\"),\ninp = document.getElementById(\"in\"),\nst = document.getElementById(\"st\");\nvar hist = [],\nhi = 0,\n"
104 "ws,\nurl =\n(location.protocol == \"https:\" ? \"wss\" : \"ws\") +\n\"://\" +\nlocation.host +\nlocation.pathn"
105 "ame.replace(/\\/$/, \"\") +\n\"/ws\";\nfunction add(t, c) {\nvar b =\nout.scrollHeight - out.clientHeight - ou"
106 "t.scrollTop < 40;\nvar s = document.createElement(\"span\");\nif (c) s.className = c;\ns.textContent = t;\nout"
107 ".appendChild(s);\nif (b) out.scrollTop = out.scrollHeight;\n}\nfunction conn() {\nws = new WebSocket(url);\nws"
108 ".onopen = function () {\nst.textContent = \"connected\";\n};\nws.onmessage = function (e) {\nadd(e.data);\n};"
109 "\nws.onclose = function () {\nst.textContent = \"disconnected — retrying…\";\nsetTimeout(conn, 1000);\n};\nws."
110 "onerror = function () {\ntry {\nws.close();\n} catch (_) {}\n};\n}\ninp.addEventListener(\"keydown\", function"
111 " (e) {\nif (e.key == \"Enter\") {\nvar v = inp.value;\nif (v) {\nif (ws && ws.readyState == 1) {\nws.send(v);"
112 "\nadd(\"> \" + v + \"\\n\");\n} else add(\"> \" + v + \" (offline)\\n\", \"e\");\nhist.push(v);\nhi = hist.len"
113 "gth;\n}\ninp.value = \"\";\n} else if (e.key == \"ArrowUp\") {\nif (hi > 0) {\nhi--;\ninp.value = hist[hi] || "
114 "\"\";\n}\n} else if (e.key == \"ArrowDown\") {\nif (hi < hist.length) {\nhi++;\ninp.value = hist[hi] || \"\";"
115 "\n}\n}\n});\nconn();</script> </body></html>";
116
117// ---- json ----
118const char DETWS_STATS_JSON[] =
119 "{\"uptime_ms\":{{uptime_ms}},\"requests\":{{requests}},\"http_2xx\":{{http_2xx}},\"http_4xx\":{{http_4xx}},\"h"
120 "ttp_5xx\":{{http_5xx}},\"active_conns\":{{active_conns}},\"free_heap\":{{free_heap}}}";
121
122// ---- text ----
123const char DETWS_METRICS_PROM[] =
124 "# HELP detws_uptime_seconds Device uptime in seconds.\n# TYPE detws_uptime_seconds gauge\ndetws_uptime_seconds"
125 " {{uptime_seconds}}\n# HELP detws_http_requests_total Total HTTP responses sent.\n# TYPE detws_http_requests_t"
126 "otal counter\ndetws_http_requests_total {{requests_total}}\n# HELP detws_http_responses_total HTTP responses b"
127 "y status class.\n# TYPE detws_http_responses_total counter\ndetws_http_responses_total{class=\"2xx\"} {{resp_2"
128 "xx}}\ndetws_http_responses_total{class=\"4xx\"} {{resp_4xx}}\ndetws_http_responses_total{class=\"5xx\"} {{resp"
129 "_5xx}}\n# HELP detws_active_connections Currently active connection slots.\n# TYPE detws_active_connections ga"
130 "uge\ndetws_active_connections {{active_conns}}\n# HELP detws_max_connections Connection slot capacity.\n# TYPE"
131 " detws_max_connections gauge\ndetws_max_connections {{max_conns}}\n# HELP detws_free_heap_bytes Free heap in b"
132 "ytes.\n# TYPE detws_free_heap_bytes gauge\ndetws_free_heap_bytes {{free_heap}}\n# HELP detws_min_free_heap_byt"
133 "es Lowest free heap observed since boot, in bytes.\n# TYPE detws_min_free_heap_bytes gauge\ndetws_min_free_hea"
134 "p_bytes {{min_free_heap}}\n# HELP detws_heap_size_bytes Total heap size, in bytes.\n# TYPE detws_heap_size_byt"
135 "es gauge\ndetws_heap_size_bytes {{heap_size}}\n# HELP detws_max_alloc_heap_bytes Largest contiguous allocatabl"
136 "e heap block, in bytes.\n# TYPE detws_max_alloc_heap_bytes gauge\ndetws_max_alloc_heap_bytes {{max_alloc_heap}"
137 "}\n";
const char DETWS_DASHBOARD_PAGE[]
Real-time SVG telemetry dashboard page (DETWS_ENABLE_DASHBOARD).
const char DETWS_PROV_SAVED_HTML[]
Success page shown after credentials are saved and the device reboots.
const char DETWS_STATS_JSON[]
Runtime stats JSON (rendered via send_template); add/rename fields to taste.
const char DETWS_TERMINAL_PAGE[]
Self-contained WebSocket terminal page (green-phosphor CRT theme; auto ws/wss).
const char DETWS_METRICS_PROM[]
All available Prometheus metrics; comment a value line out with a leading # to drop it.
const char DETWS_PROV_FORM[]
Captive-portal form for WiFi credential entry (provisioning service).
Layer 7 (Application) - embedded web assets generated from src/web/input/.