data channel working
This commit is contained in:
parent
fb5301c9fe
commit
22aeed01be
16
sketch.c
Normal file
16
sketch.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
int moisture0 = analogRead(A0);
|
||||||
|
delayMicroseconds(100);
|
||||||
|
analogRead(A1);
|
||||||
|
int moisture1 = analogRead(A1);
|
||||||
|
Serial.print("{\"A0\":");
|
||||||
|
Serial.print(moisture0);
|
||||||
|
Serial.print(",\"A1\":");
|
||||||
|
Serial.print(moisture1);
|
||||||
|
Serial.println("}");
|
||||||
|
delay(1000);
|
||||||
|
}
|
12
src/io.ts
12
src/io.ts
@ -21,9 +21,11 @@ export default class IO implements ISensors {
|
|||||||
gpio: pigpio.Gpio
|
gpio: pigpio.Gpio
|
||||||
serial: Serial;
|
serial: Serial;
|
||||||
power: boolean;
|
power: boolean;
|
||||||
|
getMoisture : ()=>number;
|
||||||
|
|
||||||
public constructor(POWER_GPIO = 17) {
|
public constructor(POWER_GPIO = 17) {
|
||||||
const serial = new Serial()
|
const serial = new Serial()
|
||||||
serial.getMoisture.bind(this);
|
this.getMoisture = serial.getMoisture.bind(serial);
|
||||||
this.serial = serial;
|
this.serial = serial;
|
||||||
// Initialize pigpio and the GPIO pin
|
// Initialize pigpio and the GPIO pin
|
||||||
const read = new pigpio.Gpio(POWER_GPIO, {mode: pigpio.Gpio.INPUT});
|
const read = new pigpio.Gpio(POWER_GPIO, {mode: pigpio.Gpio.INPUT});
|
||||||
@ -35,9 +37,6 @@ export default class IO implements ISensors {
|
|||||||
// this.serial.getMoisture.bind(this)
|
// this.serial.getMoisture.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoisture() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPower() {
|
// getPower() {
|
||||||
// // Read the current state of the GPIO pin
|
// // Read the current state of the GPIO pin
|
||||||
@ -52,16 +51,15 @@ export default class IO implements ISensors {
|
|||||||
|
|
||||||
public togglePower() {
|
public togglePower() {
|
||||||
// Toggle the power state (turn the pin on or off)
|
// Toggle the power state (turn the pin on or off)
|
||||||
console.log("toggle")
|
|
||||||
this.power = !this.power;
|
this.power = !this.power;
|
||||||
this.gpio.digitalWrite(this.power ? ON : OFF);
|
this.gpio.digitalWrite(this.power ? ON : OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSensors(): ISensors {
|
public getSensors(): ISensors {
|
||||||
console.log("serial ", this.serial)
|
// console.log("serial ", )
|
||||||
return {
|
return {
|
||||||
power: this.power,
|
power: this.power,
|
||||||
moisture: 0,
|
moisture: this.getMoisture(),
|
||||||
temperature: this.temperature,
|
temperature: this.temperature,
|
||||||
humidity: this.humidity
|
humidity: this.humidity
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,25 @@ import * as serialport from 'serialport';
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
export default class Serial {
|
export default class Serial {
|
||||||
private moisture: number;
|
private moisture0: number;
|
||||||
|
private moisture1: number;
|
||||||
|
|
||||||
public constructor(path = '/dev/ttyUSB0', baudRate = 9600, delimiter = '\n') {
|
public constructor(path = '/dev/ttyUSB0', baudRate = 9600, delimiter = '\n') {
|
||||||
const port = new serialport.SerialPort({ path, baudRate });
|
const port = new serialport.SerialPort({ path, baudRate });
|
||||||
const readline = new serialport.ReadlineParser({ delimiter });
|
const readline = new serialport.ReadlineParser({ delimiter });
|
||||||
const parser = port.pipe(readline);
|
const parser = port.pipe(readline);
|
||||||
parser.on('data', line => {
|
parser.on('data', line => {
|
||||||
const moisture = parseInt(line.trim(), 10);
|
// console.log("data line ", line)
|
||||||
if (!isNaN(moisture)) {
|
const data = JSON.parse(line)
|
||||||
this.moisture = moisture
|
const moisture0 = parseInt(data['A0'], 10);
|
||||||
|
const moisture1 = parseInt(data['A1'], 10);
|
||||||
|
if (!isNaN(moisture0) && !isNaN(moisture1)) {
|
||||||
|
// console.log("m ", this.moisture)
|
||||||
|
this.moisture0 = moisture0;
|
||||||
|
this.moisture1 = moisture1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.log("data ",data)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
port.on('error', err => {
|
port.on('error', err => {
|
||||||
@ -23,7 +32,7 @@ export default class Serial {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
public getMoisture() {
|
public getMoisture() {
|
||||||
return this.moisture;
|
return this.moisture0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import HttpServer from './http';
|
import HttpServer from './http';
|
||||||
import IO from './io';
|
import IO, { ISensors } from './io';
|
||||||
import VideoSocket from './ws';
|
import VideoSocket from './ws';
|
||||||
|
|
||||||
const HTTP_PORT = process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT, 10) : 8080;
|
const HTTP_PORT = process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT, 10) : 8080;
|
||||||
@ -26,7 +26,7 @@ const TV_DEV_0 = process.env.TV_DEV_0 ?? '/dev/video0'
|
|||||||
// zap.getSignal(adapter)
|
// zap.getSignal(adapter)
|
||||||
|
|
||||||
const io = new IO();
|
const io = new IO();
|
||||||
// const getSensors = io.getSensors.bind(this);
|
const getSensors: ()=>ISensors = io.getSensors.bind(io);
|
||||||
// setTimeout(()=>{
|
// setTimeout(()=>{
|
||||||
// console.log("sen ",io.getSensors())
|
// console.log("sen ",io.getSensors())
|
||||||
// console.log("sen2 ",getSensors())
|
// console.log("sen2 ",getSensors())
|
||||||
@ -34,7 +34,7 @@ const io = new IO();
|
|||||||
// const setPower = io.setPower.bind(this, true)
|
// const setPower = io.setPower.bind(this, true)
|
||||||
// const togglePower = io.togglePower.bind(this)
|
// const togglePower = io.togglePower.bind(this)
|
||||||
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, io);
|
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, io);
|
||||||
const videoSocket = new VideoSocket(WS_PORT, TV_DEV_0);
|
const videoSocket = new VideoSocket(WS_PORT, TV_DEV_0, getSensors);
|
||||||
|
|
||||||
httpServer.start();
|
httpServer.start();
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ httpServer.start();
|
|||||||
process.stdin.setEncoding("utf8");
|
process.stdin.setEncoding("utf8");
|
||||||
process.stdin.resume();
|
process.stdin.resume();
|
||||||
|
|
||||||
console.log("Menu:\n1) Power off\n2)Power on\n3) Power flop\n4)Read moisture");
|
console.log("Menu:\n1) Power off\n2)Power on\n3) Power flop\n4)Read Sensors");
|
||||||
|
|
||||||
process.stdin.on("data", async (data: string) => {
|
process.stdin.on("data", async (data: string) => {
|
||||||
const input = data.trim();
|
const input = data.trim();
|
||||||
@ -53,7 +53,7 @@ process.stdin.on("data", async (data: string) => {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
io.setPower(false);// console.log(io.getMoisture());
|
io.setPower(false);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
io.setPower(true);
|
io.setPower(true);
|
||||||
@ -62,7 +62,8 @@ process.stdin.on("data", async (data: string) => {
|
|||||||
io.togglePower();
|
io.togglePower();
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
io.getSensors()
|
|
||||||
|
console.log("a ", getSensors())
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("No option for "+input)
|
console.log("No option for "+input)
|
||||||
|
@ -5,13 +5,13 @@ const ws0 = new WebSocket(ws0builder);
|
|||||||
const config = {
|
const config = {
|
||||||
iceServers: [
|
iceServers: [
|
||||||
{
|
{
|
||||||
urls: ['stun:dwestgate.us:3478','turn:dwestgate.us:3478?transport=udp'],
|
urls: ['stun:dwestgate.us:3478', 'turn:dwestgate.us:3478?transport=udp'],
|
||||||
username: 'webrtcuser',
|
username: 'webrtcuser',
|
||||||
credential: 'webrtccred'
|
credential: 'webrtccred'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
const pc0 = new RTCPeerConnection(config);
|
const pc0 = new RTCPeerConnection(isSecure ? config: {});
|
||||||
const video0 = document.getElementById('video0') as HTMLVideoElement;
|
const video0 = document.getElementById('video0') as HTMLVideoElement;
|
||||||
|
|
||||||
|
|
||||||
@ -26,6 +26,23 @@ pc0.onicecandidate = ({ candidate }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Create the data channel (client initiates)
|
||||||
|
const dataChannel = pc0.createDataChannel('sensors');
|
||||||
|
console.log("📡 Data channel created by client");
|
||||||
|
|
||||||
|
dataChannel.onopen = () => {
|
||||||
|
console.log('📬 Client: Data channel opened');
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onmessage = (event) => {
|
||||||
|
console.log("📦 Client received message:", event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onclose = () => {
|
||||||
|
console.log("📴 Client: Data channel closed");
|
||||||
|
};
|
||||||
|
|
||||||
ws0.onopen = async () => {
|
ws0.onopen = async () => {
|
||||||
pc0.addTransceiver('video', { direction: 'recvonly' });
|
pc0.addTransceiver('video', { direction: 'recvonly' });
|
||||||
pc0.addTransceiver('audio', { direction: 'recvonly' })
|
pc0.addTransceiver('audio', { direction: 'recvonly' })
|
||||||
@ -37,6 +54,7 @@ ws0.onopen = async () => {
|
|||||||
ws0.onmessage = async (message) => {
|
ws0.onmessage = async (message) => {
|
||||||
const msg = JSON.parse(message.data);
|
const msg = JSON.parse(message.data);
|
||||||
if (msg.type === 'answer') {
|
if (msg.type === 'answer') {
|
||||||
|
// pc0.data
|
||||||
await pc0.setRemoteDescription(msg.data);
|
await pc0.setRemoteDescription(msg.data);
|
||||||
}
|
}
|
||||||
else if (msg.type === 'ice-candidate') {
|
else if (msg.type === 'ice-candidate') {
|
||||||
@ -44,3 +62,4 @@ ws0.onmessage = async (message) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
51
src/ws.ts
51
src/ws.ts
@ -1,6 +1,7 @@
|
|||||||
import { MediaStream, MediaStreamTrack, nonstandard, RTCPeerConnection } from '@roamhq/wrtc';
|
import { MediaStream, MediaStreamTrack, nonstandard, RTCPeerConnection, RTCDataChannel } from '@roamhq/wrtc';
|
||||||
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
|
import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
|
||||||
import * as ws from 'ws';
|
import * as ws from 'ws';
|
||||||
|
import { ISensors } from './io';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const WIDTH = 640; // Video width
|
const WIDTH = 640; // Video width
|
||||||
@ -9,7 +10,7 @@ const FRAME_SIZE = WIDTH * HEIGHT * 1.5; // YUV420P frame size
|
|||||||
|
|
||||||
export default class VideoSocket {
|
export default class VideoSocket {
|
||||||
videoDevice: string;
|
videoDevice: string;
|
||||||
public constructor(port: number, videoDevice) {
|
public constructor(port: number, videoDevice, getSensors: () => ISensors) {
|
||||||
this.videoDevice = videoDevice
|
this.videoDevice = videoDevice
|
||||||
const ffmpegProcess = this.startFFmpeg();
|
const ffmpegProcess = this.startFFmpeg();
|
||||||
const videoTrack = this.createVideoTrack(ffmpegProcess);
|
const videoTrack = this.createVideoTrack(ffmpegProcess);
|
||||||
@ -25,11 +26,35 @@ export default class VideoSocket {
|
|||||||
|
|
||||||
wss.on('connection', async (ws: ws.WebSocket) => {
|
wss.on('connection', async (ws: ws.WebSocket) => {
|
||||||
const peerConnection: RTCPeerConnection = this.createPeerConnection(videoTrack, audioTrack);
|
const peerConnection: RTCPeerConnection = this.createPeerConnection(videoTrack, audioTrack);
|
||||||
|
// The client created the data channel. The server should access it as follows:
|
||||||
|
peerConnection.ondatachannel = (event) => {
|
||||||
|
const dataChannel = event.channel; // This is the data channel created by the client
|
||||||
|
|
||||||
|
dataChannel.onopen = () => {
|
||||||
|
console.log('📬 Server: Data channel opened');
|
||||||
|
// Now you can send data through the channel
|
||||||
|
setInterval(() => {
|
||||||
|
const sensorData = getSensors(); // Example function to fetch data
|
||||||
|
dataChannel.send(JSON.stringify(sensorData)); // Send data to the client
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onmessage = (event) => {
|
||||||
|
console.log("📦 Server received message:", event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onclose = () => {
|
||||||
|
console.log("📴 Server: Data channel closed");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ws.on('message', async (message: Buffer) => {
|
ws.on('message', async (message: Buffer) => {
|
||||||
const { type, data } = JSON.parse(message.toString());
|
const { type, data } = JSON.parse(message.toString());
|
||||||
|
|
||||||
if (type == 'offer') {
|
if (type == 'offer') {
|
||||||
|
|
||||||
await peerConnection.setRemoteDescription(data);
|
await peerConnection.setRemoteDescription(data);
|
||||||
const answer = await peerConnection.createAnswer();
|
const answer = await peerConnection.createAnswer();
|
||||||
await peerConnection.setLocalDescription(answer);
|
await peerConnection.setLocalDescription(answer);
|
||||||
@ -181,6 +206,28 @@ export default class VideoSocket {
|
|||||||
return audioSource.createTrack();
|
return audioSource.createTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createDataChannel = (peerConnection: RTCPeerConnection, getSensors: () => any) => {
|
||||||
|
const dataChannel = peerConnection.createDataChannel('sensors')
|
||||||
|
console.log("create data channel");
|
||||||
|
dataChannel.onopen = () => {
|
||||||
|
console.log('✅ Data channel is open');
|
||||||
|
// Send dummy JSON for testing
|
||||||
|
setInterval(() => {
|
||||||
|
const sensorData = getSensors(); // Assuming getSensors returns JSON
|
||||||
|
dataChannel.send(JSON.stringify(sensorData));
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onerror = (error) => {
|
||||||
|
console.error('❌ DataChannel error:', error);
|
||||||
|
};
|
||||||
|
|
||||||
|
dataChannel.onclose = () => {
|
||||||
|
console.log('❎ DataChannel closed');
|
||||||
|
};
|
||||||
|
return peerConnection;
|
||||||
|
}
|
||||||
|
|
||||||
createPeerConnection = (videoTrack: MediaStreamTrack, audioTrack: MediaStreamTrack): RTCPeerConnection => {
|
createPeerConnection = (videoTrack: MediaStreamTrack, audioTrack: MediaStreamTrack): RTCPeerConnection => {
|
||||||
const peerConnection = new RTCPeerConnection({
|
const peerConnection = new RTCPeerConnection({
|
||||||
iceServers: [
|
iceServers: [
|
||||||
|
Loading…
Reference in New Issue
Block a user