diff --git a/README.md b/README.md index d59df07..d9ba100 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ A **SIMPLE** 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 make some IoT stuff. Enjoy (⁠づ⁠ ̄⁠ ⁠³⁠ ̄⁠)⁠づ +![ENA BBQ](https://media1.tenor.com/m/Nl2_tsGV-qkAAAAC/enadbbq-dreambbq.gif) + +*the animation is from ENA BBQ series by JoelG + ## Setup Tools that are required - Arduino Board @@ -9,7 +13,7 @@ Tools that are required - [Node.js](https://nodejs.org/en) v16.0.0^ or other javascript runtime ### Board -Arduino assembly guide also available in [johnny-five](https://github.com/rwaldron/johnny-five?tab=readme-ov-file#setup-and-assemble-arduino) documentation\ +Arduino assembly guide also available in [johnny-five](https://github.com/rwaldron/johnny-five?tab=readme-ov-file#setup-and-assemble-arduino) documentation 1. Plug in your Board via USB 2. Open Arduino IDE then select your Board 3. Go to `File > Examples > Firmata` Select `StandarFirmataPlus` @@ -61,8 +65,11 @@ Arduino assembly guide also available in [johnny-five](https://github.com/rwaldr - [Read pin mode](#read-pin-mode) - [Set pin mode](#set-pin-mode) - [LED](#led) - - [Read led state](#read-led-state) - - [Set led state](#set-led-state) + - [Read LED state](#read-led-state) + - [Set LED state](#set-led-state) +- [RGB LED](#rgb-led) + - [Read RGB state](#read-rgb-state) + - [Set RGB state](#set-rgb-state) ## Common HTTP Responses Some HTTP responses are sent with JSON, otherwise an HTML body will be sent which is the default express.js response @@ -82,7 +89,7 @@ Some HTTP responses are sent with JSON, otherwise an HTML body will be sent whic "pin_state": { "13": "HIGH" }, - "message": "Pin 13 Set to HIGH" + "message": "Changed pin state 13 to HIGH" } ``` | Property | Description | @@ -98,7 +105,7 @@ This is an example of javascript code sending a request to turn on the LED light async function turnOnLed() { const res = await fetch("http://localhost:3000/led/13/on"); // Set LED to HIGH const data = await res.json(); - console.log(data); + console.log(data); // { status: 200, pin_state: { 13: high }, message: "Pin 13 Set to HIGH" } } ``` @@ -168,7 +175,7 @@ async function turnOnLed() { ## LED -### Read led state +### Read LED state - **URL Endpoint** /led/:p/ @@ -195,17 +202,17 @@ async function turnOnLed() { } ``` -### Set led state +### Set LED state - **URL Endpoint** - /pin/:p/:a + /led/:p/:a - **URL Params** | Params | Mark | Type | Required | Description | |--------|------|------|----------|-------------| | p | pin | `string` | true | Seleced pin | - | a | act | `'on'`, `'off'` | true | Action | + | a | act | `'on'`, `'off'`, `'high'`, `'low'` | true | Action | - **Method(s)** @@ -219,7 +226,85 @@ async function turnOnLed() { "pin_state": { "13": "HIGH" }, - "message": "Led pin 13 setted HIGH" + "message": "Changed pin state 13 to HIGH" + } + ``` + + + +## RGB LED + +### Read RGB state +- **URL Endpoint** + + /rgb-led + +- **Body** + + ```javascript + { + r: number, + g: number, + b: number + } + ``` + +- **Method** + + `POST` + +- **Sample Response** + + ```json + { + "status": 200, + "pin_state": { + "7": true, + "6": true, + "5": false + } + } + ``` + +### Set RGB state +- **URL Endpoint** + + /rgb-led + +- **Body** + + ```javascript + { + r: { + pin: number, + value: boolean + }, + g: { + pin: number, + value: boolean + }, + b: { + pin: number, + value: boolean + } + } + ``` + +- **Method(s)** + + `PATCH` + +- **Sample Response** + + ```json + { + "status": 200, + "pin_state": { + "7": true, + "6": true, + "5": false + }, + "message": "Success changed pins 7, 6, 5 to state HIGH, HIGH, LOW" } ``` diff --git a/src/controller/led.ts b/src/controller/led.ts index 7c211e5..21044d8 100644 --- a/src/controller/led.ts +++ b/src/controller/led.ts @@ -9,13 +9,14 @@ export function readLed (req: Request, res: Response): Response { const { p } = req.params; const pin: number = Number.parseInt(p); - const pinState: digitalValue = board.pins[pin].value == 1 ? 'ON' : 'OFF'; + const pinState: voltage = board.pins[pin].value == 1 ? 'HIGH' : 'LOW'; return res.status(200).json({ status: 200, pin_state: { [pin]: pinState - } + }, + message: `Led pin ${pin} is ${pinState}` }); } catch (err) { @@ -32,20 +33,18 @@ export function writeLed (req: Request, res: Response): Response { const act: string = a.toLocaleLowerCase(); const pin: number = Number.parseInt(p); - let state: digitalValue; + let state: voltage; let volt: voltage; try { switch (act) { - case 'on': - state = 'ON'; + case 'on' || 'high': + state = 'HIGH'; volt = 1; - console.log(`${req.hostname} | ${pin} | LED: ${state}`); break; - case 'off': - state = 'OFF'; + case 'off' || 'low': + state = 'LOW'; volt = 0; - console.log(`${req.hostname} | ${pin} | LED: ${state}`); break; default: console.log(`${req.hostname} | ${pin} | LED: INVALID ACT`); @@ -54,12 +53,17 @@ export function writeLed (req: Request, res: Response): Response { message: `Invalid act ${act}` }); } - + board.digitalWrite(pin, volt); + + console.log(`${req.hostname} | ${pin} | LED: ${state}`); res.status(200).json({ status: 200, - message: `Success changed pin ${pin} to state ${state}` + pin_state: { + [pin]: state + }, + message: `Changed pin state ${pin} to ${state}` }); } catch (err) { @@ -147,19 +151,26 @@ export function writeRgbLed (req: Request, res: Response): Response c.pin.toString()).join(", "); const values: string = rgbLeds.map(c => `${c.value}`).join(", "); return res.status(200).json({ status: 200, + pin_state: { + [r.pin]: led.red.isOn, + [g.pin]: led.green.isOn, + [b.pin]: led.blue.isOn + }, message: `Success changed pins ${pins} to state ${values}` }); } diff --git a/src/controller/piezo.ts b/src/controller/piezo.ts index 9eaa93e..e077aa6 100644 --- a/src/controller/piezo.ts +++ b/src/controller/piezo.ts @@ -3,7 +3,32 @@ import { Piezo } from "johnny-five"; import { Pitch } from "../melodies"; export function piezoTone (req: Request, res: Response): Response { + const pin: number = Number.parseInt(req.params.p); + const frequency: number = Number.parseInt(req.params.f); + + const piezo: Piezo = new Piezo(pin); + + piezo.tone(frequency * 7.3, 100); + + return res.status(200).json({ + status: 200, + pin_tone: { + [pin]: frequency + }, + message: `Piezo ${pin} tone ${frequency}` + }); +} + +export function piezoNote (req: Request, res: Response): Response { const { pin, note }: { pin: number, note: string } = req.body; + const notePitch = Pitch[note.toUpperCase()]; + + if (notePitch == null) { + return res.status(400).json({ + status: 400, + message: `Invalid note ${note}` + }); + } const piezo: Piezo = new Piezo(pin); @@ -15,7 +40,13 @@ export function piezoTone (req: Request, res: Response): Response { return res.status(200).json({ status: 200, - message: `Piezo ${pin} tone ${note}` + pin_tone: { + [pin]: notePitch + }, + pin_note: { + [pin]: note.toUpperCase() + }, + message: `Piezo ${pin} tone note ${note}` }); } @@ -45,12 +76,17 @@ export function piezoPlayNotes (req: Request, res: Response): Response { }) .filter((note) => note[0].trim() != "-"); - const notesS: string = notes.join(", "); + const notesS: string = notes.length > 4 ? + notes.slice(0, 4).join(", ")+"..." : + notes.join(", "); piezo.play({ song, tempo }); return res.status(200).json({ status: 200, + pin_notes: { + [pin]: notes + }, message: `Piezo ${pin} play notes ${notesS}` }); } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 6f1555b..9a7d00c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -18,17 +18,22 @@ const io: Server = new Server(server, { } }); // I have no experience at WebSocket, so.. forgive me :) +// Server configuration const host: string = 'localhost'; const port: number = 3000; +// Express middleware app.use(express.json()); app.use(express.static('client')); +// Socket.io event handlers io.on('connection', socketHandler); +// HTTP Routes app.use('/', view); -app.use('/api-arduino', isBoardConnected, api); +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} 🗣️🗣️🗣️`); diff --git a/src/routes/api.ts b/src/routes/api.ts index 8751bb9..f4fe7c5 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -3,7 +3,7 @@ import { Router } from "express"; import { readLed, readRgbLed, writeLed, writeRgbLed } from "../controller/led"; import { readPin, setPin } from "../controller/pin"; -import { piezoNoTone, piezoPlayNotes, piezoTone } from "../controller/piezo"; +import { piezoNoTone, piezoNote, piezoPlayNotes, piezoTone } from "../controller/piezo"; import { rotateServo } from "../controller/servo"; import { readResistor } from "../controller/photoresistor"; @@ -11,22 +11,28 @@ import { isPinNumeric } from "../middleware/pin"; const router: Router = Router(); +// Client page router.get('/hello', (req, res: Response): Response => { return res.status(200).send("Hello"); }) +// PinMode router.get('/pin/:p', readPin); router.patch('/pin/:p/:m', setPin); +// LED router.get('/led/:p', isPinNumeric, readLed); router.patch('/led/:p/:a', isPinNumeric, writeLed); -router.get('/rgb-led', readRgbLed); +// RGB LED +router.post('/rgb-led', readRgbLed); router.patch('/rgb-led/', writeRgbLed); -router.patch('/piezo/', piezoTone); -router.patch('/piezo/stop/', piezoNoTone); +// Piezo +router.patch('/piezo/:p/:f', isPinNumeric, piezoTone); +router.patch('/piezo/note', piezoNote); router.patch('/piezo/music/', piezoPlayNotes); +router.patch('/piezo/stop/', piezoNoTone); // for real-time communication is deprecated and not recommended // use other protocol like websocket instead diff --git a/test/serial/piezo.ts b/test/serial/piezo.ts new file mode 100644 index 0000000..4c3bd10 --- /dev/null +++ b/test/serial/piezo.ts @@ -0,0 +1,24 @@ +import { Board, Piezo } from "johnny-five"; + +const board = new Board({ + port: '/dev/ttyUSB0', + repl: false +}); + +board.on('ready', () => { + const piezo = new Piezo(11); + + let ins = 0; + + board.loop(500, async () => { + piezo.play({ + song: "C4", + beats: 1/2, + tempo: 100 + }) + await new Promise(resolve => setTimeout(resolve, 100)); + piezo.note("C4", 100); + await new Promise(resolve => setTimeout(resolve, 100)); + piezo.tone(262 * 7.3, 100); + }) +}) \ No newline at end of file