Add receiver diagnostics and remote PicCap handover

This commit is contained in:
matze19999 committed 2026-10-06 18:35:56 +02:00
1 parent ae01879d45
commit 42aeaf56ea
19 files changed
+322 -50

No files matched your search

+12 -5
View File
@@ -11,11 +11,15 @@ function call(method,done,data){
}
function display(result){
if(result.host && !targetDirty){
document.getElementById('host').value=result.host;document.getElementById('port').value=result.port;receiver=result.receiver;
document.getElementById('host').value=result.host;document.getElementById('port').value=result.port;document.getElementById('piccapPort').value=result.piccapPort||19400;receiver=result.receiver;
document.getElementById('receiver').textContent='Receiver: '+receiver;
}
document.getElementById('token').placeholder=result.tokenSet?'Saved token (leave blank to keep)':'No token saved';
if(result.endpoint)document.getElementById('endpoint').textContent=result.receiver+' · '+result.endpoint+' · Priority 149 · 10 updates per second';
var t=result.connectionTest;
if(t)document.getElementById('testResult').textContent='Connection test: '+t.state+(t.state==='Passed'?' · '+t.ledCount+' LEDs · '+t.elapsedMs+' ms':'')+(t.error?' · '+t.error:'');
document.getElementById('testConnection').disabled=!!t && ['Connecting','Sending request','Checking authentication','Reading LED layout'].indexOf(t.state)>=0;
if(result.version)document.getElementById('diagnostics').textContent='Version '+result.version+' · '+(result.uid===0?'Root service':'Service needs root elevation')+' · '+result.captureState+' · Playback: '+result.playbackProtection+' · Capture recoveries: '+result.captureRecoveries+' (last: '+result.lastRecoveryMs+' ms)'+(result.lastOutputAgeMs>=0?' · Last histogram output: '+result.lastOutputAgeMs+' ms ago':'')+(result.retryScheduled?' · Retry in '+result.retryInMs+' ms · Attempts: '+result.retryAttempts:'')+(result.piccapError?' · '+result.piccapError:'');
var handover=document.getElementById('handover');handover.disabled=!result.piccapInstalled;
handover.setAttribute('aria-checked',String(!!result.piccapHandover));
handover.textContent=result.piccapInstalled?'Auto PicCap: '+(result.piccapHandover?'On':'Off'):'Auto PicCap: Not installed';
@@ -27,7 +31,7 @@ function display(result){
document.getElementById('regions').textContent='';return;
}
if(result.piccapHandover)document.getElementById('status').textContent+=' · HyperDRM · '+result.playbackProtection;
if(result.piccapHandover && !result.piccapTargetCompatible)document.getElementById('status').textContent+=' · Auto PicCap paused for custom target';
if(result.piccapHandover && !result.piccapTargetCompatible)document.getElementById('status').textContent+=' · Auto PicCap unavailable for remote IPv6 target';
if(result.colorValid)document.getElementById('status').textContent+=result.spatialOutput?' · '+result.ledCount+' LEDs from 16 color regions'+(result.receiver==='HyperHDR'?' · Spatial image output':''):' · Output RGB: '+result.outputColor.join(', ');
else if(result.returnValue!==false)document.getElementById('status').textContent+=' · No current color output';
if(result.blackBarDetection && result.running)document.getElementById('status').textContent+=result.letterboxDetected?' · Top/bottom black bars detected':' · Full-screen capture';
@@ -46,13 +50,16 @@ document.getElementById('start').focus();
document.getElementById('autostart').onclick=function(){var button=this;var enabled=button.getAttribute('aria-checked')!=='true';button.disabled=true;call('autostart',function(r){button.disabled=false;if(r.returnValue===false)document.getElementById('error').textContent=r.errorText;else call('status',display);},{enabled:enabled});};
document.getElementById('handover').onclick=function(){var button=this;button.disabled=true;call('handover',function(r){button.disabled=false;if(r.returnValue===false)document.getElementById('error').textContent=r.errorText;else call('status',display);},{enabled:button.getAttribute('aria-checked')!=='true'});};
['host','port','token','clearToken'].forEach(function(id){document.getElementById(id).addEventListener('input',function(){targetDirty=true;});});
['host','port','piccapPort','token','clearToken'].forEach(function(id){document.getElementById(id).addEventListener('input',function(){targetDirty=true;});});
document.getElementById('receiver').onclick=function(){receiver=receiver==='Hyperion'?'HyperHDR':'Hyperion';this.textContent='Receiver: '+receiver;targetDirty=true;};
document.getElementById('saveTarget').onclick=function(){
var port=Number(document.getElementById('port').value),button=this;
if(!Number.isInteger(port)||port<1||port>65535){document.getElementById('error').textContent='JSON port must be an integer from 1 to 65535.';return;}
var settings={host:document.getElementById('host').value.trim(),port:port,receiver:receiver,clearToken:document.getElementById('clearToken').checked};
var flatPort=Number(document.getElementById('piccapPort').value);
if(!Number.isInteger(flatPort)||flatPort<1||flatPort>65535){document.getElementById('error').textContent='PicCap FlatBuffer port must be an integer from 1 to 65535.';return;}
var settings={piccapPort:flatPort,host:document.getElementById('host').value.trim(),port:port,receiver:receiver,clearToken:document.getElementById('clearToken').checked};
var token=document.getElementById('token').value.trim();if(token)settings.token=token;
button.disabled=true;call('settings',function(r){button.disabled=false;if(r.returnValue===false){document.getElementById('error').textContent=r.errorText;return;}targetDirty=false;document.getElementById('token').value='';document.getElementById('clearToken').checked=false;call('status',display);},settings);
};
setupRemoteNavigation(['start','stop','refresh','autostart','handover','receiver','host','port','token','clearToken','saveTarget'].map(function(id){return document.getElementById(id);}),document,window);
document.getElementById('testConnection').onclick=function(){if(targetDirty){document.getElementById('error').textContent='Save receiver settings before testing the connection.';return;}this.disabled=true;call('testConnection',function(r){if(r.returnValue===false)document.getElementById('error').textContent=r.errorText;call('status',display);});};
setupRemoteNavigation(['start','stop','refresh','autostart','handover','receiver','host','port','piccapPort','token','clearToken','saveTarget','testConnection'].map(function(id){return document.getElementById(id);}),document,window);
+1 -1
View File
@@ -1 +1 @@
{"id": "org.webosbrew.histogramhyperion", "version": "0.8.1", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient lighting for webOS, Hyperion and HyperHDR", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
{"id": "org.webosbrew.histogramhyperion", "version": "0.9.0", "vendor": "Local development", "type": "web", "main": "index.html", "title": "HyperDRM", "icon": "icon.png", "resolution": "1920x1080", "disableBackHistoryAPI": true, "largeIcon": "large-icon.png", "appDescription": "Ambient lighting for webOS, Hyperion and HyperHDR", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM"}
+6 -4
View File
@@ -1,5 +1,5 @@
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>HyperDRM</title>
<style>body{background:#101827;color:#f1f5ff;font:28px sans-serif;margin:70px;max-width:1400px}h1{font-size:52px;display:flex;align-items:center;gap:24px}h1 img{border-radius:20px}button{font:inherit;padding:20px 32px;margin:12px 12px 12px 0;background:#223654;color:white;border:2px solid #739be0;border-radius:12px}button:focus{outline:5px solid #66ddff}#regions{display:flex;flex-wrap:wrap;gap:8px}.swatch{width:64px;height:64px;border:1px solid #abc}p{line-height:1.5}#error{color:#ffbc99}small{color:#c0cbe0}fieldset{border:2px solid #739be0;border-radius:12px;padding:16px}label{display:inline-flex;flex-direction:column;font-size:24px;margin:8px 20px 8px 0}input{font:inherit;padding:12px;background:#223654;color:white;border:2px solid #739be0;border-radius:8px}input:focus{outline:5px solid #66ddff}#host,#token{width:340px}#port{width:140px}#clearToken{width:28px;height:28px}</style>
<style>body{background:#101827;color:#f1f5ff;font:28px sans-serif;margin:70px;max-width:1400px}h1{font-size:52px;display:flex;align-items:center;gap:24px}h1 img{border-radius:20px}button{font:inherit;padding:20px 32px;margin:12px 12px 12px 0;background:#223654;color:white;border:2px solid #739be0;border-radius:12px}button:focus{outline:5px solid #66ddff}#regions{display:flex;flex-wrap:wrap;gap:8px}.swatch{width:64px;height:64px;border:1px solid #abc}p{line-height:1.5}#error{color:#ffbc99}small{color:#c0cbe0}fieldset{border:2px solid #739be0;border-radius:12px;padding:16px}label{display:inline-flex;flex-direction:column;font-size:24px;margin:8px 20px 8px 0}input{font:inherit;padding:12px;background:#223654;color:white;border:2px solid #739be0;border-radius:8px}input:focus{outline:5px solid #66ddff}#host,#token{width:340px}#port,#piccapPort{width:140px}#clearToken{width:28px;height:28px}</style>
<h1><img src="logo.png" alt="" width="104" height="104">HyperDRM</h1><p>Ambient lighting for webOS, Hyperion and HyperHDR.</p><p id="status">Checking service &hellip;</p><p id="error" role="alert"></p>
<div role="group" aria-label="Service controls"><button id="start">Start</button><button id="stop">Stop</button><button id="refresh">Refresh status</button>
<button id="autostart" role="switch" aria-checked="false">Autostart: Off</button>
@@ -7,10 +7,12 @@
<fieldset><legend>Receiver settings</legend><button id="receiver" type="button">Receiver: Hyperion</button>
<label>IP address <input id="host" type="text" maxlength="45" value="127.0.0.1" spellcheck="false"></label>
<label>JSON port <input id="port" type="number" min="1" max="65535" value="19444"></label>
<label>PicCap FlatBuffer port <input id="piccapPort" type="number" min="1" max="65535" value="19400"></label>
<label>API token (optional) <input id="token" type="password" maxlength="256" autocomplete="off"></label>
<label><input id="clearToken" type="checkbox"> Remove saved token</label><button id="saveTarget" type="button">Save receiver</button>
<label><input id="clearToken" type="checkbox"> Remove saved token</label><button id="saveTarget" type="button">Save receiver</button><button id="testConnection" type="button">Test connection</button><p id="testResult" role="status">Connection test: Not tested</p>
<p><small>Use the receiver's JSON TCP port, usually 19444. IPv4 and IPv6 addresses are supported. Leave the token blank to keep a saved token. Save applies the new target to a running session. Use Up/Down to move between fields; Left/Right edit text.</small></p>
<p id="piccapTargetHint"><small>Auto PicCap requires the default local receiver; custom targets use HyperDRM for all playback. PicCap settings are managed in PicCap.</small></p></fieldset>
<p id="piccapTargetHint"><small>Auto PicCap uses the same receiver IP with its FlatBuffer port, usually 19400. Enable the FlatBuffer server on the receiver. When switching to PicCap, its saved address, port and Unix socket setting are updated; other PicCap preferences are preserved. PicCap supports IPv4 targets; remote IPv6 uses HyperDRM. The API token applies to JSON only.</small></p></fieldset>
<p><small id="endpoint">Priority 149 &middot; 10 updates per second</small></p>
<div id="regions" aria-label="Histogram colors"></div><p><small>The Hyperion layout determines the number and positions of LEDs. Colors come from 16 LG histogram regions with interpolated edge colors. HyperHDR receives a generated color plane, which its image mapping converts to LED colors. Restart the service after changing the LED layout.</small></p>
<p><small id="diagnostics"></small></p>
<div id="regions" aria-label="Histogram colors"></div><p><small>Adjust saturation, brightness and smoothing in your receiver. The receiver layout determines the number and positions of LEDs. Colors come from 16 LG histogram regions with interpolated edge colors. HyperHDR receives a generated color plane, which its image mapping converts to LED colors. Restart the service after changing the LED layout.</small></p>
<script src="remote.js"></script><script src="app.js"></script></html>