Refact json response and fixed piezo tone
This commit is contained in:
parent
76e9ae14e5
commit
e064e198a3
105
README.md
105
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 (づ ̄ ³ ̄)づ
|
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 (づ ̄ ³ ̄)づ
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<small>*the animation is from ENA BBQ series by JoelG</small>
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
Tools that are required
|
Tools that are required
|
||||||
- Arduino Board
|
- Arduino Board
|
||||||
@ -9,7 +13,7 @@ Tools that are required
|
|||||||
- [Node.js](https://nodejs.org/en) v16.0.0^ or other javascript runtime
|
- [Node.js](https://nodejs.org/en) v16.0.0^ or other javascript runtime
|
||||||
|
|
||||||
### Board
|
### 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
|
1. Plug in your Board via USB
|
||||||
2. Open Arduino IDE then select your Board
|
2. Open Arduino IDE then select your Board
|
||||||
3. Go to `File > Examples > Firmata` Select `StandarFirmataPlus`
|
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)
|
- [Read pin mode](#read-pin-mode)
|
||||||
- [Set pin mode](#set-pin-mode)
|
- [Set pin mode](#set-pin-mode)
|
||||||
- [LED](#led)
|
- [LED](#led)
|
||||||
- [Read led state](#read-led-state)
|
- [Read LED state](#read-led-state)
|
||||||
- [Set led state](#set-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
|
## Common HTTP Responses
|
||||||
Some HTTP responses are sent with JSON, otherwise an HTML body will be sent which is the default express.js response
|
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": {
|
"pin_state": {
|
||||||
"13": "HIGH"
|
"13": "HIGH"
|
||||||
},
|
},
|
||||||
"message": "Pin 13 Set to HIGH"
|
"message": "Changed pin state 13 to HIGH"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
| Property | Description |
|
| 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() {
|
async function turnOnLed() {
|
||||||
const res = await fetch("http://localhost:3000/led/13/on"); // Set LED to HIGH
|
const res = await fetch("http://localhost:3000/led/13/on"); // Set LED to HIGH
|
||||||
const data = await res.json();
|
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
|
## LED
|
||||||
|
|
||||||
### Read led state
|
### Read LED state
|
||||||
- **URL Endpoint**
|
- **URL Endpoint**
|
||||||
|
|
||||||
/led/:p/
|
/led/:p/
|
||||||
@ -195,17 +202,17 @@ async function turnOnLed() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Set led state
|
### Set LED state
|
||||||
- **URL Endpoint**
|
- **URL Endpoint**
|
||||||
|
|
||||||
/pin/:p/:a
|
/led/:p/:a
|
||||||
|
|
||||||
- **URL Params**
|
- **URL Params**
|
||||||
|
|
||||||
| Params | Mark | Type | Required | Description |
|
| Params | Mark | Type | Required | Description |
|
||||||
|--------|------|------|----------|-------------|
|
|--------|------|------|----------|-------------|
|
||||||
| p | pin | `string` | true | Seleced pin |
|
| p | pin | `string` | true | Seleced pin |
|
||||||
| a | act | `'on'`, `'off'` | true | Action |
|
| a | act | `'on'`, `'off'`, `'high'`, `'low'` | true | Action |
|
||||||
|
|
||||||
- **Method(s)**
|
- **Method(s)**
|
||||||
|
|
||||||
@ -219,7 +226,85 @@ async function turnOnLed() {
|
|||||||
"pin_state": {
|
"pin_state": {
|
||||||
"13": "HIGH"
|
"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"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -9,13 +9,14 @@ export function readLed (req: Request, res: Response): Response<string | any> {
|
|||||||
const { p } = req.params;
|
const { p } = req.params;
|
||||||
const pin: number = Number.parseInt(p);
|
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({
|
return res.status(200).json({
|
||||||
status: 200,
|
status: 200,
|
||||||
pin_state: {
|
pin_state: {
|
||||||
[pin]: pinState
|
[pin]: pinState
|
||||||
}
|
},
|
||||||
|
message: `Led pin ${pin} is ${pinState}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
@ -32,20 +33,18 @@ export function writeLed (req: Request, res: Response): Response<string | any> {
|
|||||||
const act: string = a.toLocaleLowerCase();
|
const act: string = a.toLocaleLowerCase();
|
||||||
const pin: number = Number.parseInt(p);
|
const pin: number = Number.parseInt(p);
|
||||||
|
|
||||||
let state: digitalValue;
|
let state: voltage;
|
||||||
let volt: voltage;
|
let volt: voltage;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (act) {
|
switch (act) {
|
||||||
case 'on':
|
case 'on' || 'high':
|
||||||
state = 'ON';
|
state = 'HIGH';
|
||||||
volt = 1;
|
volt = 1;
|
||||||
console.log(`${req.hostname} | ${pin} | LED: ${state}`);
|
|
||||||
break;
|
break;
|
||||||
case 'off':
|
case 'off' || 'low':
|
||||||
state = 'OFF';
|
state = 'LOW';
|
||||||
volt = 0;
|
volt = 0;
|
||||||
console.log(`${req.hostname} | ${pin} | LED: ${state}`);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log(`${req.hostname} | ${pin} | LED: INVALID ACT`);
|
console.log(`${req.hostname} | ${pin} | LED: INVALID ACT`);
|
||||||
@ -57,9 +56,14 @@ export function writeLed (req: Request, res: Response): Response<string | any> {
|
|||||||
|
|
||||||
board.digitalWrite(pin, volt);
|
board.digitalWrite(pin, volt);
|
||||||
|
|
||||||
|
console.log(`${req.hostname} | ${pin} | LED: ${state}`);
|
||||||
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
status: 200,
|
status: 200,
|
||||||
message: `Success changed pin ${pin} to state ${state}`
|
pin_state: {
|
||||||
|
[pin]: state
|
||||||
|
},
|
||||||
|
message: `Changed pin state ${pin} to ${state}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
@ -147,19 +151,26 @@ export function writeRgbLed (req: Request, res: Response): Response<string | any
|
|||||||
isAnode: true
|
isAnode: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isHigh: boolean | string = true || 'HIGH' || 'high';
|
||||||
|
|
||||||
led.red = new Led(r.pin);
|
led.red = new Led(r.pin);
|
||||||
led.green = new Led(g.pin);
|
led.green = new Led(g.pin);
|
||||||
led.blue = new Led(b.pin);
|
led.blue = new Led(b.pin);
|
||||||
|
|
||||||
if (r.value == true) led.red.on(); else led.red.off();
|
if (r.value == isHigh) led.red.on(); else led.red.off();
|
||||||
if (g.value == true) led.green.on(); else led.green.off();
|
if (g.value == isHigh) led.green.on(); else led.green.off();
|
||||||
if (b.value == true) led.blue.on(); else led.blue.off();
|
if (b.value == isHigh) led.blue.on(); else led.blue.off();
|
||||||
|
|
||||||
const pins: string = rgbLeds.map(c => c.pin.toString()).join(", ");
|
const pins: string = rgbLeds.map(c => c.pin.toString()).join(", ");
|
||||||
const values: string = rgbLeds.map(c => `${c.value}`).join(", ");
|
const values: string = rgbLeds.map(c => `${c.value}`).join(", ");
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: 200,
|
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}`
|
message: `Success changed pins ${pins} to state ${values}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,32 @@ import { Piezo } from "johnny-five";
|
|||||||
import { Pitch } from "../melodies";
|
import { Pitch } from "../melodies";
|
||||||
|
|
||||||
export function piezoTone (req: Request, res: Response): Response {
|
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 { 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);
|
const piezo: Piezo = new Piezo(pin);
|
||||||
|
|
||||||
@ -15,7 +40,13 @@ export function piezoTone (req: Request, res: Response): Response {
|
|||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: 200,
|
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() != "-");
|
.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 });
|
piezo.play({ song, tempo });
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: 200,
|
status: 200,
|
||||||
|
pin_notes: {
|
||||||
|
[pin]: notes
|
||||||
|
},
|
||||||
message: `Piezo ${pin} play notes ${notesS}`
|
message: `Piezo ${pin} play notes ${notesS}`
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -18,17 +18,22 @@ const io: Server = new Server(server, {
|
|||||||
}
|
}
|
||||||
}); // I have no experience at WebSocket, so.. forgive me :)
|
}); // I have no experience at WebSocket, so.. forgive me :)
|
||||||
|
|
||||||
|
// Server configuration
|
||||||
const host: string = 'localhost';
|
const host: string = 'localhost';
|
||||||
const port: number = 3000;
|
const port: number = 3000;
|
||||||
|
|
||||||
|
// Express middleware
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.static('client'));
|
app.use(express.static('client'));
|
||||||
|
|
||||||
|
// Socket.io event handlers
|
||||||
io.on('connection', socketHandler);
|
io.on('connection', socketHandler);
|
||||||
|
|
||||||
|
// HTTP Routes
|
||||||
app.use('/', view);
|
app.use('/', view);
|
||||||
app.use('/api-arduino', isBoardConnected, api);
|
app.use('/api-arduino', isBoardConnected, api); // Board API Controllers
|
||||||
|
|
||||||
|
// Run server
|
||||||
console.log("\nRunning Server...");
|
console.log("\nRunning Server...");
|
||||||
server.listen(port, () => {
|
server.listen(port, () => {
|
||||||
console.log(`Server is connected and running in ${host} at port ${port} 🗣️🗣️🗣️`);
|
console.log(`Server is connected and running in ${host} at port ${port} 🗣️🗣️🗣️`);
|
||||||
|
@ -3,7 +3,7 @@ import { Router } from "express";
|
|||||||
|
|
||||||
import { readLed, readRgbLed, writeLed, writeRgbLed } from "../controller/led";
|
import { readLed, readRgbLed, writeLed, writeRgbLed } from "../controller/led";
|
||||||
import { readPin, setPin } from "../controller/pin";
|
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 { rotateServo } from "../controller/servo";
|
||||||
import { readResistor } from "../controller/photoresistor";
|
import { readResistor } from "../controller/photoresistor";
|
||||||
|
|
||||||
@ -11,22 +11,28 @@ import { isPinNumeric } from "../middleware/pin";
|
|||||||
|
|
||||||
const router: Router = Router();
|
const router: Router = Router();
|
||||||
|
|
||||||
|
// Client page
|
||||||
router.get('/hello', (req, res: Response): Response<string> => {
|
router.get('/hello', (req, res: Response): Response<string> => {
|
||||||
return res.status(200).send("Hello");
|
return res.status(200).send("Hello");
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// PinMode
|
||||||
router.get('/pin/:p', readPin);
|
router.get('/pin/:p', readPin);
|
||||||
router.patch('/pin/:p/:m', setPin);
|
router.patch('/pin/:p/:m', setPin);
|
||||||
|
|
||||||
|
// LED
|
||||||
router.get('/led/:p', isPinNumeric, readLed);
|
router.get('/led/:p', isPinNumeric, readLed);
|
||||||
router.patch('/led/:p/:a', isPinNumeric, writeLed);
|
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('/rgb-led/', writeRgbLed);
|
||||||
|
|
||||||
router.patch('/piezo/', piezoTone);
|
// Piezo
|
||||||
router.patch('/piezo/stop/', piezoNoTone);
|
router.patch('/piezo/:p/:f', isPinNumeric, piezoTone);
|
||||||
|
router.patch('/piezo/note', piezoNote);
|
||||||
router.patch('/piezo/music/', piezoPlayNotes);
|
router.patch('/piezo/music/', piezoPlayNotes);
|
||||||
|
router.patch('/piezo/stop/', piezoNoTone);
|
||||||
|
|
||||||
// for real-time communication is deprecated and not recommended
|
// for real-time communication is deprecated and not recommended
|
||||||
// use other protocol like websocket instead
|
// use other protocol like websocket instead
|
||||||
|
24
test/serial/piezo.ts
Normal file
24
test/serial/piezo.ts
Normal file
@ -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);
|
||||||
|
})
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user