Add configurable battery and USB display behavior
Persist separate display modes and timeouts in seconds for battery and USB power, expose four controls in WebConfig and CLI, and apply one shared policy across display-equipped roles. Detect R8 external power from a USB host or calibrated battery voltage above 4.21 V, with cached sampling and hysteresis. Add policy, persistence, browser, and R8 power-detection regression coverage.
This commit is contained in:
1 parent
d83153e935
commit
a814a00ce7
39 files changed
+3187
-2488
No files matched your search
@@ -393,6 +393,18 @@ body.tab-cli{padding-bottom:0}
|
||||
</div>
|
||||
<div class="f"><label>TX power (dBm)</label><input type="number" data-k="tx" min="-9" max="30" style="max-width:120px"></div>
|
||||
</div>
|
||||
<div class="card hide" id="display-settings">
|
||||
<h2>Display</h2>
|
||||
<div class="row">
|
||||
<div class="f"><label>On battery</label><select data-k="display.mode"><option value="off">Off</option><option value="on">On</option><option value="button">Button</option><option value="pairing">Pairing only</option><option value="button-pairing">Button + pairing</option><option value="automatic">Automatic</option></select></div>
|
||||
<div class="f"><label>Timeout (seconds)</label><input type="number" data-k="display.timeout" min="1" max="3600" step="1"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="f"><label>On USB power</label><select data-k="display.usb.mode"><option value="off">Off</option><option value="on">On</option><option value="button">Button</option><option value="pairing">Pairing only</option><option value="button-pairing">Button + pairing</option><option value="automatic">Automatic</option></select></div>
|
||||
<div class="f"><label>Timeout (seconds)</label><input type="number" data-k="display.usb.timeout" min="1" max="3600" step="1"></div>
|
||||
</div>
|
||||
<div class="hint">Automatic shows startup and messages while the app is disconnected. Connecting blanks the display; a button or pairing request can wake it. USB power detection depends on the board.</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>Advanced</h2>
|
||||
<div class="row">
|
||||
@@ -800,6 +812,10 @@ function cfgVal(k){ // map a `set` key to its current value string, from st.cfg
|
||||
case"radio.fem.rxgain":return r.fem_rxgain?"on":"off";
|
||||
case"radio.rxps":return rxpsCfgValue(r);
|
||||
case"powersaving":return r.powersaving?"on":"off";
|
||||
case"display.mode":return (st.cfg.display||{}).mode||"button";
|
||||
case"display.timeout":return String((st.cfg.display||{}).timeout||15);
|
||||
case"display.usb.mode":return (st.cfg.display||{}).usb_mode||"button";
|
||||
case"display.usb.timeout":return String((st.cfg.display||{}).usb_timeout||15);
|
||||
case"repeat":return r.repeat?"on":"off";
|
||||
case"flood.max":return String(r.flood_max);
|
||||
case"flood.max.advert":return String(r.flood_max_advert);
|
||||
@@ -945,6 +961,9 @@ function loadConfig(loadCapture){
|
||||
});
|
||||
$$("[data-cfm]").forEach(function(el){el.value=""});
|
||||
$$("[data-rg]").forEach(function(el){el.value=String(c.radio[el.dataset.rg]);el.classList.remove("dirty")});
|
||||
$("#display-settings").classList.toggle("hide",!c.display);
|
||||
$$('#display-settings option[value="pairing"],#display-settings option[value="button-pairing"]').forEach(function(el){el.hidden=!(c.display&&c.display.pairing);el.disabled=el.hidden});
|
||||
syncDisplayTimeouts();
|
||||
loadRxps(c.radio);
|
||||
st.orig.radio=radioCombo();afHint();
|
||||
for(var i=1;i<=st.nslots;i++){refreshSlotFields($("#app-slots"),i);refreshSlotFields($("#wz-slots"),i)}
|
||||
@@ -957,10 +976,17 @@ function loadConfig(loadCapture){
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function syncDisplayTimeouts(){
|
||||
["display","display.usb"].forEach(function(prefix){
|
||||
var mode=$('[data-k="'+prefix+'.mode"]').value;
|
||||
$('[data-k="'+prefix+'.timeout"]').disabled=(mode==="off"||mode==="on"||mode==="pairing");
|
||||
});
|
||||
}
|
||||
function markDirty(k,v,el){
|
||||
if(v===st.orig[k]){delete st.dirty[k]}else{st.dirty[k]=v}
|
||||
if(el)el.classList.toggle("dirty",k in st.dirty);
|
||||
if(k==="af")afHint();
|
||||
if(k==="display.mode"||k==="display.usb.mode")syncDisplayTimeouts();
|
||||
updateSaveBar();
|
||||
}
|
||||
// The CLI's `dutycycle` is not its own pref - it just writes airtime_factor as
|
||||
@@ -1860,6 +1886,10 @@ var CLI_VERBS=[
|
||||
mode: 0 = get and set, 1 = get only, 2 = set only
|
||||
values: enum offered as value completions after `set <key> ` */
|
||||
var CLI_KEYS=[
|
||||
["display.mode","Display on battery",0,"off|on|button|pairing|button-pairing|automatic"],
|
||||
["display.timeout","Battery display timeout in seconds (1-3600)",0],
|
||||
["display.usb.mode","Display on USB power",0,"off|on|button|pairing|button-pairing|automatic"],
|
||||
["display.usb.timeout","USB display timeout in seconds (1-3600)",0],
|
||||
["name","Node name",0],
|
||||
["lat","Advert latitude",0],
|
||||
["lon","Advert longitude",0],
|
||||
@@ -2000,6 +2030,10 @@ var CLI_COMPANION_VERBS=[
|
||||
["reboot","Restart the node"]
|
||||
];
|
||||
var CLI_COMPANION_KEYS=[
|
||||
["display.mode","Display on battery",0,"off|on|button|pairing|button-pairing|automatic"],
|
||||
["display.timeout","Battery display timeout in seconds (1-3600)",0],
|
||||
["display.usb.mode","Display on USB power",0,"off|on|button|pairing|button-pairing|automatic"],
|
||||
["display.usb.timeout","USB display timeout in seconds (1-3600)",0],
|
||||
["prv.key","Read this node's private identity key",1],
|
||||
["name","Node name",0], ["role","Node role",1],
|
||||
["lat","Advert latitude",0], ["lon","Advert longitude",0],
|
||||
|
||||
Reference in new issue
Block a user