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

+49
View File
@@ -0,0 +1,49 @@
"""Test-only FlatBuffer TCP relay; accepts only the configured TV address."""
import argparse
import select
import socket
import socketserver
parser = argparse.ArgumentParser()
parser.add_argument('--bind', required=True)
parser.add_argument('--port', type=int, default=19446)
parser.add_argument('--upstream', required=True)
parser.add_argument('--upstream-port', type=int, default=19400)
args = parser.parse_args()
class Relay(socketserver.BaseRequestHandler):
def handle(self):
if self.client_address[0] != args.upstream:
return
transferred = 0
try:
with socket.create_connection((args.upstream, args.upstream_port), timeout=3) as remote:
self.request.settimeout(3)
while True:
readable, _, _ = select.select([self.request, remote], [], [], 3)
if not readable:
break
for source in readable:
data = source.recv(65536)
if not data:
return
destination = remote if source is self.request else self.request
destination.sendall(data)
if source is self.request:
if not transferred:
print('PicCap FlatBuffer data received', flush=True)
transferred += len(data)
except OSError:
pass
finally:
print(f'FlatBuffer connection closed: {transferred} bytes from TV', flush=True)
class Server(socketserver.ThreadingTCPServer):
daemon_threads = True
with Server((args.bind, args.port), Relay) as server:
print('FlatBuffer relay ready', flush=True)
server.serve_forever()
+24
View File
@@ -0,0 +1,24 @@
'use strict';
const assert=require('assert'),fs=require('fs'),vm=require('vm');
const ids=['host','port','piccapPort','receiver','token','clearToken','endpoint','handover','autostart','error','status','regions','start','stop','refresh','saveTarget','testConnection','testResult','diagnostics'];
const elements={};
ids.forEach(id=>elements[id]={value:'',textContent:'',disabled:false,checked:false,attributes:{},style:{},addEventListener(){},focus(){},appendChild(){},setAttribute(k,v){this.attributes[k]=v;},getAttribute(k){return this.attributes[k];}});
const requests=[];
const status={returnValue:true,version:'0.9.0',host:'127.0.0.1',port:19444,piccapPort:19400,receiver:'HyperHDR',tokenSet:true,piccapInstalled:true,autostart:true,captureState:'Histogram',playbackProtection:'protected',connectionTest:{state:'Passed',ledCount:120,elapsedMs:300,error:''},uid:0};
class Bridge {
call(uri,data){requests.push({uri,data:JSON.parse(data)});this.onservicecallback(JSON.stringify(uri.endsWith('/status')?status:{returnValue:true}));}
cancel(){}
}
let controls;
const context={PalmServiceBridge:Bridge,document:{getElementById:id=>elements[id],createElement:()=>({style:{}})},window:{},setTimeout:()=>1,clearTimeout(){},setInterval(){},setupRemoteNavigation(list){controls=list;}};
vm.runInNewContext(fs.readFileSync('app/app.js','utf8'),context);
assert(elements.testResult.textContent.includes('120 LEDs'));
assert(elements.diagnostics.textContent.includes('Root service'));
assert(controls.includes(elements.piccapPort)&&controls.includes(elements.testConnection));
context.targetDirty=true;elements.testConnection.onclick();assert(elements.error.textContent.includes('Save receiver'));
elements.piccapPort.value='0';elements.saveTarget.onclick();assert(elements.error.textContent.includes('FlatBuffer port'));
elements.piccapPort.value='19446';elements.host.value='10.1.0.100';elements.token.value='';elements.saveTarget.onclick();
const saved=requests.find(r=>r.uri.endsWith('/settings'));assert.strictEqual(saved.data.piccapPort,19446);assert.strictEqual(saved.data.host,'10.1.0.100');assert(!('token' in saved.data));
elements.testConnection.onclick();assert(requests.some(r=>r.uri.endsWith('/testConnection')));
assert.strictEqual(elements.token.value,'');assert(!elements.diagnostics.textContent.includes('fixture-token'));
console.log('PASS: receiver fields, port validation, saved-token retention, test control and diagnostics');