diff --git a/package-lock.json b/package-lock.json index 0f827e2..ad220eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,15 +10,18 @@ "license": "MIT", "dependencies": { "@serialport/bindings": "^9.2.9", + "chalk": "^4.1.2", "express": "^4.18.3", "firmata": "^2.3.0", "nodemon": "^3.1.0", - "serialport": "^12.0.0" + "serialport": "^12.0.0", + "socket.io": "^4.7.4" }, "devDependencies": { "@types/express": "^4.17.21", "@types/firmata": "^0.19.8", "@types/nodemon": "^1.19.6", + "@types/socket.io": "^3.0.2", "ts-node": "^10.9.2", "typescript": "^5.3.3" } @@ -320,6 +323,11 @@ "url": "https://opencollective.com/serialport/donate" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -363,6 +371,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/express": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", @@ -413,7 +434,6 @@ "version": "20.11.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -470,6 +490,16 @@ "@types/node": "*" } }, + "node_modules/@types/socket.io": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-3.0.2.tgz", + "integrity": "sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ==", + "deprecated": "This is a stub types definition. socket.io provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "socket.io": "*" + } + }, "node_modules/@types/streamjs": { "version": "1.5.32", "resolved": "https://registry.npmjs.org/@types/streamjs/-/streamjs-1.5.32.tgz", @@ -522,6 +552,20 @@ "node": ">=0.10.0" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -610,6 +654,14 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -741,6 +793,40 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -777,6 +863,22 @@ "node": ">=0.10.0" } }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -824,6 +926,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -943,6 +1057,42 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.4.tgz", + "integrity": "sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -2213,6 +2363,44 @@ "node": ">=10" } }, + "node_modules/socket.io": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.4.tgz", + "integrity": "sha512-DcotgfP1Zg9iP/dH9zvAQcWrE0TtbMVwXmlV4T4mqsvY+gw+LqUGPfx2AoVyRk0FLME+GQhufDMyacFmw7ksqw==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2415,8 +2603,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -2474,6 +2661,26 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, + "node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index ce84a8e..acaaa4e 100644 --- a/package.json +++ b/package.json @@ -12,15 +12,18 @@ }, "dependencies": { "@serialport/bindings": "^9.2.9", + "chalk": "^4.1.2", "express": "^4.18.3", "firmata": "^2.3.0", "nodemon": "^3.1.0", - "serialport": "^12.0.0" + "serialport": "^12.0.0", + "socket.io": "^4.7.4" }, "devDependencies": { "@types/express": "^4.17.21", "@types/firmata": "^0.19.8", "@types/nodemon": "^1.19.6", + "@types/socket.io": "^3.0.2", "ts-node": "^10.9.2", "typescript": "^5.3.3" } diff --git a/src/controller/led.ts b/src/controller/led.ts index b7707b7..89bf24e 100644 --- a/src/controller/led.ts +++ b/src/controller/led.ts @@ -1,6 +1,12 @@ import { Request, Response } from "express"; import { board } from "../setup"; +export interface ColorChannel { + r: string, + g: string, + b: string +} + export async function readLed (req: Request, res: Response) { const { p } = req.params; const pin = Number.parseInt(p); @@ -36,14 +42,14 @@ export async function writeLed (req: Request, res: Response) { switch (act) { case 'on': board.digitalWrite(pin, board.HIGH); - console.log(`${req.hostname} | ${pin} | ${act.toLocaleUpperCase()}`); + console.log(`${req.hostname} | ${pin} | LED: ${act.toLocaleUpperCase()}`); break; case 'off': board.digitalWrite(pin, board.LOW); - console.log(`${req.hostname} | ${pin} | ${act.toLocaleUpperCase()}`); + console.log(`${req.hostname} | ${pin} | LED: ${act.toLocaleUpperCase()}`); break; default: - console.log(`${req.hostname} | ${pin} | INVALID ACT`); + console.log(`${req.hostname} | ${pin} | LED: INVALID ACT`); } res.status(200).json({ diff --git a/src/index.ts b/src/index.ts index 811615c..2e1ad1b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,21 @@ +import http from 'node:http'; import express, { Request, Response } from 'express'; -import { board, comport } from './setup'; +import { Server } from 'socket.io'; +import chalk from 'chalk'; + +import { board, suBoard, comport } from './setup'; + import view from './routes/view'; import api from './routes/api'; const app = express(); +const server = http.createServer(app); +const io = new Server(server); // I have no experience at WebSocket, so.. forgive me :) const host = 'localhost'; const port = 3000; +app.use(express.json()); app.use(express.static('client')); app.use('/', view); @@ -16,9 +24,10 @@ app.use('/api-arduino', api); app.listen(port, host, () => { console.log(`Server is running in ${host} at port ${port} 🗣️🗣️🗣️`); console.log(`URL: http://${host}:${port}/\n`); - console.log("Connecting to Board"); + console.log(chalk.yellow(`Connecting to Board`)); board.on('ready', () => { - console.log(`Board at port ${comport} Connected!! \⁠(⁠^⁠o⁠^⁠)⁠/`); + console.log(chalk.green(`Board at port ${comport} Connected!! \⁠(⁠^⁠o⁠^⁠)⁠/`)); + suBoard.connected = true; }) }); \ No newline at end of file diff --git a/src/middleware/connection.ts b/src/middleware/connection.ts new file mode 100644 index 0000000..fca7275 --- /dev/null +++ b/src/middleware/connection.ts @@ -0,0 +1,14 @@ +import { NextFunction, Request, Response } from "express"; +import { suBoard } from "../setup"; + +export function isBoardConnected (req: Request, res: Response, next: NextFunction) { + if (suBoard.connected) { + next(); + } + else { + return res.status(500).json({ + status: 500, + message: "Internal server error: No Boards connected" + }) + } +} \ No newline at end of file diff --git a/src/routes/api.ts b/src/routes/api.ts index f35e2fa..7b30c61 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -1,14 +1,15 @@ import { Response } from "express"; import { Router } from "express"; import { readLed, writeLed } from "../controller/led"; +import { isBoardConnected } from "../middleware/connection"; const router = Router(); router.get('/hello', (req, res: Response) => { - res.send("Hello"); + res.status(200).send("Hello"); }) -router.get('/led/:p', readLed); -router.patch('/led/:p/:a', writeLed); +router.get('/led/:p', isBoardConnected, readLed); +router.patch('/led/:p/:a', isBoardConnected, writeLed); export default router; \ No newline at end of file diff --git a/src/setup/index.ts b/src/setup/index.ts index 62a597b..3b3c909 100644 --- a/src/setup/index.ts +++ b/src/setup/index.ts @@ -1,13 +1,16 @@ import Firmata from 'firmata'; -export const comport = '/dev/ttyUSB0'; -export const board = new Firmata(comport); +export const comport: string = '/dev/ttyUSB0'; +export const board: Firmata = new Firmata(comport); -export const PIN = { - servo: 0, - rgb_led: { - r: 10, - g: 9, - b: 8 +export const suBoard = { + connected: false, + PIN: { + servo: 0, + rgb_led: { + r: 10, + g: 9, + b: 8 + } } } \ No newline at end of file