Compare commits
62 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3623b7335e | ||
|
|
2920e220e3 | ||
|
|
b7946a9e4d | ||
|
|
f894887452 | ||
|
|
7ed74a8804 | ||
|
|
a8cf50c7b4 | ||
|
|
874b7ade9f | ||
|
|
aaa4035e7e | ||
|
|
700d602701 | ||
|
|
d4092eb6ef | ||
|
|
12ee3ef61b | ||
|
|
bfd7c20426 | ||
|
|
2a40b1444c | ||
|
|
9d1a189c92 | ||
|
|
83e14d02b7 | ||
|
|
a1fd20c23c | ||
|
|
536df6bd1e | ||
|
|
0176c93acf | ||
|
|
a92e04d218 | ||
|
|
c9ecab57be | ||
|
|
d10cabb6e3 | ||
|
|
58430f29f1 | ||
|
|
18399e27a8 | ||
|
|
8eeb1d0c7a | ||
|
|
b1319313c7 | ||
|
|
a7ec84f7c4 | ||
|
|
c0812e1144 | ||
|
|
a21c9a206f | ||
|
|
50a5af1213 | ||
|
|
e8d3dd6954 | ||
|
|
ed4e97f0a3 | ||
|
|
1f52fe01f9 | ||
|
|
d562b34890 | ||
|
|
14022293b4 | ||
|
|
6bde7147a9 | ||
|
|
2da9904981 | ||
|
|
fbfa2201db | ||
|
|
c7272a64ed | ||
|
|
9b6e8d9787 | ||
|
|
e7b47c384e | ||
|
|
bad04cef59 | ||
|
|
1134c5985b | ||
|
|
f0551dff3b | ||
|
|
abb1e80a43 | ||
|
|
9b0997b8fc | ||
|
|
3c2f1c9217 | ||
|
|
e18d38e7d6 | ||
|
|
0e13b8aef1 | ||
|
|
bd8745a7be | ||
|
|
fb7303eacb | ||
|
|
62cc18a3cd | ||
|
|
bb4c4272d5 | ||
|
|
7500a11bbe | ||
|
|
f9a07a6abb | ||
|
|
17ef2c2487 | ||
|
|
b826823041 | ||
|
|
efb8bd0286 | ||
|
|
b0ce189ff0 | ||
|
|
e1f26c365a | ||
|
|
89074c9848 | ||
|
|
187e7c5fe4 | ||
|
|
ec6eb8a631 |
11 changed files with 447 additions and 49 deletions
|
|
@ -22,21 +22,23 @@ class ClientCLI extends CLI {
|
|||
|
||||
init() {
|
||||
|
||||
let options = {};
|
||||
|
||||
if(! process.env.AIO_CLIENT_USER || ! process.env.AIO_CLIENT_KEY)
|
||||
return this.requireAuth(this.yargs);
|
||||
|
||||
const options = {
|
||||
success: this.setupAPI.bind(this, this.yargs),
|
||||
failure: this.error.bind(this)
|
||||
};
|
||||
|
||||
if(process.env.AIO_CLIENT_HOST)
|
||||
options.host = process.env.AIO_CLIENT_HOST;
|
||||
|
||||
if(process.env.AIO_CLIENT_PORT)
|
||||
options.port = process.env.AIO_CLIENT_PORT;
|
||||
|
||||
this.client = new Client(process.env.AIO_CLIENT_USER, process.env.AIO_CLIENT_KEY, options);
|
||||
new Client(process.env.AIO_CLIENT_USER, process.env.AIO_CLIENT_KEY, options)
|
||||
.then((client) => {
|
||||
this.client = client;
|
||||
this.setupAPI(this.yargs);
|
||||
})
|
||||
.catch((err) => this.error(JSON.stringify(err)));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -68,10 +70,12 @@ class ClientCLI extends CLI {
|
|||
|
||||
};
|
||||
|
||||
this.client = new Client(process.env.AIO_CLIENT_USER, process.env.AIO_CLIENT_KEY, {
|
||||
success: parse.bind(this),
|
||||
failure: this.error.bind(this)
|
||||
});
|
||||
new Client(process.env.AIO_CLIENT_USER, process.env.AIO_CLIENT_KEY)
|
||||
.then((client) => {
|
||||
this.client = client;
|
||||
parse();
|
||||
})
|
||||
.catch(this.error.bind(this));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +200,14 @@ class ClientCLI extends CLI {
|
|||
this.info('Success');
|
||||
console.log(res.obj);
|
||||
})
|
||||
.catch(res => this.error(res.obj.toString().replace('Error: ', '')));
|
||||
.catch(res => {
|
||||
|
||||
if(argv.json)
|
||||
return console.log(res.statusText);
|
||||
|
||||
this.error(JSON.parse(res.statusText).error);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const questions = Object.keys(body.schema.properties).map(name => {
|
||||
|
|
@ -219,7 +230,14 @@ class ClientCLI extends CLI {
|
|||
this.info('Success');
|
||||
console.log(res.obj);
|
||||
})
|
||||
.catch(res => this.error(res.obj.toString().replace('Error: ', '')));
|
||||
.catch(res => {
|
||||
|
||||
if(argv.json)
|
||||
return console.log(res.statusText);
|
||||
|
||||
this.error(JSON.parse(res.statusText).error);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
|||
132
cli/homekit.js
Normal file
132
cli/homekit.js
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
'use strict';
|
||||
|
||||
const Client = require('../client'),
|
||||
CLI = require('./index'),
|
||||
Yargs = require('yargs'),
|
||||
uuid = require('hap-nodejs').uuid,
|
||||
storage = require('node-persist'),
|
||||
Bridge = require('hap-nodejs').Bridge,
|
||||
Accessory = require('hap-nodejs').Accessory,
|
||||
inquirer = require('inquirer'),
|
||||
Accessories = require('../homekit'),
|
||||
crypto = require('crypto');
|
||||
|
||||
storage.initSync();
|
||||
|
||||
|
||||
class HomekitCLI extends CLI {
|
||||
|
||||
constructor() {
|
||||
|
||||
super('homekit');
|
||||
|
||||
this.completions = [
|
||||
'help',
|
||||
'light'
|
||||
];
|
||||
|
||||
this.yargs = Yargs(process.argv.slice(3));
|
||||
this.client = false;
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
if(! process.env.AIO_CLIENT_USER || ! process.env.AIO_CLIENT_KEY)
|
||||
return this.requireAuth(this.yargs);
|
||||
|
||||
const options = {
|
||||
success: this.clientReady.bind(this, this.yargs),
|
||||
failure: this.error.bind(this)
|
||||
};
|
||||
|
||||
if(process.env.AIO_CLIENT_HOST)
|
||||
options.host = process.env.AIO_CLIENT_HOST;
|
||||
|
||||
if(process.env.AIO_CLIENT_PORT)
|
||||
options.port = process.env.AIO_CLIENT_PORT;
|
||||
|
||||
this.client = new Client(process.env.AIO_CLIENT_USER, process.env.AIO_CLIENT_KEY, options);
|
||||
|
||||
}
|
||||
|
||||
clientReady(yargs) {
|
||||
|
||||
const argv = yargs
|
||||
.command('light', 'Light')
|
||||
.command('help', 'Show help')
|
||||
.demand(1, 'You must supply a valid homekit command')
|
||||
.argv;
|
||||
|
||||
if(! argv)
|
||||
return;
|
||||
|
||||
const command = argv._[0];
|
||||
|
||||
if(command === 'help')
|
||||
return yargs.showHelp();
|
||||
|
||||
if(! this[command])
|
||||
return yargs.showHelp();
|
||||
|
||||
this[command](Yargs(process.argv.slice(4)));
|
||||
|
||||
}
|
||||
|
||||
light(yargs) {
|
||||
|
||||
yargs.usage(`Usage: adafruit-io homekit light [options]`)
|
||||
.command('help', 'Show help')
|
||||
.alias('n', 'name').demand('name')
|
||||
.nargs('n', 1).describe('n', 'the name of the light');
|
||||
|
||||
const argv = yargs.argv,
|
||||
command = argv._[0];
|
||||
|
||||
if(command === 'help')
|
||||
return yargs.showHelp();
|
||||
|
||||
const name = argv.name || 'light',
|
||||
bridge = new Bridge('Adafruit IO', uuid.generate('Adafruit IO'));
|
||||
|
||||
bridge.on('identify', (paired, cb) => cb());
|
||||
|
||||
const light = new Accessories.light(name, this.client);
|
||||
|
||||
bridge.addBridgedAccessory(light);
|
||||
|
||||
this.logo();
|
||||
this.info('advertising homekit light accessory...');
|
||||
this.info('PIN: 100-11-100');
|
||||
|
||||
bridge.publish({
|
||||
username: 'AD:A0:AD:A0:AD:A0',
|
||||
port: 60000,
|
||||
pincode: '100-11-100',
|
||||
category: Accessory.Categories.BRIDGE
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
requireAuth(yargs) {
|
||||
|
||||
const argv = yargs
|
||||
.usage('Usage: adafruit-io homekit config [options]')
|
||||
.alias('h', 'host').nargs('h', 1).default('h', process.env.AIO_CLIENT_HOST || 'io.adafruit.com').describe('h', 'Server hostname')
|
||||
.alias('p', 'port').nargs('p', 1).default('p', process.env.AIO_CLIENT_PORT || '80').describe('p', 'Server port')
|
||||
.alias('u', 'username').demand('username').nargs('u', 1).describe('u', 'Adafruit IO Username')
|
||||
.alias('k', 'key').demand('key').nargs('k', 1).describe('k', 'Adafruit IO Key')
|
||||
.command('help', 'Show help')
|
||||
.argv;
|
||||
|
||||
process.env.AIO_CLIENT_HOST = argv.host;
|
||||
process.env.AIO_CLIENT_PORT = argv.port;
|
||||
process.env.AIO_CLIENT_USER = argv.username;
|
||||
process.env.AIO_CLIENT_KEY = argv.key;
|
||||
|
||||
this.saveEnv();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports = module.exports = HomekitCLI;
|
||||
|
|
@ -16,6 +16,7 @@ class CLI {
|
|||
this.type = type || 'cli';
|
||||
this.completions = [
|
||||
'client',
|
||||
'homekit',
|
||||
'server',
|
||||
'tunnel',
|
||||
'help',
|
||||
|
|
@ -24,6 +25,7 @@ class CLI {
|
|||
|
||||
this.sub = {
|
||||
client: require('./client'),
|
||||
homekit: require('./homekit'),
|
||||
server: require('./server'),
|
||||
tunnel: require('./tunnel')
|
||||
};
|
||||
|
|
@ -50,6 +52,7 @@ class CLI {
|
|||
this.yargs
|
||||
.usage('Usage: adafruit-io <command>')
|
||||
.command('server', 'Adafruit IO local server')
|
||||
.command('homekit', 'Adafruit IO homekit bridge')
|
||||
.command('client', 'Adafruit IO client')
|
||||
.command('tunnel', 'TLS tunnel to io.adafruit.com')
|
||||
.command('help', 'Show help')
|
||||
|
|
@ -163,7 +166,7 @@ class CLI {
|
|||
if(Object.keys(children).indexOf(commands[0]) < 0)
|
||||
return done([]);
|
||||
|
||||
if(commands[0] === 'server' || commands[0] === 'tunnel') {
|
||||
if(commands[0] === 'server' || commands[0] === 'tunnel' || commands[0] === 'homekit') {
|
||||
|
||||
const child = new children[commands[0]]();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
const Swagger = require('swagger-client-promises'),
|
||||
const Swagger = require('./lib/client'),
|
||||
Stream = require('./lib/stream'),
|
||||
Signature = require('./lib/signature'),
|
||||
pkg = require('../package.json');
|
||||
|
||||
class HeaderKey {
|
||||
|
|
@ -26,11 +27,12 @@ class Client {
|
|||
this.port = 80;
|
||||
this.username = username || false;
|
||||
this.key = key || false;
|
||||
this.swagger_path = '/api/docs/v1.json';
|
||||
this.success = function() {};
|
||||
this.failure = function(err) { throw err; };
|
||||
this.swagger_path = '/api/docs/v2.json';
|
||||
this.authorizations = {
|
||||
HeaderKey: new HeaderKey(this.key)
|
||||
};
|
||||
|
||||
Object.assign(this, options);
|
||||
Object.assign(this, options || {});
|
||||
|
||||
if(! this.username)
|
||||
throw new Error('client username is required');
|
||||
|
|
@ -38,14 +40,14 @@ class Client {
|
|||
if(! this.key)
|
||||
throw new Error('client key is required');
|
||||
|
||||
this.swagger = new Swagger({
|
||||
return new Swagger({
|
||||
url: `http://${this.host}:${this.port}${this.swagger_path}`,
|
||||
debug: true,
|
||||
success: this._defineGetters.bind(this),
|
||||
failure: this.failure,
|
||||
authorizations: {
|
||||
HeaderKey: new HeaderKey(this.key)
|
||||
}
|
||||
usePromise: true,
|
||||
authorizations: this.authorizations
|
||||
}).then((client) => {
|
||||
this.swagger = client;
|
||||
this._defineGetters();
|
||||
return this;
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -68,6 +70,7 @@ class Client {
|
|||
this.swagger[api].readable = (id) => { stream.connect(id); return stream; };
|
||||
this.swagger[api].writable = (id) => { stream.connect(id); return stream; };
|
||||
|
||||
// add dynamic getter to this class for the API
|
||||
Object.defineProperty(this, api, {
|
||||
get: () => {
|
||||
return this.swagger[api];
|
||||
|
|
@ -76,8 +79,14 @@ class Client {
|
|||
|
||||
});
|
||||
|
||||
this.success();
|
||||
}
|
||||
|
||||
static get Signature() {
|
||||
return Signature;
|
||||
}
|
||||
|
||||
static get Stream() {
|
||||
return Stream;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
12
client/lib/client.js
Normal file
12
client/lib/client.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const Swagger = require('swagger-client');
|
||||
|
||||
class Client extends Swagger {
|
||||
|
||||
idFromOp(path, httpMethod, op) {
|
||||
op.operationId = op['x-swagger-router-action'];
|
||||
return super.idFromOp(path, httpMethod, op);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports = module.exports = Client;
|
||||
99
client/lib/signature.js
Normal file
99
client/lib/signature.js
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
'use strict';
|
||||
|
||||
const crypto = require('crypto'),
|
||||
url = require('url');
|
||||
|
||||
class Signature {
|
||||
|
||||
constructor(options) {
|
||||
|
||||
this.username = false;
|
||||
this.key = false;
|
||||
this.host = false;
|
||||
this.method = 'GET';
|
||||
this.params = false;
|
||||
this.path = false;
|
||||
this.parsed = false;
|
||||
|
||||
Object.assign(this, options || {});
|
||||
|
||||
if(! this.username)
|
||||
throw new Error('Username is required');
|
||||
|
||||
if(! this.key)
|
||||
throw new Error('AIO Key is required');
|
||||
|
||||
if(! this.path)
|
||||
throw new Error('path is required');
|
||||
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
const step1 = this.hmac(this.key, this.date()),
|
||||
step2 = this.hmac(step1, this.host),
|
||||
step3 = this.hmac(step2, this.method),
|
||||
step4 = this.hmac(step3, this.params);
|
||||
|
||||
const signing_key = this.hmac(step4, this.version),
|
||||
canonical_request = this.hash(this.request),
|
||||
to_sign = `${this.algorithm}\n${this.date}\n${canonical_request}`;
|
||||
|
||||
return this.hmac(signing_key, to_sign);
|
||||
|
||||
}
|
||||
|
||||
get request() {
|
||||
|
||||
return `${this.method}\n${this.path}?${this.params}
|
||||
host: ${this.host}
|
||||
x-aio-date: ${this.date}`;
|
||||
|
||||
}
|
||||
|
||||
get version() {
|
||||
return 'aio-signature-v1';
|
||||
}
|
||||
|
||||
get credential() {
|
||||
return `${this.username}/${this.version}`;
|
||||
}
|
||||
|
||||
get date() {
|
||||
return (new Date()).toISOString();
|
||||
}
|
||||
|
||||
get algorithm() {
|
||||
return 'sha512';
|
||||
}
|
||||
|
||||
get algorithmName() {
|
||||
return `aio-hmac-${this.algorithm()}`;
|
||||
}
|
||||
|
||||
get path() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
set path(path) {
|
||||
|
||||
this.parsed = url.parse(path, true);
|
||||
this.params = Object.keys(this.parsed.query).sort().map(q => q.toLowerCase()).join('&');
|
||||
this.host = this.parsed.host;
|
||||
this.path = this.parsed.href.split('?')[0];
|
||||
|
||||
}
|
||||
|
||||
hash(data) {
|
||||
const hash = crypto.createHash(this.algorithm());
|
||||
return hmac.update(data).digest('hex');
|
||||
}
|
||||
|
||||
hmac(key, data) {
|
||||
const hmac = crypto.createHmac(this.algorithm(), key);
|
||||
return hmac.update(data).digest('hex');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports = module.exports = Signature;
|
||||
25
gulpfile.js
25
gulpfile.js
|
|
@ -1,34 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
const gulp = require('gulp'),
|
||||
jshint = require('gulp-jshint');
|
||||
eslint = require('gulp-eslint');
|
||||
|
||||
gulp.task('lint', function() {
|
||||
|
||||
const lint = jshint({
|
||||
"esnext": true,
|
||||
"curly": false,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"newcap": false,
|
||||
"noarg": true,
|
||||
"sub": true,
|
||||
"unused": "var",
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"node": true,
|
||||
"-W086": true
|
||||
});
|
||||
const config = {
|
||||
ecmaFeatures: {
|
||||
templateStrings: true
|
||||
},
|
||||
env: ['node', 'es6']
|
||||
};
|
||||
|
||||
return gulp.src([
|
||||
'index.js',
|
||||
'cli/*.js',
|
||||
'homekit/*.js',
|
||||
'client/**/*.js',
|
||||
'server/index.js',
|
||||
'server/lib/*.js',
|
||||
'tunnel/index.js',
|
||||
'tunnel/lib/*.js'
|
||||
]).pipe(lint).pipe(jshint.reporter('jshint-stylish'));
|
||||
]).pipe(eslint(config)).pipe(eslint.format()).pipe(eslint.failAfterError());
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
3
homekit/index.js
Normal file
3
homekit/index.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
exports = module.exports = {
|
||||
light: require('./light')
|
||||
};
|
||||
129
homekit/light.js
Normal file
129
homekit/light.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
'use strict';
|
||||
|
||||
const Hap = require('hap-nodejs'),
|
||||
Accessory = Hap.Accessory,
|
||||
Service = Hap.Service,
|
||||
Characteristic = Hap.Characteristic,
|
||||
uuid = Hap.uuid;
|
||||
|
||||
class Light extends Accessory {
|
||||
|
||||
constructor(name, io) {
|
||||
|
||||
super(name, uuid.generate(`adafruit:accessories:light-${name}`));
|
||||
|
||||
this.getService(Service.AccessoryInformation)
|
||||
.setCharacteristic(Characteristic.Manufacturer, 'Adafruit Industries')
|
||||
.setCharacteristic(Characteristic.Model, 'Adafruit IO Light')
|
||||
.setCharacteristic(Characteristic.SerialNumber, 'AIOLIGHT01');
|
||||
|
||||
// just call cb on ident
|
||||
this.on('identify', (paired, cb) => cb());
|
||||
|
||||
this._name = name;
|
||||
this._io = io;
|
||||
|
||||
this._state = {
|
||||
power: 0,
|
||||
brightness: 100,
|
||||
hue: 255,
|
||||
saturation: 100
|
||||
};
|
||||
|
||||
this._stream = this._io.Groups.writable(this._name);
|
||||
|
||||
let timer = setTimeout(() => {
|
||||
this._writeState();
|
||||
}, 1000);
|
||||
|
||||
this._stream.on('data', (group) => {
|
||||
|
||||
if(timer) {
|
||||
clearTimeout(timer);
|
||||
timer = false;
|
||||
}
|
||||
|
||||
group = JSON.parse(group.toString());
|
||||
|
||||
Object.keys(group.feeds).forEach((key) => {
|
||||
if(/^brightness/.test(key))
|
||||
this._state.brightness = parseInt(group.feeds[key]);
|
||||
if(/^power/.test(key))
|
||||
this._state.power = parseInt(group.feeds[key]);
|
||||
if(/^hue/.test(key))
|
||||
this._state.hue = parseInt(group.feeds[key]);
|
||||
if(/^saturation/.test(key))
|
||||
this._state.saturation = parseInt(group.feeds[key]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
const service = this.addService(Service.Lightbulb, `Adafruit Light`);
|
||||
|
||||
service.getCharacteristic(Characteristic.On)
|
||||
.on('set', this._lightOnSet.bind(this))
|
||||
.on('get', this._lightOnGet.bind(this));
|
||||
|
||||
service.getCharacteristic(Characteristic.Brightness)
|
||||
.on('set', this._lightBrightnessSet.bind(this))
|
||||
.on('get', this._lightBrightnessGet.bind(this));
|
||||
|
||||
service.getCharacteristic(Characteristic.Hue)
|
||||
.on('set', this._lightHueSet.bind(this))
|
||||
.on('get', this._lightHueGet.bind(this));
|
||||
|
||||
service.getCharacteristic(Characteristic.Saturation)
|
||||
.on('set', this._lightSaturationSet.bind(this))
|
||||
.on('get', this._lightSaturationGet.bind(this));
|
||||
|
||||
}
|
||||
|
||||
_lightOnGet(cb) {
|
||||
cb(null, this._state.power);
|
||||
}
|
||||
|
||||
_lightOnSet(value, cb) {
|
||||
this._state.power = value ? 1 : 0;
|
||||
this._writeState();
|
||||
cb();
|
||||
}
|
||||
|
||||
_lightBrightnessGet(cb) {
|
||||
cb(null, this._state.brightness);
|
||||
}
|
||||
|
||||
_lightBrightnessSet(value, cb) {
|
||||
this._state.brightness = parseInt(value);
|
||||
this._writeState();
|
||||
cb();
|
||||
}
|
||||
_lightSaturationGet(cb) {
|
||||
cb(null, this._state.saturation);
|
||||
}
|
||||
|
||||
_lightSaturationSet(value, cb) {
|
||||
this._state.saturation = parseInt(value);
|
||||
this._writeState();
|
||||
cb();
|
||||
}
|
||||
|
||||
_lightHueGet(cb) {
|
||||
cb(null, this._state.hue);
|
||||
}
|
||||
|
||||
_lightHueSet(value, cb) {
|
||||
this._state.hue = parseInt(value);
|
||||
this._writeState();
|
||||
cb();
|
||||
}
|
||||
|
||||
_writeState() {
|
||||
Object.keys(this._state).forEach((key) => {
|
||||
this._state[key] = this._state[key] || 0;
|
||||
});
|
||||
this._stream.write(JSON.stringify({ feeds: this._state }));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
exports = module.exports = Light;
|
||||
6
index.js
6
index.js
|
|
@ -1,3 +1,3 @@
|
|||
exports = module.exports = require('./client');
|
||||
|
||||
module.exports.CLI = require('./cli/index');
|
||||
exports = {
|
||||
Client: require('./client')
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,9 +19,8 @@
|
|||
"homepage": "https://github.com/adafruit/adafruit-io-node#readme",
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-jshint": "^1.11.2",
|
||||
"gulp-mocha": "^2.1.3",
|
||||
"jshint-stylish": "^2.0.1"
|
||||
"gulp-eslint": "^1.0.0",
|
||||
"gulp-mocha": "^2.1.3"
|
||||
},
|
||||
"keywords": [
|
||||
"adafruit",
|
||||
|
|
@ -45,12 +44,13 @@
|
|||
"dotenv": "^1.2.0",
|
||||
"express": "^4.13.3",
|
||||
"express-csv": "^0.6.0",
|
||||
"hap-nodejs": "^0.3.2",
|
||||
"inquirer": "^0.10.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mqtt": "^1.4.1",
|
||||
"nedb": "^1.1.3",
|
||||
"restler": "^3.2.2",
|
||||
"swagger-client-promises": "^1.0.2",
|
||||
"swagger-client": "^2.1.14",
|
||||
"swagger-tools": "^0.9.5",
|
||||
"winston": "^1.0.1",
|
||||
"xml": "^1.0.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue