ws2801-webserver
Version:
A ready-to-use webserver for the WS2801-Pi package.
221 lines (220 loc) • 10.3 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Ws2801Webserver = void 0;
const child_process_1 = require("child_process");
const path_1 = __importDefault(require("path"));
const ws2801_pi_1 = __importDefault(require("ws2801-pi"));
const auth_service_1 = require("./auth-service");
const config_1 = require("./config/config");
const led_strip_validation_1 = require("./led-strip-validation");
const socket_io_server_1 = require("./socket-io-server");
const webserver_1 = require("./webserver");
class Ws2801Webserver {
constructor(config, ledController) {
this.config = config ? config : config_1.DefaultConfig;
if (!ledController && !this.config.amountOfLeds) {
throw new Error(`Either a ledController must be provided or the amount of leds must be provided via config!`);
}
this.ledController = ledController ? ledController : new ws2801_pi_1.default(this.config.amountOfLeds);
this.webserver = new webserver_1.Webserver(this.config.port, this.config.logRequests === true);
this.authService = new auth_service_1.AuthService(this.config, this.webserver);
this.socketIoServer = new socket_io_server_1.SocketIoServer(this.webserver.getHttpServer());
}
start() {
if (this.config.useAuth) {
this.authService.start();
}
this.addRoutes();
// this.addSocketIoListeners();
this.addSocketIoEmitters();
this.webserver.start();
}
stop() {
this.authService.stop();
this.webserver.stop();
}
getLedController() {
return this.ledController;
}
getExpressServer() {
return this.webserver.getExpressServer();
}
addRoutes() {
this.webserver.addGetRoute('/login-required', this.loginRequired.bind(this));
this.webserver.addGetRoute('/led-strip', this.getLedStrip.bind(this));
this.webserver.addPostRoute('/led-strip/fill', this.fillLedStrip.bind(this));
this.webserver.addPostRoute('/led-strip/clear', this.clearLedStrip.bind(this));
this.webserver.addPostRoute('/led-strip/led/:ledIndex/set', this.setSingleLedColor.bind(this));
this.webserver.addPostRoute('/led-strip/brightness/set', this.setBrightness.bind(this));
this.webserver.addGetRoute('/led-strip/brightness', this.getBrightness.bind(this));
this.webserver.addPostRoute('/led-strip/set', this.setLedStrip.bind(this));
this.webserver.addPostRoute('/led-strip/animation/start', this.startAnimation.bind(this));
this.webserver.addDeleteRoute('/led-strip/animation/stop', this.stopAnimation.bind(this));
this.webserver.addGetRoute('/led-strip/animation/finished', this.waitForAnimationToFinish.bind(this));
}
// private addSocketIoListeners(): void {
// }
addSocketIoEmitters() {
this.ledController.onLedStripChanged((ledStrip) => {
this.socketIoServer.send('led-strip__changed', ledStrip);
});
this.ledController.onBrightnessChanged((brightness) => {
this.socketIoServer.send('brightness__changed', brightness);
});
}
// Route functions
loginRequired(_, response) {
response.status(200).json({ loginRequired: this.config.useAuth });
}
async getLedStrip(_, response) {
if (this.currentAnimationProcess) {
await new Promise((resolve) => {
this.currentAnimationProcess.on('message', (receivedLedStrip) => {
response.status(200).json({ ledStrip: receivedLedStrip });
resolve();
});
this.currentAnimationProcess.send({ action: 'get-led-strip' });
});
return;
}
const ledStrip = this.ledController.getLedStrip();
response.status(200).json({ ledStrip: ledStrip });
}
async fillLedStrip(request, response) {
const color = request.body.color;
const brightness = request.body.brightness;
if (!color) {
response.status(400).send(`Request body must contain a 'color', e.g. {red: 255, green: 0, blue: 0}.`);
return;
}
this.ledController.fillLeds(color);
if (brightness) {
this.ledController.setBrightness(brightness);
}
await this.ledController.show();
const ledStrip = this.ledController.getLedStrip();
this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip });
response.status(200).json({ ledStrip: ledStrip });
}
async clearLedStrip(request, response) {
await this.ledController.clearLeds().show();
const ledStrip = this.ledController.getLedStrip();
this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip });
response.status(200).json({ ledStrip: ledStrip });
}
async setSingleLedColor(request, response) {
const enteredLedIndex = request.params.ledIndex;
const ledIndex = parseInt(enteredLedIndex);
const color = request.body.color;
const brightness = request.body.brightness;
if (Number.isNaN(ledIndex) || ledIndex < 0 || ledIndex >= this.config.amountOfLeds) {
response.status(400).send(`URL must contain a led index between 0 and ${this.config.amountOfLeds - 1} (Received ${enteredLedIndex}).`);
return;
}
if (!color) {
response.status(400).send(`Request body must contain a 'color', e.g. {red: 255, green: 0, blue: 0}.`);
return;
}
this.ledController.setLed(ledIndex, color);
if (brightness) {
this.ledController.setBrightness(brightness);
}
await this.ledController.show();
const ledStrip = this.ledController.getLedStrip();
this.socketIoServer.send('led-strip-changed', { ledStrip: ledStrip });
response.status(200).json({ ledStrip: ledStrip });
}
async setBrightness(request, response) {
const brightness = request.body.brightness;
if (brightness == undefined || (typeof brightness !== 'number' && brightness !== 'auto') || brightness < 0 || brightness > 100) {
response.status(400).send(`Request body must contain a 'brightness' (number between 0 and 100 or 'auto' for automatic brightness).`);
return;
}
await this.ledController.setBrightness(brightness).show();
if (this.currentAnimationProcess) {
this.currentAnimationProcess.send({ action: 'set-brightness', brightness: brightness });
}
this.socketIoServer.send('brightness-changed', { brightness: brightness });
response.status(200).send('success');
}
async getBrightness(request, response) {
const brightness = this.ledController.getBrightness();
response.status(200).json({ brightness: brightness });
}
async setLedStrip(request, response) {
const ledStrip = request.body.ledStrip;
const brightness = request.body.brightness;
if (!ledStrip) {
response.status(400).send(`Request body must contain a 'ledStrip' (an array of LedColors with the length of the led strip).`);
return;
}
try {
led_strip_validation_1.validateLedStrip(this.ledController.getLedStrip().length, ledStrip);
}
catch (error) {
response.status(400).send(error.message);
return;
}
for (let ledIndex = 0; ledIndex < ledStrip.length; ledIndex++) {
this.ledController.setLed(ledIndex, ledStrip[ledIndex]);
}
if (brightness) {
this.ledController.setBrightness(brightness);
}
await this.ledController.show();
const renderedLedStrip = this.ledController.getLedStrip();
this.socketIoServer.send('led-strip-changed', { ledStrip: renderedLedStrip });
response.status(200).json({ ledStrip: renderedLedStrip });
}
async startAnimation(request, response) {
const animationScript = request.body.animationScript;
if (animationScript == undefined) {
response.status(400).send(`Request body must contain a 'animationScript'.`);
return;
}
if (this.currentAnimationProcess) {
this.currentAnimationProcess.kill();
this.currentAnimationProcess = undefined;
}
const brightness = this.ledController.getBrightness();
this.currentAnimationProcess =
child_process_1.fork(path_1.default.join(__dirname, 'animator.js'), [this.ledController.getLedStrip().length.toString(), animationScript, brightness.toString()], {});
this.socketIoServer.send('animation__started');
// tslint:disable-next-line: typedef no-any
const eventCallback = (message) => {
if (message === 'animation-finished') {
this.currentAnimationProcess.kill();
this.currentAnimationProcess = undefined;
this.socketIoServer.send('animation__finished');
}
else if (message.action === 'led-strip-changed') {
this.socketIoServer.send('led-strip__changed', message.ledStrip);
}
};
this.currentAnimationProcess.on('message', eventCallback);
response.status(200).send('success!');
}
async stopAnimation(request, response) {
if (this.currentAnimationProcess) {
this.currentAnimationProcess.kill();
this.currentAnimationProcess = undefined;
}
this.socketIoServer.send('animation__stopped');
response.status(200).send('success!');
}
async waitForAnimationToFinish(request, response) {
if (!this.currentAnimationProcess) {
response.status(200).send('success!');
}
// tslint:disable-next-line: typedef no-any
this.currentAnimationProcess.on('message', (message) => {
if (message === 'animation-finished') {
response.status(200).send('success!');
}
});
}
}
exports.Ws2801Webserver = Ws2801Webserver;