signal feature prototype
This commit is contained in:
parent
e8a007a4a9
commit
15f73327ee
@ -8,7 +8,7 @@ export default class HttpServer {
|
|||||||
private httpServer: http.Server;
|
private httpServer: http.Server;
|
||||||
private port: number;
|
private port: number;
|
||||||
private root: string;
|
private root: string;
|
||||||
public constructor(port: number, root: string, tune: (ch: string, adp?: number) => void, getChannels: ()=>string[]) {
|
public constructor(port: number, root: string, tune: (ch: string, adp?: number) => void, getChannels: ()=>string[], getSignal: (adapter:number)=>object) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.httpServer = http.createServer((req, res) => {
|
this.httpServer = http.createServer((req, res) => {
|
||||||
@ -27,6 +27,11 @@ export default class HttpServer {
|
|||||||
body = JSON.stringify(getChannels());
|
body = JSON.stringify(getChannels());
|
||||||
status = 200;
|
status = 200;
|
||||||
break;
|
break;
|
||||||
|
case "signal":
|
||||||
|
const adapter = parseInt(url.searchParams.get('adapter'));
|
||||||
|
body = JSON.stringify(getSignal(adapter));
|
||||||
|
status = 200;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -23,7 +23,10 @@ const tune = (reqChannel: string, reqAdapter?: number) => {
|
|||||||
const getChannels = () =>
|
const getChannels = () =>
|
||||||
zap.getChannels();
|
zap.getChannels();
|
||||||
|
|
||||||
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, tune, getChannels);
|
const getSignal = (adapter: number) =>
|
||||||
|
zap.getSignal(adapter)
|
||||||
|
|
||||||
|
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, tune, getChannels, getSignal);
|
||||||
const tvWebSocket0 = new TVWebSocket(WS_PORT, TV_DEV_0);
|
const tvWebSocket0 = new TVWebSocket(WS_PORT, TV_DEV_0);
|
||||||
const tvWebSocket1 = new TVWebSocket(WS_PORT + 1, TV_DEV_1);
|
const tvWebSocket1 = new TVWebSocket(WS_PORT + 1, TV_DEV_1);
|
||||||
httpServer.start();
|
httpServer.start();
|
||||||
|
@ -26,6 +26,8 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
h1 {}
|
h1 {}
|
||||||
|
|
||||||
p {}
|
p {}
|
||||||
@ -35,7 +37,7 @@ body {
|
|||||||
}
|
}
|
||||||
.content{
|
.content{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
.player{
|
.player{
|
||||||
|
|
||||||
|
@ -18,12 +18,17 @@
|
|||||||
<video id="video0" autoplay playsinline controls></video>
|
<video id="video0" autoplay playsinline controls></video>
|
||||||
<div id="channel-container-0" class="channel-group"></div>
|
<div id="channel-container-0" class="channel-group"></div>
|
||||||
<button onClick="tune(0)">Tune</button>
|
<button onClick="tune(0)">Tune</button>
|
||||||
|
<p id="signal-0">N/A</p>
|
||||||
|
<button onClick="getSignal(0)">Get Signal</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="player">
|
<div class="player">
|
||||||
<video id="video1" autoplay playsinline controls></video>
|
<video id="video1" autoplay playsinline controls></video>
|
||||||
<div id="channel-container-1" class="channel-group"></div>
|
<div id="channel-container-1" class="channel-group"></div>
|
||||||
<button onClick="tune(1)">Tune</button>
|
<button onClick="tune(1)">Tune</button>
|
||||||
|
<p id="signal-1">N/A</p>
|
||||||
|
<button onClick="getSignal(1)">Get Signal</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,53 +1,61 @@
|
|||||||
const PLAYERS = 2;
|
const PLAYERS = 2;
|
||||||
|
|
||||||
const populateChannels = (players:number) => {
|
const populateChannels = (players: number) => {
|
||||||
fetch('/api/list').then(async (res) => {
|
fetch('/api/list').then(async (res) => {
|
||||||
const channelNames: string[] = await res.json()
|
const channelNames: string[] = await res.json()
|
||||||
|
|
||||||
|
|
||||||
for(let i = 0; i < players; ++i){
|
for (let i = 0; i < players; ++i) {
|
||||||
const radioGroup = document.getElementById(`channel-container-${i}`);
|
const radioGroup = document.getElementById(`channel-container-${i}`);
|
||||||
if (!radioGroup) {
|
if (!radioGroup) {
|
||||||
throw new Error("Radio group not found")
|
throw new Error("Radio group not found")
|
||||||
}
|
}
|
||||||
radioGroup.innerHTML = ''
|
radioGroup.innerHTML = ''
|
||||||
channelNames.forEach((channelName,_) => {
|
channelNames.forEach((channelName, _) => {
|
||||||
const id = `radio-${channelName}`;
|
const id = `radio-${i}-${channelName}`;
|
||||||
|
|
||||||
const input = document.createElement('input');
|
const input = document.createElement('input');
|
||||||
input.type = "radio"
|
input.type = "radio"
|
||||||
input.name = `channel-radio-${i}`;
|
input.name = `channel-radio-${i}`;
|
||||||
input.value = channelName;
|
input.value = `${channelName}`;
|
||||||
input.id = id
|
input.id = id
|
||||||
|
|
||||||
|
|
||||||
const lbl = document.createElement("label");
|
const lbl = document.createElement("label");
|
||||||
lbl.htmlFor = id;
|
lbl.htmlFor = id;
|
||||||
lbl.textContent = channelName;
|
lbl.textContent = channelName;
|
||||||
|
|
||||||
// Wrap in a div or line
|
|
||||||
const wrapper = document.createElement("div");
|
const wrapper = document.createElement("div");
|
||||||
wrapper.appendChild(input);
|
wrapper.appendChild(input);
|
||||||
wrapper.appendChild(lbl);
|
wrapper.appendChild(lbl);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
radioGroup.appendChild(wrapper)
|
radioGroup.appendChild(wrapper)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.log("nope ",err)
|
console.log("nope ", err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const tune = (adapter=0) =>{
|
const tune = (adapter = 0) => {
|
||||||
const choice = document.querySelector<HTMLInputElement>(`input[name="channel-radio-${adapter}"]:checked`)
|
const choice = document.querySelector<HTMLInputElement>(`input[name="channel-radio-${adapter}"]:checked`)
|
||||||
const channel = choice?.value;
|
const channel = choice?.value;
|
||||||
if(channel){
|
if (channel) {
|
||||||
fetch(`/api/tune/${channel}?adapter=${adapter}`, {method:'PUT'})
|
fetch(`/api/tune/${channel}?adapter=${adapter}`, { method: 'PUT' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSignal = (adapter = 0) => {
|
||||||
|
const signalElement = document.getElementById(`signal-${adapter}`);
|
||||||
|
if (!signalElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch(`/api/signal?adapter=${adapter}`).then(res =>
|
||||||
|
res.json()
|
||||||
|
).then((strength: any) => {
|
||||||
|
signalElement.innerHTML = `Signal: ${strength.signal} C/N: ${strength.cn}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
populateChannels(PLAYERS);
|
populateChannels(PLAYERS);
|
37
src/zap.ts
37
src/zap.ts
@ -5,6 +5,10 @@ export interface IZap {
|
|||||||
process: ChildProcessWithoutNullStreams | null,
|
process: ChildProcessWithoutNullStreams | null,
|
||||||
channel: string,
|
channel: string,
|
||||||
adapter: 0 | 1
|
adapter: 0 | 1
|
||||||
|
strength: {
|
||||||
|
signal: string;
|
||||||
|
cn: string;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Zap {
|
export default class Zap {
|
||||||
@ -12,16 +16,28 @@ export default class Zap {
|
|||||||
private zap1: IZap;
|
private zap1: IZap;
|
||||||
private channelNameList: string[];
|
private channelNameList: string[];
|
||||||
private fileName: string;
|
private fileName: string;
|
||||||
|
|
||||||
|
private regex = /Signal=\s*(-?\d+(\.\d+)?dBm)\s+C\/N=\s*(\d+(\.\d+)?dB)/;
|
||||||
|
|
||||||
|
|
||||||
public constructor(fileName = "dvb_channel.conf", channel = "ION") {
|
public constructor(fileName = "dvb_channel.conf", channel = "ION") {
|
||||||
const zap0: IZap = {
|
const zap0: IZap = {
|
||||||
process: null,
|
process: null,
|
||||||
channel,
|
channel,
|
||||||
adapter: 0
|
adapter: 0,
|
||||||
|
strength: {
|
||||||
|
signal: "None",
|
||||||
|
cn: "None"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const zap1: IZap = {
|
const zap1: IZap = {
|
||||||
process: null,
|
process: null,
|
||||||
channel,
|
channel,
|
||||||
adapter: 1
|
adapter: 1,
|
||||||
|
strength: {
|
||||||
|
signal: "None",
|
||||||
|
cn: "None"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.zap0 = zap0;
|
this.zap0 = zap0;
|
||||||
this.zap1 = zap1;
|
this.zap1 = zap1;
|
||||||
@ -37,6 +53,18 @@ export default class Zap {
|
|||||||
return this.channelNameList;
|
return this.channelNameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getSignal(adapter: number) {
|
||||||
|
if(adapter == 0){
|
||||||
|
return this.zap0.strength;
|
||||||
|
}
|
||||||
|
else if (adapter == 1){
|
||||||
|
return this.zap1.strength;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {signal: 'N/A', cn: 'N/A'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private nextChannel(channel: string) :string {
|
private nextChannel(channel: string) :string {
|
||||||
const size = this.channelNameList.length;
|
const size = this.channelNameList.length;
|
||||||
const currentIndex = this.channelNameList.indexOf(channel);
|
const currentIndex = this.channelNameList.indexOf(channel);
|
||||||
@ -108,7 +136,12 @@ export default class Zap {
|
|||||||
|
|
||||||
if (/Lock/.test(output)) {
|
if (/Lock/.test(output)) {
|
||||||
clearTimeout(lockTimer);
|
clearTimeout(lockTimer);
|
||||||
|
const match = output.match(this.regex);
|
||||||
zap.channel = verifiedChannel;
|
zap.channel = verifiedChannel;
|
||||||
|
zap.strength = {
|
||||||
|
signal: match[1],
|
||||||
|
cn: match[3]
|
||||||
|
}
|
||||||
resolve(zap);
|
resolve(zap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user