Dev prototype #1

Merged
david merged 7 commits from dev into main 2025-04-24 11:34:49 -07:00
7 changed files with 61 additions and 63 deletions
Showing only changes of commit 14786f378a - Show all commits

View File

@ -1,15 +1,14 @@
import * as http from "http";
import * as fs from "fs";
import * as path from "path";
import IO, { ISensors } from "./io";
import IO from "./io";
export default class HttpServer {
class HttpServer {
private httpServer: http.Server;
private port: number;
private root: string;
// public constructor(port: number, root: string, tune: (ch: string, adp?: number) => void, getChannels: ()=>string[], getSignal: (adapter:number)=>object) {
public constructor(port: number, root: string, io: IO) {
this.port = port;
@ -76,10 +75,6 @@ export default class HttpServer {
}
}
};
export default HttpServer;

View File

@ -35,7 +35,7 @@ export default class IO {
this.gpioLights = new pigpio.Gpio(LIGHTS_GPIO, { mode: pigpio.Gpio.OUTPUT });
const readHeat = new pigpio.Gpio(HEAT_GPIO, { mode: pigpio.Gpio.INPUT });
this.lights = readHeat.digitalRead() == ON ? true : false
this.heat = readHeat.digitalRead() == ON ? true : false
this.gpioHeat = new pigpio.Gpio(HEAT_GPIO, { mode: pigpio.Gpio.OUTPUT });

View File

@ -14,16 +14,20 @@ export default class Serial {
const readline = new serialport.ReadlineParser({ delimiter });
const parser = port.pipe(readline);
parser.on('data', line => {
try{
const data = JSON.parse(line)
const moisture0 = parseInt(data['A0'], 10);
const moisture1 = parseInt(data['A1'], 10);
if (!isNaN(moisture0) && !isNaN(moisture1)) {
if (isNaN(moisture0) || isNaN(moisture1)){
throw new Error("isNan " + moisture0 + " " + moisture1)
}
this.moisture0 = moisture0;
this.moisture1 = moisture1;
}
else {
console.error("Error reading analog data")
catch(e){
console.log(e)
}
});
port.on('error', err => {
console.error('Serial Error:', err.message);

View File

@ -7,32 +7,10 @@ const WS_PORT = process.env.WS_PORT ? parseInt(process.env.WS_PORT, 10) : 3003;
const STATIC_ROOT = process.cwd() + "/dist/static";
const TV_DEV_0 = process.env.TV_DEV_0 ?? '/dev/video0'
// const zap = new Zap();
// const tune = (reqChannel: string, reqAdapter?: number) => {
// const adapter = reqAdapter === 0 || reqAdapter === 1 ? reqAdapter : 0;
// zap.zapTo(reqChannel, adapter).then((zap: IZap) => {
// console.log(`Tuned ${zap.adapter} to ${zap.channel}`)
// }).catch((err: Error) => {
// console.error(err.message);
// });
// }
// const getChannels = () =>
// zap.getChannels();
// const getSignal = (adapter: number) =>
// zap.getSignal(adapter)
const io = new IO();
const getSensors: ()=>ISensors = io.getSensors.bind(io);
// setTimeout(()=>{
// console.log("sen ",io.getSensors())
// console.log("sen2 ",getSensors())
// },200)
// const setPower = io.setPower.bind(this, true)
// const togglePower = io.togglePower.bind(this)
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, io);
const videoSocket = new VideoSocket(WS_PORT, TV_DEV_0, getSensors);

View File

@ -5,18 +5,15 @@
<title>WebRTC Stream</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="css/index.css" />
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<header></header>
<main>
<h1>Video streams</h1>
<h2>WebRTC</h2>
<div class="content">
<div class="player">
<video id="video0" autoplay playsinline controls></video>
<div id="channel-container-0" class="channel-group"></div>
</div>
<div id="data-container">
<!-- <p id="power"></p>

View File

@ -13,13 +13,17 @@ const dataContainer = document.getElementById('data-container') as HTMLDivElemen
const config = {
iceServers: [
{
urls: ['stun:dwestgate.us:3478', 'turn:dwestgate.us:3478?transport=udp'],
urls: [
'stun:dwestgate.us:3478',
'turn:dwestgate.us:3478?transport=udp',
'turn:dwestgate.us:3478?transport=tcp'
],
username: 'webrtcuser',
credential: 'webrtccred'
}
]
};
const pc0 = new RTCPeerConnection(isSecure ? config : {});
const pc0 = new RTCPeerConnection(isSecure ? config : {iceServers: []});
const video0 = document.getElementById('video0') as HTMLVideoElement;
@ -30,6 +34,7 @@ pc0.ontrack = (event) => {
pc0.onicecandidate = ({ candidate }) => {
if (candidate) {
console.log("Ice candidate: ",candidate.candidate)
ws0.send(JSON.stringify({ type: 'ice-candidate', data: candidate }));
}
};
@ -41,6 +46,11 @@ console.log("📡 Data channel created by client");
dataChannel.onopen = () => {
console.log('📬 Client: Data channel opened');
setInterval(() => {
if (dataChannel.readyState === 'open') {
dataChannel.send('keep-alive');
}
}, 15000);
};
dataChannel.onmessage = (event) => {

View File

@ -20,6 +20,14 @@ export default class VideoSocket {
// ffmpegProcess.stdio[2].on('data', data => {
// console.log("stdio[2] ",data.toString())
// })
ffmpegProcess.stdio[2].on('error', data => {
console.log("stdio[2] error",data.toString())
})
ffmpegProcess.stderr.on('data', (data) => {
// console.error(`ffmpeg stderr data: ${data}`);
});
// WebSocket signaling server
const wss = new ws.WebSocketServer({ port });
@ -34,8 +42,11 @@ export default class VideoSocket {
console.log('📬 Server: Data channel opened');
// Now you can send data through the channel
setInterval(() => {
if (dataChannel.readyState === 'open') {
const sensorData = getSensors(); // Example function to fetch data
dataChannel.send(JSON.stringify(sensorData)); // Send data to the client
}
}, 1000);
};
@ -91,21 +102,23 @@ export default class VideoSocket {
// Function to start FFmpeg and capture raw video
startFFmpeg = (): ChildProcessWithoutNullStreams => {
const p = spawn('ffmpeg', [
'-loglevel', 'debug',
// '-loglevel', 'debug',
'-i', this.videoDevice,
// Video
'-map', '0:v:0',
'-vf', `scale=${WIDTH}:${HEIGHT}`,
'-vcodec', 'rawvideo',
'-framerate', '24',
'-video_size', `${WIDTH}x${HEIGHT}`,
'-vf', `scale=${WIDTH}:${HEIGHT}:flags=fast_bilinear`,
'-pix_fmt', 'yuv420p',
'-f', 'rawvideo',
'-threads', '1',
//quality
'-fflags', '+discardcorrupt',
'-err_detect', 'ignore_err',
'-analyzeduration', '100M',
'-probesize', '100M',
// '-fflags', '+discardcorrupt',
// '-err_detect', 'ignore_err',
// '-analyzeduration', '100M',
// '-probesize', '100M',
'pipe:3',
@ -222,6 +235,7 @@ export default class VideoSocket {
console.error('❌ DataChannel error:', error);
};
dataChannel.onclose = () => {
console.log('❎ DataChannel closed');
};
@ -231,14 +245,14 @@ export default class VideoSocket {
createPeerConnection = (videoTrack: MediaStreamTrack, audioTrack: MediaStreamTrack): RTCPeerConnection => {
const peerConnection = new RTCPeerConnection({
iceServers: [
{
urls: 'stun:192.168.0.3:3478'
},
{
urls: 'turn:192.168.0.3:3478?transport=udp',
username: 'webrtcuser',
credential: 'webrtccred'
}
// {
// urls: 'stun:192.168.0.3:3478'
// },
// {
// urls: 'turn:192.168.0.3:3478?transport=udp',
// username: 'webrtcuser',
// credential: 'webrtccred'
// }
]
});
const stream = new MediaStream()