From ca72e479f3cc7d1642cece653ed9205c68c0abe2 Mon Sep 17 00:00:00 2001 From: norman-andrians Date: Sun, 3 Mar 2024 11:52:41 +0700 Subject: [PATCH] resetup led --- README.md | 2 +- src/controller/index.d.ts | 15 ++++ src/controller/led.ts | 120 +++++++++++++++++++++++++---- src/controller/pin.ts | 46 +++++++++++ src/index.ts | 6 +- src/middleware/pin.ts | 22 ++++++ src/promises/index.js | 9 --- src/promises/index.ts | 23 ++++++ src/routes/api.ts | 14 +++- src/setup/index.ts | 15 +--- src/setup/support.ts | 20 +++++ test/serial/analogReadDigital.ts | 17 ++++ {src/test => test/serial}/blink.js | 0 test/serial/monitoringAllPins.ts | 18 +++++ {src/test => test/serial}/read.js | 0 test/serial/readResistor.ts | 11 +++ test/serial/servo.ts | 0 tsconfig.json | 2 +- 18 files changed, 296 insertions(+), 44 deletions(-) create mode 100644 src/controller/index.d.ts create mode 100644 src/controller/pin.ts create mode 100644 src/middleware/pin.ts delete mode 100644 src/promises/index.js create mode 100644 src/promises/index.ts create mode 100644 src/setup/support.ts create mode 100644 test/serial/analogReadDigital.ts rename {src/test => test/serial}/blink.js (100%) create mode 100644 test/serial/monitoringAllPins.ts rename {src/test => test/serial}/read.js (100%) create mode 100644 test/serial/readResistor.ts create mode 100644 test/serial/servo.ts diff --git a/README.md b/README.md index 4d7011a..340ce36 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Lunar Vein Arduino +# Lunar Vein: Arduino An API server and client to communicate with Arduino boards, that's it. Idk about electronics and networking actually. But that piece of knowledge motivated me to interact it with other software. Enjoy (⁠づ⁠ ̄⁠ ⁠³⁠ ̄⁠)⁠づ diff --git a/src/controller/index.d.ts b/src/controller/index.d.ts new file mode 100644 index 0000000..353a8a1 --- /dev/null +++ b/src/controller/index.d.ts @@ -0,0 +1,15 @@ + +export type digitalValue = 'ON' | 'OFF'; +export type voltage = 'HIGH' | 'LOW'; +export type sPinModes = 'INPUT' | 'OUTPUT' | 'ANALOG' | 'PWM' | 'SERVO' |'SHIFT' |'I2C' |'ONEWIRE' |'STEPPER' |'SERIAL' |'PULLUP' |'IGNORE' |'PING_READ' | 'UNKOWN'; + +export interface ChannelPins { + pin: number, + value: digitalValue +} + +export interface ColorChannel { + r: string, + g: string, + b: string +} \ No newline at end of file diff --git a/src/controller/led.ts b/src/controller/led.ts index 89bf24e..b78cb9e 100644 --- a/src/controller/led.ts +++ b/src/controller/led.ts @@ -1,15 +1,12 @@ import { Request, Response } from "express"; import { board } from "../setup"; +import { ChannelPins, digitalValue, voltage } from "."; +import { digitalRead } from "../promises"; -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); + const pin: number = Number.parseInt(p); if (Number.isNaN(pin)) { return res.status(400).json({ @@ -18,18 +15,23 @@ export async function readLed (req: Request, res: Response) { }); } - const pinState = board.pins[pin].value == 1 ? 'ON' : 'OFF'; + const pinState: digitalValue = board.pins[pin].value == 1 ? 'ON' : 'OFF'; return res.status(200).json({ status: 200, - message: `Pin ${pin} state ${pinState}` + pin_state: { + [pin]: pinState + } }); } export async function writeLed (req: Request, res: Response) { const { p, a } = req.params; - const act = a.toLocaleLowerCase(); - const pin = Number.parseInt(p); + const act: string = a.toLocaleLowerCase(); + const pin: number = Number.parseInt(p); + + let state: digitalValue; + let volt: voltage; try { if (Number.isNaN(pin)) { @@ -41,20 +43,108 @@ export async function writeLed (req: Request, res: Response) { switch (act) { case 'on': - board.digitalWrite(pin, board.HIGH); - console.log(`${req.hostname} | ${pin} | LED: ${act.toLocaleUpperCase()}`); + state = 'ON'; + volt = 'HIGH'; + console.log(`${req.hostname} | ${pin} | LED: ${state}`); break; case 'off': - board.digitalWrite(pin, board.LOW); - console.log(`${req.hostname} | ${pin} | LED: ${act.toLocaleUpperCase()}`); + state = 'OFF'; + volt = 'LOW'; + console.log(`${req.hostname} | ${pin} | LED: ${state}`); break; default: console.log(`${req.hostname} | ${pin} | LED: INVALID ACT`); + return res.status(400).json({ + status: 400, + message: `Invalid act ${act}` + }); } + board.digitalWrite(pin, board[volt]); + res.status(200).json({ status: 200, - message: `Success changed pin ${pin} to state ${act}` + message: `Success changed pin ${pin} to state ${state}` + }); + } + catch (err) { + console.error(err); + res.status(500).json({ + status: 500, + message: "Internal Server Error" + }); + } +}; + + +export async function readRgbLed (req: Request, res: Response) { + const r: number = Number.parseInt(req.body.r); + const g: number = Number.parseInt(req.body.b); + const b: number = Number.parseInt(req.body.b); + + const rgbPins: number[] = Object.values({ r, g, b }); + const pinStates: number[] = []; + + for (let i = 0; i < rgbPins.length; i++) { + const pin = rgbPins[i]; + + if (Number.isNaN(pin)) { + return res.status(400).json({ + status: 400, + message: `Invalid pin ${pin} param, it should be integer` + }); + } + + const state: number = await digitalRead(board, pin); + pinStates.push(state); + } + + return res.status(200).json({ + status: 200, + pin_state: { + [r]: pinStates[0], + [g]: pinStates[1], + [b]: pinStates[2] + } + }); +} + +export async function writeRgbLed (req: Request, res: Response) { + const r: ChannelPins = req.body.r; + const g: ChannelPins = req.body.b; + const b: ChannelPins = req.body.b; + + const rgbLeds: ChannelPins[] = Object.values({ r, g, b }); + + try { + rgbLeds.forEach((led, i) => { + if (Number.isNaN(led.pin)) { + return res.status(400).json({ + status: 400, + message: `Invalid pin ${led.pin} param, it should be integer` + }); + } + + switch (led.value) { + case 'ON': + board.analogWrite(led.pin, board.HIGH); + console.log(`${req.hostname} | ${led.pin} | LED: ${led.value}`); + break; + case 'OFF': + board.analogWrite(led.pin, board.LOW); + console.log(`${req.hostname} | ${led.pin} | LED: ${led.value}`); + break; + default: + console.log(`${req.hostname} | ${led.pin} | LED: INVALID VALUE`); + } + }) + + const pins: string[] = rgbLeds.map(c => `${c.pin}, `); + const values: string[] = rgbLeds.map(c => `${c.value}, `); + + res.status(200).json({ + status: 200, + message: `Success changed pins ${pins} to state ${values}` }); } catch (err) { diff --git a/src/controller/pin.ts b/src/controller/pin.ts new file mode 100644 index 0000000..6463bca --- /dev/null +++ b/src/controller/pin.ts @@ -0,0 +1,46 @@ +import { Request, Response } from "express"; +import { board, suBoard } from "../setup"; +import { sPinModes } from "."; + +export function readPin (req: Request, res: Response) { + const pin: number = Number.parseInt(req.params.p); + + if (Number.isNaN(pin)) { + return res.status(400).json({ + status: 400, + message: 'Invalid pin param, it should be integer' + }); + } + + const { mode } = board.pins[pin]; + + return res.status(200).json({ + status: 200, + state: { + used: true + }, + message: `Pin ${pin} is ${mode}` + }); +} + +export function setPin (req: Request, res: Response) { + const pin: number = Number.parseInt(req.params.p); + const mode: sPinModes | string = req.params.m.toUpperCase(); + + if (Number.isNaN(pin)) { + return res.status(400).json({ + status: 400, + message: 'Invalid pin param, it should be integer' + }); + } + + board.pinMode(pin, board.MODES[mode]); + + suBoard.PINS.pwm.push(pin); + suBoard.sort(); + + return res.status(200).json({ + status: 200, + message: `Pin ${pin} setted as ${mode}` + }); +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2e1ad1b..58f1a02 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import chalk from 'chalk'; import { board, suBoard, comport } from './setup'; +import { isBoardConnected } from './middleware/connection'; import view from './routes/view'; import api from './routes/api'; @@ -19,10 +20,11 @@ app.use(express.json()); app.use(express.static('client')); app.use('/', view); -app.use('/api-arduino', api); +app.use('/api-arduino', isBoardConnected, api); app.listen(port, host, () => { - console.log(`Server is running in ${host} at port ${port} 🗣️🗣️🗣️`); + console.log(`Server is connected and running in ${host} at port ${port} 🗣️🗣️🗣️`); + console.log(`Press CTRL+C to exit`); console.log(`URL: http://${host}:${port}/\n`); console.log(chalk.yellow(`Connecting to Board`)); diff --git a/src/middleware/pin.ts b/src/middleware/pin.ts new file mode 100644 index 0000000..cfbb3bb --- /dev/null +++ b/src/middleware/pin.ts @@ -0,0 +1,22 @@ +import { NextFunction, Request, Response } from "express"; +import { suBoard } from "../setup"; + +export function isPinBeingUsed(req: Request, res: Response, next: NextFunction) { + const pin: number = Number.parseInt(req.params.p); + + if (Number.isNaN(pin)) { + return res.status(400).json({ + status: 400, + message: 'Invalid pin param, it should be integer' + }); + } + + if (suBoard.PINS.pwm.indexOf(pin) != -1) { + return res.status(400).json({ + status: 400, + message: `Pin ${pin}, is used` + }); + } + + next(); +} \ No newline at end of file diff --git a/src/promises/index.js b/src/promises/index.js deleted file mode 100644 index 868247f..0000000 --- a/src/promises/index.js +++ /dev/null @@ -1,9 +0,0 @@ -function digitalRead (board, pin) { - return new Promise((resolve, reject) => { - board.digitalRead(pin, (val) => { - resolve(val); - }); - }); -} - -module.exports = { digitalRead }; \ No newline at end of file diff --git a/src/promises/index.ts b/src/promises/index.ts new file mode 100644 index 0000000..643edc5 --- /dev/null +++ b/src/promises/index.ts @@ -0,0 +1,23 @@ +import Board, { PIN_MODE } from "firmata"; + +export function digitalRead (board: Board, pin: number): Promise { + return new Promise((resolve, reject) => { + board.digitalRead(pin, (val) => { + resolve(val); + }); + setTimeout(() => { + reject(new Error("Reading digital timeout")); + }, 5000); + }); +} + +export function analogRead (board: Board, pin: number): Promise { + return new Promise((resolve, reject) => { + board.analogRead(pin, (val) => { + resolve(val); + }) + setTimeout(() => { + reject(new Error("Reading analog timeout")); + }, 5000); + }) +} \ No newline at end of file diff --git a/src/routes/api.ts b/src/routes/api.ts index 7b30c61..8b113c9 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -1,7 +1,7 @@ import { Response } from "express"; import { Router } from "express"; -import { readLed, writeLed } from "../controller/led"; -import { isBoardConnected } from "../middleware/connection"; +import { readLed, readRgbLed, writeLed, writeRgbLed } from "../controller/led"; +import { readPin, setPin } from "../controller/pin"; const router = Router(); @@ -9,7 +9,13 @@ router.get('/hello', (req, res: Response) => { res.status(200).send("Hello"); }) -router.get('/led/:p', isBoardConnected, readLed); -router.patch('/led/:p/:a', isBoardConnected, writeLed); +router.get('/pin/:p', readPin); +router.patch('/pin/:p/:m', setPin); + +router.get('/led/:p', readLed); +router.patch('/led/:p/:a', writeLed); + +router.get('/rgb-led', readRgbLed); +router.patch('/rgb-led/', writeRgbLed); export default router; \ No newline at end of file diff --git a/src/setup/index.ts b/src/setup/index.ts index 3b3c909..c8001ad 100644 --- a/src/setup/index.ts +++ b/src/setup/index.ts @@ -1,16 +1,7 @@ import Firmata from 'firmata'; +import { SuBoard } from './support'; -export const comport: string = '/dev/ttyUSB0'; +export const comport: string = '/dev/ttyUSB1'; export const board: Firmata = new Firmata(comport); -export const suBoard = { - connected: false, - PIN: { - servo: 0, - rgb_led: { - r: 10, - g: 9, - b: 8 - } - } -} \ No newline at end of file +export const suBoard: SuBoard = new SuBoard(); \ No newline at end of file diff --git a/src/setup/support.ts b/src/setup/support.ts new file mode 100644 index 0000000..10ea7ef --- /dev/null +++ b/src/setup/support.ts @@ -0,0 +1,20 @@ +export interface SupportBoard { + connected: boolean, + PINS: { + pwm: number[], + analog: number[], + } + sort: () => void +} + +export class SuBoard implements SupportBoard { + public connected = false; + public PINS = { + pwm: [], + analog: [] + }; + public sort() { + this.PINS.pwm = this.PINS.pwm.sort((a, b) => b - a); + this.PINS.analog = this.PINS.analog.sort((a, b) => b - a); + } +} \ No newline at end of file diff --git a/test/serial/analogReadDigital.ts b/test/serial/analogReadDigital.ts new file mode 100644 index 0000000..a602a23 --- /dev/null +++ b/test/serial/analogReadDigital.ts @@ -0,0 +1,17 @@ +import Firmata, { PIN_MODE, PIN_STATE } from 'firmata'; + +const board = new Firmata('/dev/ttyUSB2'); + +board.on('ready', async () => { + // board.analogWrite(0, 255); + // board.analogWrite(1, 255); + // board.analogWrite(2, 255); + + board.analogRead(0, (val) => { + console.log(val); + }) + + while (true) { + await new Promise (resolve => setTimeout(resolve, 90)); + } +}) \ No newline at end of file diff --git a/src/test/blink.js b/test/serial/blink.js similarity index 100% rename from src/test/blink.js rename to test/serial/blink.js diff --git a/test/serial/monitoringAllPins.ts b/test/serial/monitoringAllPins.ts new file mode 100644 index 0000000..6c66119 --- /dev/null +++ b/test/serial/monitoringAllPins.ts @@ -0,0 +1,18 @@ +import Firmata from 'firmata'; + +const board = new Firmata('/dev/ttyUSB2'); + +board.on('ready', async () => { + board.analogRead(2, (val) => { + console.log(board.analogPins[2]); + const output = board.pins.map((p, i) => { + return `Pin ${i}: ${p.value}` + }).join(", "); + + console.log(output); + }) + + while (true) { + await new Promise(resolve => setTimeout(resolve, 200)); + } +}) \ No newline at end of file diff --git a/src/test/read.js b/test/serial/read.js similarity index 100% rename from src/test/read.js rename to test/serial/read.js diff --git a/test/serial/readResistor.ts b/test/serial/readResistor.ts new file mode 100644 index 0000000..4a4e5ef --- /dev/null +++ b/test/serial/readResistor.ts @@ -0,0 +1,11 @@ +import Firmata from 'firmata'; + +const board = new Firmata('/dev/ttyUSB1'); + +board.on('ready', () => { + board.pinMode(0, Firmata.PIN_MODE.INPUT); + + board.analogRead(0, (val) => { + console.log(val); + }) +}) \ No newline at end of file diff --git a/test/serial/servo.ts b/test/serial/servo.ts new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index b158ae8..d577cf1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,5 +6,5 @@ "sourceMap": false, "outDir": "dist" }, - "include": ["src/**/*"] + "include": ["src/**/*", "test/**/*"] } \ No newline at end of file