mi32 refactor web UI (#23979)
This commit is contained in:
parent
a245696d7c
commit
20566dd1dc
@ -26,7 +26,7 @@ extern void be_MI32_set_temp(int slot, int temp_val);
|
||||
BE_FUNC_CTYPE_DECLARE(be_MI32_set_temp, "", "ii");
|
||||
|
||||
extern bbool be_MI32_widget(const char *sbuf, void* function);
|
||||
BE_FUNC_CTYPE_DECLARE(be_MI32_widget, "b", "s[c]");
|
||||
BE_FUNC_CTYPE_DECLARE(be_MI32_widget, "b", "[sc]");
|
||||
|
||||
#include "be_fixed_MI32.h"
|
||||
|
||||
|
||||
@ -484,76 +484,27 @@ enum MI32_BLEInfoMsg {
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
const char HTTP_BTN_MENU_MI32[] PROGMEM = "<p></p><form action='m32' method='get'><button>Mi Dashboard</button></form>";
|
||||
const char HTTP_BTN_MENU_MI32[] PROGMEM = "<p></p><form action='m32' method='get'><button>Dashboard</button></form>";
|
||||
|
||||
const char HTTP_MI32_SCRIPT_1[] PROGMEM =
|
||||
"function setUp(){setInterval(countUp,1000); setInterval(update,200);}"
|
||||
"function countUp(){let ti=document.querySelectorAll('.Ti');eb('clock').innerText=Date().slice(4,24);"
|
||||
"eb('numDev').innerText=eb('pr').childElementCount-1;"
|
||||
"for(const el of ti){var t=parseInt(el.innerText);el.innerText=t+1;}}"
|
||||
"function update(){"
|
||||
"fetch('/m32?wi=1').then(r=>r.text())"
|
||||
".then((r)=>{"
|
||||
// console.log(r); // optional
|
||||
"if(r.length>0){"
|
||||
"var d=document.createElement('div');"
|
||||
"d.innerHTML=r.trim();"
|
||||
"var old=eb(d.firstChild.id);"
|
||||
"if(old == null){eb('pr').appendChild(d.firstChild);}"
|
||||
"else{old.parentNode.replaceChild(d.firstChild, old);}"
|
||||
"}"
|
||||
"})"
|
||||
//".catch((e) => {console.error(e);});" //optional
|
||||
"};"
|
||||
;
|
||||
|
||||
const char HTTP_MI32_STYLE[] PROGMEM =
|
||||
"<style onload=setTimeout(setUp,500)>body{display:flex;flex-direction:column;}"
|
||||
".parent{display:grid;grid-template-columns:repeat(auto-fill,350px);grid-template-rows:repeat(auto-fill,220px);"
|
||||
"grid-auto-rows:220px;grid-auto-columns:350px;gap:1rem;justify-content:center;}"
|
||||
"svg{float:inline-end;}"
|
||||
".box{padding:10px;border-radius:0.8rem;background-color:rgba(221, 221, 221, 0.2);overflow-y:auto;}"
|
||||
"@media screen and (min-width: 720px){.wide{grid-column:span 2;grid-row:span 1;}.big {grid-column:span 2;grid-row:span 2;}}"
|
||||
".tall {grid-column:span 1;grid-row:span 2;}"
|
||||
"</style>";
|
||||
|
||||
const char HTTP_MI32_STYLE_SVG[] PROGMEM =
|
||||
"<svg height='0'><defs><linearGradient id='grd%u' x1='0%%' y1='0%%' x2='0%%' y2='15%%'>"
|
||||
"<stop offset='0' stop-color='rgba(%u, %u, %u, 0.5)'/>"
|
||||
"<stop offset='1' stop-color='rgba(%u, %u, %u, 0)'/></linearGradient></defs></svg>"
|
||||
;
|
||||
const char HTTP_MI32_BOOTSTRAP[] PROGMEM =
|
||||
"wl(_=>fetch('/m32?wi=0').then(r=>r.text()).then(t=>{"
|
||||
"d=document;" // this is global now
|
||||
"x=d.createElement('div');"
|
||||
"x.innerHTML=t;" // was global already
|
||||
"x.querySelectorAll('style').forEach(n=>d.head.appendChild(n.cloneNode(1)));"
|
||||
"x.querySelectorAll('script').forEach(n=>{s=d.createElement('script');s.textContent=n.textContent;d.body.appendChild(s)});"
|
||||
"eb('m').innerHTML=(x.querySelector('body')||x).innerHTML;"
|
||||
"}));";
|
||||
|
||||
const char HTTP_MI32_PARENT_BLE_ROLE[] PROGMEM = "None|Observer|Peripheral|Central";
|
||||
|
||||
const char HTTP_MI32_PARENT_START[] PROGMEM =
|
||||
"<div class='parent'id='pr'>"
|
||||
"<div class='box tall'><h2>MI32 Bridge</h2>"
|
||||
"<span id='clock'></span><br><br>"
|
||||
"Observing <span id='numDev'>%u</span> devices<br><br>"
|
||||
"Uptime: <span class='Ti'>%u</span> seconds<br><br>"
|
||||
"Free Heap: %u kB<br><br>"
|
||||
"BLE Role: %s"
|
||||
"</div>";
|
||||
|
||||
const char HTTP_MI32_WIDGET[] PROGMEM =
|
||||
"<div class='box' id='box%u' style='opacity:%u.5;'>MAC:%s RSSI:%d %s<br>"
|
||||
"<small>‌%s</small>"
|
||||
"<h2 style='margin-top:0em;'>%s"
|
||||
"<svg height='24' width='24' style='float:inline-end;'>"
|
||||
"<circle cx='11' cy='11' r='0' fill='#90ee90' opacity='0'>"
|
||||
"<animate attributeName='r' from='11' to='0' dur='9s' repeatCount='1'></animate>"
|
||||
"<animate attributeName='opacity' from='1' to='0' dur='9s' repeatCount='1'></animate></circle></svg>"
|
||||
"{ci}" // circle animation
|
||||
"</h2>";
|
||||
|
||||
const char HTTP_MI32_GRAPH[] PROGMEM =
|
||||
"<svg height='20' width='150'>"
|
||||
"<polyline points='%s'"
|
||||
"style='stroke:rgb(%u, %u, %u);fill:none;'></polyline>"
|
||||
"<polyline points='%s138,20 0,20'"
|
||||
"style='stroke:none;fill:url(#grd%u);'></polyline>"
|
||||
"</svg>";
|
||||
//rgb(185, 124, 124) - red, rgb(185, 124, 124) - blue, rgb(242, 240, 176) - yellow
|
||||
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
const char HTTP_MI32_POWER_WIDGET[] PROGMEM =
|
||||
"<div class='box' id='box%u'>"
|
||||
@ -563,6 +514,620 @@ const char HTTP_MI32_POWER_WIDGET[] PROGMEM =
|
||||
"<p>" D_CURRENT ": %.3f " D_UNIT_AMPERE "</p>";
|
||||
#endif //USE_MI_ESP32_ENERGY
|
||||
|
||||
/*
|
||||
STATIC_PAGE MI32_STATIC_PAGE
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
code {
|
||||
word-break: break-all;
|
||||
}
|
||||
.parent {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill,350px);
|
||||
grid-template-rows: repeat(auto-fill,220px);
|
||||
grid-auto-rows: 220px;
|
||||
grid-auto-columns: 350px;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
}
|
||||
svg {
|
||||
float: inline-end;
|
||||
}
|
||||
svg text {
|
||||
font-size: 0.95em;
|
||||
fill: currentColor;
|
||||
}
|
||||
.box {
|
||||
padding: 10px;
|
||||
border-radius: 0.8rem;
|
||||
background-color: rgba(221,221,221,0.2);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.box svg {
|
||||
max-width: 100%;
|
||||
}
|
||||
.box.w1 { grid-column: span 1; }
|
||||
.box.w2 { grid-column: span 2; }
|
||||
.box.w3 { grid-column: span 3; }
|
||||
.box.h1 { grid-row: span 1; }
|
||||
.box.h2 { grid-row: span 2; }
|
||||
.box.h3 { grid-row: span 3; }
|
||||
@media (width < 720px) {
|
||||
.box.w2, .box.w3 { grid-column: span 1; }
|
||||
.box.h3 { grid-row: span 2; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
let sz=[], u=0; // sizes, uptime
|
||||
//global vars from tasmota header script for local reuse:
|
||||
// x,lt,to,tp,pc
|
||||
// d = document from the bootstrap script
|
||||
// we also have:
|
||||
// eb=s=>document.getElementById(s);
|
||||
// qs=s=>document.querySelector(s);
|
||||
// wl=f=>window.addEventListener('load',f);
|
||||
|
||||
function pulse(s) { // size
|
||||
sz.push(s);
|
||||
if (sz.length > 60) sz.shift();
|
||||
lt = "(0,200,0):" + sz.join(",");
|
||||
pc = `{l,250,20,${lt}}`;
|
||||
eb('pulse').innerHTML = "AJAX: " + render(pc);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
setInterval(cU, 1000); // countUp
|
||||
setInterval(update, 200);
|
||||
}
|
||||
|
||||
function cU() {
|
||||
x = eb('clock');
|
||||
if (x) x.innerHTML = Date().slice(4,24);
|
||||
}
|
||||
|
||||
function updateMetrics(m) {
|
||||
let fk = +(m[3] / 1024).toFixed(1); // freeKB
|
||||
let tk = +(m[4] / 1024).toFixed(1); // totalKB
|
||||
let fp = +(m[7] / 1024).toFixed(0); // freePSRAM
|
||||
let tp = +(m[6] / 1024).toFixed(0); // totalPSRAM
|
||||
let fh = +(m[5]); // fragHeap
|
||||
|
||||
eb('r').innerHTML = 'RSSI: ' + m[0] + ' dBm';
|
||||
eb('mo').innerHTML = 'Mode: ' + ['Low Rate','802.11b','802.11g','HT20 (11n)','HT40 (11n)','HE20 (11ax)'][m[2]] + ' / Channel: ' + m[1];
|
||||
eb('heap_gauge').innerHTML = render(`{g,50,50,${fk},0,${tk},255,102,102,0,255,255,153,40,0,200,0,80,kB}`);
|
||||
eb('psram_gauge').innerHTML = render(`{g,50,50,${fp},0,${tp},255,102,102,0,255,255,153,100,0,200,0,250,kB}`);
|
||||
eb('heap').innerHTML = 'Heap free: ' + fk + '/' + tk + ' kB<br>(frag. ' + fh + '%)';
|
||||
eb('psram').innerHTML = 'PSRAM free: ' + fp + '/' + tp + ' kB';
|
||||
eb('ut').innerHTML = 'Uptime: ' + m[8] + ' sec';
|
||||
eb('ro').innerHTML = 'BLE role: ' + ['none','observer','peripheral','central'][m[9]];
|
||||
eb('sd').innerHTML = 'MI32 sensors: ' + m[10];
|
||||
}
|
||||
|
||||
function update() {
|
||||
try {
|
||||
fetch('/m32?wi=1').then(r => r.text()).then(html => {
|
||||
x = html.length; // number of characters ≈ bytes
|
||||
pulse(x); // pass size instead of true/false
|
||||
if (!html) {
|
||||
return;
|
||||
}
|
||||
let parts = html.trim().split(/[\n\r,]+/);
|
||||
if (parts.length === 11 && parts.every(p => /^-?\d+$/.test(p))) {
|
||||
updateMetrics(parts.map(Number));
|
||||
return;
|
||||
}
|
||||
|
||||
let ciSVG =
|
||||
"<svg height='24' width='24' >" // style='float:right;'
|
||||
+ "<circle cx='11' cy='11' r='0' fill='#90ee90' opacity='0'>"
|
||||
+ "<animate attributeName='r' from='11' to='0' dur='9s' repeatCount='1'/>"
|
||||
+ "<animate attributeName='opacity' from='1' to='0' dur='9s' repeatCount='1'/>"
|
||||
+ "</circle></svg>";
|
||||
|
||||
let replaced = html
|
||||
.replace(/{ci}/g, ciSVG)
|
||||
.replace(/\{[lLhHgG],[^}]+\}/g, match => {
|
||||
try { return render(match); }
|
||||
catch (e) {
|
||||
console.warn("DSL render error:", e);
|
||||
return "<small>graph unavailable</small>";
|
||||
}
|
||||
});
|
||||
|
||||
x = d.createElement('div');
|
||||
x.innerHTML = replaced.trim();
|
||||
|
||||
lt = Array.from(x.getElementsByTagName('script'));
|
||||
lt.forEach(el => el.remove());
|
||||
|
||||
tp = x.firstChild; //new element
|
||||
to = eb(tp.id); // old element
|
||||
if (to) to.parentNode.replaceChild(tp, to);
|
||||
else eb('pr').appendChild(tp);
|
||||
|
||||
lt.forEach(el => {
|
||||
let sc = d.createElement('script');
|
||||
sc.textContent = el.textContent;
|
||||
d.body.appendChild(sc);
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
// console.warn("update error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(setUp, 500);
|
||||
|
||||
// Dispatcher for compact DSL only: {type,w,h,(r,g,b):v1,v2…[|…]}
|
||||
// Uppercase ⇒ WITH grid; lowercase ⇒ WITHOUT grid
|
||||
function render(payload) {
|
||||
let s = String(payload).trim();
|
||||
if (!s.startsWith("{") || !s.endsWith("}")) return "";
|
||||
let inner = s.slice(1, -1);
|
||||
|
||||
// First char = type
|
||||
let typeChar = inner[0];
|
||||
let showGrid = typeChar === typeChar.toUpperCase();
|
||||
let type = typeChar.toLowerCase();
|
||||
|
||||
// Handle line/histogram with series syntax
|
||||
if ("lh".includes(type)) {
|
||||
let m = inner.match(/^([lLhH]),(\d+),(\d+),(.+)$/);
|
||||
if (!m) return "";
|
||||
|
||||
let [, , wStr, hStr, sStr] = m;
|
||||
let w = +wStr; // width
|
||||
let h = +hStr; // height
|
||||
|
||||
// Extract xl: parameter if present
|
||||
let xl = null; // xLabels - custom X-axis labels
|
||||
let seg = sStr.split("|");
|
||||
for (let i = 0; i < seg.length; i++) {
|
||||
if (seg[i].startsWith("xl:")) {
|
||||
xl = seg[i].substring(3).split(",");
|
||||
seg.splice(i, 1); // remove xl: segment from array
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let sl = seg.map(seg => { // sl = seriesList
|
||||
let mm = seg.match(/^\((\d+),(\d+),(\d+)\):(.*)$/);
|
||||
if (!mm) return null;
|
||||
return {
|
||||
rgb: [+mm[1], +mm[2], +mm[3]],
|
||||
values: mm[4].split(",").map(v => Number(v.trim()))
|
||||
};
|
||||
}).filter(Boolean);
|
||||
|
||||
switch (type) {
|
||||
case "l":
|
||||
return renderLG(sl, w, h, showGrid, xl);
|
||||
break;
|
||||
case "h":
|
||||
if (sl.length === 1)
|
||||
return renderH(sl[0].values, sl[0].rgb, w, h, showGrid, xl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle gauge DSL separately
|
||||
// Gauge DSL: {g,w,h,val,min,max,r1,g1,b1,threshold1,r2,g2,b2,threshold2,...,unit}
|
||||
// Example: {g,200,140,75,0,100,0,200,0,0,200,160,0,40,200,0,0,75,%}
|
||||
// Stops: RGB triplet + threshold value, repeating. Unit string at end.
|
||||
if (type === "g") {
|
||||
let p = inner.split(',');
|
||||
let w = +p[1], h = +p[2], val = +p[3], min = +p[4], max = +p[5];
|
||||
let stops = [];
|
||||
for (let i = 6; i < p.length - 1; i += 4) {
|
||||
stops.push({
|
||||
value: +p[i+3],
|
||||
color: `rgb(${p[i]},${p[i+1]},${p[i+2]})`
|
||||
});
|
||||
}
|
||||
let unit = p[p.length - 1];
|
||||
let showValue = (typeChar === "G");
|
||||
return renderG(val, min, max, w, h, stops, unit, showValue);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function buildGrid(w, h, mv, dL, yt = 4, cX = null) { // maxVal, dataLength, yTicks, customXLabels
|
||||
let ln = [], lb = [], xl = []; // lines, labels, xLabels
|
||||
let nm = Math.ceil(mv / 10) * 10; // niceMax
|
||||
let ti = nm / yt; // tickInterval
|
||||
if (ti <= 5) ti = 5;
|
||||
else if (ti <= 10) ti = 10;
|
||||
else if (ti <= 25) ti = 25;
|
||||
else ti = Math.ceil(ti / 50) * 50;
|
||||
nm = Math.ceil(mv / ti) * ti;
|
||||
let at = Math.ceil(nm / ti); // actualTicks
|
||||
for (let i = 0; i <= at; i++) {
|
||||
let v = i * ti;
|
||||
let y = h - (v * h / nm);
|
||||
ln.push(`<line x1="0" y1="${y}" x2="${w}" y2="${y}" stroke="#ddd" stroke-width="1"/>`);
|
||||
if (i < at) lb.push(`<text x="-5" y="${y+4}" text-anchor="end">${v}</text>`);
|
||||
}
|
||||
if (cX && cX.length > 0) { // X-axis labels - use custom if provided, otherwise default numeric
|
||||
let xs = cX.length - 1; // xSteps
|
||||
for (let i = 0; i < cX.length; i++) {
|
||||
let x = xs > 0 ? i * (w / xs) : w / 2;
|
||||
xl.push(`<text x="${x}" y="${h+20}" text-anchor="middle">${cX[i]}</text>`);
|
||||
}
|
||||
} else {
|
||||
let xs = 4; // xSteps
|
||||
for (let i = 0; i <= xs; i++) {
|
||||
let x = i * (w / xs);
|
||||
let xi = Math.round(i * (dL - 1) / xs);
|
||||
xl.push(`<text x="${x}" y="${h+20}" text-anchor="middle">${xi}</text>`);
|
||||
}
|
||||
}
|
||||
return { lines: ln.join(""), labels: lb.join(""), xl: xl.join("") };
|
||||
}
|
||||
|
||||
function renderG(v, mn, mx, w, h, st, u = "", sv = true) { // value, min, max, stops, unit, showValue
|
||||
let cl = x => Math.max(mn, Math.min(mx, x)); // clamp
|
||||
let vl = cl(v); // val
|
||||
let sp = mx - mn || 1; // span
|
||||
let t = (vl - mn) / sp;
|
||||
let cx = w / 2, cy = h / 2;
|
||||
let ro = Math.min(w, h) * 0.45; // rOuter
|
||||
let ri = ro * 0.75; // rInner
|
||||
let so = ro * 0.06, si = ro * 0.35; // swOuter, swInner
|
||||
let gd = 2; // gapDeg
|
||||
let sd = -135 + gd, ed = 135 - gd, swd = ed - sd; // startDeg, endDeg, sweepDeg
|
||||
|
||||
function polar(cx, cy, r, d) { // deg
|
||||
let rd = (d - 90) * Math.PI / 180; // rad
|
||||
return { x: cx + r * Math.cos(rd), y: cy + r * Math.sin(rd) };
|
||||
}
|
||||
function arcPath(cx, cy, r, a0, a1) {
|
||||
let la = Math.abs(a1 - a0) > 180 ? 1 : 0; // largeArc
|
||||
let sw = a1 > a0 ? 1 : 0; // sweep
|
||||
let p0 = polar(cx, cy, r, a0);
|
||||
let p1 = polar(cx, cy, r, a1);
|
||||
return `M ${p0.x},${p0.y} A ${r},${r} 0 ${la} ${sw} ${p1.x},${p1.y}`;
|
||||
}
|
||||
function colorFor(v) {
|
||||
if (!st.length) return "rgb(120,120,120)";
|
||||
let c = st[0].color;
|
||||
for (let i = 0; i < st.length; i++) {
|
||||
if (v >= st[i].value) c = st[i].color;
|
||||
else break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
let os = ""; // outerSegs
|
||||
for (let i = 0; i < st.length; i++) {
|
||||
let fr = (st[i].value - mn) / sp; // from
|
||||
let to = (i + 1 < st.length) ? (st[i+1].value - mn) / sp : 1;
|
||||
let a0 = sd + swd * fr, a1 = sd + swd * to;
|
||||
if (a1 <= a0) continue;
|
||||
os += `<path d="${arcPath(cx, cy, ro, a0, a1)}" stroke="${st[i].color}" stroke-width="${so}" fill="none"/>`;
|
||||
}
|
||||
let bt = `<path d="${arcPath(cx, cy, ri, sd, ed)}" stroke="rgba(120,120,120,0.25)" stroke-width="${si}" fill="none"/>`; // bgTrack
|
||||
let pc = colorFor(vl); // progColor
|
||||
let pe = sd + swd * t; // progEnd
|
||||
let ia = t > 0 ? `<path d="${arcPath(cx, cy, ri, sd, pe)}" stroke="${pc}" stroke-width="${si}" fill="none"/>` : ""; // innerArc
|
||||
let tx = ""; // text
|
||||
if (sv) {
|
||||
let fs = Math.round(Math.min(w, h) * 0.18); // fontSize
|
||||
tx = `<text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="middle" font-size="${fs}" fill="${pc}" font-weight="600">${vl}${u}</text>`;
|
||||
}
|
||||
return `<svg width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">${os}${bt}${ia}${tx}</svg>`.trim();
|
||||
}
|
||||
|
||||
function renderLG(sl, w, h, sg = true, customXL = null) { // showGrid, customXLabels
|
||||
let mv = Math.max(...sl.flatMap(s => s.values), 1); // maxVal
|
||||
let gd = sg ? buildGrid(w, h, mv, sl[0].values.length, 4, customXL) : { lines: "", labels: "", xl: "" }; // grid
|
||||
let clipId = `clip_${Math.random().toString(36).slice(2)}`; // Clip path to hide vertical edges at x=0 and x=w
|
||||
let clip = `<clipPath id="${clipId}"><rect x="0" y="0" width="${w}" height="${h}"/></clipPath>`;
|
||||
let df = [], ly = []; // defs, layers
|
||||
sl.forEach((s, i) => {
|
||||
let gi = `g${i}_${Math.random().toString(36).slice(2)}`; // gradId
|
||||
df.push(`<linearGradient id="${gi}" x1="0" y1="0" x2="0" y2="${h}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="rgba(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]},0.35)"/><stop offset="100%" stop-color="rgba(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]},0)"/></linearGradient>`);
|
||||
let pt = s.values.map((v, j) => { // points
|
||||
let x = s.values.length > 1 ? (j * w) / (s.values.length - 1) : 0;
|
||||
let y = v <= 0 ? h : h - (v / mv) * h;
|
||||
return `${x},${y}`;
|
||||
}).join(" ");
|
||||
ly.push(`<polyline points="-20,${h} ${pt} ${w+20},${h}" fill="url(#${gi})" stroke="rgb(${s.rgb[0]},${s.rgb[1]},${s.rgb[2]})" stroke-width="2" clip-path="url(#${clipId})"/>`);
|
||||
});
|
||||
return `<svg width="${w}" height="${h+30}" viewBox="-50 0 ${w+100} ${h+40}">${gd.lines}${gd.labels}${gd.xl}<defs>${clip}${df.join("")}</defs>${ly.join("")}</svg>`.trim();
|
||||
}
|
||||
|
||||
function renderH(vs, rgb, w, h, sg = true, cX = null) { // values, showGrid, customXLabels
|
||||
let mv = Math.max(...vs); // maxVal
|
||||
let sc = mv > h ? h / mv : 1; // scale
|
||||
let gp = 2; // gap
|
||||
let tg = (vs.length - 1) * gp; // totalGaps
|
||||
let bw = (w - tg) / vs.length; // barW
|
||||
let gi = "hg_" + (Math.random()*1e9|0); // gradId
|
||||
let df = `<linearGradient id="${gi}" x1="0%" y1="0%" x2="0%" y2="${h}" gradientUnits="userSpaceOnUse"><stop offset="0%" stop-color="rgba(${rgb[0]},${rgb[1]},${rgb[2]},1)"/><stop offset="100%" stop-color="rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.1)"/></linearGradient>`; // defs
|
||||
let rs = ''; // rects
|
||||
vs.forEach((v, i) => {
|
||||
let bh = Math.min(v * sc, h); // barH
|
||||
let y = h - bh;
|
||||
let x = i * (bw + gp);
|
||||
rs += `<rect x="${x}" y="${y}" width="${bw}" height="${bh}" fill="url(#${gi})"/>`;
|
||||
});
|
||||
if (!sg) return `<svg width="${w}" height="${h}"><defs>${df}</defs>${rs}</svg>`;
|
||||
let gd = buildGrid(w, h, mv, vs.length, 4, cX); // grid
|
||||
return `<svg width="${w}" height="${h+30}" viewBox="-50 0 ${w+100} ${h+40}">${gd.lines}${gd.labels}${gd.xl}<defs>${df}</defs>${rs}</svg>`.trim();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="parent" id="pr">
|
||||
<div class="box h2" id="info">
|
||||
<h2 id="clock"></h2>
|
||||
<p id="ut"></p>
|
||||
<p id="ro"></p>
|
||||
<p id="sd"></p><br>
|
||||
|
||||
<p id="r"></p>
|
||||
<p id="mo"></p>
|
||||
<p id="pulse"></p><br>
|
||||
|
||||
<div id="heap_gauge"></div>
|
||||
<p id="heap"></p>
|
||||
<div id="psram_gauge"></div>
|
||||
<p id="psram"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
END_STATIC_PAGE
|
||||
*/
|
||||
|
||||
|
||||
const char MI32_STATIC_PAGE[] PROGMEM = {
|
||||
/* AUTO-GENERATED (BEGIN) */
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x1a, 0x5c, 0xe1, 0x68, 0x02, 0xff, 0xc5, 0x39, 0xfd, 0x73, 0xdb, 0x36,
|
||||
0xb2, 0xbf, 0xf7, 0xaf, 0x60, 0x59, 0xa7, 0x22, 0x2c, 0x4a, 0x22, 0x65, 0x2b, 0x4d, 0x24, 0x41,
|
||||
0xbe, 0x24, 0xd7, 0x4b, 0x72, 0xe3, 0xf4, 0x3a, 0x4d, 0x73, 0x2f, 0x33, 0x8e, 0x5a, 0x53, 0x24,
|
||||
0x44, 0xb2, 0xe6, 0xd7, 0x10, 0x90, 0x44, 0x55, 0xe1, 0xff, 0x7e, 0xbb, 0x00, 0x48, 0x51, 0x76,
|
||||
0x92, 0xcb, 0x7b, 0xef, 0x66, 0x6e, 0xc6, 0x26, 0x81, 0xdd, 0xc5, 0x62, 0xb1, 0xdf, 0xa0, 0xe6,
|
||||
0x5c, 0xec, 0x13, 0xb6, 0x58, 0xe5, 0xc1, 0xfe, 0x10, 0xc4, 0xbc, 0x48, 0xbc, 0xfd, 0x74, 0x9d,
|
||||
0xb0, 0x6a, 0x86, 0x8f, 0x41, 0x10, 0x97, 0xcc, 0x17, 0x71, 0x9e, 0x4d, 0xfd, 0x3c, 0xd9, 0xa4,
|
||||
0x59, 0xed, 0xe7, 0x01, 0x3b, 0xec, 0xf2, 0x32, 0x18, 0xac, 0x4a, 0xe6, 0xdd, 0x4d, 0xe5, 0x73,
|
||||
0xe0, 0x25, 0x49, 0x3d, 0x2c, 0xbc, 0x92, 0x65, 0xa2, 0x65, 0x12, 0x96, 0x71, 0x30, 0xc3, 0xc7,
|
||||
0x40, 0xb0, 0x14, 0x20, 0x82, 0x0d, 0x14, 0x0f, 0x3e, 0x2d, 0x59, 0xc1, 0x3c, 0x61, 0x79, 0x1b,
|
||||
0x91, 0x0f, 0xd6, 0x71, 0x92, 0xd8, 0x17, 0x13, 0xa7, 0xa8, 0xc8, 0x3d, 0xea, 0x32, 0xdf, 0x7d,
|
||||
0x82, 0x74, 0x3c, 0x3e, 0x92, 0x4a, 0xa8, 0x24, 0x93, 0xd0, 0x0e, 0xb0, 0xd9, 0x49, 0x32, 0x9e,
|
||||
0x85, 0x5e, 0x31, 0x75, 0x4b, 0x96, 0xce, 0xfe, 0xd8, 0x70, 0x11, 0xaf, 0xf7, 0x80, 0xce, 0x04,
|
||||
0xc8, 0x3a, 0xf5, 0xe1, 0xc1, 0xca, 0x9a, 0x6f, 0xc3, 0xc3, 0x3a, 0xc9, 0x3d, 0x31, 0x8d, 0xb3,
|
||||
0x24, 0xce, 0xd8, 0x80, 0x65, 0x01, 0x02, 0x0d, 0xc1, 0x2a, 0x71, 0x58, 0x03, 0xf1, 0x80, 0xc7,
|
||||
0x7f, 0xb2, 0xa9, 0x33, 0x7c, 0x3a, 0x01, 0x2e, 0x28, 0xc7, 0xd4, 0xdf, 0x94, 0x78, 0xdc, 0x17,
|
||||
0x79, 0x92, 0x97, 0xf5, 0x70, 0x95, 0x57, 0x87, 0xc2, 0x0b, 0x82, 0x38, 0x0b, 0xa7, 0x2e, 0x6e,
|
||||
0xb9, 0x02, 0x15, 0xb1, 0x72, 0x50, 0x7a, 0x41, 0xbc, 0xe1, 0xb0, 0xf0, 0x09, 0x6e, 0xbf, 0xf2,
|
||||
0xfc, 0xbb, 0xb0, 0xcc, 0x37, 0x59, 0x80, 0x02, 0xe6, 0xe5, 0xb4, 0x0c, 0x57, 0x9e, 0x35, 0x1e,
|
||||
0xbb, 0x76, 0xf3, 0xef, 0x0c, 0xc7, 0x64, 0x96, 0x6f, 0x59, 0x09, 0xe2, 0xec, 0x06, 0xfb, 0x29,
|
||||
0x1e, 0x46, 0x72, 0x37, 0x50, 0xc6, 0xd4, 0xab, 0x06, 0xbb, 0x38, 0x10, 0x11, 0xec, 0xe1, 0x3c,
|
||||
0x92, 0xf0, 0xe1, 0xce, 0x3d, 0xc8, 0x63, 0xab, 0x13, 0x4f, 0x79, 0xe1, 0x65, 0x86, 0xab, 0x51,
|
||||
0xe3, 0x87, 0xa8, 0xb1, 0x46, 0x5d, 0x3c, 0x44, 0x5d, 0x28, 0x54, 0xa4, 0x19, 0x82, 0x5e, 0x4f,
|
||||
0xb8, 0x45, 0xe3, 0x7b, 0x70, 0xcd, 0x2a, 0xba, 0xb8, 0x07, 0xbf, 0xa8, 0xff, 0x92, 0xb2, 0x20,
|
||||
0xf6, 0x0c, 0x4b, 0xca, 0x6a, 0xcc, 0x8d, 0x1f, 0xa4, 0xcd, 0x0e, 0x5a, 0x28, 0xfb, 0xb3, 0x12,
|
||||
0xb8, 0x9f, 0xe1, 0x38, 0xae, 0xeb, 0xf9, 0x48, 0xf9, 0xe9, 0x9c, 0xfb, 0x65, 0x5c, 0x88, 0x45,
|
||||
0xc2, 0x84, 0xc1, 0xff, 0xa4, 0x37, 0x4b, 0x7b, 0x43, 0x9d, 0xd9, 0x7a, 0x93, 0x49, 0x2f, 0x35,
|
||||
0x8a, 0x4d, 0xc2, 0x99, 0xc5, 0xc9, 0x81, 0xff, 0x39, 0x2c, 0x36, 0x3c, 0x82, 0xe1, 0x2c, 0x5e,
|
||||
0x5b, 0x30, 0x4b, 0x58, 0x16, 0x8a, 0x68, 0xf1, 0xd8, 0x21, 0x30, 0xe1, 0x51, 0xbc, 0x16, 0x16,
|
||||
0x99, 0x25, 0x82, 0x9a, 0x96, 0x63, 0x8f, 0x1d, 0xc7, 0x76, 0xc8, 0xd4, 0xec, 0x03, 0xea, 0x8f,
|
||||
0x3c, 0xce, 0x2c, 0xd3, 0x36, 0xc9, 0xac, 0xf0, 0xe9, 0xed, 0x01, 0x1c, 0x6e, 0x82, 0x04, 0xf6,
|
||||
0xd9, 0x21, 0x11, 0x75, 0x7d, 0x3b, 0x63, 0x2b, 0xab, 0x27, 0x77, 0xe9, 0x91, 0x61, 0x9c, 0x65,
|
||||
0xac, 0x7c, 0xf5, 0xeb, 0x9b, 0x6b, 0x6a, 0x3e, 0xfb, 0xfb, 0xb3, 0xf7, 0x53, 0xc3, 0xec, 0x83,
|
||||
0x4f, 0x80, 0xdd, 0xad, 0xc2, 0x27, 0xb3, 0xfa, 0x9b, 0x56, 0x2c, 0xce, 0xc4, 0xbb, 0xc2, 0x02,
|
||||
0xa9, 0x98, 0x78, 0x8d, 0x1e, 0xb7, 0xf5, 0x12, 0xcb, 0x7f, 0x67, 0x83, 0x15, 0x1d, 0x32, 0xeb,
|
||||
0x02, 0x37, 0x45, 0x00, 0xae, 0x8f, 0x02, 0x9d, 0xac, 0xf7, 0xdf, 0xc1, 0xe2, 0x8a, 0xe2, 0xde,
|
||||
0x7e, 0x92, 0xfb, 0x77, 0x3d, 0x79, 0xaa, 0x8a, 0x54, 0x1d, 0x11, 0xfe, 0x0a, 0x0b, 0x2d, 0x32,
|
||||
0xe4, 0x49, 0xec, 0x33, 0xeb, 0xd2, 0x1e, 0x5f, 0x9e, 0x70, 0x50, 0x8c, 0xdf, 0x30, 0x51, 0xc6,
|
||||
0x3e, 0xb7, 0x52, 0x72, 0x40, 0x05, 0xae, 0xef, 0x68, 0xdf, 0x4a, 0x6f, 0x2e, 0x96, 0x23, 0xd7,
|
||||
0x01, 0xfa, 0xa1, 0xc8, 0xff, 0x16, 0x57, 0x2c, 0xb0, 0x5c, 0xd0, 0x0c, 0xa0, 0x85, 0x42, 0x5f,
|
||||
0x7e, 0x06, 0xbd, 0x2e, 0x24, 0xfa, 0x87, 0xfb, 0x68, 0x47, 0xaf, 0x56, 0xe8, 0xc7, 0x9f, 0x41,
|
||||
0xaf, 0x23, 0x89, 0x9e, 0x2c, 0x89, 0x54, 0x69, 0x79, 0xa2, 0xce, 0xde, 0x2f, 0x6f, 0xdf, 0xbe,
|
||||
0x9e, 0x1a, 0xbd, 0x7e, 0x7a, 0xe3, 0x2c, 0xfb, 0x3d, 0x23, 0x78, 0x9e, 0xf6, 0x24, 0x59, 0x9a,
|
||||
0x9f, 0xd2, 0xbd, 0x81, 0x74, 0x84, 0x74, 0x37, 0xbd, 0xeb, 0x7c, 0x67, 0xfc, 0x02, 0x47, 0xec,
|
||||
0xd9, 0xbd, 0x27, 0xce, 0x78, 0xe8, 0xba, 0xab, 0x76, 0x14, 0xc2, 0xe8, 0xd5, 0xaf, 0x63, 0xc7,
|
||||
0xb0, 0x5c, 0x37, 0x23, 0x72, 0x72, 0xd9, 0x99, 0xfc, 0xa8, 0x30, 0x5e, 0x45, 0x7a, 0xcb, 0x9b,
|
||||
0xf4, 0x66, 0xbc, 0xc4, 0x1d, 0x47, 0xc6, 0x8b, 0xc8, 0x83, 0x7d, 0x12, 0x25, 0x85, 0xbb, 0x94,
|
||||
0xdb, 0x47, 0xcc, 0x2b, 0x7e, 0x0f, 0xbd, 0x4d, 0x78, 0x6a, 0x7d, 0x6d, 0xf4, 0xdb, 0x43, 0x68,
|
||||
0x83, 0xb3, 0x4c, 0xd0, 0x59, 0xd6, 0x77, 0xb5, 0x8d, 0x6f, 0x01, 0xef, 0xf1, 0x64, 0x02, 0xa6,
|
||||
0x1e, 0xcb, 0x7f, 0x47, 0xce, 0x24, 0x64, 0x72, 0x61, 0x5f, 0x3a, 0xb6, 0xf6, 0x3e, 0xfb, 0x89,
|
||||
0x63, 0xdf, 0x3d, 0xaf, 0x6f, 0x95, 0x36, 0x0a, 0x5e, 0x7a, 0xe9, 0x57, 0x6e, 0x54, 0xe8, 0x8d,
|
||||
0x8a, 0x2f, 0x6d, 0xe4, 0x3a, 0xc7, 0x9d, 0xd0, 0xa1, 0x8f, 0x5b, 0xe1, 0x91, 0x4e, 0x75, 0xfa,
|
||||
0x0a, 0x20, 0xc6, 0xba, 0x64, 0x52, 0xb1, 0xeb, 0xbb, 0x7e, 0x6f, 0xd4, 0xeb, 0x0b, 0x78, 0x19,
|
||||
0x77, 0xcf, 0xe7, 0xab, 0x72, 0x61, 0xad, 0x4b, 0x2f, 0x1c, 0x22, 0x2a, 0xea, 0xf7, 0x1e, 0x91,
|
||||
0xde, 0x51, 0xe0, 0x53, 0x36, 0x3f, 0xbf, 0xfd, 0xe5, 0xd9, 0x9b, 0x23, 0x9f, 0x42, 0xf1, 0x29,
|
||||
0x24, 0x1f, 0xb5, 0x68, 0x23, 0x4e, 0x57, 0xbc, 0x2b, 0x44, 0x9c, 0x32, 0xa5, 0xf0, 0x27, 0x68,
|
||||
0x04, 0xce, 0x7c, 0x45, 0x59, 0xde, 0x33, 0xfb, 0xf3, 0xeb, 0x1f, 0x8d, 0x32, 0x4f, 0xb4, 0xe9,
|
||||
0xb3, 0x3c, 0x43, 0xb3, 0xe7, 0x2b, 0x0e, 0x41, 0xc4, 0x4a, 0x18, 0x16, 0x0c, 0x92, 0x44, 0xc4,
|
||||
0x4a, 0x2f, 0x81, 0x09, 0x26, 0x79, 0x1c, 0xa1, 0x71, 0x9f, 0x2e, 0x95, 0x21, 0x79, 0x70, 0xcf,
|
||||
0x8f, 0x5e, 0x5f, 0x8c, 0x61, 0xbb, 0x8c, 0xe7, 0x25, 0xd7, 0x16, 0x77, 0x96, 0x0f, 0xe3, 0x07,
|
||||
0xa2, 0x50, 0x94, 0xfb, 0xc3, 0x9a, 0x09, 0x3f, 0xb2, 0x7a, 0xa3, 0xf4, 0x62, 0x7c, 0xb5, 0x8b,
|
||||
0xa9, 0x0b, 0xbc, 0x44, 0xc4, 0x32, 0xab, 0xa4, 0x8b, 0x72, 0x88, 0x35, 0xc3, 0x22, 0x1a, 0x12,
|
||||
0x89, 0x34, 0xa1, 0x0b, 0x08, 0x5d, 0x1c, 0xe8, 0x1c, 0x34, 0x53, 0x49, 0xaa, 0x92, 0x31, 0xfc,
|
||||
0x2d, 0x22, 0xc8, 0xa1, 0x64, 0x62, 0x53, 0x66, 0xb0, 0x21, 0x86, 0x06, 0x14, 0x52, 0xc1, 0xd5,
|
||||
0x0a, 0x08, 0xd7, 0x14, 0x83, 0xba, 0x48, 0x62, 0x61, 0x8d, 0x6e, 0x3e, 0x64, 0x1f, 0x4a, 0x7b,
|
||||
0xd9, 0x1f, 0xc9, 0xa5, 0x92, 0x4c, 0xf3, 0xa4, 0x94, 0xba, 0xee, 0xf7, 0xdf, 0x2b, 0x10, 0x03,
|
||||
0x25, 0xec, 0xad, 0x82, 0x2e, 0x46, 0xbf, 0x0d, 0xae, 0x3e, 0x04, 0xfd, 0xb3, 0x11, 0x08, 0xc5,
|
||||
0x85, 0x55, 0x10, 0x42, 0x0e, 0xa7, 0x89, 0x40, 0x2d, 0x48, 0xbd, 0xc2, 0xfa, 0x69, 0x93, 0xae,
|
||||
0x58, 0x49, 0xc8, 0xec, 0x44, 0x14, 0x3f, 0x7e, 0xfb, 0xcf, 0x97, 0xd4, 0x9c, 0x63, 0x31, 0x8c,
|
||||
0x58, 0x1c, 0x46, 0x82, 0xf6, 0xc6, 0x97, 0x3d, 0x43, 0x66, 0x76, 0x35, 0x5c, 0x98, 0xdf, 0xf4,
|
||||
0xcd, 0xb9, 0x1f, 0x97, 0x7e, 0xc2, 0x0c, 0xbf, 0xa2, 0x3d, 0xd7, 0xed, 0x19, 0xfe, 0x5e, 0xbd,
|
||||
0x4b, 0xda, 0x73, 0x7a, 0x06, 0x16, 0x4c, 0xda, 0xfb, 0xee, 0xa9, 0xc3, 0xd8, 0x53, 0x98, 0xe6,
|
||||
0x85, 0xe7, 0xc7, 0x62, 0x8f, 0x28, 0xb5, 0xd8, 0xcb, 0xe2, 0x14, 0x84, 0x32, 0x3c, 0x01, 0x52,
|
||||
0xad, 0x36, 0x82, 0xfd, 0xe4, 0xa5, 0x8c, 0x42, 0x4e, 0x00, 0xf7, 0xc9, 0x53, 0xc5, 0x49, 0xe4,
|
||||
0x92, 0x55, 0xb0, 0x01, 0x96, 0x4f, 0x39, 0x70, 0x96, 0x8d, 0xc1, 0x0b, 0x28, 0xa6, 0x20, 0x92,
|
||||
0xdb, 0x1b, 0x7d, 0x91, 0x93, 0xde, 0xb1, 0xe5, 0xf7, 0xb5, 0xec, 0x46, 0xea, 0x58, 0x0b, 0xa8,
|
||||
0x3e, 0xdb, 0x70, 0x61, 0xca, 0xc4, 0x05, 0x94, 0x89, 0xe7, 0xb3, 0x40, 0x19, 0x48, 0xcf, 0xac,
|
||||
0xd1, 0xc1, 0x8f, 0xeb, 0x51, 0x68, 0x4b, 0x85, 0x91, 0x23, 0xf8, 0xc3, 0xe1, 0x26, 0xb9, 0x8e,
|
||||
0x5e, 0x85, 0x2f, 0x97, 0xf6, 0xcd, 0x6f, 0xf5, 0xb2, 0xff, 0x01, 0x89, 0x40, 0x44, 0x3f, 0x02,
|
||||
0xb7, 0x40, 0x5f, 0x52, 0xea, 0x36, 0x74, 0x64, 0x4b, 0x0c, 0x26, 0x6e, 0x1f, 0x07, 0x16, 0x23,
|
||||
0x07, 0x68, 0x55, 0x38, 0x78, 0xfa, 0x70, 0xe7, 0x95, 0x50, 0x97, 0xfe, 0xfa, 0xf6, 0x5a, 0x93,
|
||||
0x1a, 0xac, 0x2c, 0xa1, 0x83, 0x30, 0x6d, 0xd6, 0x98, 0x0c, 0xac, 0x94, 0x42, 0x23, 0xb6, 0x08,
|
||||
0x4b, 0xaf, 0x88, 0x8c, 0x4d, 0xe6, 0x6d, 0xbd, 0x38, 0xf1, 0x56, 0x09, 0x03, 0xe9, 0x25, 0xc2,
|
||||
0x9c, 0xd5, 0x35, 0x99, 0x55, 0x34, 0x18, 0xfa, 0xd0, 0xb5, 0x09, 0xf6, 0x63, 0xc2, 0x52, 0x88,
|
||||
0x0d, 0xab, 0x17, 0xc4, 0x5b, 0xa8, 0x28, 0xd5, 0x49, 0xa2, 0x51, 0x87, 0xd4, 0x0e, 0x88, 0x85,
|
||||
0xf2, 0x59, 0x59, 0x7a, 0xfb, 0x21, 0x2a, 0xd0, 0xaa, 0x86, 0x21, 0x13, 0x7a, 0x35, 0x7f, 0xbe,
|
||||
0xff, 0xd5, 0x0b, 0x51, 0xcd, 0x10, 0x55, 0xb2, 0x36, 0xf7, 0x08, 0xd2, 0x0f, 0xd7, 0x79, 0xf9,
|
||||
0xa3, 0x87, 0x67, 0x80, 0x00, 0x60, 0xa8, 0xa8, 0x14, 0xfa, 0x1a, 0x08, 0x8c, 0x19, 0x14, 0x86,
|
||||
0x6a, 0xb8, 0x8e, 0x4b, 0x2e, 0x5e, 0x44, 0x71, 0x12, 0xcc, 0xc0, 0x14, 0x10, 0x92, 0xa2, 0x18,
|
||||
0xc6, 0x81, 0xf4, 0x6b, 0x91, 0x13, 0x91, 0xeb, 0x6e, 0xf2, 0x27, 0xc8, 0xef, 0x8d, 0x32, 0x25,
|
||||
0x35, 0xd0, 0xd9, 0x40, 0x30, 0x63, 0x10, 0x42, 0x86, 0xcc, 0x3c, 0x58, 0x39, 0xbc, 0xa2, 0x00,
|
||||
0xa5, 0x34, 0x04, 0x0f, 0xb6, 0x97, 0xc5, 0x8e, 0xfb, 0x0f, 0x0f, 0xde, 0x08, 0x3c, 0xe3, 0xbe,
|
||||
0x8c, 0xdb, 0x17, 0xaa, 0x2f, 0xa4, 0x20, 0x6f, 0x67, 0x3a, 0x0b, 0x86, 0xd8, 0x1e, 0x9f, 0xec,
|
||||
0xc2, 0xb1, 0xc0, 0xab, 0xbf, 0xd6, 0x54, 0x75, 0xfd, 0x0d, 0xd4, 0xf2, 0x5f, 0x21, 0x87, 0xe5,
|
||||
0x1b, 0x61, 0xc9, 0x9a, 0x0f, 0x39, 0x1a, 0xea, 0x5d, 0x9b, 0x45, 0x9a, 0xee, 0xc0, 0xdb, 0x43,
|
||||
0xb7, 0x19, 0xa8, 0x22, 0xcc, 0xe9, 0x5b, 0x50, 0x72, 0x16, 0xb6, 0xd0, 0x46, 0xe7, 0x98, 0x1d,
|
||||
0xf8, 0x90, 0x0b, 0x0c, 0xd1, 0xff, 0x89, 0x45, 0x64, 0x99, 0x07, 0x93, 0x7c, 0xfc, 0x08, 0x30,
|
||||
0xe0, 0xa2, 0x21, 0xb5, 0x49, 0x88, 0xb6, 0xbe, 0xf2, 0x4e, 0x69, 0x42, 0xca, 0x75, 0x1b, 0xe0,
|
||||
0xda, 0x83, 0xa6, 0x96, 0xef, 0x0b, 0x50, 0xa0, 0x57, 0x52, 0x49, 0x00, 0x55, 0x55, 0x42, 0x79,
|
||||
0x94, 0xef, 0x5e, 0x42, 0xab, 0x45, 0x5b, 0x34, 0x6d, 0x87, 0x50, 0xb0, 0xdf, 0xc1, 0x81, 0xcb,
|
||||
0x17, 0x1e, 0x24, 0xab, 0x23, 0x93, 0x2e, 0x1e, 0x6a, 0x6e, 0x8b, 0x07, 0x69, 0xcd, 0x24, 0x32,
|
||||
0xc1, 0x87, 0xfc, 0x64, 0x13, 0x30, 0x6e, 0x21, 0x1d, 0x51, 0x47, 0x4c, 0xd5, 0xae, 0x43, 0xe9,
|
||||
0xdd, 0xd6, 0xe8, 0x37, 0x4b, 0xc6, 0xc4, 0x92, 0xd8, 0x16, 0x64, 0xa7, 0xf6, 0x39, 0xec, 0x93,
|
||||
0x33, 0x95, 0xd9, 0xbe, 0x4d, 0x4f, 0x0e, 0x75, 0x63, 0xdb, 0x3b, 0xd0, 0x91, 0x1d, 0xe1, 0x83,
|
||||
0xc3, 0x63, 0x49, 0x53, 0x29, 0xcf, 0x8e, 0xf6, 0x11, 0x21, 0xc7, 0xd0, 0x4e, 0x44, 0xcd, 0xb8,
|
||||
0x4a, 0x68, 0xb6, 0x49, 0x12, 0x75, 0x44, 0x16, 0x52, 0x5c, 0xa3, 0x73, 0xa8, 0xf9, 0x11, 0x3a,
|
||||
0x3b, 0xf0, 0x0d, 0x4b, 0x2a, 0x0b, 0x5a, 0xc7, 0x78, 0x0e, 0x14, 0x4d, 0x66, 0x8e, 0xfb, 0x7d,
|
||||
0x72, 0xc0, 0x7e, 0x91, 0x85, 0x37, 0xf1, 0xf2, 0x44, 0xf7, 0x55, 0x32, 0x05, 0x5d, 0x1f, 0x80,
|
||||
0x75, 0x83, 0xdc, 0xac, 0xb8, 0x32, 0xdc, 0x45, 0x93, 0xa0, 0x65, 0xdb, 0x88, 0xec, 0x70, 0x0a,
|
||||
0xea, 0x8f, 0x6d, 0xd0, 0xbe, 0xbc, 0x21, 0x41, 0xe4, 0xc9, 0x7c, 0xca, 0xe5, 0x72, 0x99, 0x70,
|
||||
0x51, 0x30, 0xe5, 0x99, 0x69, 0xaa, 0x81, 0x4a, 0x3b, 0x1f, 0xac, 0x13, 0xb5, 0xe0, 0xf3, 0x03,
|
||||
0x99, 0x5a, 0xc3, 0xf3, 0xa3, 0x7a, 0x1a, 0xfd, 0x18, 0xf2, 0x98, 0x6a, 0x7c, 0x80, 0xcb, 0xc4,
|
||||
0xf4, 0xa6, 0x9f, 0x62, 0xb3, 0x62, 0xe3, 0x6b, 0xac, 0x5e, 0x17, 0xcb, 0xa5, 0x0d, 0xad, 0xe5,
|
||||
0x86, 0xf1, 0x69, 0x8a, 0xcd, 0x5c, 0x47, 0x56, 0x29, 0xc7, 0x96, 0x2e, 0x54, 0xee, 0xb7, 0xb6,
|
||||
0xda, 0xf3, 0x08, 0xa9, 0xc1, 0xb1, 0x21, 0x44, 0x13, 0xe8, 0x4a, 0xad, 0xe7, 0x39, 0xa4, 0x1f,
|
||||
0x2f, 0x83, 0x83, 0xed, 0x62, 0x14, 0x50, 0xda, 0xf5, 0xe0, 0x83, 0xd5, 0xcd, 0xc4, 0x9c, 0x9e,
|
||||
0xa4, 0xaf, 0xeb, 0x97, 0x16, 0x4f, 0xec, 0x9d, 0x1d, 0xd9, 0x8d, 0x63, 0xd9, 0x55, 0xd2, 0x68,
|
||||
0x40, 0xae, 0x88, 0xcc, 0x29, 0xaa, 0x37, 0xe9, 0x94, 0x2d, 0xf2, 0xcd, 0x09, 0x8f, 0x57, 0x80,
|
||||
0x05, 0xf7, 0x1c, 0x2a, 0x91, 0x6d, 0x35, 0x81, 0xa3, 0x7d, 0x8e, 0x2d, 0x28, 0x16, 0x73, 0x06,
|
||||
0x7a, 0x26, 0xa5, 0x66, 0x68, 0x2a, 0x8f, 0x2b, 0xb4, 0xc7, 0xa9, 0xb3, 0x42, 0x13, 0x40, 0x1a,
|
||||
0x87, 0x29, 0x50, 0x3d, 0x11, 0xbe, 0xc7, 0x52, 0x2f, 0x38, 0xba, 0x58, 0xda, 0x69, 0x9c, 0xe1,
|
||||
0xe8, 0x12, 0x46, 0x5e, 0x85, 0xa3, 0x89, 0x8e, 0x10, 0x91, 0x17, 0x1c, 0xae, 0x19, 0x1d, 0x9f,
|
||||
0x79, 0x0c, 0x3e, 0x53, 0xe8, 0x03, 0x0c, 0x5c, 0xf0, 0x19, 0x7a, 0x09, 0x9d, 0x3d, 0xd2, 0xa9,
|
||||
0x2b, 0xc7, 0x41, 0x8a, 0x3e, 0x05, 0x1e, 0x71, 0x1f, 0x38, 0xab, 0x9b, 0xde, 0x2d, 0x1c, 0xc1,
|
||||
0x3a, 0x3b, 0x00, 0x6c, 0x59, 0xdb, 0xf2, 0xdd, 0x77, 0xdb, 0xd1, 0x78, 0x59, 0x93, 0x5b, 0x4c,
|
||||
0x25, 0xd2, 0x47, 0x36, 0x59, 0x2c, 0x68, 0x71, 0x73, 0xdc, 0xe2, 0x18, 0xab, 0xff, 0x44, 0xce,
|
||||
0xd4, 0xea, 0x44, 0xab, 0xf9, 0xd2, 0x6c, 0xf2, 0xbf, 0x56, 0xe0, 0x4b, 0x0b, 0xf6, 0xc7, 0xf3,
|
||||
0xe0, 0x49, 0x94, 0xd6, 0x50, 0x36, 0x1b, 0xd9, 0xda, 0x2d, 0x13, 0xdc, 0xac, 0x8d, 0xb1, 0x4e,
|
||||
0x9f, 0xb3, 0xda, 0x40, 0x76, 0x43, 0x15, 0x5b, 0xb8, 0x32, 0xdd, 0xda, 0xc1, 0xb5, 0xbd, 0x17,
|
||||
0xf4, 0xd2, 0xf6, 0xdf, 0xcb, 0x98, 0x52, 0xea, 0x4d, 0x32, 0xbc, 0x79, 0x25, 0x2b, 0x7c, 0x42,
|
||||
0x44, 0xdc, 0x28, 0x09, 0xb3, 0x94, 0xbe, 0xf1, 0x44, 0x34, 0xf4, 0x59, 0x9c, 0x58, 0xe9, 0x16,
|
||||
0xfa, 0x7e, 0x72, 0xee, 0x3a, 0x2a, 0x73, 0xc4, 0x34, 0x4b, 0x47, 0x7b, 0x21, 0xf3, 0x7b, 0x3c,
|
||||
0xa7, 0x13, 0x02, 0x90, 0x89, 0xca, 0xe2, 0x1a, 0x04, 0xd4, 0x00, 0x03, 0xfa, 0x2e, 0x70, 0x2c,
|
||||
0x09, 0xc7, 0x9a, 0x12, 0x86, 0xc7, 0x0d, 0x44, 0x3c, 0x9a, 0xc0, 0x06, 0x13, 0x67, 0x76, 0x7f,
|
||||
0x5f, 0x11, 0x93, 0x73, 0x11, 0xcb, 0x7d, 0x3d, 0xd1, 0x41, 0x81, 0x04, 0x80, 0xba, 0x17, 0xfd,
|
||||
0xd4, 0x13, 0x2a, 0xec, 0x11, 0xb4, 0xa5, 0x71, 0xb3, 0x72, 0x4f, 0xa3, 0x81, 0xb5, 0x3d, 0x8f,
|
||||
0x46, 0x59, 0x0a, 0xbe, 0x93, 0x29, 0xd3, 0xde, 0xce, 0xf1, 0xf3, 0x80, 0x51, 0xb9, 0xd4, 0x74,
|
||||
0x4c, 0x63, 0x0f, 0xaf, 0xb3, 0xc3, 0xbe, 0x36, 0x8d, 0x6a, 0x8c, 0xa3, 0x1d, 0x8c, 0xf6, 0xe3,
|
||||
0x06, 0x06, 0xc9, 0x21, 0xbf, 0x63, 0xd4, 0xfc, 0x2e, 0x08, 0x82, 0x66, 0xa6, 0x6e, 0xef, 0xd4,
|
||||
0x74, 0xcd, 0xd1, 0xe2, 0x56, 0xc6, 0x72, 0x3c, 0xf7, 0x04, 0x49, 0x56, 0x0d, 0x7b, 0xac, 0x3a,
|
||||
0x46, 0x45, 0xcd, 0xc1, 0x04, 0x58, 0x49, 0x4e, 0xfd, 0x4b, 0xe0, 0x85, 0xe0, 0x81, 0x97, 0xf9,
|
||||
0x51, 0x5e, 0x52, 0x13, 0xac, 0x6c, 0x2e, 0xce, 0x0e, 0x5b, 0xb8, 0x13, 0x23, 0x1c, 0x19, 0xc9,
|
||||
0x18, 0xf0, 0xdf, 0x7f, 0xff, 0xbd, 0xff, 0xbe, 0xb9, 0xe8, 0x3a, 0xea, 0x44, 0x15, 0xa7, 0x2d,
|
||||
0x0c, 0x9c, 0xf5, 0xf4, 0xec, 0x2d, 0xe6, 0xa8, 0x81, 0x8a, 0x56, 0x7c, 0xe1, 0x5c, 0xc5, 0xe7,
|
||||
0xd6, 0x6e, 0x54, 0x71, 0x32, 0xdd, 0x8d, 0xc6, 0xb3, 0x2a, 0xb9, 0x2f, 0xde, 0xd9, 0xa1, 0xaa,
|
||||
0xb5, 0x80, 0x51, 0x7f, 0xec, 0xdc, 0x97, 0x30, 0x8d, 0x83, 0x20, 0x61, 0x28, 0xa4, 0xff, 0x1e,
|
||||
0x1d, 0xbe, 0x23, 0x68, 0x8d, 0x86, 0x6c, 0x24, 0xbb, 0xbc, 0x6f, 0x8b, 0x8a, 0x77, 0x25, 0x69,
|
||||
0x84, 0x50, 0x39, 0x5d, 0xdb, 0x5e, 0x7e, 0x3e, 0xb1, 0x00, 0x15, 0x5c, 0x43, 0x6d, 0x93, 0xe8,
|
||||
0xff, 0x87, 0x7c, 0x55, 0x7c, 0x22, 0x9c, 0x0e, 0x89, 0x03, 0x5a, 0x99, 0x4f, 0xc1, 0xea, 0xea,
|
||||
0x6b, 0x80, 0x49, 0x6c, 0x68, 0xa4, 0x40, 0xf2, 0x29, 0x58, 0xaa, 0x05, 0x41, 0x45, 0x80, 0x9d,
|
||||
0x9b, 0x69, 0xdd, 0x8d, 0xa2, 0x36, 0x12, 0xed, 0x14, 0xc2, 0xb0, 0x89, 0x42, 0x7b, 0x43, 0x4d,
|
||||
0xd3, 0xe6, 0x5b, 0x2a, 0x4a, 0x08, 0x40, 0x79, 0x48, 0x3f, 0xa1, 0x15, 0x5d, 0xc8, 0x83, 0x41,
|
||||
0xb4, 0x5a, 0x40, 0xad, 0xc6, 0xc0, 0x13, 0x96, 0x55, 0x44, 0x9d, 0x7d, 0x9b, 0x50, 0x3f, 0xb1,
|
||||
0xb6, 0x6a, 0xc2, 0x0b, 0x9a, 0x56, 0x83, 0x34, 0xfb, 0xf8, 0xd1, 0x55, 0xa1, 0x45, 0xad, 0x6d,
|
||||
0x02, 0x73, 0x32, 0xe2, 0x85, 0x04, 0x40, 0x0f, 0x0e, 0x56, 0xb3, 0xa1, 0x05, 0x8f, 0xc0, 0x78,
|
||||
0xb2, 0x65, 0xcd, 0x69, 0xcb, 0x16, 0x44, 0x21, 0xe7, 0xce, 0xf0, 0x72, 0xa2, 0x30, 0x31, 0x2d,
|
||||
0x73, 0x98, 0xfe, 0xa0, 0xa6, 0x3c, 0x57, 0x53, 0xe7, 0xb1, 0xcd, 0x35, 0xe6, 0x42, 0x61, 0xc2,
|
||||
0x80, 0x2a, 0x5e, 0x3c, 0xa0, 0x03, 0xf7, 0x62, 0xd2, 0x0f, 0x03, 0x1b, 0x7a, 0x60, 0x18, 0x0d,
|
||||
0x60, 0xc4, 0x77, 0x01, 0x65, 0xc1, 0x80, 0x07, 0x9d, 0x2f, 0x31, 0x79, 0xe2, 0x95, 0x96, 0x5f,
|
||||
0x81, 0x1c, 0x76, 0x69, 0xeb, 0x5e, 0xa7, 0x0c, 0xa8, 0x15, 0x0c, 0x9e, 0x42, 0xd8, 0x4a, 0x79,
|
||||
0x7e, 0x7e, 0x3d, 0x72, 0x9f, 0x38, 0x4d, 0xfd, 0xaa, 0xa6, 0x7e, 0xd5, 0x2f, 0x15, 0xc6, 0xcf,
|
||||
0xb9, 0x55, 0x06, 0xc4, 0xde, 0x4f, 0xfd, 0x7d, 0x03, 0xe3, 0x20, 0x3d, 0xc0, 0x4e, 0x14, 0xed,
|
||||
0x95, 0xfe, 0xcf, 0x80, 0x6b, 0xf7, 0xf1, 0x1c, 0xdb, 0x73, 0x75, 0x8e, 0xf2, 0xd4, 0xa1, 0xbd,
|
||||
0x15, 0xb7, 0x3c, 0x77, 0xe0, 0x39, 0x64, 0x01, 0x9b, 0x5d, 0xb9, 0x53, 0x95, 0x91, 0xf8, 0x8e,
|
||||
0x7a, 0xee, 0xc2, 0x3b, 0x02, 0x0a, 0x87, 0x9e, 0xca, 0xec, 0xe9, 0x2f, 0x15, 0x85, 0x7b, 0x1f,
|
||||
0xe1, 0x36, 0x29, 0xf7, 0xf6, 0x8d, 0x01, 0x19, 0xdc, 0x19, 0x56, 0x32, 0x93, 0x3b, 0xc3, 0x7d,
|
||||
0x6d, 0x3c, 0x03, 0x48, 0x89, 0xd3, 0xb2, 0x36, 0x1c, 0x18, 0x27, 0x5e, 0x0d, 0x4f, 0xbe, 0xc3,
|
||||
0x67, 0xe1, 0x6a, 0x4a, 0x17, 0x28, 0x6f, 0x4f, 0x3e, 0xf0, 0x60, 0x91, 0xf8, 0x1b, 0x04, 0xc3,
|
||||
0x56, 0xf6, 0x1f, 0xdf, 0x72, 0xa1, 0x23, 0xb3, 0x69, 0x84, 0xb0, 0x7c, 0xb8, 0x63, 0xc7, 0xd6,
|
||||
0xff, 0x44, 0x75, 0x7b, 0x3e, 0xe5, 0x02, 0xeb, 0xa3, 0x5c, 0x7e, 0xbf, 0xad, 0x11, 0xf7, 0xbb,
|
||||
0x9a, 0xed, 0x02, 0xc9, 0x63, 0x5d, 0x5b, 0x89, 0xaf, 0x67, 0x6a, 0xb1, 0x4c, 0xb0, 0xba, 0xa4,
|
||||
0x36, 0x15, 0xd9, 0xd7, 0x15, 0x29, 0xe7, 0xe0, 0xb8, 0x5f, 0x66, 0x2f, 0x3f, 0xe9, 0x94, 0xd4,
|
||||
0xea, 0x6c, 0xd0, 0xf5, 0x49, 0xe8, 0xf1, 0x2d, 0xa8, 0x78, 0xc7, 0x55, 0xe4, 0x4a, 0x92, 0x42,
|
||||
0x11, 0x3c, 0x21, 0x9e, 0x2a, 0x9f, 0xf6, 0x1c, 0xca, 0x83, 0x3e, 0x78, 0xd5, 0xf9, 0x1a, 0xd5,
|
||||
0xdd, 0x4c, 0x44, 0x8e, 0x29, 0xd3, 0x73, 0x21, 0x69, 0x3b, 0x04, 0xbf, 0xe1, 0xc6, 0xd9, 0x86,
|
||||
0xcd, 0x72, 0xde, 0xa7, 0xb7, 0xf3, 0x02, 0x6c, 0x6d, 0x04, 0x18, 0xf1, 0x1d, 0x9f, 0x80, 0x7b,
|
||||
0xa8, 0x0d, 0xde, 0x6f, 0x03, 0x43, 0xf8, 0x77, 0x49, 0x27, 0x2d, 0x83, 0x4d, 0x8e, 0xa7, 0xaf,
|
||||
0xef, 0x27, 0x68, 0xc0, 0xe6, 0x00, 0x94, 0x17, 0x57, 0x13, 0xbf, 0x2f, 0x60, 0xc2, 0xd6, 0xda,
|
||||
0x58, 0x89, 0x2f, 0x6f, 0x17, 0xdb, 0x10, 0x24, 0xb6, 0xc1, 0x82, 0xee, 0x76, 0xf2, 0x4b, 0x6f,
|
||||
0xc7, 0x80, 0xf8, 0xa5, 0x77, 0x42, 0x3e, 0xb1, 0x6d, 0xfc, 0x70, 0x5b, 0xe9, 0x84, 0x3e, 0x3d,
|
||||
0xfa, 0x48, 0xa2, 0x1d, 0x93, 0xb5, 0x8a, 0x51, 0xbd, 0xbf, 0x47, 0x05, 0xe4, 0xee, 0xaf, 0x11,
|
||||
0x0e, 0x5a, 0xb8, 0x13, 0x5d, 0x14, 0x7e, 0xfd, 0x55, 0xb2, 0x4c, 0xf5, 0x35, 0x43, 0x54, 0xe8,
|
||||
0x11, 0xd8, 0xca, 0x6d, 0xb5, 0xed, 0x79, 0x37, 0x3d, 0xdf, 0xcf, 0x36, 0xee, 0x13, 0xb8, 0xf6,
|
||||
0x55, 0xb4, 0x9b, 0xa0, 0xfd, 0x36, 0x43, 0xfb, 0xfb, 0xcf, 0xe4, 0x67, 0x23, 0xc8, 0x81, 0x87,
|
||||
0x97, 0x89, 0xc1, 0x0a, 0x7a, 0x47, 0xcc, 0xc9, 0x47, 0x54, 0xfb, 0x51, 0x1e, 0x39, 0xac, 0x79,
|
||||
0x2b, 0xa8, 0x3e, 0x8a, 0x44, 0xef, 0xd4, 0x07, 0x0b, 0xf3, 0xb1, 0xe3, 0xc8, 0x82, 0x99, 0xd4,
|
||||
0x67, 0x87, 0x4d, 0x9b, 0xef, 0x5b, 0x37, 0xbf, 0x95, 0x5f, 0x37, 0xda, 0x53, 0x63, 0x15, 0xd7,
|
||||
0x9f, 0x3a, 0xb0, 0x7c, 0xc0, 0x6c, 0x1b, 0xb3, 0xdd, 0xf3, 0x1c, 0xa4, 0x76, 0x64, 0x44, 0xcb,
|
||||
0x50, 0x06, 0x38, 0xb0, 0xcc, 0x39, 0xb0, 0x5c, 0x09, 0x78, 0xc4, 0x1e, 0x3c, 0x44, 0x55, 0xab,
|
||||
0x2f, 0x05, 0xb7, 0xcd, 0x1d, 0xee, 0x41, 0x4d, 0xe8, 0xb4, 0xc8, 0xa1, 0xac, 0x03, 0xb6, 0xbf,
|
||||
0x81, 0xfe, 0x2c, 0x7d, 0x7f, 0xdd, 0x69, 0xaf, 0xd2, 0x2d, 0x6d, 0x4b, 0xc2, 0x70, 0x08, 0x77,
|
||||
0xb9, 0xe1, 0x3a, 0xf1, 0xc4, 0x1b, 0xbc, 0x34, 0xd0, 0x05, 0xd7, 0xad, 0x31, 0xb1, 0xf5, 0xd5,
|
||||
0x0e, 0x52, 0x33, 0x0f, 0xaf, 0x1e, 0x34, 0x6e, 0xdd, 0x36, 0x5a, 0x07, 0x9d, 0x7d, 0xd9, 0xee,
|
||||
0x46, 0xa6, 0xba, 0xc8, 0x41, 0x45, 0xd2, 0xb5, 0x0d, 0x46, 0x78, 0xc9, 0x31, 0x6b, 0x95, 0x5a,
|
||||
0x92, 0xb8, 0x78, 0x1d, 0xd0, 0x5b, 0x7c, 0xff, 0x7e, 0x76, 0x50, 0xc6, 0xf5, 0x32, 0x30, 0x89,
|
||||
0x85, 0xdf, 0x72, 0xf5, 0x9d, 0xf5, 0xe2, 0x71, 0xf3, 0xc5, 0x79, 0x4c, 0xea, 0xdb, 0x76, 0x21,
|
||||
0x58, 0x1a, 0x5f, 0xe8, 0x7a, 0x46, 0x2c, 0x1d, 0x51, 0xb1, 0x03, 0xa5, 0xcd, 0xf1, 0x07, 0x25,
|
||||
0x74, 0x01, 0x47, 0x9a, 0x1f, 0x9e, 0x9f, 0xd7, 0xfc, 0x68, 0x31, 0x1f, 0x35, 0x7c, 0x74, 0x1c,
|
||||
0x04, 0x6b, 0xd9, 0x79, 0xee, 0xb1, 0xe7, 0x44, 0xbd, 0xe8, 0x5b, 0xbe, 0xc5, 0xed, 0x98, 0xe8,
|
||||
0xeb, 0x54, 0x18, 0xd3, 0xdb, 0x10, 0x2c, 0x52, 0x7f, 0xb5, 0xd8, 0xc1, 0xba, 0xdb, 0xde, 0x79,
|
||||
0xe5, 0x4b, 0xfc, 0xd9, 0x06, 0x2e, 0xfe, 0x5a, 0xf6, 0x10, 0xe3, 0xa0, 0xd3, 0xf3, 0x39, 0xaa,
|
||||
0xe1, 0x73, 0x9a, 0x6e, 0x0f, 0x7d, 0x24, 0xd4, 0x4b, 0xde, 0x41, 0x97, 0x0d, 0xd9, 0x72, 0xc3,
|
||||
0x59, 0xf9, 0xb6, 0xf0, 0x7c, 0xf6, 0x8f, 0xec, 0x1d, 0x5c, 0x7b, 0x16, 0x73, 0xec, 0xc1, 0x8d,
|
||||
0x7c, 0xbd, 0xe6, 0x0c, 0x0e, 0xe7, 0x3c, 0x32, 0xe5, 0xc5, 0x42, 0xfd, 0x0a, 0xa4, 0x93, 0x03,
|
||||
0xc4, 0x1b, 0xde, 0x73, 0xc0, 0x68, 0x58, 0x22, 0xd4, 0xd8, 0xed, 0x8c, 0xe1, 0x92, 0x60, 0x63,
|
||||
0x39, 0x26, 0xa8, 0x96, 0x13, 0x76, 0xf8, 0x63, 0xd0, 0xff, 0x95, 0xa1, 0xe4, 0x36, 0x3a, 0x3d,
|
||||
0x36, 0xf6, 0x42, 0x32, 0xbf, 0x08, 0xda, 0x38, 0x9b, 0xbc, 0x29, 0x42, 0x3b, 0xf3, 0x47, 0xa3,
|
||||
0xe4, 0xea, 0x88, 0xd2, 0x0d, 0xa7, 0x7b, 0x65, 0xfd, 0x71, 0xbe, 0x23, 0x23, 0xeb, 0x1e, 0x02,
|
||||
0xba, 0x34, 0x5d, 0x61, 0xf7, 0x74, 0x3b, 0xa7, 0xce, 0x55, 0x34, 0xc5, 0xce, 0x7a, 0x94, 0x6e,
|
||||
0xc9, 0x79, 0xd4, 0xd4, 0x51, 0x6c, 0xd8, 0x6c, 0xec, 0x9b, 0x6f, 0xf1, 0xe6, 0xa9, 0x7a, 0x2a,
|
||||
0x03, 0x6e, 0x36, 0xc9, 0xbe, 0xb1, 0x0c, 0x94, 0xe0, 0xbd, 0x6c, 0xbe, 0x0b, 0x40, 0xa2, 0x8a,
|
||||
0x07, 0xf2, 0x47, 0x99, 0x48, 0xd6, 0x55, 0x81, 0xcf, 0x1d, 0x76, 0x7a, 0xb6, 0x32, 0x87, 0x4a,
|
||||
0x06, 0x9b, 0x32, 0xb1, 0xbe, 0x93, 0xf6, 0x23, 0x27, 0x99, 0xf8, 0x6b, 0x54, 0xf3, 0x20, 0x37,
|
||||
0x8f, 0x4d, 0xe9, 0xda, 0x03, 0x4c, 0xae, 0x2d, 0x6b, 0xed, 0xd6, 0x44, 0xf5, 0xf3, 0x75, 0xdb,
|
||||
0x17, 0x7c, 0x31, 0xa5, 0xf4, 0x2f, 0x9c, 0x6e, 0x56, 0x19, 0x4c, 0x74, 0x5e, 0xe9, 0x83, 0x21,
|
||||
0x65, 0x6e, 0xe9, 0x5f, 0x3a, 0x32, 0xbd, 0x84, 0xc1, 0x50, 0x06, 0x69, 0xad, 0x86, 0x32, 0x4c,
|
||||
0xd5, 0xb8, 0x4a, 0xea, 0x79, 0xc0, 0xd6, 0x7c, 0xa1, 0x44, 0x00, 0x20, 0xf8, 0x70, 0xdb, 0x8a,
|
||||
0xce, 0x47, 0x1a, 0x07, 0xea, 0xeb, 0x00, 0xbf, 0x9c, 0x99, 0x5e, 0x59, 0x5b, 0x6e, 0xb7, 0x17,
|
||||
0xed, 0x26, 0x39, 0xbd, 0xff, 0x7c, 0x5a, 0xda, 0xea, 0xce, 0x9c, 0xfb, 0x34, 0xdd, 0x2e, 0xa2,
|
||||
0xab, 0x08, 0x4c, 0xaa, 0xeb, 0x77, 0x58, 0xe8, 0x6e, 0x51, 0x84, 0xd0, 0x9d, 0x76, 0x3c, 0xe1,
|
||||
0x3c, 0x54, 0xfd, 0xc0, 0x6a, 0x47, 0xad, 0xdd, 0x40, 0x84, 0x64, 0xd4, 0x62, 0x67, 0x3a, 0x76,
|
||||
0xcd, 0x28, 0xfc, 0xdd, 0xec, 0x5b, 0x27, 0x91, 0x7b, 0xee, 0xb2, 0xa7, 0x1f, 0x75, 0x3b, 0x06,
|
||||
0x19, 0xe0, 0xdf, 0xc6, 0xe9, 0x23, 0x1d, 0xa8, 0x8f, 0x74, 0xa4, 0x3e, 0xfa, 0x4f, 0x87, 0xea,
|
||||
0xd1, 0x79, 0x8e, 0xae, 0xd3, 0xc4, 0x94, 0xfb, 0xbf, 0x88, 0xd0, 0x2f, 0xf1, 0x81, 0xb2, 0xf9,
|
||||
0xe9, 0xe8, 0x54, 0x9d, 0x3b, 0xa7, 0xbd, 0xde, 0x0c, 0xb4, 0xd7, 0xa6, 0xc0, 0xed, 0x31, 0x05,
|
||||
0xae, 0xa2, 0x63, 0xc3, 0xbf, 0x3d, 0xe7, 0x3e, 0x54, 0xe1, 0xf6, 0x52, 0xbb, 0x52, 0x9a, 0x96,
|
||||
0xd7, 0xab, 0xd5, 0xae, 0x1f, 0x16, 0xe0, 0xb4, 0xb2, 0x83, 0x6a, 0x12, 0x73, 0xe7, 0xf2, 0x84,
|
||||
0x95, 0xb9, 0xf5, 0xe2, 0xd5, 0xa9, 0x1b, 0xaf, 0x3e, 0x1d, 0x67, 0xb2, 0x4f, 0xd2, 0x1f, 0x2f,
|
||||
0x43, 0xf2, 0x75, 0x15, 0x76, 0xd1, 0xf8, 0x72, 0xb0, 0x3e, 0xfa, 0x6e, 0xc9, 0x1b, 0x97, 0x6d,
|
||||
0xaa, 0xdc, 0x83, 0x12, 0xb7, 0xed, 0x16, 0xb6, 0xf7, 0xff, 0x8d, 0xe0, 0xfb, 0xb4, 0xc0, 0x6d,
|
||||
0x8c, 0xc1, 0x5c, 0xfd, 0x5c, 0x3d, 0x0f, 0xe2, 0xad, 0x7c, 0x40, 0x0e, 0xf1, 0x38, 0xa7, 0xea,
|
||||
0xeb, 0x36, 0xfa, 0x6d, 0x51, 0x76, 0xe1, 0x26, 0xfe, 0xd4, 0x1f, 0x41, 0xaa, 0x01, 0x4c, 0x9c,
|
||||
0xad, 0xf3, 0xc5, 0x3c, 0x1a, 0xe3, 0x58, 0xfe, 0xea, 0x0b, 0xae, 0x10, 0x8d, 0x17, 0xf3, 0x02,
|
||||
0x01, 0x1b, 0xe0, 0x39, 0x2a, 0xf4, 0xa4, 0xcc, 0x3b, 0x13, 0x1e, 0xa8, 0xc9, 0xaa, 0x6c, 0xb0,
|
||||
0x1d, 0x64, 0xda, 0xa5, 0x94, 0xbf, 0x43, 0x1d, 0x89, 0x51, 0x0a, 0x80, 0x1e, 0x7f, 0xe3, 0x04,
|
||||
0x94, 0x14, 0xbb, 0x68, 0xc0, 0x8a, 0x56, 0xd3, 0x75, 0x7e, 0xa3, 0x3c, 0x21, 0x94, 0x70, 0x45,
|
||||
0xa9, 0xa0, 0x9d, 0xe7, 0xbf, 0x00, 0xe4, 0xe5, 0x5a, 0x82, 0x6d, 0x22, 0x00, 0x00
|
||||
/* AUTO-GENERATED (END) */
|
||||
};
|
||||
constexpr unsigned int MI32_STATIC_PAGE_len = sizeof(MI32_STATIC_PAGE);
|
||||
|
||||
|
||||
#endif //USE_MI_EXT_GUI
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
|
||||
@ -80,6 +80,13 @@ extern "C" {
|
||||
}
|
||||
|
||||
bool be_MI32_widget(const char* sbuf, void* function){
|
||||
if (!sbuf && !function){
|
||||
if(be_MI32Widget.size == 0){
|
||||
return true; // we can safely overwrite sbuf
|
||||
} else {
|
||||
return false; // sbuf is notsent yet, keep it
|
||||
}
|
||||
}
|
||||
if (function){
|
||||
be_MI32Widget.callback = function;
|
||||
}
|
||||
|
||||
@ -565,45 +565,55 @@ void MI32triggerTele(void){
|
||||
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
/**
|
||||
* @brief Saves a sensor value mapped to the graph range of 0-20 pixel, this function automatically reads the actual hour from system time
|
||||
* @brief Saves a sensor value mapped to the graph range of 0–127.
|
||||
* This function automatically reads the actual hour from system time.
|
||||
*
|
||||
* @param history - pointer to uint8_t[23]
|
||||
* @param value - value as float, this
|
||||
* @param type - internal type. for BLE: 0 - temperature, 1 - humidity, 2 - illuminance, for internal sensors: 100 - wattage
|
||||
* @param history - pointer to uint8_t[24]
|
||||
* @param value - sensor value as int
|
||||
* @param type - internal type. for BLE: 0 - temperature, 1 - humidity,
|
||||
* 2 - illuminance, 3 - BLE sightings,
|
||||
* for internal sensors: 100 - wattage
|
||||
*/
|
||||
void MI32addHistory(uint8_t history[24], float value, const uint32_t type){
|
||||
const uint32_t _hour = (LocalTime()%SECS_PER_DAY)/SECS_PER_HOUR;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history hour: %u"),_hour);
|
||||
switch(type){
|
||||
case 0: //temperature
|
||||
history[_hour] = ((((value + 5.0f)/4) + 1) + 0b10000000); //temp
|
||||
void MI32addHistory(uint8_t history[24], int value, const uint32_t type) {
|
||||
const uint32_t _hour = (LocalTime() % SECS_PER_DAY) / SECS_PER_HOUR;
|
||||
uint8_t scaled = 0;
|
||||
|
||||
switch (type) {
|
||||
case 0: { // temperature, -20..60 °C
|
||||
scaled = changeIntScale((int16_t)value, -20, 60, 1, 127);
|
||||
break;
|
||||
case 1: //humidity
|
||||
history[_hour] = (((value/5.0f) + 1) + 0b10000000) ; //hum
|
||||
}
|
||||
case 1: { // humidity, 0..100 %
|
||||
scaled = changeIntScale((int16_t)value, 0, 100, 1, 127);
|
||||
break;
|
||||
case 2: //light
|
||||
if(value>100.0f) value=100.0f; //clamp it for now
|
||||
history[_hour] = (((value/5.0f) + 1) + 0b10000000); //lux
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history lux: %u in hour:%u"),history[_hour], _hour);
|
||||
}
|
||||
case 2: { // light, 0..1000 lux
|
||||
scaled = changeIntScale((int16_t)value, 0, 1000, 1, 127);
|
||||
break;
|
||||
case 3: //BLE device sighting
|
||||
uint16_t sightings = history[_hour] & 0b01111111;
|
||||
if(sightings<20){
|
||||
history[_hour] = (sightings | 0b10000000) + 1;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history sighting: %u in hour:%u"),history[_hour], _hour);
|
||||
}
|
||||
case 3: { // BLE sightings, count up to 127
|
||||
uint8_t sightings = history[_hour] & 0x7F;
|
||||
if (sightings < 127) {
|
||||
scaled = sightings + 1;
|
||||
} else {
|
||||
scaled = 127;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
case 100: // energy
|
||||
if(value == 0.0f) value = 1.0f;
|
||||
const uint8_t _watt = ((MI32ln(value)*2) + 0b10000000); //watt
|
||||
history[_hour] = _watt;
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: history energy: %u for value:%u"),history[_hour], value); //still playing with the mapping
|
||||
case 100: { // energy/wattage, logarithmic mapping
|
||||
if (value <= 0) value = 1;
|
||||
int16_t lnval = MI32ln(value);
|
||||
scaled = changeIntScale(lnval, 0, 64, 1, 127);
|
||||
break;
|
||||
#endif //USE_MI_ESP32_ENERGY
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Set MSB to mark “valid datapoint”
|
||||
history[_hour] = (scaled & 0x7F) | 0x80;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns a value between 0-21 for use as a data point in the history graph of the extended web UI
|
||||
*
|
||||
@ -611,11 +621,13 @@ void MI32addHistory(uint8_t history[24], float value, const uint32_t type){
|
||||
* @param hour - hour of datapoint
|
||||
* @return uint8_t - value for the y-axis, should be between 0-21
|
||||
*/
|
||||
uint8_t MI32fetchHistory(uint8_t history[24], uint32_t hour){
|
||||
if((hour>23 || bitRead(history[hour],7)) == 0) {
|
||||
return 0; //invalidated data
|
||||
}
|
||||
return (history[hour]) - 0b10000000;
|
||||
uint8_t MI32fetchHistory(uint8_t history[24], uint32_t hour) {
|
||||
if (hour > 23) return 0;
|
||||
uint8_t v = history[hour];
|
||||
if ((v & 0x80) == 0) {
|
||||
return 0; // no data received
|
||||
}
|
||||
return v & 0x7F; // strip MSB, return 1..127
|
||||
}
|
||||
|
||||
/**
|
||||
@ -957,10 +969,33 @@ extern "C" {
|
||||
}
|
||||
|
||||
void MI32sendBerryWidget() {
|
||||
static uint32_t lastMetricsTime = UINT32_MAX; //we want an overlow in the first run
|
||||
if(be_MI32Widget.size != 0) {
|
||||
WSContentSend(be_MI32Widget.data, be_MI32Widget.size);
|
||||
be_MI32Widget.data = nullptr;
|
||||
be_MI32Widget.size = 0;
|
||||
} else {
|
||||
uint32_t now = millis();
|
||||
if (now - lastMetricsTime >= 10000) {
|
||||
lastMetricsTime = now;
|
||||
char metricsBuf[64];
|
||||
// Fields: RSSI (dBm), Channel, PHY Mode, Free Heap (bytes), Total Heap (bytes), Heap Fragmentation (%), PSRAM Total (bytes), PSRAM Free (bytes), Uptime (sec), MI32.role, BLE Sensors Count
|
||||
snprintf(metricsBuf, sizeof(metricsBuf),
|
||||
"%i,%u,%u,%d,%d,%d,%d,%d,%d,%d,%d",
|
||||
WiFi.RSSI(),
|
||||
WiFi.channel(),
|
||||
WiFiHelper::getPhyMode(),
|
||||
ESP.getFreeHeap(),
|
||||
ESP.getHeapSize(),
|
||||
ESP_getHeapFragmentation(),
|
||||
ESP.getPsramSize(),
|
||||
ESP.getFreePsram(),
|
||||
UpTime(),
|
||||
MI32.role,
|
||||
MIBLEsensors.size()
|
||||
);
|
||||
WSContentSend(metricsBuf, 64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1821,7 +1856,7 @@ if(decryptRet!=0){
|
||||
}
|
||||
MIBLEsensors[_slot].eventType.lux = 1;
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
MI32addHistory(MIBLEsensors[_slot].lux_history, (float)MIBLEsensors[_slot].lux, 2);
|
||||
MI32addHistory(MIBLEsensors[_slot].lux_history, MIBLEsensors[_slot].lux, 2);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("Mode 7: U24: %u Lux"), _payload.lux & 0x00ffffff);
|
||||
break;
|
||||
@ -1879,7 +1914,7 @@ if(decryptRet!=0){
|
||||
MIBLEsensors[_slot].NMT = 0;
|
||||
MI32.mode.shallTriggerTele = 1;
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
MI32addHistory(MIBLEsensors[_slot].lux_history, (float)MIBLEsensors[_slot].lux, 2);
|
||||
MI32addHistory(MIBLEsensors[_slot].lux_history, MIBLEsensors[_slot].lux, 2);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("motion: primary"),MIBLEsensors[_slot].lux );
|
||||
break;
|
||||
@ -2050,8 +2085,8 @@ void MI32ParseATCPacket(char * _buf, uint32_t length, uint8_t addr[6], int RSSI)
|
||||
MIBLEsensors[_slot].eventType.bat = 1;
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
bitSet(MI32.widgetSlot,_slot);
|
||||
MI32addHistory(MIBLEsensors[_slot].temp_history, (float)MIBLEsensors[_slot].temp, 0);
|
||||
MI32addHistory(MIBLEsensors[_slot].hum_history, (float)MIBLEsensors[_slot].hum, 1);
|
||||
MI32addHistory(MIBLEsensors[_slot].temp_history, MIBLEsensors[_slot].temp, 0);
|
||||
MI32addHistory(MIBLEsensors[_slot].hum_history, MIBLEsensors[_slot].hum, 1);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
MIBLEsensors[_slot].shallSendMQTT = 1;
|
||||
if(MI32.option.directBridgeMode == 1) MI32.mode.shallTriggerTele = 1;
|
||||
@ -2074,7 +2109,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int RSSI
|
||||
MIBLEsensors[_slot].eventType.temp = 1;
|
||||
DEBUG_SENSOR_LOG(PSTR("CGD1: temp updated"));
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
MI32addHistory(MIBLEsensors[_slot].temp_history, (float)MIBLEsensors[_slot].temp, 0);
|
||||
MI32addHistory(MIBLEsensors[_slot].temp_history, MIBLEsensors[_slot].temp, 0);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
}
|
||||
_tempFloat=(float)(_packet.hum)/10.0f;
|
||||
@ -2083,7 +2118,7 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int RSSI
|
||||
MIBLEsensors[_slot].eventType.hum = 1;
|
||||
DEBUG_SENSOR_LOG(PSTR("CGD1: hum updated"));
|
||||
#ifdef USE_MI_EXT_GUI
|
||||
MI32addHistory(MIBLEsensors[_slot].hum_history, (float)MIBLEsensors[_slot].hum, 1);
|
||||
MI32addHistory(MIBLEsensors[_slot].hum_history, MIBLEsensors[_slot].hum, 1);
|
||||
#endif //USE_MI_EXT_GUI
|
||||
}
|
||||
DEBUG_SENSOR_LOG(PSTR("CGD1: U16: %x Temp U16: %x Hum"), _packet.temp, _packet.hum);
|
||||
@ -2164,7 +2199,7 @@ void MI32HandleEveryDevice(const NimBLEAdvertisedDevice* advertisedDevice, uint8
|
||||
memcpy(_sensor.payload, advertisedDevice->getPayload().data(), advertisedDevice->getPayload().size());
|
||||
_sensor.payload_len = advertisedDevice->getPayload().size();
|
||||
bitSet(MI32.widgetSlot,_slot);
|
||||
MI32addHistory(_sensor.temp_history, 0.0f, 3); // reuse temp_history as sighting history
|
||||
MI32addHistory(_sensor.temp_history, 0, 3); // reuse temp_history as sighting history
|
||||
_sensor.RSSI=RSSI;
|
||||
_sensor.feature.payload = 1;
|
||||
_sensor.eventType.payload = 1;
|
||||
@ -2417,57 +2452,72 @@ bool MI32HandleWebGUIResponse(void){
|
||||
}
|
||||
char tmp[16];
|
||||
WebGetArg(PSTR("wi"), tmp, sizeof(tmp));
|
||||
if (!tmp[0]) return false;
|
||||
WSContentBegin(200, CT_PLAIN);
|
||||
uint32_t slot = MI32.widgetSlot;
|
||||
if (slot) {
|
||||
uint32_t i = __builtin_ctz(slot); // index of first set bit
|
||||
MI32sendWidget(i);
|
||||
MI32.widgetSlot &= ~(1UL << i); // clear that bit
|
||||
} else {
|
||||
MI32sendBerryWidget();
|
||||
}
|
||||
WSContentEnd();
|
||||
if (!tmp[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (atoi(tmp) == 0) {
|
||||
MI32ServeStaticPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
WSContentBegin(200, CT_PLAIN);
|
||||
uint32_t slot = MI32.widgetSlot;
|
||||
if (slot) {
|
||||
uint32_t i = __builtin_ctz(slot); // index of first set bit
|
||||
MI32sendWidget(i);
|
||||
MI32.widgetSlot &= ~(1UL << i); // clear that bit
|
||||
} else {
|
||||
MI32sendBerryWidget();
|
||||
}
|
||||
WSContentEnd();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
//https://gist.github.com/LingDong-/7e4c4cae5cbbc44400a05fba65f06f23
|
||||
// used for logarithmic mapping of 0 - 3600 watts to 0-20 pixel - TaylorLog did not work as expected
|
||||
float MI32ln(float x) {
|
||||
unsigned int bx = * (unsigned int *) (&x);
|
||||
unsigned int ex = bx >> 23;
|
||||
signed int t = (signed int)ex-(signed int)127;
|
||||
unsigned int s = (t < 0) ? (-t) : t;
|
||||
bx = 1065353216 | (bx & 8388607);
|
||||
x = * (float *) (&bx);
|
||||
return -1.49278+(2.11263+(-0.729104+0.10969*x)*x)*x+0.6931471806*t;
|
||||
// ultra simple integer log2 using builtin CLZ
|
||||
int MI32ln(uint32_t x) {
|
||||
return 31 - __builtin_clz(v);
|
||||
}
|
||||
#endif //USE_MI_ESP32_ENERGY
|
||||
|
||||
void MI32createPolyline(char *polyline, uint8_t *history){
|
||||
uint32_t _pos = 0;
|
||||
uint32_t _inc = 0;
|
||||
for (uint32_t i = 0; i<24;i++){
|
||||
uint32_t y = 21-MI32fetchHistory(history,i);
|
||||
if (y>20){
|
||||
y = 150; //create a big gap in the graph to represent invalidated data
|
||||
}
|
||||
_inc = snprintf_P(polyline+_pos,10,PSTR("%u,%u "),i*6,y);
|
||||
_pos+=_inc;
|
||||
void MI32createGraph(char *buffer, uint8_t *history, uint8_t r, uint8_t g, uint8_t b) {
|
||||
constexpr size_t bufferSize = 256; // total size of buffer
|
||||
uint32_t pos = 0;
|
||||
uint16_t w = 150;
|
||||
uint16_t h = 20;
|
||||
// Start compact DSL for a single-series histogram: "{h,width,height,(r,g,b):"
|
||||
if (pos < bufferSize - 20) {
|
||||
pos += snprintf_P(buffer + pos, bufferSize - pos,
|
||||
PSTR("{h,%u,%u,(%u,%u,%u):"),
|
||||
w, h, r, g, b);
|
||||
}
|
||||
|
||||
// Emit 24 history values separated by commas
|
||||
for (uint8_t i = 0; i < 24 && pos < bufferSize - 10; i++) {
|
||||
uint8_t value = MI32fetchHistory(history, i);
|
||||
if (i > 0 && pos < bufferSize - 1) {
|
||||
buffer[pos++] = ','; // add comma
|
||||
buffer[pos] = '\0';
|
||||
}
|
||||
pos += snprintf_P(buffer + pos, bufferSize - pos,
|
||||
PSTR("%u"),
|
||||
value);
|
||||
}
|
||||
// Close the DSL block "}"
|
||||
if (pos < bufferSize - 2) {
|
||||
pos += snprintf_P(buffer + pos, bufferSize - pos,
|
||||
PSTR("}"));
|
||||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: polyline: %s"),polyline);
|
||||
}
|
||||
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
void MI32sendEnergyWidget(){
|
||||
if (Energy->current_available && Energy->voltage_available) {
|
||||
WSContentSend_P(HTTP_MI32_POWER_WIDGET,MIBLEsensors.size()+1, Energy->voltage,Energy->current[1]);
|
||||
char _polyline[176];
|
||||
MI32createPolyline(_polyline,MI32.energy_history);
|
||||
WSContentSend_P(PSTR("<p>" D_POWERUSAGE ": %.1f " D_UNIT_WATT ""),Energy->active_power);
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,185,124,124,_polyline,1);
|
||||
WSContentSend_P(PSTR("</p></div>"));
|
||||
char _graph[256];
|
||||
MI32createGraph(_graph, MI32.energy_history, 185, 124, 124);
|
||||
WSContentSend_P(PSTR("<p>" D_POWERUSAGE ": %.1f " D_UNIT_WATT "%s</p></div>"), Energy->active_power, _graph);
|
||||
}
|
||||
}
|
||||
#endif //USE_MI_ESP32_ENERGY
|
||||
@ -2524,18 +2574,14 @@ void MI32sendWidget(uint32_t slot){
|
||||
|
||||
if(_sensor.feature.temp == 1 && _sensor.feature.hum == 1){
|
||||
if(!isnan(_sensor.temp)){
|
||||
char _polyline[176];
|
||||
MI32createPolyline(_polyline,_sensor.temp_history);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_TEMPERATURE ": %.1f °C"),_sensor.temp);
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,185,124,124,_polyline,1);
|
||||
WSContentSend_P(PSTR("</p>"));
|
||||
char _graph[256];
|
||||
MI32createGraph(_graph, _sensor.temp_history, 185, 124, 124);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_TEMPERATURE ": %.1f °C%s</p>"), _sensor.temp, _graph);
|
||||
}
|
||||
if(!isnan(_sensor.hum)){
|
||||
char _polyline[176];
|
||||
MI32createPolyline(_polyline,_sensor.hum_history);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_HUMIDITY ": %.1f %%"),_sensor.hum);
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,151,190,216,_polyline,2);
|
||||
WSContentSend_P(PSTR("</p>"));
|
||||
char _graph[256];
|
||||
MI32createGraph(_graph, _sensor.hum_history, 151, 190, 216);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_HUMIDITY ": %.1f %%%s</p>"), _sensor.hum, _graph);
|
||||
}
|
||||
if(!isnan(_sensor.temp) && !isnan(_sensor.hum)){
|
||||
WSContentSend_P(PSTR("" D_JSON_DEWPOINT ": %.1f °C"),CalcTempHumToDew(_sensor.temp,_sensor.hum));
|
||||
@ -2543,20 +2589,16 @@ void MI32sendWidget(uint32_t slot){
|
||||
}
|
||||
else if(_sensor.feature.temp == 1){
|
||||
if(!isnan(_sensor.temp)){
|
||||
char _polyline[176];
|
||||
MI32createPolyline(_polyline,_sensor.temp_history);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_TEMPERATURE ": %.1f °C"),_sensor.temp);
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,185,124,124,_polyline,1);
|
||||
WSContentSend_P(PSTR("</p>"));
|
||||
char _graph[256];
|
||||
MI32createGraph(_graph, _sensor.temp_history, 185, 124, 124);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_TEMPERATURE ": %.1f °C%s</p>"), _sensor.temp, _graph);
|
||||
}
|
||||
}
|
||||
if(_sensor.feature.lux == 1){
|
||||
if(_sensor.lux!=0x00ffffff){
|
||||
char _polyline[176];
|
||||
MI32createPolyline(_polyline,_sensor.lux_history);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_ILLUMINANCE ": %d Lux"),_sensor.lux);
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,242,240,176,_polyline,3);
|
||||
WSContentSend_P(PSTR("</p>"));
|
||||
char _graph[256];
|
||||
MI32createGraph(_graph, _sensor.lux_history, 242, 240, 176);
|
||||
WSContentSend_P(PSTR("<p>" D_JSON_ILLUMINANCE ": %d Lux%s</p>"), _sensor.lux, _graph);
|
||||
}
|
||||
}
|
||||
if(_sensor.feature.knob == 1){
|
||||
@ -2599,12 +2641,10 @@ void MI32sendWidget(uint32_t slot){
|
||||
if(_sensor.feature.payload == 1){
|
||||
if(_sensor.payload != nullptr){
|
||||
char _payload[128];
|
||||
char _polyline[176];
|
||||
char _graph[256];
|
||||
ToHex_P((const unsigned char*)_sensor.payload,_sensor.payload_len,_payload, (_sensor.payload_len * 2) + 1);
|
||||
MI32createPolyline(_polyline,_sensor.temp_history);
|
||||
WSContentSend_P(PSTR("<p>Payload:"));
|
||||
WSContentSend_P(HTTP_MI32_GRAPH,_polyline,60,240,176,_polyline,4);
|
||||
WSContentSend_P(PSTR("</p><code style='word-break: break-all;'>%s</code>"),_payload);
|
||||
MI32createGraph(_graph, _sensor.temp_history, 60, 240, 176);
|
||||
WSContentSend_P(PSTR("<p>Payload:%s</p><code>%s</code>"),_graph,_payload);
|
||||
}
|
||||
}
|
||||
WSContentSend_P(PSTR("<p>Timestamp: %s</p>"),GetDT(_sensor.lastTime).c_str());
|
||||
@ -2614,38 +2654,25 @@ void MI32sendWidget(uint32_t slot){
|
||||
void MI32InitGUI(void){
|
||||
MI32.widgetSlot=0;
|
||||
WSContentStart_P("m32");
|
||||
WSContentSend_P(HTTP_MI32_SCRIPT_1);
|
||||
WSContentSend_P(HTTP_MI32_BOOTSTRAP);
|
||||
WSContentSendStyle();
|
||||
WSContentSend_P(HTTP_MI32_STYLE);
|
||||
WSContentSend_P(HTTP_MI32_STYLE_SVG,1,185,124,124,185,124,124);
|
||||
WSContentSend_P(HTTP_MI32_STYLE_SVG,2,151,190,216,151,190,216);
|
||||
WSContentSend_P(HTTP_MI32_STYLE_SVG,3,242,240,176,242,240,176);
|
||||
WSContentSend_P(HTTP_MI32_STYLE_SVG,4,60,240,176,60,240,176);
|
||||
|
||||
char _role[16];
|
||||
GetTextIndexed(_role, sizeof(_role), MI32.role, HTTP_MI32_PARENT_BLE_ROLE);
|
||||
WSContentSend_P((HTTP_MI32_PARENT_START),MIBLEsensors.size(),UpTime(),ESP.getFreeHeap()/1024,_role);
|
||||
|
||||
uint32_t _slot;
|
||||
for(_slot = 0;_slot<MIBLEsensors.size();_slot++){
|
||||
MI32sendWidget(_slot);
|
||||
}
|
||||
|
||||
#ifdef USE_MI_ESP32_ENERGY
|
||||
MI32sendEnergyWidget();
|
||||
#endif //USE_MI_ESP32_ENERGY
|
||||
#ifdef USE_WEBCAM
|
||||
MI32sendCamWidget();
|
||||
#endif //USE_WEBCAM
|
||||
WSContentSend_P(PSTR("</div>"));
|
||||
WSContentSend_P("<div id='m'></div>");
|
||||
WSContentSpaceButton(BUTTON_MAIN);
|
||||
WSContentStop();
|
||||
}
|
||||
|
||||
void MI32ServeStaticPage(void) {
|
||||
Webserver->sendHeader(F("Content-Encoding"), F("gzip"));
|
||||
Webserver->sendHeader(F("Cache-Control"), F("no-store, no-cache, must-revalidate, max-age=0"));
|
||||
Webserver->send_P(200, PSTR("text/html"), MI32_STATIC_PAGE, MI32_STATIC_PAGE_len);
|
||||
}
|
||||
|
||||
void MI32HandleWebGUI(void){
|
||||
if (!HttpCheckPriviledgedAccess()) { return; }
|
||||
if (MI32HandleWebGUIResponse()) { return; }
|
||||
MI32InitGUI();
|
||||
size_t n = MIBLEsensors.size();
|
||||
MI32.widgetSlot = ((1u << n) - 1);
|
||||
}
|
||||
#endif //USE_MI_EXT_GUI
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user