Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Former-commit-id: e38cf3c
  • Loading branch information
ZachLTech committed Jul 1, 2024
2 parents 35f8e07 + 7cbb9ae commit b41c693
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 45 deletions.
167 changes: 124 additions & 43 deletions src/js/backend/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
import { SerialPort, DelimiterParser } from 'serialport';
import {Daemon, Listener} from 'node-gpsd';
import { WebSocketServer } from 'ws';
import express from 'express';
import fs from "fs";

class AEVBackend {
constructor(config, logger) {
this.logger = logger;
this.config = config;
this.ports = {
MCU: {
BMS: {
enabled: false,
port: null,
parser: null,
Expand Down Expand Up @@ -37,61 +38,62 @@ class AEVBackend {
};

this.continue = {
MCU: true,
BMS: true,
GPS: true,
}

this.api = null;
this.wss = null;
}

start() {
this.logger.warn("Logger initialized in backend!");
this.initMCU();
this.initBMS();
this.initGPS();
this.initSocket();
}

initMCU() {
// Initialize serial port for MCU
if (fs.existsSync(this.config.MCU.path)) {
this.logger.success("MCU serial port is being opened...")
this.ports.MCU.enabled = true;
this.ports.MCU.port = new SerialPort({
path: this.config.MCU.path,
baudRate: this.config.MCU.baudRate,
initBMS() {
// Initialize serial port for BMS
if (fs.existsSync(this.config.BMS.path)) {
this.logger.success("BMS serial port is being opened...")
this.ports.BMS.enabled = true;
this.ports.BMS.port = new SerialPort({
path: this.config.BMS.path,
baudRate: this.config.BMS.baudRate,
autoOpen: false,
});

this.ports.MCU.parser = this.ports.MCU.port.pipe(new DelimiterParser({
this.ports.BMS.parser = this.ports.BMS.port.pipe(new DelimiterParser({
delimiter: 'sh',
}));

// console.log(this.logger)
this.ports.MCU.port.on('open', () => {
this.ports.BMS.port.on('open', () => {
// const logger = this.logger;
this.logger.success("MCU serial port opened");
this.continue.MCU = true;
this.logger.success("BMS serial port opened");
this.continue.BMS = true;
});
this.ports.MCU.parser.on('data', (data) => {
this.ports.BMS.parser.on('data', (data) => {
this.parseBMSData(data.toString().split("\n"));
});
this.ports.MCU.port.on('error', (error) => {
// this.logger.warn(`MCU serial port error: ${error}`);
this.ports.BMS.port.on('error', (error) => {
// this.logger.warn(`BMS serial port error: ${error}`);
});
this.ports.MCU.port.on('close', () => {
this.logger.warn("MCU serial port closed");
this.continue.MCU = false;
this.ports.BMS.port.on('close', () => {
this.logger.warn("BMS serial port closed");
this.continue.BMS = false;
});
this.ports.MCU.port.on('drain', () => {
this.logger.success("MCU serial port drained (write failed)");
this.ports.BMS.port.on('drain', () => {
this.logger.success("BMS serial port drained (write failed)");
});

this.ports.MCU.port.open( (err) => {
this.ports.BMS.port.open( (err) => {
if (err) console.error(err)
})

} else {
this.logger.fail("MCU serial port not found at " + this.config.MCU.path);
this.logger.fail("BMS serial port not found at " + this.config.BMS.path);
}
}

Expand Down Expand Up @@ -139,14 +141,21 @@ class AEVBackend {
}
}

stopMCU() {
this.continue.MCU = false;
this.ports.MCU.port.close();
this.logger.warn("MCU serial port closed");
stopGPS() {
this.continue.GPS = false;
this.ports.GPS.listener.disconnect();
this.ports.GPS.daemon.stop();
this.logger.warn("GPS daemon stopped");
}

stopBMS() {
this.continue.BMS = false;
this.ports.BMS.port.close();
this.logger.warn("BMS serial port closed");
}

initSocket() {
if (this.ports.MCU.enabled || this.ports.GPS.enabled) {
if (this.ports.BMS.enabled || this.ports.GPS.enabled) {
// Initialize WebSocket server
this.wss = new WebSocketServer({
port: this.config.mainPort
Expand All @@ -155,15 +164,21 @@ class AEVBackend {

this.wss.on('connection', (ws) => {
this.logger.success("Client connected to WebSocket server");
if (this.ports.MCU.enabled) {
if (this.ports.MCU.port.isOpen) {
if (this.ports.BMS.enabled) {
if (this.ports.BMS.port.isOpen) {
// Send BMS data to client half a second under a try-catch block
setInterval(() => {
try {
if (this.continue.MCU) {
this.ports.MCU.port.write("sh\n");
// ws.send(JSON.stringify(this.ports.MCU.data));
this.logger.debug("Updated BMS Data")
if (this.continue.BMS) {
try {
this.ports.BMS.port.write("\nsh\n");
this.ports.BMS.port.drain();
// ws.send(JSON.stringify(this.ports.BMS.data));
// this.logger.debug("Updated BMS Data")
this.logger.debug("Wrote all commands, waiting for data response");
} catch (error) {
console.log(error)
}
} else {
this.logger.warn("Told not to continue sending BMS data through socket");
}
Expand All @@ -181,7 +196,7 @@ class AEVBackend {
this.logger.debug("Received message from client: " + message);
if (message === "bms-data") {
this.logger.success("Client requested BMS data, sending it over")
reply = JSON.stringify(this.ports.MCU.data);
reply = JSON.stringify(this.ports.BMS.data);
} else if (message === "gps-data") {
this.logger.success("Client requested GPS data, sending it over")
reply = JSON.stringify(this.ports.GPS.data);
Expand All @@ -195,8 +210,8 @@ class AEVBackend {
}
} else if (message === "bms-restart") {
try {
this.stopMCU();
this.initMCU();
this.stopBMS();
this.initBMS();
reply = "BMS restarted";
this.logger.success("BMS restarted");
} catch (error) {
Expand All @@ -215,10 +230,76 @@ class AEVBackend {
}
}

initAPI() {
this.api = express();
this.api.use(express.json());

this.api.get('/', (req, res) => {
this.logger.success("Recieved GET request on /, replied with API status");
res.send({
message: "API server is running",
ports: {
BMS: this.ports.BMS.enabled,
GPS: this.ports.GPS.enabled,
}
});
});

this.api.get('/bms', (req, res) => {
this.logger.success("Recieved GET request on /bms, replied with BMS status: " + this.ports.BMS.enabled);
if (this.ports.GPS.enabled) {
res.send({ enabled: true });
} else {
res.send({ enabled: false });
}
});
this.api.get('/bms/data', (req, res) => {
this.logger.success("Recieved GET request on /bms/data, replied with BMS data");
res.send(JSON.stringify(this.ports.BMS.data));
});
this.api.get('/bms/restart', (req, res) => {
try {
this.logger.success("Recieved GET request on /bms/restart, restarting BMS");
this.stopBMS();
this.initBMS();
res.send({ status: "BMS restarted" });
} catch (error) {
res.send({ status: "Error restarting BMS: " + error });
}
});

this.api.get('/gps', (req, res) => {
this.logger.success("Recieved GET request on /gps, replied with GPS status: " + this.ports.GPS.enabled);
if (this.ports.GPS.enabled) {
res.send({ enabled: true });
} else {
res.send({ enabled: false });
}
});
this.api.get('/gps/data', (req, res) => {
this.logger.success("Recieved GET request on /gps/data, replied with GPS data");
res.send(JSON.stringify(this.ports.GPS.data));
});
this.api.get('/gps/restart', (req, res) => {
try {
this.logger.success("Recieved GET request on /gps/restart, restarting GPS");
this.stopGPS();
this.initGPS();
res.send({ status: "GPS restarted" });
} catch (error) {
res.send({ status: "Error restarting GPS: " + error });
}
});

this.api.listen(3002, () => {
this.logger.success("API server started on port", 3002);
});
}

parseBMSData(data) {
// Parse BMS data
try {
// Trim the first two elements of the array and the last element of the array (useless bc first is "\r" and last is "mcu> ")
// Trim the first two elements of the array and the last element of the array (useless bc first is "\r" and last is "BMS> ")
data.shift();
data.shift();
data.pop();
Expand Down Expand Up @@ -311,11 +392,11 @@ class AEVBackend {

// this.logger.log(dataObj)

this.ports.MCU.data = dataObj;
return this.ports.MCU.data;
this.ports.BMS.data = dataObj;
return this.ports.BMS.data;
} catch (error) {
this.logger.warn("Error parsing BMS data: " + error);
return this.ports.MCU.data;
return this.ports.BMS.data;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/js/backend/src/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
let config = {
"MCU": {
"BMS": {
"path": "/dev/ttyUSB0",
"baudRate": 115200
},
Expand Down
27 changes: 27 additions & 0 deletions src/js/backend/src/tests/api-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// GET request to the following routes for localhost:3002: /hello, /goodbye
// Print all responses to the console
import axios from 'axios';

const responses = {};

const api = axios.create({
baseURL: 'http://localhost:3002',
});

api.get('/hello')
.then((response) => {
responses['/hello'] = response;
console.log(response);
})
api.get('/goodbye')
.then((response) => {
responses['/goodbye'] = response;
console.log(response);
})


// When everything is done, print all responses
// api.all([api.get('/hello'), api.get('/goodbye')])
// .then(axios.spread((...responses) => {
// console.log(responses);
// }));
13 changes: 13 additions & 0 deletions src/js/backend/src/tests/api-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from 'express';
const app = express();

app.get('/hello', (req, res) => {
res.send('Hello World');
});
app.get('/goodbye', (req, res) => {
res.send('Goodbye World');
});

app.listen(3003, () => {
console.log('Server running on port 3002');
});
54 changes: 54 additions & 0 deletions src/js/backend/src/tests/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// GET request to the following routes for localhost:3002: /, /bms, /bms/data, /bms/restart, /gps, /gps/data, /gps/restart
// Print all responses to the console
import axios from 'axios';

const responses = {};

const api = axios.create({
baseURL: 'http://localhost:3002',
});

api.get('/')
.then((response) => {
responses['/'] = response;
console.log(response);
})

api.get('/bms')
.then((response) => {
responses['/bms'] = response;
console.log(response);
})
api.get('/bms/data')
.then((response) => {
responses['/bms/data'] = response;
console.log(response);
})
api.get('/bms/restart')
.then((response) => {
responses['/bms/restart'] = response;
console.log(response);
})

api.get('/gps')
.then((response) => {
responses['/gps'] = response;
console.log(response);
})
api.get('/gps/data')
.then((response) => {
responses['/gps/data'] = response;
console.log(response);
})
api.get('/gps/restart')
.then((response) => {
responses['/gps/restart'] = response;
console.log(response);
})


// When everything is done, print all responses
api.all([api.get('/'), api.get('/bms'), api.get('/bms/data'), api.get('/bms/restart'), api.get('/gps'), api.get('/gps/data'), api.get('/gps/restart')])
.then(axios.spread((...responses) => {
console.log(responses);
}));
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import WebSocket from "ws";
import Logger from "./src/logger.cjs";
import Logger from "../logger.cjs";
const logger = new Logger();
const ws = new WebSocket("ws://localhost:3001");

Expand Down

0 comments on commit b41c693

Please sign in to comment.