fetching + broadcasting dynamic data from RotClient-s

This commit is contained in:
2026-03-19 22:35:29 +01:00
parent b545d89a97
commit 47286248ef
5 changed files with 175 additions and 106 deletions

View File

@@ -395,6 +395,7 @@
this.state = new RotatorState();
this.ui = new RotatorUI(this.state);
this.renderer = new RotatorRenderer('MainCanvas', this.state);
this.websocket = null;
this.bindEvents();
}
@@ -415,22 +416,10 @@
}
async initialize() {
// Sequential fetch to protect embedded web servers from connection exhaustion
const endpoints = [
{ key: 'azShift', url: 'readStart', isNum: true },
{ key: 'azRange', url: 'readMax', isNum: true },
{ key: 'antRadiationAngle', url: 'readAnt', isNum: true },
{ key: 'antName', url: 'readAntName', isNum: false },
{ key: 'mapUrl', url: 'readMapUrl', isNum: false },
{ key: 'mac', url: 'readMAC', isNum: false },
{ key: 'elevation', url: 'readElevation', isNum: true }
];
const initData = await this.startWs();
for (let conf of endpoints) {
const val = await RotatorAPI.fetchText(conf.url);
if (val !== null) {
this.state[conf.key] = conf.isNum ? Number(val) : val;
}
for (const [key, value] of Object.entries(initData)) {
this.state[key] = value;
}
this.ui.updateStatic();
@@ -438,59 +427,53 @@
// Start timers
// this.startLoops();
this.startWs();
}
startWs() {
const websocket = new WebSocket(document.location.href.replace(/\/?$/, '/') + "ws");
websocket.addEventListener("message", (e) => {
if (!e || !e.data)
return;
const data = JSON.parse(e.data);
if (!data)
return;
async startWs() {
return new Promise((resolve, reject) => {
this.websocket = new WebSocket(document.location.href.replace(/\/?$/, '/') + "ws");
this.websocket.addEventListener("message", (e) => {
if (!e || !e.data)
return;
console.log(`RECEIVED: `, data);
const parsed = JSON.parse(e.data);
if (!parsed)
return;
const data = parsed.data;
if (!data)
return;
const rotData = data['rot14'];
if (rotData.initData) {
resolve(rotData.initData); // super ugly
}
if (rotData.dynamic) {
const numAz = rotData.dynamic.azimuth;
const numStat = rotData.dynamic.status;
let needsRender = false;
if (this.state.azimuth !== numAz || this.state.status !== numStat) {
needsRender = true;
}
this.state.adc = rotData.dynamic.adc;
this.state.azimuth = numAz;
this.state.status = numStat;
this.state.lastSeen = Date.now();
if (needsRender) this.renderer.render();
}
console.log(`RECEIVED: `, data);
});
setInterval(() => {
this.websocket.send(JSON.stringify({ ping: 1 }));
}, 2000);
});
setInterval(() => {
websocket.send(JSON.stringify({ ping: 1 }));
}, 2000);
}
async pollData() {
const adc = await RotatorAPI.fetchText('readADC');
const az = await RotatorAPI.fetchText('readAZ');
const stat = await RotatorAPI.fetchText('readStat');
if (adc !== null && az !== null && stat !== null) {
const numAz = Number(az);
const numStat = Number(stat);
let needsRender = false;
if (this.state.azimuth !== numAz || this.state.status !== numStat) {
needsRender = true;
}
this.state.adc = Number(adc);
this.state.azimuth = numAz;
this.state.status = numStat;
this.state.lastSeen = Date.now();
if (needsRender) this.renderer.render();
}
this.ui.updateDynamic();
}
startLoops() {
// Data polling
setInterval(() => this.pollData(), 500);
// Force UI status check (offline state handling)
setInterval(() => this.ui.updateDynamic(), 2000);
// Map refresh
setInterval(() => this.renderer.updateMap(this.state.mapUrl), 600000);
// Trigger first poll instantly
this.pollData();
}
}