WS statt Telnet
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
module.exports = {
|
||||
|
||||
fluidnc: {
|
||||
host: "fluidncsilver.local",
|
||||
port: 81,
|
||||
host: "fluidncred.local",
|
||||
port: 80,
|
||||
reconnectDelay: 30000
|
||||
},
|
||||
|
||||
|
||||
@@ -1,104 +1,69 @@
|
||||
const WebSocket = require("ws");
|
||||
const EventEmitter = require("events");
|
||||
|
||||
const config = require("../config/config");
|
||||
const net = require("net");
|
||||
const { resolve } = require("path");
|
||||
const TelnetSocket = require("telnet-stream");
|
||||
class FluidNCClient extends EventEmitter {
|
||||
constructor(cfg) {
|
||||
super();
|
||||
|
||||
this.host = cfg.host;
|
||||
this.port = cfg.port || 81;
|
||||
|
||||
this.ws = null;
|
||||
this.reconnectDelay = 2000;
|
||||
|
||||
class FluidNCClient {
|
||||
constructor() {
|
||||
console.log("[FluidNCClient] Initializing...");
|
||||
|
||||
this.url = config.fluidnc.host;
|
||||
this.port = config.fluidnc.port || 23;
|
||||
this.tSocket = null;
|
||||
this.connected = false;
|
||||
this.state = { x:0, z:0, state:"unknown" };
|
||||
this.listeners = [];
|
||||
|
||||
this._connect();
|
||||
this.connect();
|
||||
}
|
||||
|
||||
_connect() {
|
||||
console.log(`[FluidNCClient] Connecting to FluidNC: ${this.url}`);
|
||||
connect() {
|
||||
const url = `ws://${this.host}:${this.port}`;
|
||||
console.log("[FluidNC] Connecting to:", url);
|
||||
|
||||
let socket = null;
|
||||
this.ws = new WebSocket(url);
|
||||
|
||||
new Promise((resolve, reject) => {
|
||||
socket = net.createConnection({host:this.url, port:this.port}, () => {
|
||||
resolve(socket);
|
||||
}).on("error", reject);
|
||||
}).then(connection => {
|
||||
console.log("[FluidNCClient] Telnet socket connected");
|
||||
this.connected = true;
|
||||
this.ws.on("open", () => {
|
||||
console.log("[FluidNC] Connected (WS)");
|
||||
});
|
||||
|
||||
connection.on("data", data => {
|
||||
const msg = data.toString().replace(/\r/g,"").trim();
|
||||
if(!msg) return;
|
||||
console.log("[FluidNCClient] Received:", msg);
|
||||
this.ws.on("message", (msg) => {
|
||||
this.emit("message", msg.toString());
|
||||
});
|
||||
|
||||
if(msg.startsWith("<") && msg.includes("MPos:")){
|
||||
const match = msg.match(/MPos:([\d\.\-]+),[\d\.\-]+,([\d\.\-]+)/);
|
||||
if(match){
|
||||
this.state.x = parseFloat(match[1]);
|
||||
this.state.z = parseFloat(match[2]);
|
||||
this.state.state = msg.split(",")[0].replace("<","");
|
||||
this._broadcast(this.state);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.ws.on("close", () => {
|
||||
console.log("[FluidNC] Disconnected → retry");
|
||||
setTimeout(() => this.connect(), this.reconnectDelay);
|
||||
});
|
||||
|
||||
if(socket != null){
|
||||
this.tSocket = TelnetSocket(socket);
|
||||
|
||||
this.tSocket.on("close", () => {
|
||||
console.log("[FluidNCClient] Telnet Closed");
|
||||
this.tSocket = null;
|
||||
this.connected = false;
|
||||
setTimeout(()=>this._connect(), 30000);
|
||||
});
|
||||
}
|
||||
|
||||
}, error => {
|
||||
console.log("[FluidNCClient] Telnet Connection Error:", error.toString());
|
||||
this.tSocket = null;
|
||||
this.connected = false;
|
||||
setTimeout(()=>this._connect(), 30000);
|
||||
this.ws.on("error", (err) => {
|
||||
console.log("[FluidNC] WS Error:", err.message);
|
||||
});
|
||||
}
|
||||
|
||||
_broadcast(msg){
|
||||
this.listeners.forEach(fn => fn(msg));
|
||||
}
|
||||
|
||||
onMessage(fn){
|
||||
this.listeners.push(fn);
|
||||
}
|
||||
|
||||
send(cmd){
|
||||
if(this.tSocket){
|
||||
console.log("[FluidNCClient] Sending:", cmd);
|
||||
this.tSocket.write(cmd + "\r\n");
|
||||
// --- BASIC COMMANDS ---
|
||||
sendLine(cmd) {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(cmd + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
jog(axis, value){
|
||||
if(!this.connected) return;
|
||||
this.send("G91");
|
||||
this.send(`G0 ${axis.toUpperCase()}${value}`);
|
||||
this.send("G90");
|
||||
requestStatus() {
|
||||
this.sendLine("?");
|
||||
}
|
||||
|
||||
sendGcode(cmd){
|
||||
if(!this.connected) return;
|
||||
this.send("G90");
|
||||
this.send(cmd);
|
||||
jog(axis, value) {
|
||||
const cmd = `$J=G91 ${axis}${value} F2000`;
|
||||
this.sendLine(cmd);
|
||||
}
|
||||
|
||||
setZero(){
|
||||
if(!this.connected) return;
|
||||
this.send("G10 L20 P1 X0 Z0");
|
||||
sendGcode(cmd) {
|
||||
this.sendLine(cmd);
|
||||
}
|
||||
|
||||
setZero() {
|
||||
this.sendLine("G92 X0 Y0 Z0");
|
||||
}
|
||||
|
||||
onMessage(fn) {
|
||||
this.on("message", fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,88 +9,72 @@ const FluidNCClient = require("./fluidnc/FluidNCClient");
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.static(path.join(__dirname,"../web")));
|
||||
// Serve frontend
|
||||
app.use(express.static(path.join(__dirname, "../web")));
|
||||
|
||||
const server = https.createServer({
|
||||
key: fs.readFileSync(path.join(__dirname,"../cert/key.pem")),
|
||||
cert: fs.readFileSync(path.join(__dirname,"../cert/cert.pem"))
|
||||
},app);
|
||||
// HTTPS server
|
||||
const server = https.createServer(
|
||||
{
|
||||
key: fs.readFileSync(path.join(__dirname, "../cert/key.pem")),
|
||||
cert: fs.readFileSync(path.join(__dirname, "../cert/cert.pem"))
|
||||
},
|
||||
app);
|
||||
|
||||
const wss = new WebSocket.Server({server});
|
||||
// Websocket server (browser connections)
|
||||
const wss = new WebSocket.Server({ server });
|
||||
|
||||
const fluid = new FluidNCClient();
|
||||
// Create FluidNC WebSocket client
|
||||
const fluid = new FluidNCClient(config.fluidnc);
|
||||
|
||||
// Connected browser clients
|
||||
let clients = [];
|
||||
|
||||
wss.on("connection",(ws)=>{
|
||||
|
||||
console.log("[WS] Client connected");
|
||||
|
||||
wss.on("connection", (ws) => {
|
||||
console.log("[WS] Browser connected");
|
||||
clients.push(ws);
|
||||
|
||||
ws.on("message",(msg)=>{
|
||||
|
||||
try{
|
||||
|
||||
ws.on("message", (msg) => {
|
||||
try {
|
||||
const data = JSON.parse(msg);
|
||||
|
||||
console.log("[WS] Received message:", data);
|
||||
|
||||
if(data.type==="jog"){
|
||||
|
||||
fluid.jog(data.axis,data.value);
|
||||
|
||||
if (data.type === "jog") {
|
||||
fluid.jog(data.axis, data.value);
|
||||
}
|
||||
|
||||
if(data.type==="gcode"){
|
||||
|
||||
if (data.type === "gcode") {
|
||||
fluid.sendGcode(data.cmd);
|
||||
|
||||
}
|
||||
|
||||
if(data.type==="zero"){
|
||||
|
||||
if (data.type === "zero") {
|
||||
fluid.setZero();
|
||||
|
||||
}
|
||||
|
||||
}catch(e){
|
||||
|
||||
console.log("[WS] Error parsing message:", e);
|
||||
|
||||
} catch (e) {
|
||||
console.log("[WS] Error parsing:", e);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
ws.on("close",()=>{
|
||||
|
||||
clients = clients.filter(c=>c!==ws);
|
||||
|
||||
console.log("[WS] Client disconnected");
|
||||
|
||||
ws.on("close", () => {
|
||||
clients = clients.filter(c => c !== ws);
|
||||
console.log("[WS] Browser disconnected");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
fluid.onMessage((msg)=>{
|
||||
|
||||
const json = JSON.stringify(msg);
|
||||
|
||||
clients.forEach(c=>{
|
||||
|
||||
if(c.readyState===WebSocket.OPEN){
|
||||
|
||||
c.send(json);
|
||||
|
||||
// FluidNC → Browser broadcasting
|
||||
fluid.onMessage((msg) => {
|
||||
clients.forEach(c => {
|
||||
if (c.readyState === WebSocket.OPEN) {
|
||||
c.send(msg.toString());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
server.listen(config.server.port,()=>{
|
||||
|
||||
// Status polling ("?" every 200ms)
|
||||
setInterval(() => {
|
||||
fluid.requestStatus();
|
||||
}, 200);
|
||||
|
||||
server.listen(config.server.port, () => {
|
||||
console.log("[Server] Running at:");
|
||||
console.log(`https://localhost:${config.server.port}`);
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user