desktop-controller
Advanced tools
Comparing version 0.0.1 to 0.1.0
module.exports = { | ||
FEATURES: { | ||
POWER: 0, | ||
RESET: 1, | ||
WIFI: 2, | ||
UV: 4, | ||
LED: 8 | ||
}, | ||
AUTO_RELEASE: 5000, | ||
POWER_MODES: { | ||
BUTTON_MODE: { | ||
PRESSED: 0, | ||
NOT_PRESSED: 1 | ||
}, | ||
SWITCH_MODE: { | ||
ON: 0, | ||
OFF: 1 | ||
}, | ||
COLOR_MODE: { | ||
OFF: undefined | ||
} | ||
}; |
@@ -1,28 +0,275 @@ | ||
const { AUTO_RELEASE, POWER_MODES } = require('./constant.js'); | ||
const { FEATURES, BUTTON_MODE, COLOR_MODE, SWITCH_MODE, AUTO_RELEASE } = require('./constant.js'); | ||
const Color = require('color'); | ||
const getFeaturePinsForArgs = require('./get-feature-pins-for-args.js'); | ||
const getGpioManager = require('./get-gpio-manager.js'); | ||
// const args = process.argv.slice(2); | ||
// const isMock = args.indexOf('-m') !== -1; | ||
const args = process.argv.slice(2); | ||
module.exports = { | ||
_powerMode: POWER_MODES.NOT_PRESSED, | ||
const getDefaultModeToFeature = feature => { | ||
switch (feature) { | ||
case FEATURES.POWER: | ||
case FEATURES.RESET: | ||
return BUTTON_MODE.NOT_PRESSED; | ||
case FEATURES.LED: | ||
return COLOR_MODE.OFF; | ||
default: | ||
return SWITCH_MODE.OFF; | ||
} | ||
}; | ||
const featurePins = getFeaturePinsForArgs(args); | ||
const activatedFeatures = Object.keys(featurePins).map(key => Number(key)); | ||
if (activatedFeatures.length === 0) { | ||
throw new Error(` | ||
No features are activated, to activate a feature add parameters to "desktop-controller" command. | ||
Available features ${Object.keys(FEATURES).map(featureName => `"-${featureName.toLowerCase()}"`).join(', ')} | ||
`); | ||
} | ||
let gpioManager; | ||
const gpioManagerPromise = getGpioManager(activatedFeatures, featurePins).then(_gpioManager => { | ||
gpioManager = _gpioManager; | ||
}, err => { | ||
throw err; | ||
}); | ||
const controllerInterface = { | ||
status: activatedFeatures.reduce((obj, feature) => Object.assign(obj, { | ||
[feature]: getDefaultModeToFeature(feature) | ||
}), {}), | ||
inProcess: activatedFeatures.reduce((obj, feature) => Object.assign(obj, { | ||
[feature]: false | ||
}), {}), | ||
pressPower() { | ||
if (activatedFeatures.indexOf(FEATURES.POWER) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.POWER] === BUTTON_MODE.PRESSED) { | ||
throw new Error('Power is already pressed.'); | ||
} | ||
if (this.inProcess[FEATURES.POWER]) { | ||
throw new Error('Power is already in process.'); | ||
} | ||
this.inProcess[FEATURES.POWER] = true; | ||
return gpioManager.pressPower().then(() => { | ||
this.inProcess[FEATURES.POWER] = false; | ||
this.status[FEATURES.POWER] = BUTTON_MODE.PRESSED; | ||
setTimeout(() => { | ||
if (this.status[FEATURES.POWER] === BUTTON_MODE.PRESSED) { | ||
this._releasePower().then(undefined, err => { | ||
console.log(err); | ||
}); | ||
} | ||
}, AUTO_RELEASE); | ||
return this._releasePower.bind(this); | ||
}, () => { | ||
this.inProcess[FEATURES.POWER] = false; | ||
}); | ||
}, | ||
_releasePower() { | ||
if (this._powerMode === POWER_MODES.NOT_PRESSED) { | ||
if (activatedFeatures.indexOf(FEATURES.POWER) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.POWER] === BUTTON_MODE.NOT_PRESSED) { | ||
throw new Error(`Power is already released, can't call \`releasePower\` again, might been called after program auto released the button (after ${AUTO_RELEASE}ms).`); | ||
} | ||
this._powerMode = POWER_MODES.NOT_PRESSED; | ||
console.log('releasing power!'); | ||
if (this.inProcess[FEATURES.POWER]) { | ||
throw new Error('Power is already in process.'); | ||
} | ||
this.inProcess[FEATURES.POWER] = true; | ||
return gpioManager.releasePower().then(() => { | ||
this.inProcess[FEATURES.POWER] = false; | ||
this.status[FEATURES.POWER] = BUTTON_MODE.NOT_PRESSED; | ||
}, () => { | ||
this.inProcess[FEATURES.POWER] = false; | ||
}); | ||
}, | ||
pressPower() { | ||
if (this._powerMode === POWER_MODES.PRESSED) { | ||
throw new Error('Power is already pressed, can\'t call `pressPower` again.'); | ||
pressReset() { | ||
if (activatedFeatures.indexOf(FEATURES.RESET) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
this._powerMode = POWER_MODES.PRESSED; | ||
console.log('pressing power!'); | ||
if (this.status[FEATURES.RESET] === BUTTON_MODE.PRESSED) { | ||
throw new Error('Reset is already pressed, can\'t call `pressReset` again.'); | ||
} | ||
if (this.inProcess[FEATURES.RESET]) { | ||
throw new Error('Reset is already in process.'); | ||
} | ||
this.inProcess[FEATURES.RESET] = true; | ||
setTimeout(() => { | ||
if (this._powerMode === POWER_MODES.PRESSED) { | ||
this._releasePower(); | ||
if (this.status[FEATURES.RESET] === BUTTON_MODE.PRESSED) { | ||
this._releaseReset(); | ||
} | ||
}, AUTO_RELEASE); | ||
return this._releasePower.bind(this); | ||
return gpioManager.pressReset().then(() => { | ||
this.inProcess[FEATURES.RESET] = false; | ||
this.status[FEATURES.RESET] = BUTTON_MODE.PRESSED; | ||
return this._releaseReset.bind(this); | ||
}, () => { | ||
this.inProcess[FEATURES.RESET] = false; | ||
}); | ||
}, | ||
_releaseReset() { | ||
if (activatedFeatures.indexOf(FEATURES.RESET) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.RESET] === BUTTON_MODE.NOT_PRESSED) { | ||
throw new Error(`Reset is already released, can't call \`releaseReset\` again, might been called after program auto released the button (after ${AUTO_RELEASE}ms).`); | ||
} | ||
if (this.inProcess[FEATURES.RESET]) { | ||
throw new Error('Reset is already in process.'); | ||
} | ||
this.inProcess[FEATURES.RESET] = true; | ||
return gpioManager.releaseReset().then(() => { | ||
this.inProcess[FEATURES.RESET] = false; | ||
this.status[FEATURES.RESET] = BUTTON_MODE.NOT_PRESSED; | ||
}, () => { | ||
this.inProcess[FEATURES.RESET] = false; | ||
}); | ||
}, | ||
turnOnWifi() { | ||
if (activatedFeatures.indexOf(FEATURES.WIFI) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.WIFI] === SWITCH_MODE.ON) { | ||
throw new Error('Wifi is already on, can\'t call `turnOnWifi` again.'); | ||
} | ||
if (this.inProcess[FEATURES.WIFI]) { | ||
throw new Error('Wifi is already in process.'); | ||
} | ||
this.inProcess[FEATURES.WIFI] = true; | ||
return gpioManager.turnOnWifi().then(() => { | ||
this.inProcess[FEATURES.WIFI] = false; | ||
this.status[FEATURES.WIFI] = SWITCH_MODE.ON; | ||
}, () => { | ||
this.inProcess[FEATURES.WIFI] = false; | ||
}); | ||
}, | ||
turnOffWifi() { | ||
if (activatedFeatures.indexOf(FEATURES.WIFI) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.WIFI] === SWITCH_MODE.OFF) { | ||
throw new Error('Wifi is already off, can\'t call `turnOffWifi` again.'); | ||
} | ||
if (this.inProcess[FEATURES.WIFI]) { | ||
throw new Error('Wifi is already in process.'); | ||
} | ||
this.inProcess[FEATURES.WIFI] = true; | ||
return gpioManager.turnOffWifi().then(() => { | ||
this.inProcess[FEATURES.WIFI] = false; | ||
this.status[FEATURES.WIFI] = SWITCH_MODE.OFF; | ||
}, () => { | ||
this.inProcess[FEATURES.WIFI] = false; | ||
}); | ||
}, | ||
turnOnUvLight() { | ||
if (activatedFeatures.indexOf(FEATURES.UV) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.UV] === SWITCH_MODE.ON) { | ||
throw new Error('UvLight is already on, can\'t call `turnOnUvLight` again.'); | ||
} | ||
if (this.inProcess[FEATURES.UV]) { | ||
throw new Error('UvLight is already in process.'); | ||
} | ||
this.inProcess[FEATURES.UV] = true; | ||
return gpioManager.turnOnUvLight().then(() => { | ||
this.inProcess[FEATURES.UV] = false; | ||
this.status[FEATURES.UV] = SWITCH_MODE.ON; | ||
}, () => { | ||
this.inProcess[FEATURES.UV] = false; | ||
}); | ||
}, | ||
turnOffUvLight() { | ||
if (activatedFeatures.indexOf(FEATURES.UV) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.UV] === SWITCH_MODE.OFF) { | ||
throw new Error('UvLight is already off, can\'t call `turnOffUvLight` again.'); | ||
} | ||
if (this.inProcess[FEATURES.UV]) { | ||
throw new Error('UvLight is already in process.'); | ||
} | ||
this.inProcess[FEATURES.UV] = true; | ||
return gpioManager.turnOffUvLight().then(() => { | ||
this.inProcess[FEATURES.UV] = false; | ||
this.status[FEATURES.UV] = SWITCH_MODE.OFF; | ||
}, () => { | ||
this.inProcess[FEATURES.UV] = false; | ||
}); | ||
}, | ||
turnOnLed(color) { | ||
if (activatedFeatures.indexOf(FEATURES.LED) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (color === undefined) { | ||
throw new Error('`color` is required as first argument.'); | ||
} | ||
if (this.status[FEATURES.LED] !== COLOR_MODE.OFF) { | ||
throw new Error('Led is already on, can\'t call `turnOnLed` again.'); | ||
} | ||
if (this.inProcess[FEATURES.LED]) { | ||
throw new Error('Led is already in process.'); | ||
} | ||
this.inProcess[FEATURES.LED] = true; | ||
const colorObj = Color(color); | ||
return gpioManager.turnOnLed(colorObj.red(), colorObj.green(), colorObj.blue()).then(() => { | ||
this.inProcess[FEATURES.LED] = false; | ||
this.status[FEATURES.LED] = colorObj.rgbString(); | ||
}, () => { | ||
this.inProcess[FEATURES.LED] = false; | ||
}); | ||
}, | ||
turnOffLed() { | ||
if (activatedFeatures.indexOf(FEATURES.LED) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (this.status[FEATURES.LED] === COLOR_MODE.OFF) { | ||
throw new Error('Led is already off, can\'t call `turnOffLed` again.'); | ||
} | ||
if (this.inProcess[FEATURES.LED]) { | ||
throw new Error('Led is already in process.'); | ||
} | ||
this.inProcess[FEATURES.LED] = true; | ||
return gpioManager.turnOffLed().then(() => { | ||
this.inProcess[FEATURES.LED] = false; | ||
this.status[FEATURES.LED] = COLOR_MODE.OFF; | ||
}, () => { | ||
this.inProcess[FEATURES.LED] = false; | ||
}); | ||
}, | ||
setLed(color) { | ||
if (activatedFeatures.indexOf(FEATURES.LED) === -1) { | ||
throw new Error('This feature is not activated.'); | ||
} | ||
if (color === undefined) { | ||
throw new Error('`color` is required as first argument.'); | ||
} | ||
if (this.status[FEATURES.LED] === COLOR_MODE.OFF) { | ||
throw new Error('Led is off and it\'s color cannot be set, can\'t call `setLed`.'); | ||
} | ||
if (this.inProcess[FEATURES.LED]) { | ||
throw new Error('Led is already in process.'); | ||
} | ||
const colorObj = Color(color); | ||
this.inProcess[FEATURES.LED] = true; | ||
return gpioManager.setLed(colorObj.red(), colorObj.green(), colorObj.blue()).then(() => { | ||
this.inProcess[FEATURES.LED] = false; | ||
this.status[FEATURES.LED] = colorObj.rgbString(); | ||
}, () => { | ||
this.inProcess[FEATURES.LED] = false; | ||
}); | ||
} | ||
}; | ||
module.exports = { | ||
activatedFeatures, | ||
getInterface() { | ||
if (gpioManager !== undefined) { | ||
return new Promise(resolve => resolve(controllerInterface)); | ||
} else { | ||
return gpioManagerPromise.then(() => controllerInterface); | ||
} | ||
} | ||
}; |
180
index.js
@@ -0,29 +1,171 @@ | ||
#!/usr/bin/env node | ||
const path = require('path'); | ||
const express = require('express'); | ||
const controller = require('./controller.js'); | ||
const getStyleForArgs = require('./get-style-for-args.js'); | ||
const args = process.argv.slice(2); | ||
const useWebpack = args.indexOf('-w') !== -1; | ||
const app = express(); | ||
const PORT = 80; | ||
const appPath = path.join(__dirname, 'dist'); | ||
const PORT = useWebpack ? 8080 : 80; | ||
app.use(express.static(appPath)); | ||
const style = getStyleForArgs(args); | ||
const activatedFeatures = controller.activatedFeatures; | ||
let releasePower; | ||
// Press | ||
app.post('/power', (req, res) => { | ||
releasePower = controller.pressPower(); | ||
res.status(200).end(); | ||
}); | ||
controller.getInterface().then(controllerInterface => { | ||
const config = { | ||
style, | ||
activatedFeatures | ||
}; | ||
app.get('/config', (req, res) => { | ||
res.json(Object.assign({}, config, { | ||
status: controllerInterface.status | ||
})); | ||
}); | ||
// Release | ||
app.delete('/power', (req, res) => { | ||
if (releasePower) { | ||
releasePower(); | ||
releasePower = undefined; | ||
res.status(200).end(); | ||
let releasePower; | ||
// Press | ||
app.post('/power', (req, res) => { | ||
controllerInterface.pressPower().then(_releasePower => { | ||
releasePower = _releasePower; | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// Release | ||
app.delete('/power', (req, res) => { | ||
if (releasePower) { | ||
releasePower().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
releasePower = undefined; | ||
} | ||
}); | ||
let releaseReset; | ||
// Press | ||
app.post('/reset', (req, res) => { | ||
controllerInterface.pressReset().then(_releaseReset => { | ||
releaseReset = _releaseReset; | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// Release | ||
app.delete('/reset', (req, res) => { | ||
if (releaseReset) { | ||
releaseReset().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
releaseReset = undefined; | ||
} | ||
}); | ||
// On | ||
app.post('/wifi', (req, res) => { | ||
controllerInterface.turnOnWifi().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// Off | ||
app.delete('/wifi', (req, res) => { | ||
controllerInterface.turnOffWifi().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// On | ||
app.post('/uv', (req, res) => { | ||
controllerInterface.turnOnUvLight().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// Off | ||
app.delete('/uv', (req, res) => { | ||
controllerInterface.turnOffUvLight().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// On | ||
app.post('/led/:color', (req, res) => { | ||
const { color } = req.params; | ||
controllerInterface.turnOnLed(color).then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// set | ||
app.put('/led/:color', (req, res) => { | ||
const { color } = req.params; | ||
controllerInterface.setLed(color).then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
// Off | ||
app.delete('/led', (req, res) => { | ||
controllerInterface.turnOffLed().then(() => { | ||
res.end(); | ||
}, err => { | ||
throw err; | ||
}); | ||
}); | ||
const start = () => { | ||
app.listen(PORT, () => { | ||
console.log(`App started on port ${PORT}!`); | ||
}); | ||
}; | ||
if (useWebpack) { | ||
// Disabling global require so it won't require that dependency in prod | ||
/* eslint-disable global-require */ | ||
const webpack = require('webpack'); | ||
const webpackMiddleware = require('webpack-dev-middleware'); | ||
const webpackHotMiddleware = require('webpack-hot-middleware'); | ||
const getWebpackConfig = require('./get-webpack-config.js'); | ||
/* eslint-enable global-require */ | ||
const webpackConfig = getWebpackConfig({ isWebpackDevServer: true }); | ||
const webpackCompiler = webpack(webpackConfig); | ||
const webpackDevMiddlewareInstance = webpackMiddleware(webpackCompiler, | ||
{ | ||
publicPath: '', | ||
noInfo: false, | ||
quiet: false | ||
} | ||
); | ||
app.use(webpackDevMiddlewareInstance); | ||
app.use(webpackHotMiddleware(webpackCompiler)); | ||
webpackDevMiddlewareInstance.waitUntilValid(start); | ||
} else { | ||
app.use(express.static(path.join(__dirname, 'dist'))); | ||
start(); | ||
} | ||
}, err => { | ||
throw err; | ||
}); | ||
app.listen(PORT, () => { | ||
console.log(`App started on port ${PORT}!`); | ||
}); |
{ | ||
"name": "desktop-controller", | ||
"version": "0.0.1", | ||
"version": "0.1.0", | ||
"description": "Desktop controller", | ||
@@ -13,4 +13,3 @@ "main": "index.js", | ||
"build:prod": "webpack -p", | ||
"start": "webpack-dev-server --port 8080 --host 0.0.0.0 --inline --hot --progress --colors", | ||
"start:mock": "npm run build && npm run start:prod -m", | ||
"start": "npm run start:prod -- -m -w -power 1 -reset 2 -wifi 3 -uv 4 -led 5,6,7", | ||
"start:prod": "node ./index.js" | ||
@@ -33,5 +32,7 @@ }, | ||
"dependencies": { | ||
"color": "^0.11.3", | ||
"express": "^4.14.0", | ||
"path": "^0.12.7" | ||
}, | ||
"optionalDependencies": {}, | ||
"devDependencies": { | ||
@@ -49,3 +50,3 @@ "babel-core": "^6.17.0", | ||
"eslint-config-airbnb": "^12.0.0", | ||
"eslint-plugin-import": "^2.0.1", | ||
"eslint-plugin-import": "^1.16.0", | ||
"eslint-plugin-jsx-a11y": "^2.2.3", | ||
@@ -60,4 +61,7 @@ "eslint-plugin-react": "^6.4.1", | ||
"json-loader": "^0.5.4", | ||
"material-ui": "^0.16.1", | ||
"react": "^15.3.2", | ||
"react-color": "^2.8.0", | ||
"react-dom": "^15.3.2", | ||
"react-tap-event-plugin": "^1.0.0", | ||
"replace-loader": "^0.2.0", | ||
@@ -67,5 +71,6 @@ "style-loader": "^0.13.1", | ||
"webpack": "^1.13.2", | ||
"webpack-dev-server": "^1.16.2", | ||
"webpack-dev-middleware": "^1.8.4", | ||
"webpack-hot-middleware": "^2.13.0", | ||
"whatwg-fetch": "^1.0.0" | ||
} | ||
} |
[![Build Status](https://travis-ci.org/unimonkiez/desktop-controller.svg?branch=master)](https://travis-ci.org/unimonkiez/desktop-controller) | ||
# Desktop controller | ||
## Installation | ||
1. Install NodeJS on your raspberry. | ||
2. (Optional) install yarn by running `sudo npm install -g yarn`. | ||
3. install the application by running `sudo npm install -g desktop-controller` or `sudo yarn global add desktop-controller`. | ||
## Usage | ||
to run the server simply run `sudo desktop-controller [options]`. | ||
Here are the options - | ||
|Flag|Is required|Default|Description| | ||
|:---:|:---:|:---:|:---:| | ||
|`-power`|:heavy_multiplication_x:||Gpio pin number for power relay.| | ||
|`-reset`|:heavy_multiplication_x:||Gpio pin number for reset relay.| | ||
|`-wifi`|:heavy_multiplication_x:||Gpio pin number for wifi relay.| | ||
|`-uv`|:heavy_multiplication_x:||Gpio pin number for uv light relay.| | ||
|`-led`|:heavy_multiplication_x:||Gpio pin numbers (seperated by `,`, for example `-led 4,5,6`) for led mosfets.| | ||
|`-m`|:heavy_multiplication_x:||Use this flag if you want to mock gpio calls (won't actually do anything other than logs).| | ||
|`-primary-color`|:heavy_multiplication_x:|`#000` (black)|Change primary color of the application (can be text, hex or rgb).| | ||
|`-secondary-color`|:heavy_multiplication_x:|`#0F0` (green)|Change secondary color of the application (can be text, hex or rgb).| |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7762887
17
29096
23
3
33
+ Addedcolor@^0.11.3
+ Addedclone@1.0.4(transitive)
+ Addedcolor@0.11.4(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addedcolor-string@0.3.0(transitive)