Piezo buzzer, portlist and update documentation
This commit is contained in:
parent
71c4ec5072
commit
f90387bab9
27
README.md
27
README.md
@ -1,7 +1,28 @@
|
||||
# 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 (づ ̄ ³ ̄)づ
|
||||
A REST API based serial communication, assisted Firmata protocol and johnny-five API, enabling software communication with the Arduino board using the Server API., that's it. Idk about electronics and networking actually. But that piece of knowledge motivated me to interact it with other software. Enjoy (づ ̄ ³ ̄)づ
|
||||
|
||||
### Setup
|
||||
## Setup
|
||||
|
||||
- Install all packages with `npm i` or `yarn`
|
||||
### Board
|
||||
Arduino assembly guide also available in [johnny-five](https://github.com/rwaldron/johnny-five?tab=readme-ov-file#setup-and-assemble-arduino) documentation
|
||||
1. Download [Arduino IDE](https://www.arduino.cc/en/software)
|
||||
2. Plug in your Board via USB
|
||||
3. Open Arduino IDE then select your Board
|
||||
4. Go to `File > Examples > Firmata` Select `StandarFirmataPlus`
|
||||
5. Upload the sketch
|
||||
|
||||
### Server
|
||||
1. Clone project and Install
|
||||
```bash
|
||||
> git clone https://github.com/norman-andrians/lunar-vein-arduino.git && cd lunar-vein-arduino
|
||||
> npm i
|
||||
```
|
||||
2. Add `.env` file in the project root directory with the `SERIAL_PORT` variable
|
||||
```
|
||||
SERIAL_PORT=/dev/ttyUSB0
|
||||
```
|
||||
3. Run the project
|
||||
```bash
|
||||
> npm start
|
||||
```
|
59
package-lock.json
generated
59
package-lock.json
generated
@ -10,7 +10,9 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@serialport/bindings": "^9.2.9",
|
||||
"@serialport/list": "^12.0.0",
|
||||
"chalk": "^4.1.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"firmata": "^2.3.0",
|
||||
"johnny-five": "^2.1.0",
|
||||
@ -23,6 +25,7 @@
|
||||
"@types/firmata": "^0.19.8",
|
||||
"@types/johnny-five": "^2.1.9",
|
||||
"@types/nodemon": "^1.19.6",
|
||||
"@types/serialport": "^8.0.5",
|
||||
"@types/socket.io": "^3.0.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
@ -200,6 +203,24 @@
|
||||
"url": "https://opencollective.com/serialport/donate"
|
||||
}
|
||||
},
|
||||
"node_modules/@serialport/list": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@serialport/list/-/list-12.0.0.tgz",
|
||||
"integrity": "sha512-TyGSCbnBbdpjL93uYb3gyFINkux5q2Ksqz3yL5yqwS6RpORNDudD/x7BEvG1o7SNAwhbC6JZAaXq4WnE3fr9sg==",
|
||||
"dependencies": {
|
||||
"@serialport/bindings-cpp": "12.0.1",
|
||||
"commander": "11.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"serialport-list": "dist/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/serialport/donate"
|
||||
}
|
||||
},
|
||||
"node_modules/@serialport/parser-byte-length": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@serialport/parser-byte-length/-/parser-byte-length-12.0.0.tgz",
|
||||
@ -420,6 +441,16 @@
|
||||
"@types/serialport": "^4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/firmata/node_modules/@types/serialport": {
|
||||
"version": "4.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/serialport/-/serialport-4.0.16.tgz",
|
||||
"integrity": "sha512-JbeHlODoEPbKmo0Q1xv/EbawShWYyNZJEW5V8cuPRvRofwwC5VKzGbZZkk8MfIo5lkpmcJWhKzTGgQ1jVXUgjQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/streamjs": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-errors": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
||||
@ -481,13 +512,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/serialport": {
|
||||
"version": "4.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/serialport/-/serialport-4.0.16.tgz",
|
||||
"integrity": "sha512-JbeHlODoEPbKmo0Q1xv/EbawShWYyNZJEW5V8cuPRvRofwwC5VKzGbZZkk8MfIo5lkpmcJWhKzTGgQ1jVXUgjQ==",
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/serialport/-/serialport-8.0.5.tgz",
|
||||
"integrity": "sha512-Lw082WIy46fYLnOzyf+8QN/vZaR3d9ol9WNyEGHsKJJ1pmZogFbloHGbnXyNcxfV9aTbgviWU8jktrIjRheYFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/streamjs": "*"
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/serve-static": {
|
||||
@ -896,6 +926,14 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
|
||||
"integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@ -1053,6 +1091,17 @@
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.4.5",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
@ -12,7 +12,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@serialport/bindings": "^9.2.9",
|
||||
"@serialport/list": "^12.0.0",
|
||||
"chalk": "^4.1.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.3",
|
||||
"firmata": "^2.3.0",
|
||||
"johnny-five": "^2.1.0",
|
||||
@ -25,6 +27,7 @@
|
||||
"@types/firmata": "^0.19.8",
|
||||
"@types/johnny-five": "^2.1.9",
|
||||
"@types/nodemon": "^1.19.6",
|
||||
"@types/serialport": "^8.0.5",
|
||||
"@types/socket.io": "^3.0.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
|
28
src/controller/piezo.ts
Normal file
28
src/controller/piezo.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Request, Response } from "express";
|
||||
import { Piezo } from "johnny-five";
|
||||
import { Pitch } from "../melodies";
|
||||
|
||||
export function piezoTone (req: Request, res: Response) {
|
||||
const pin: number = Number.parseInt(req.params.p);
|
||||
const note: string = req.params.n;
|
||||
|
||||
if (Number.isNaN(pin)) {
|
||||
return res.status(400).json({
|
||||
status: 400,
|
||||
message: 'Invalid pin param, it should be integer'
|
||||
});
|
||||
}
|
||||
|
||||
const piezo = new Piezo(pin);
|
||||
|
||||
piezo.play({
|
||||
song: note.toUpperCase(),
|
||||
beats: 1/2,
|
||||
tempo: 100
|
||||
})
|
||||
|
||||
return res.status(200).json({
|
||||
status: 200,
|
||||
message: `Piezo ${pin} tone ${note}`
|
||||
});
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import http from 'node:http';
|
||||
import express, { Request, Response } from 'express';
|
||||
import express from 'express';
|
||||
import { Server } from 'socket.io';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@ -8,6 +8,7 @@ import { board, suBoard, comport } from './setup';
|
||||
import { isBoardConnected } from './middleware/connection';
|
||||
import view from './routes/view';
|
||||
import api from './routes/api';
|
||||
import { selectPort } from './ports';
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
@ -22,10 +23,11 @@ app.use(express.static('client'));
|
||||
app.use('/', view);
|
||||
app.use('/api-arduino', isBoardConnected, api);
|
||||
|
||||
console.log("\nRunning Server...");
|
||||
app.listen(port, host, () => {
|
||||
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(`* 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', () => {
|
||||
|
91
src/melodies/index.ts
Normal file
91
src/melodies/index.ts
Normal file
@ -0,0 +1,91 @@
|
||||
export const Pitch = {
|
||||
B0: 31,
|
||||
C1: 33,
|
||||
CS1: 35,
|
||||
D1: 37,
|
||||
DS1: 39,
|
||||
E1: 41,
|
||||
F1: 44,
|
||||
FS1: 46,
|
||||
G1: 49,
|
||||
GS1: 52,
|
||||
A1: 55,
|
||||
AS1: 58,
|
||||
B1: 62,
|
||||
C2: 65,
|
||||
CS2: 69,
|
||||
D2: 73,
|
||||
DS2: 78,
|
||||
E2: 82,
|
||||
F2: 87,
|
||||
FS2: 93,
|
||||
G2: 98,
|
||||
GS2: 104,
|
||||
A2: 110,
|
||||
AS2: 117,
|
||||
B2: 123,
|
||||
C3: 131,
|
||||
CS3: 139,
|
||||
D3: 147,
|
||||
DS3: 156,
|
||||
E3: 165,
|
||||
F3: 175,
|
||||
FS3: 185,
|
||||
G3: 196,
|
||||
GS3: 208,
|
||||
A3: 220,
|
||||
AS3: 233,
|
||||
B3: 247,
|
||||
C4: 262,
|
||||
CS4: 277,
|
||||
D4: 294,
|
||||
DS4: 311,
|
||||
E4: 330,
|
||||
F4: 349,
|
||||
FS4: 370,
|
||||
G4: 392,
|
||||
GS4: 415,
|
||||
A4: 440,
|
||||
AS4: 466,
|
||||
B4: 494,
|
||||
C5: 523,
|
||||
CS5: 554,
|
||||
D5: 587,
|
||||
DS5: 622,
|
||||
E5: 659,
|
||||
F5: 698,
|
||||
FS5: 740,
|
||||
G5: 784,
|
||||
GS5: 831,
|
||||
A5: 880,
|
||||
AS5: 932,
|
||||
B5: 988,
|
||||
C6: 1047,
|
||||
CS6: 1109,
|
||||
D6: 1175,
|
||||
DS6: 1245,
|
||||
E6: 1319,
|
||||
F6: 1397,
|
||||
FS6: 1480,
|
||||
G6: 1568,
|
||||
GS6: 1661,
|
||||
A6: 1760,
|
||||
AS6: 1865,
|
||||
B6: 1976,
|
||||
C7: 2093,
|
||||
CS7: 2217,
|
||||
D7: 2349,
|
||||
DS7: 2489,
|
||||
E7: 2637,
|
||||
F7: 2794,
|
||||
FS7: 2960,
|
||||
G7: 3136,
|
||||
GS7: 3322,
|
||||
A7: 3520,
|
||||
AS7: 3729,
|
||||
B7: 3951,
|
||||
C8: 4186,
|
||||
CS8: 4435,
|
||||
D8: 4699,
|
||||
DS8: 4978
|
||||
}
|
29
src/ports/index.ts
Normal file
29
src/ports/index.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import readline from 'node:readline/promises';
|
||||
import { ReadPorts } from "./read";
|
||||
import { board, suBoard } from '../setup';
|
||||
|
||||
export async function selectPort (cb: () => void) {
|
||||
const ports = await ReadPorts();
|
||||
|
||||
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}`);
|
||||
})
|
||||
|
||||
const selectedInput: string = await line.question("Enter number: ");
|
||||
const selectedNumber: number = Number.parseInt(selectedInput);
|
||||
const selectedPort: string = ports[selectedNumber-1];
|
||||
|
||||
suBoard.port = selectedPort;
|
||||
board.port = selectedPort;
|
||||
|
||||
console.log(`Selected port: ${selectedPort}`);
|
||||
line.close();
|
||||
|
||||
cb();
|
||||
}
|
8
src/ports/read.ts
Normal file
8
src/ports/read.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import * as SerialPort from 'serialport';
|
||||
|
||||
export async function ReadPorts (): Promise<string[]> {
|
||||
const ports = await SerialPort.SerialPort.list();
|
||||
return ports
|
||||
.filter(port => port.pnpId != null)
|
||||
.map(port => port.path)
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
import { Response } from "express";
|
||||
import { Router } from "express";
|
||||
|
||||
import { readLed, readRgbLed, writeLed, writeRgbLed } from "../controller/led";
|
||||
import { readPin, setPin } from "../controller/pin";
|
||||
import { piezoTone } from "../controller/piezo";
|
||||
|
||||
const router = Router();
|
||||
const router: Router = Router();
|
||||
|
||||
router.get('/hello', (req, res: Response) => {
|
||||
res.status(200).send("Hello");
|
||||
router.get('/hello', (req, res: Response): Response<string> => {
|
||||
return res.status(200).send("Hello");
|
||||
})
|
||||
|
||||
router.get('/pin/:p', readPin);
|
||||
@ -18,4 +20,6 @@ router.patch('/led/:p/:a', writeLed);
|
||||
router.get('/rgb-led', readRgbLed);
|
||||
router.patch('/rgb-led/', writeRgbLed);
|
||||
|
||||
router.patch('/piezo/:p/:n', piezoTone);
|
||||
|
||||
export default router;
|
@ -1,11 +1,14 @@
|
||||
import { SuBoard } from './support';
|
||||
import { Board } from 'johnny-five';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
export const comport: string = '/dev/ttyUSB0';
|
||||
export const board: Board = new Board({
|
||||
config();
|
||||
|
||||
export const comport: string = process.env.SERIAL_PORT || '/dev/ttyUSB0';
|
||||
export const suBoard: SuBoard = new SuBoard();
|
||||
|
||||
export const board: Board | null = new Board({
|
||||
port: comport,
|
||||
repl: false,
|
||||
debug: false
|
||||
});
|
||||
|
||||
export const suBoard: SuBoard = new SuBoard();
|
@ -1,4 +1,5 @@
|
||||
export interface SupportBoard {
|
||||
port: string | null,
|
||||
connected: boolean,
|
||||
PINS: {
|
||||
pwm: number[],
|
||||
@ -8,6 +9,7 @@ export interface SupportBoard {
|
||||
}
|
||||
|
||||
export class SuBoard implements SupportBoard {
|
||||
public port = null;
|
||||
public connected = false;
|
||||
public PINS = {
|
||||
pwm: [],
|
||||
|
Loading…
x
Reference in New Issue
Block a user