netbeast
Version:
Resources for node.js wrapper
351 lines (292 loc) • 11.1 kB
JavaScript
var Promise = require('bluebird')
var request = require('superagent-bluebird-promise')
var chalk = require('chalk')
var mqtt = require('mqtt')
var scan = require('./lib/scan')
var NETBEAST = require('./lib/init')() // load env variables if needed or crash program
const HTTP_API = 'http://' + NETBEAST + '/api/resources'
const HTTP_SCENES = 'http://' + NETBEAST + '/api/scenes'
const APP_PROXY = 'http://' + NETBEAST + '/i/'
function netbeast (topic) {
var self = {}
self.props = {}
self.props.topic = topic
self.props.location = null
self.props.alias = null
self.props.group = null
// definiciones
// Add a device to a given scene
self.addDeviceScene = function (deviceid) {
return request.get(HTTP_API).query({ id: deviceid })
.then(function (res) {
if (!res.body.length) return Promise.reject('These resources doesn´t exists!')
return request.get(APP_PROXY + res.body[0].app + res.body[0].hook)
.then(function (res) {
// Registra dispositivo en la escena
var device = {
id: deviceid,
sceneid: self.props.topic,
location: self.props.location,
state: JSON.stringify(res.body)
}
return request.post(HTTP_SCENES).send(device).promise()
})
})
}
// Specified the alias of the objects
self.alias = function (alias) {
self.props.alias = alias
return self
}
// Apply the values saved on a Scene
self.applyScene = function () {
if (!self.props.topic) return Promise.reject('There isn´t any scene selected')
return self.getScene()
.then(function (res) {
res.body.forEach(function (device) {
return self.setById(device.id, JSON.parse(device.state))
})
})
}
// Specified the location of the objects
self.at = function (location) {
self.props.location = location
return self
}
self.changeAlias = function (alias) {
if (!alias) return Promise.reject(new Error('Alias required --> netbeast(<id>).changeAlias(<alias>)'))
if (!self.props.topic) return Promise.reject(new Error('Id required --> netbeast(<id>).changeAlias(<alias>)'))
return request.patch(HTTP_API + '?id=' + self.props.topic).send({alias: alias}).promise()
}
self.changeLocation = function (location) {
if (!location) return Promise.reject(new Error('Location required --> netbeast(<id>).changeLocation(<location>)'))
if (!self.props.topic) return Promise.reject(new Error('Id required --> netbeast(<id>).changeLocation(<location>)'))
return request.patch(HTTP_API + '?id=' + self.props.topic).send({location: location}).promise()
}
self.create = function (args) {
if (!self.props.topic && !args.topic) return Promise.reject(new Error('Topic required'))
if (!args.hook) return Promise.reject(new Error('Hook required'))
if (!args.app) return Promise.reject(new Error('App name required'))
return request.post(HTTP_API).send(queryCustom(args)).promise()
}
// Create a Scene with the given sates of the devices
self.createCustomScene = function (states) {
return Promise.map(states, function (device, done) {
// Registra dispositivo en la escena
device.sceneid = self.props.topic
device.state = JSON.stringify(device.status)
for (var key in device) {
if (['id', 'sceneid', 'state'].indexOf(key) < 0) delete device[key]
}
return request.post(HTTP_SCENES).send(device).promise()
})
}
// Create a Scene with the current sates of the devices
self.createScene = function (devicesid) {
return Promise.map(devicesid, function (id) {
self.addDeviceScene(id)
})
}
// Method that performs the delete request
self.delete = function (args) {
const queryString = queryCustom(normalizeArguments(args))
return request.del(HTTP_API).query(queryString).promise()
}
// Method that performs the delete request for a specific device
self.deleteById = function (id) {
return request.del(HTTP_API).query({ id: id }).promise()
}
// Method that performs the delete request for a specific device
self.deleteByAlias = function (alias) {
return request.del(HTTP_API).query({ alias: alias }).promise()
}
// Delete a device from a Scene
self.deleteDeviceScene = function (deviceid) {
return request.del(HTTP_SCENES).query({sceneid: self.props.topic, id: deviceid}).promise()
}
// Delete a Scene
self.deleteScene = function () {
return request.del(HTTP_SCENES).query({sceneid: self.props.topic}).promise()
}
// Method that performs the get request
self.get = function (args) {
if (self.props.topic === undefined) return Promise.reject(new Error('Topic required'))
return request.get(HTTP_API + '/topic/' + self.props.topic).query(self.props).promise()
}
// Obtain all the Scene´s name already declared
self.getAllScenes = function () {
return request.get(HTTP_SCENES).promise()
}
// Method that performs the get request for a specific device
self.getById = function (id) {
return request.get(HTTP_API + '/id/' + id).promise()
}
// Method that performs the get request for a specific device
self.getByAlias = function (alias) {
return request.get(HTTP_API + '/alias/' + alias).promise()
}
// Obtain all the details of a given Scene
self.getScene = function () {
return request.get(HTTP_SCENES).query(queryCustomScene()).promise()
}
// Specified if the resource belongs to a certain group
self.groupBy = function (group) {
self.props.group = group
return self
}
self.groupDevices = function (name, devices) {
return Promise.map(devices, function (item) {
request.patch(HTTP_API).query({id: item}).send({groupname: name}).promise()
})
}
self.publish = function (message) {
var client = mqtt.connect('ws://' + process.env.NETBEAST)
client.on('connect', function () {
client.publish('netbeast/' + self.props.topic, JSON.stringify({message}))
})
}
// Method that performs the set request
self.set = function (args) {
return request.post(HTTP_API + '/topic/' + self.props.topic).query(queryCustom()).send(args).promise()
}
// Method that performs the set request for a specific device
self.setById = function (id, args) {
return request.post(HTTP_API + '/id/' + id).send(args).promise()
}
// Method that performs the set request for a specific device
self.setByAlias = function (alias, args) {
return request.post(HTTP_API + '/alias/' + alias).send(args).promise()
}
// Specified the location of the objects
self.topic = function (topic) {
self.props.topic = topic
return self
}
self.updateDB = function (args) {
if (!self.props.topic && !args.topic) return Promise.reject(new Error('Topic required'))
if (!args.hook) return Promise.reject(new Error('Hook required'))
if (!args.app) return Promise.reject(new Error('App name required'))
console.log(HTTP_API + '/update')
return request.post(HTTP_API + '/update').send(queryCustom(args)).promise()
}
function queryCustom (args) {
var queryString = args || {}
if (self.props.topic) queryString.topic = self.props.topic
if (self.props.alias) queryString.alias = self.props.alias
if (self.props.location) queryString.location = self.props.location
if (self.props.group) queryString.groupname = self.props.group
return queryString
}
function queryCustomScene (args) {
var queryString = args || {}
if (self.props.location) queryString.location = self.props.location
if (self.props.topic) queryString.sceneid = self.props.topic
return queryString
}
function normalizeArguments (args) {
// Prepare query to be an object out of args unless it is undefined
var query = typeof args === 'undefined' ? undefined : {}
// if it is an string turn it into an array
args = typeof args === 'string' ? [args] : args
// and normalize it into an object again
if (args instanceof Array) {
args.forEach(function (param) { query[param] = '' })
} else if (typeof args === 'object') {
query = args
}
return query
}
return self
}
netbeast.scan = function () {
return new Promise(function (resolve, reject) {
scan(function (beast) {
if (beast && beast[0]) {
netbeast.set(beast[0]) // set environment variable
return resolve(beast)
}
return reject(new Error('No netbeasts found in subnet'))
})
})
}
netbeast.find = function () {
if (process.env.NETBEAST) return Promise.resolve(process.env.NETBEAST)
return netbeast.scan()
}
netbeast.set = function (networkObject) {
process.env.NETBEAST = networkObject.address + ':' + networkObject.port
return netbeast
}
netbeast.emit = function (msg) {
// Log notification through console
var str = chalk.bgCyan('ws') +
chalk.bold.bgCyan(msg.title || '::')
switch (msg.emphasis) {
case 'error':
str = str + chalk.bgRed(msg.body)
break
case 'warning':
str = str + chalk.bgYellow(msg.body)
break
case 'info':
str = str + chalk.bgBlue(msg.body)
break
case 'success':
str = str + chalk.bgGreen(msg.body)
break
}
var client = mqtt.connect('ws://' + process.env.NETBEAST)
console.log(str)
client.publish('netbeast/push', JSON.stringify(msg))
client.end()
}
netbeast.error = function (body, title) {
netbeast.emit({ emphasis: 'error', body: body, title: title })
}
netbeast.info = function (body, title) {
netbeast.emit({ emphasis: 'info', body: body, title: title })
}
netbeast.success = function (body, title) {
netbeast.emit({ emphasis: 'success', body: body, title: title })
}
netbeast.warning = function (body, title) {
netbeast.emit({ emphasis: 'warning', body: body, title: title })
}
netbeast.on = function (topic, callback) {
var client = mqtt.connect('ws://' + process.env.NETBEAST)
client.on('connect', function () {
console.log('connected')
client.subscribe('netbeast/' + topic)
})
if (!topic) return Promise.reject(new Error('Topic required'))
client.on('message', function (topic, message) {
console.log(message)
if (message) {
message = JSON.parse(message.toString())
callback(null, message)
}
})
}
// Search for devices of a given brand (or all)
netbeast.discoverDevices = function (app) {
var apps = []
var promise = new Promise(function (resolve, reject) {
request.get(process.env.NETBEAST + '/plugins')
.then(function (res) {
for (var aplication in res.body) {
if (apps.indexOf(res.body[aplication].name) < 0) apps.push(res.body[aplication].name)
}
if (!app || app === 'all') {
return Promise.each(apps, function (item) {
request.get(APP_PROXY + item + '/discover').promise()
})
} else if (apps.indexOf(app) >= 0) {
return request.get(APP_PROXY + app + '/discover')
} else {
return reject(new Error('App not supported yet'))
}
})
})
return promise
}
module.exports = netbeast