Maybe i can make server app
This commit is contained in:
parent
b9671dbf21
commit
5deaf0f600
@ -1,5 +1,4 @@
|
||||
{
|
||||
"watch": ["src"],
|
||||
"ext": ".ts,.js",
|
||||
"exec": "ts-node ./src/index.ts"
|
||||
"ext": ".ts,.js"
|
||||
}
|
15
package-lock.json
generated
15
package-lock.json
generated
@ -11,11 +11,13 @@
|
||||
"dependencies": {
|
||||
"@serialport/bindings": "^9.2.9",
|
||||
"@serialport/list": "^12.0.0",
|
||||
"@types/ip": "^1.1.3",
|
||||
"chalk": "^4.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"firmata": "^2.3.0",
|
||||
"ip": "^2.0.1",
|
||||
"johnny-five": "^2.1.0",
|
||||
"nodemon": "^3.1.0",
|
||||
"serialport": "^12.0.0",
|
||||
@ -458,6 +460,14 @@
|
||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/ip": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.3.tgz",
|
||||
"integrity": "sha512-64waoJgkXFTYnCYDUWgSATJ/dXEBanVkaP5d4Sbk7P6U7cTTMhxVyROTckc6JKdwCrgnAjZMn0k3177aQxtDEA==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/johnny-five": {
|
||||
"version": "2.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/johnny-five/-/johnny-five-2.1.9.tgz",
|
||||
@ -1739,6 +1749,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
||||
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
|
@ -7,18 +7,21 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "nodemon",
|
||||
"start": "nodemon --exec ts-node ./src",
|
||||
"dev": "nodemon --exec ts-node ./src/dev.ts",
|
||||
"ports": "ts-node src/ports/print.ts",
|
||||
"test-blink": "nodemon test/blink.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@serialport/bindings": "^9.2.9",
|
||||
"@serialport/list": "^12.0.0",
|
||||
"@types/ip": "^1.1.3",
|
||||
"chalk": "^4.1.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"firmata": "^2.3.0",
|
||||
"ip": "^2.0.1",
|
||||
"johnny-five": "^2.1.0",
|
||||
"nodemon": "^3.1.0",
|
||||
"serialport": "^12.0.0",
|
||||
|
40
src/app.ts
Normal file
40
src/app.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import readline from "node:readline/promises";
|
||||
import chalk from "chalk";
|
||||
import { Board } from "johnny-five";
|
||||
|
||||
import { selectPort } from "./ports";
|
||||
import { run } from "./server";
|
||||
import { suBoard } from "./setup";
|
||||
import { cfg } from "./setup/config";
|
||||
import { getPublicIp } from "./utils/network";
|
||||
|
||||
async function questions () {
|
||||
const line = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
})
|
||||
|
||||
const exposeHost = await line.question("Run in public network? (y/n) ");
|
||||
|
||||
if (exposeHost.toLowerCase() == "y") {
|
||||
console.warn(chalk.yellow("Running a server on a public host may not be able to use the socket.io api"));
|
||||
cfg.server.host = getPublicIp();
|
||||
}
|
||||
|
||||
line.close();
|
||||
}
|
||||
|
||||
export default async function main () {
|
||||
const port = await selectPort();
|
||||
await questions();
|
||||
|
||||
console.log(`Selected port ${port}`);
|
||||
|
||||
cfg.port = port;
|
||||
suBoard.board = new Board({
|
||||
port: port,
|
||||
debug: false,
|
||||
repl: false
|
||||
});
|
||||
run();
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board } from "../../setup";
|
||||
import { suBoard } from "../../setup";
|
||||
import * as Promises from "../../promises";
|
||||
|
||||
|
||||
interface AnalogState {
|
||||
pin: string,
|
||||
value: number
|
||||
}
|
||||
|
||||
export function analogWrite (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const { pin, value }: AnalogState = req.body;
|
||||
|
||||
try {
|
||||
@ -27,6 +29,7 @@ export function analogWrite (req: Request, res: Response): Response<string | any
|
||||
}
|
||||
|
||||
export async function analogRead (req: Request, res: Response) {
|
||||
const { board } = suBoard;
|
||||
let { pin } = req.params;
|
||||
pin = pin[0] == "A" ? pin.slice(1, pin.length) : pin;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board } from "../../setup";
|
||||
import { suBoard } from "../../setup";
|
||||
|
||||
interface DigitalState {
|
||||
pin: number | string,
|
||||
@ -7,6 +7,7 @@ interface DigitalState {
|
||||
}
|
||||
|
||||
export function digitalWrite (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const { pin, state }: DigitalState = req.body;
|
||||
let value: number;
|
||||
|
||||
@ -38,6 +39,7 @@ export function digitalWrite (req: Request, res: Response): Response<string | an
|
||||
}
|
||||
|
||||
export function digitalRead (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
try {
|
||||
const { pin } = req.params;
|
||||
const value = board.pins[pin].value == 1 ? 'HIGH' : 'LOW';
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board, suBoard } from "../../setup";
|
||||
import { suBoard } from "../../setup";
|
||||
import { sPinModes } from "..";
|
||||
import { Pin } from "johnny-five";
|
||||
|
||||
|
||||
export function readPin (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const pin: string = req.params.p;
|
||||
|
||||
const { mode } = board.pins[pin];
|
||||
@ -21,6 +23,7 @@ export function readPin (req: Request, res: Response): Response<string | any> {
|
||||
}
|
||||
|
||||
export function readPins (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const pins: string[] = req.body.p;
|
||||
const pinModes = [];
|
||||
|
||||
@ -39,12 +42,13 @@ export function readPins (req: Request, res: Response): Response<string | any> {
|
||||
}
|
||||
|
||||
export function setPin (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const pin: string = req.params.p;
|
||||
const mode: sPinModes | string = req.params.m.toUpperCase();
|
||||
|
||||
board.pinMode(pin, Pin[mode]);
|
||||
|
||||
suBoard.PINS.pwm.push(pin);
|
||||
suBoard.PINS.digital.push(pin);
|
||||
suBoard.sort();
|
||||
|
||||
return res.status(200).json({
|
||||
@ -60,6 +64,7 @@ export function setPin (req: Request, res: Response): Response<string | any> {
|
||||
}
|
||||
|
||||
export function setPins (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
type PinModes = {
|
||||
pin: string,
|
||||
mode: sPinModes | string
|
||||
@ -71,7 +76,7 @@ export function setPins (req: Request, res: Response): Response<string | any> {
|
||||
const { pin, mode } = p;
|
||||
board.pinMode(pin, Pin[mode]);
|
||||
|
||||
suBoard.PINS.pwm.push(pin);
|
||||
suBoard.PINS.digital.push(pin);
|
||||
suBoard.sort();
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board } from "../../setup";
|
||||
import { ChannelPins, digitalValue, voltage } from "..";
|
||||
import { suBoard } from "../../setup";
|
||||
import { ChannelPins, voltage } from "..";
|
||||
import { Led } from "johnny-five";
|
||||
|
||||
|
||||
export function readLed (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
try {
|
||||
const { p } = req.params;
|
||||
const pin: number = Number.parseInt(p);
|
||||
@ -29,6 +29,7 @@ export function readLed (req: Request, res: Response): Response<string | any> {
|
||||
}
|
||||
|
||||
export function writeLed (req: Request, res: Response): Response<string | any> {
|
||||
const { board } = suBoard;
|
||||
const { p, a } = req.params;
|
||||
const act: string = a.toLocaleLowerCase();
|
||||
const pin: number = Number.parseInt(p);
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board } from "../../setup";
|
||||
import { suBoard } from "../../setup";
|
||||
import { analogRead } from "../../promises";
|
||||
|
||||
|
||||
export async function readResistor (req: Request, res: Response): Promise<Response<string, any>> {
|
||||
const { board } = suBoard;
|
||||
const { p } = req.params;
|
||||
const pin: string = req.params.p.startsWith("A") ? req.params.p.slice(0, p.length) : req.params.p;
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Request, Response } from "express";
|
||||
import { board } from "../../setup";
|
||||
import { suBoard } from "../../setup";
|
||||
|
||||
export function rotateServo (req: Request, res: Response): Response<string, any> {
|
||||
const { board } = suBoard;
|
||||
const { p } = req.params;
|
||||
const pin: string = req.params.p.startsWith("A") ? req.params.p.slice(0, p.length) : req.params.p;
|
||||
const angle: number = Number.parseInt(req.params.ang);
|
||||
|
7
src/dev.ts
Normal file
7
src/dev.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { Board } from "johnny-five";
|
||||
import { run } from "./server";
|
||||
import { defaultBoardOption, suBoard } from "./setup";
|
||||
|
||||
suBoard.board = new Board(defaultBoardOption);
|
||||
|
||||
run();
|
@ -1,6 +1,8 @@
|
||||
import { Socket } from "socket.io";
|
||||
import { Pin, Sensor } from "johnny-five";
|
||||
import { board } from "../setup";
|
||||
import { suBoard } from "../setup";
|
||||
|
||||
const { board } = suBoard;
|
||||
|
||||
export default (socket: Socket) => {
|
||||
console.log(`${socket.id} | ${socket.client.request.headers.host} | Joined`);
|
||||
|
62
src/index.ts
62
src/index.ts
@ -1,61 +1,3 @@
|
||||
import http from 'node:http';
|
||||
import path from 'node:path';
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { Server } from 'socket.io';
|
||||
import chalk from 'chalk';
|
||||
import main from "./app";
|
||||
|
||||
import { board, suBoard, comport } from './setup';
|
||||
|
||||
import { isBoardConnected } from './middleware/connection';
|
||||
import view from './routes/view';
|
||||
import api from './routes/api';
|
||||
import socketHandler from './handlers/socketHandler';
|
||||
|
||||
const app = express();
|
||||
const server: http.Server = http.createServer(app);
|
||||
const io: Server = new Server(server, {
|
||||
cors: {
|
||||
origin: "*"
|
||||
}
|
||||
}); // I have no experience at WebSocket, so.. forgive me :)
|
||||
|
||||
// Server configuration
|
||||
const host: string = 'localhost';
|
||||
const port: number = 3000;
|
||||
|
||||
// Express middleware
|
||||
app.use(cors({ origin: "*" }));
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, 'client')));
|
||||
|
||||
// Socket.io event handlers
|
||||
io.on('connection', socketHandler);
|
||||
|
||||
// HTTP Routes
|
||||
app.use('/', view);
|
||||
app.use('/api-arduino', isBoardConnected, api); // Board API Controllers
|
||||
|
||||
// Run server
|
||||
console.log("\nRunning Server...");
|
||||
server.listen(port, () => {
|
||||
console.log(`Server is connected and running in ${host} at port ${port} 🗣️🗣️🗣️`);
|
||||
console.log(`* Press ${chalk.bold(chalk.yellow("CTRL+C"))} to exit`);
|
||||
console.log(`* URL: ${chalk.bold(`http://${host}:${port}/\n`)}`);
|
||||
console.log(chalk.yellow(`Connecting to Board`));
|
||||
|
||||
board.on('ready', () => {
|
||||
console.log(chalk.green(`Board at port ${comport} Connected!! \(^o^)/`));
|
||||
suBoard.connected = true;
|
||||
})
|
||||
|
||||
board.on('error', (err) => {
|
||||
console.error(chalk.red("\nError while connecting to Board"));
|
||||
console.error(chalk.red(err.message));
|
||||
console.log("Enter 'rs' to try again");
|
||||
})
|
||||
|
||||
board.on('exit', () => {
|
||||
console.log("Bye bye");
|
||||
})
|
||||
});
|
||||
main();
|
@ -1,5 +1,7 @@
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import { board, suBoard } from "../setup";
|
||||
import { suBoard } from "../setup";
|
||||
|
||||
const { board } = suBoard;
|
||||
|
||||
export function isBoardConnected (req: Request, res: Response, next: NextFunction) {
|
||||
if (suBoard.connected) {
|
||||
|
@ -24,7 +24,7 @@ export function isPinBeingUsed (req: Request, res: Response, next: NextFunction)
|
||||
});
|
||||
}
|
||||
|
||||
if (suBoard.PINS.pwm.indexOf(pin) != -1) {
|
||||
if (suBoard.PINS.digital.indexOf(pin) != -1) {
|
||||
return res.status(400).json({
|
||||
status: 400,
|
||||
message: `Pin ${pin}, is used`
|
||||
|
@ -1,29 +1,23 @@
|
||||
import readline from 'node:readline/promises';
|
||||
import { ReadPorts } from "./read";
|
||||
import { board, suBoard } from '../setup';
|
||||
|
||||
export async function selectPort (cb: () => void) {
|
||||
export async function selectPort (): Promise<string | any> {
|
||||
const ports = await ReadPorts();
|
||||
|
||||
const line =readline.createInterface({
|
||||
const line = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
console.log(`Select number of ports (0-${ports.length})`);
|
||||
ports.forEach((port, i) => {
|
||||
console.log(`${i+1}. ${port}`);
|
||||
console.log(`${i+1}. ${port.path} - ${port.name}${port.serialNumber ? " - Recomended" : ""}`);
|
||||
})
|
||||
|
||||
const selectedInput: string = await line.question("Enter number: ");
|
||||
const selectedNumber: number = Number.parseInt(selectedInput);
|
||||
const selectedPort: string = ports[selectedNumber-1];
|
||||
const selectedPort: { name?: string, path?: string } = ports[selectedNumber-1];
|
||||
|
||||
suBoard.port = selectedPort;
|
||||
board.port = selectedPort;
|
||||
|
||||
console.log(`Selected port: ${selectedPort}`);
|
||||
line.close();
|
||||
|
||||
cb();
|
||||
return selectedPort.path;
|
||||
}
|
@ -3,6 +3,6 @@ import { ReadPorts } from "./read";
|
||||
ReadPorts().then((ports) => {
|
||||
console.log(`${ports.length} Ports available`);
|
||||
ports.forEach((port, i) => {
|
||||
console.log((i+1) + ", " + port);
|
||||
console.log(`${i+1}. ${port.path} - ${port.name}`);
|
||||
})
|
||||
})
|
@ -1,8 +1,14 @@
|
||||
import * as SerialPort from 'serialport';
|
||||
|
||||
export async function ReadPorts (): Promise<string[]> {
|
||||
export async function ReadPorts (): Promise<{ name?: string, path?: string, serialNumber?: string | number }[]> {
|
||||
const ports = await SerialPort.SerialPort.list();
|
||||
return ports
|
||||
.filter(port => port.pnpId != null)
|
||||
.map(port => port.path)
|
||||
.map(port => {
|
||||
return {
|
||||
name: port['friendlyName'],
|
||||
path: port.path,
|
||||
serialNumber: port.serialNumber
|
||||
}
|
||||
})
|
||||
}
|
73
src/server.ts
Normal file
73
src/server.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import http from 'node:http';
|
||||
import path from 'node:path';
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { Server } from 'socket.io';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { suBoard, comport } from './setup';
|
||||
import { cfg } from './setup/config';
|
||||
|
||||
import { isBoardConnected } from './middleware/connection';
|
||||
import view from './routes/view';
|
||||
import api from './routes/api';
|
||||
import socketHandler from './handlers/socketHandler';
|
||||
|
||||
const app = express();
|
||||
const server: http.Server = http.createServer(app);
|
||||
const io: Server = new Server(server, {
|
||||
cors: {
|
||||
origin: cfg.server.cors
|
||||
}
|
||||
}); // I have no experience at WebSocket, so.. forgive me :)
|
||||
|
||||
// Express middleware
|
||||
app.use(cors({ origin: "*" }));
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, 'client')));
|
||||
|
||||
// Socket.io event handlers
|
||||
io.on('connection', socketHandler);
|
||||
|
||||
// HTTP Routes
|
||||
app.use('/', view);
|
||||
app.use('/api-arduino', isBoardConnected, api); // Board API Controllers
|
||||
|
||||
// Run server
|
||||
export function run () {
|
||||
const { board } = suBoard;
|
||||
const { port, host } = cfg.server;
|
||||
|
||||
try {
|
||||
|
||||
if (!board) {
|
||||
throw new Error("Failed to use API, process canceled. No new API boards have been declared as of yet");
|
||||
}
|
||||
|
||||
console.log("\nRunning Server...");
|
||||
server.listen(port, () => {
|
||||
console.log(`Server is connected and running in ${host} at port ${port} 🗣️🗣️🗣️`);
|
||||
console.log(`* Enter ${chalk.bold(chalk.yellow("rs"))} to restart`);
|
||||
console.log(`* Press ${chalk.bold(chalk.yellow("CTRL+C"))} to exit`);
|
||||
console.log(`* URL: ${chalk.bold(`http://${host}:${port}/\n`)}`);
|
||||
console.log(chalk.yellow(`Connecting to Board`));
|
||||
|
||||
board.on('ready', () => {
|
||||
console.log(chalk.green(`Board at port ${comport} Connected!! \(^o^)/`));
|
||||
suBoard.connected = true;
|
||||
})
|
||||
|
||||
board.on('error', (err) => {
|
||||
console.error(chalk.red("\nError while connecting to Board"));
|
||||
console.error(chalk.red(err.message));
|
||||
console.log("Enter 'rs' to try again");
|
||||
})
|
||||
|
||||
board.on('exit', () => {
|
||||
console.log("Bye bye");
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Fatal error. ", err);
|
||||
}
|
||||
}
|
12
src/setup/config.ts
Normal file
12
src/setup/config.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { config } from 'dotenv';
|
||||
|
||||
config();
|
||||
|
||||
export const cfg = {
|
||||
port: process.env.SERIAL_PORT || '/dev/ttyUSB0',
|
||||
server: {
|
||||
port: 3000,
|
||||
host: 'localhost',
|
||||
cors: "*"
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { SuBoard } from './support';
|
||||
import { Board } from 'johnny-five';
|
||||
import { Board, BoardOption } from 'johnny-five';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
config();
|
||||
@ -7,8 +7,8 @@ config();
|
||||
export const comport: string = process.env.SERIAL_PORT || '/dev/ttyUSB0';
|
||||
export const suBoard: SuBoard = new SuBoard();
|
||||
|
||||
export const board: Board | null = new Board({
|
||||
export const defaultBoardOption: BoardOption = {
|
||||
port: comport,
|
||||
debug: false,
|
||||
repl: false,
|
||||
debug: false
|
||||
});
|
||||
};
|
@ -1,22 +1,25 @@
|
||||
import { Board } from "johnny-five";
|
||||
|
||||
export interface SupportBoard {
|
||||
port: string | null,
|
||||
connected: boolean,
|
||||
PINS: {
|
||||
pwm: number[],
|
||||
digital: number[],
|
||||
analog: number[],
|
||||
}
|
||||
sort: () => void
|
||||
}
|
||||
|
||||
export class SuBoard implements SupportBoard {
|
||||
public board: Board | null;
|
||||
public port = null;
|
||||
public connected = false;
|
||||
public PINS = {
|
||||
pwm: [],
|
||||
digital: [],
|
||||
analog: []
|
||||
};
|
||||
public sort() {
|
||||
this.PINS.pwm = this.PINS.pwm.sort((a, b) => b - a);
|
||||
this.PINS.digital = this.PINS.digital.sort((a, b) => b - a);
|
||||
this.PINS.analog = this.PINS.analog.sort((a, b) => b - a);
|
||||
}
|
||||
}
|
5
src/utils/network.ts
Normal file
5
src/utils/network.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { address } from 'ip';
|
||||
|
||||
export function getPublicIp () {
|
||||
return address("public", "ipv4") || '127.0.0.1';
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user