Skip to content

Commit b1d65da

Browse files
committed
have yourself a Matrix LED Christmas!
0 parents  commit b1d65da

23 files changed

+8123
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
.idea
3+
node_modules
4+
typings
5+
coverage
6+
/node_modules

README.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
Christmas Jumper API
2+
=================
3+
4+
In this repository is a node app for running audio recognition and an API for returning festive themed iconography. There's also an arudino sketch, that powers an AdaFruit Feather Huzzah that will display the images on strips of NeoPixels.
5+
6+
## Contents
7+
8+
* Quickstart
9+
10+
Web
11+
12+
* Configuration
13+
** AudD
14+
** Azure
15+
* Running
16+
* Testing
17+
* Usage
18+
19+
Hardware
20+
21+
* Hardware Requirements
22+
* Configuration
23+
24+
## Quickstart
25+
26+
If you're familiar with running AdaFruit or Arduino code, and node applications - do the following:
27+
28+
* Edit config.js to contain valid AudD API keys and Azure storage bucket keys
29+
* Edit arduino.ino setting your Wifi SSID and password
30+
* Edit arduino.ino to provide the URL and port you'll use to run the node app in server.js
31+
* NPM start / host the app on something (Azure, Heroku, etc)
32+
* Upload Arduino sketch to hardware with your settings embedded.
33+
34+
Web
35+
===
36+
37+
## Configuration
38+
39+
You're going to need some API keys for this sample to work.
40+
41+
### AudD
42+
43+
* AudD API key - Get one from (the Telegram bot) at: https://audd.io/
44+
* You'll need to use telegram on your mobile device to get a working key, but the process is nice and easy, don't panic!
45+
46+
### Azure
47+
48+
You'll need to create a storage account, container, and grab the associated API key.
49+
50+
* Create an Azure account - signup here - https://azure.microsoft.com/en-gb/services/storage/blobs/
51+
* Create a storage account - https://portal.azure.com/#blade/HubsExtension/BrowseResource/resourceType/Microsoft.Storage%2FStorageAccounts
52+
* Create a storage container for the app
53+
* On the storage container, change the access level to "Blob (anonymous read access for blobs only)"
54+
* Grab your API key and account information.
55+
56+
> Home > Storage Accounts > YOUR STORAGE ACCOUNT - Access Keys
57+
58+
You'll see some information there you need:
59+
* Storage Account Name
60+
* Key 1
61+
* Connection String
62+
* Key 2
63+
* Connection String
64+
65+
You just need to grab the account name, and one of the keys.
66+
67+
### Using your API keys
68+
69+
* Open the file config.js
70+
71+
Fill in:
72+
* The name of your azure storage-account (e.g. "jumperstorageaccount") into azure-account
73+
* The azure storage container name into "azure-containerName"
74+
* The full URL of your blob storage account into "azure-blobStorage"
75+
76+
This will look like
77+
78+
> https://your-azure-storage-account.blob.core.windows.net
79+
80+
* Your azure-key from either "Key 1" or "Key 2" into "azure-key"
81+
* Your AudD token into "audd-token".
82+
83+
84+
## Running
85+
86+
First, make sure you `npm install`.
87+
88+
Browsing to the root of the webserver on http://localhost:12271 will take you to the audio capture page.
89+
90+
You can start the app by running `npm start`.
91+
92+
> npm start
93+
94+
> [email protected] start C:\dev\christmas-jumper
95+
> node server.js
96+
97+
Your app is listening on port 12271
98+
99+
If you want to develop against this with hot-reload and debugging enabled, first, make sure you've installed nodemon
100+
101+
> npm install -g nodemon
102+
103+
then you can simply run `npm run devserver`
104+
105+
> npm run devserver
106+
107+
> [email protected] devserver C:\dev\christmas-jumper
108+
> nodemon --inspect server.js
109+
110+
[nodemon] 1.19.4
111+
[nodemon] to restart at any time, enter `rs`
112+
[nodemon] watching dir(s): *.*
113+
[nodemon] watching extensions: js,mjs,json
114+
[nodemon] starting `node --inspect server.js`
115+
Debugger listening on ws://127.0.0.1:9229/5ce30222-84d5-4b69-81bd-23a6b1647594
116+
For help, see: https://nodejs.org/en/docs/inspector
117+
Your app is listening on port 12271
118+
119+
This will run the server on the same port, with --inspect enabled to connect `VSCode` or `WebStorm` debuggers to step through the code.
120+
It'll also hot-reload any javascript changes, so you don't have to cycle your node process during dev.
121+
122+
* For VSCode see: https://code.visualstudio.com/docs/nodejs/nodejs-debugging
123+
* For WebStorm see: https://www.jetbrains.com/help/webstorm/running-and-debugging-node-js.html
124+
125+
## Testing
126+
127+
Requires jest. You probably want to
128+
129+
> npm install -g jest
130+
131+
and restart your terminal for this to work well.
132+
133+
From the command line, run `npm test` (or just `jest`) - to run the entire test suite.
134+
135+
> npm test
136+
137+
> [email protected] test C:\dev\christmas-jumper
138+
> jest
139+
140+
PASS commands/SongDetector.test.js (5.092s)
141+
Song detector
142+
√ Execute returns song title from AudD API call. (2ms)
143+
√ Execute calls AudD with API token from configuration
144+
√ Execute instructs AudD to download song from azure blob storage
145+
√ Integration test: Can detect song that we know about when run against the real AudD API (3952ms)
146+
147+
Test Suites: 1 passed, 1 total
148+
Tests: 4 passed, 4 total
149+
Snapshots: 0 total
150+
Time: 5.741s
151+
Ran all test suites.
152+
153+
Or use your favourite jest supporting tool.
154+
155+
## Usage
156+
157+
Just open your browser!
158+
159+
Hardware
160+
=========
161+
162+
## Hardware Requirements
163+
164+
* AdaFruit Feather Huzzah
165+
* USB Cable (usb-a to micro USB)
166+
* NeoPixels Addressable RGB LEDs
167+
* Some power! (a battery, or usb-power etc)
168+
169+
## Software
170+
171+
* Arduino IDE - https://www.arduino.cc/en/main/software
172+
173+
## Configuration
174+
175+
* Open arduino.ino in Arduino IDE
176+
* Edit line 39 to contain your WiFi access point SSID
177+
* Edit line 40 to contain your WiFi password!
178+
* Edit line 58 to be the URL of your running Web app (see above!)
179+
* Web app needs to be running on port 80, over HTTP.
180+
181+
## Usage
182+
183+
* Plug cable into PC
184+
* Plug cable into AdaFruit Huzzah
185+
* Click Upload button in Arduino IDE
186+
* Watch all the code run in the serial debugging window if you like!
187+

app.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const JumperApi = require("./commands/JumperApi");
2+
const express = require("express");
3+
const bodyParser = require('body-parser');
4+
5+
const app = express();
6+
7+
// Configure express to support parsing base64 chunks of audio in json
8+
// The default message body that can be parsed is ~100kb, and our audio
9+
// snippets are going to be a little bit longer than that (200-300kb)
10+
// 50mb is probably... somewhat gracious, but ¯\_(ツ)_/¯
11+
12+
app.use(bodyParser.json({limit: '50mb'}));
13+
14+
// Serve our front-end HTML for audio recording
15+
16+
app.use(express.static("public"));
17+
app.use("/", express.static(__dirname + "/public", { index: "index.html" }));
18+
19+
// Create instance of the Jumper API and wire it up to our Urls
20+
// /active-image maps to getActiveImageKey() - returns the most recently identified image-key.
21+
// /what-song accepts a json wrapped base64 encoded ogg-opus audio snippet from the MediaRecorder browser API
22+
23+
const jumperApiSingleton = new JumperApi();
24+
25+
app.get("/active-image", async (request, response) => {
26+
const result = await jumperApiSingleton.getActiveImageKey();
27+
response.send(result.body);
28+
});
29+
30+
app.post("/what-song", async (request, response) => {
31+
const result = await jumperApiSingleton.detectSongFromClip(request.body.bytes);
32+
response.send(result);
33+
});
34+
35+
module.exports = app;

app.test.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const request = require('supertest');
2+
const app = require("./app");
3+
4+
describe("The App", () => {
5+
6+
it("/active-image defaults to 'default'", async () => {
7+
const result = await request(app).get('/active-image');
8+
9+
expect(result.statusCode).toBe(200);
10+
expect(result.text).toBe("default");
11+
});
12+
});

0 commit comments

Comments
 (0)