UNPKG

piapi

Version:

Client library for interfacing with PiAPI running on your raspberry pi

420 lines (368 loc) 11.6 kB
const http = require("http"); class Private { static checkUrl(Pi) { if (!(Pi.ipAddress != "" || Pi.urlOverride != "")) { throw "API url not provided"; } } static parseUri (url) { let o = { strictMode: false, key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], q: { name: "queryKey", parser: /(?:^|&)([^&=]*)=?([^&]*)/g }, parser: { strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ } } let m = o.parser[o.strictMode ? "strict" : "loose"].exec(url); let uri = {}; let i = 14; while (i--) uri[o.key[i]] = m[i] || ""; uri[o.q.name] = {}; uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { if ($1) uri[o.q.name][$1] = $2; }); return uri; } static createRequestOptions(url, requestType) { let uri = this.parseUri(url); let options = { hostname: uri.host, port: Number(uri.port), path: uri.path, method: requestType } if(uri.port != "") { options.port = Number(uri.port) } return options; } static isJSON(text) { return (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@'). replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) } } /** * Adds easy functionality to help interface with PiAPI * https://github.com/Bolillo-Kremer/PiAPI * https://youtube.com/BolilloKremer */ class Pi { /** * Initiates connection to PiAPI * @param {string} address Either PiAPI IP address or full address to PiAPI * @param {Number} port The port that PiAPI is running on (Not needed if given full address) */ constructor(address, port = -1) { if (Number(port) != -1) { this.ipAddress = address; this.port = Number(port); this.urlOverride = ""; this.rawUrl = `http://${this.ipAddress}:${this.port}`; } else { this.ipAddress = ""; this.port = -1; this.urlOverride = address; this.rawUrl = this.urlOverride; } } /** * Returns the default port of PiAPI */ static defaultPort() { return "5000"; } /** * Initiates pin on the raspberry pi * @param {Number} pin The pin on the raspberry pi * @param {string} direction The direction of the pin * @param {string} edge (OPTIONAL) The edge of the pin * @param {Number} edgeTimeout (OPTIONAL) The edge timeout of the pin */ async initPin(pin, direction, edge=null, edgeTimeout=-1) { Private.checkUrl(this); let url = this.rawUrl + "/InitPin"; let pinSettings = { "pin": pin, "direction": direction }; if (edge != null) { pinSettings["edge"] = edge; } if (edgeTimeout != -1) { pinSettings["edgeTimeout"] = edgeTimeout; } return await Utilities.post(url, JSON.stringify(pinSettings)); } /** * Unexports a given pin on the raspberry pi * @param {Number} pin The pin to unexport */ async unexportPin(pin) { Private.checkUrl(this); let url = this.rawUrl + "/Unexport"; return await Utilities.post(url, pin.toString()); } /** * Unexports all pins on the raspberry pi */ async cleanExit() { Private.checkUrl(this); let url = this.rawUrl + "/CleanExit"; return await Utilities.get(url); } /** * Sets state of a given pin on the raspberry pi * @param {Number} pin The pin to change the state of * @param {Number} state The state to change to */ async setState(pin, state) { Private.checkUrl(this); let url = this.rawUrl + "/SetState"; let pinSettings = { "pin": Number(pin), "state": Number(state) } return await Utilities.post(url, JSON.stringify(pinSettings)); } /** * Sets state of all pins on the raspberry pi * @param {Number} state State to set all pins to */ async setAllStates(state) { Private.checkUrl(this); let url = this.rawUrl + "/SetState" let pinSettings = { "pin": Helpers.Pin.all(), "state": Number(state) } return await Utilities.post(url, JSON.stringify(pinSettings)); } /** * Gets the state of a given pin * @param {Number} pin The pin to get the state of */ async getState(pin) { Private.checkUrl(this); let url = this.rawUrl + "/GetState"; return Number(await Utilities.post(url, pin.toString())); } /** * Gets a JSON of all the states of all active pins */ async getAllStates() { Private.checkUrl(this); let url = this.rawUrl + "/GetState"; return JSON.parse(await Utilities.post(url, Helpers.Pin.all())); } /** * Gets a JSON of all active pins */ async activePins() { Private.checkUrl(this); let url = this.rawUrl + "/ActivePins"; return JSON.parse(await Utilities.get(url)); } /** * Executes a terminal command on the raspberry pi * @param {string} command The command to execute */ async command(command) { Private.checkUrl(this); let url = this.rawUrl + "/Command"; return await Utilities.post(url, command); } /** * Reboots the raspberry pi */ reboot() { this.command("sudo reboot"); } /** * Shuts down the raspberry pi */ shutdown() { this.command("sudo shutdown -h"); } /** * Gets a PiAPI setting value * @param {string} settingName The name of the setting */ async getAPISetting(settingName) { Private.checkUrl(this); let url = this.rawUrl + "/GetSetting"; let res = await Utilities.post(url, settingName); return (Private.isJSON(res)) ? JSON.parse(res) : res; } /** * Sets a PiAPI setting value * @param {string} settingName The name of the setting * @param {*} settingValue The value of the setting */ setAPISetting(settingName, settingValue) { Private.checkUrl(this); let url = this.rawUrl + "/SetSetting"; let setting = { "setting": settingName, "val": settingValue } Utilities.post(url, JSON.stringify(setting)); } /** * Gets the port that PiAPI is running on */ async getAPIPort() { return await this.getAPISetting("port"); } /** * Sets the port that PiAPI is running on * @param {Number} port The new port that PiAPI will run on */ setAPIPort(port) { this.setAPISetting("port", Number(port)); } } /** * Extra utilities that might help improve your PiAPI expirience */ class Utilities { /** * Makes an HTTP POST request * @param {string} url The URL to post to * @param {string} data The data to post to the url * @returns Promise with response value */ static post(url, data) { return new Promise((resolve, reject) => { let options = Private.createRequestOptions(url, "POST"); options.headers = { 'Content-Type': 'application/json', 'Content-Length': data.length } let req = http.request(options, res => { res.on('data', d => { resolve(d.toString("ascii")); }); }); req.on('error', error => { reject((Private.isJSON(error.toString())) ? JSON.parse(error.toString()) : error); }); req.write(data) req.end() }); } /** * Makes an HTTP GET request * @param {string} url The url to get from * @returns Promise with response value */ static get(url) { return new Promise((resolve, reject) => { let options = Private.createRequestOptions(url, "GET"); let req = http.request(options, res => { res.on('data', d => { resolve(d.toString("ascii")); }) }) req.on('error', error => { reject((Private.isJSON(error.toString())) ? JSON.parse(error.toString()) : error); }) req.end() }); } /** * A Promise that waits a given amount of miliseconds before resolving * @param {Number} miliseconds How many miliseconds to wait */ static wait(miliseconds) { return new Promise((resolve) => { setTimeout(resolve, miliseconds); }); } } /** * Raspberry Pi value helpers */ class Helpers { /** * Pin value helpers */ static Pin = { /** * @returns Pin in value */ in: () => {return "in"}, /** * @returns Pin out value */ out: () => {return "out"}, /** * @returns All pins value */ all: () => {return "*"}, /** * @returns High state value */ high: () => {return 1}, /** * @returns Low state value */ low: () => {return 0}, /** * @returns Toggle state value */ toggle: () => {return -1} } /** * Edge value helpers */ static Edge = { /** * @returns Rising edge value */ rising: () => {return "rising"}, /** * @returns Falling edge value */ falling: () => {return "falling"}, /** * @returns Both edge value */ both: () => {return "both"} } /** * Pull value helpers */ static Pull = { /** * @returns Pull up value */ up: () => {return "up"}, /** * @returns Pull down value */ down: () => {return "down"} } /** * Pin Mode value helpers */ static Mode = { /** * @returns BCM pin mode value */ BCM: () => {return "bcm"}, /** * @returns Board pin mode value */ board: () => {return "board"} } } module.exports.Pi = Pi; module.exports.Utilities = Utilities; module.exports.Helpers = Helpers;