diff --git a/bin/tessel-2.js b/bin/tessel-2.js index 1d610efe..f03bc285 100755 --- a/bin/tessel-2.js +++ b/bin/tessel-2.js @@ -23,18 +23,21 @@ function closeSuccessfulCommand() { process.exit(0); } -function closeFailedCommand(err) { - // If the returned value is an error +// Allow options to be partially applied +function closeFailedCommand(opts, err) { + if (!err) { + err = opts; + opts = {}; + } + if (err instanceof Error) { - // Throw it throw err; + } else { + // Print a stern warning by default + opts.type = opts.type || 'warn'; + logs[opts.type](err); } - // Otherwise - else { - // Print a stern warning - logs.warn(err); - } - // Exit with non-zero code + // NOTE: Exit code is non-zero process.exit(1); } @@ -186,12 +189,24 @@ parser.command('init') parser.command('wifi') .callback(function(opts) { - //TODO: Refactor switch case into controller.wifi + // TODO: Refactor switch case into controller.wifi if (opts.list) { controller.printAvailableNetworks(opts) .then(closeSuccessfulCommand, closeFailedCommand); - } else if (opts.ssid && opts.password) { - controller.connectToNetwork(opts) + } else if (opts.ssid || opts.password) { + if (opts.ssid && opts.password) { + controller.connectToNetwork(opts) + .then(closeSuccessfulCommand, closeFailedCommand); + } else { + var msg = opts.ssid ? + 'Please provide a password with -p ' : + 'Please provide a network name (SSID) with -n '; + closeFailedCommand({ + type: 'err' + }, msg); + } + } else { + controller.getWifiInfo(opts) .then(closeSuccessfulCommand, closeFailedCommand); } }) diff --git a/lib/controller.js b/lib/controller.js index 6ba2a1b3..f24dac12 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -451,6 +451,45 @@ controller.printAvailableNetworks = function(opts) { }); }; +controller.getWifiInfo = function(opts) { + return Tessel.get(opts) + .then(function(selectedTessel) { + return selectedTessel.getWifiInfo() + .then(function(network) { + // Grab inet lines, flatmap them, remove empty + // Wanted to do this with awk and cut inside commands.js + var ips = network.ips.filter(function(item) { + return /inet/.exec(item); + }) + .map(function(line) { + return line.split(' '); + }) + .reduce(function(a, b) { + return a.concat(b); + }) + .filter(function(item) { + return /addr/.exec(item); + }) + .map(function(chunk) { + return chunk.split(':')[1]; + }) + .filter(function(addr) { + return addr.length; + }); + + logs.info('Connected to "' + network.ssid + '"'); + ips.forEach(function(ip) { + logs.info('IP Address: ' + ip); + }); + logs.info('Signal Strength: (' + network.quality + '/' + network.quality_max + ')'); + logs.info('Bitrate: ' + Math.round(network.bitrate / 1000) + 'mbps'); + }) + .then(function() { + return controller.closeTesselConnections(selectedTessel); + }); + }); +}; + controller.connectToNetwork = function(opts) { // Grab the preferred Tessel return Tessel.get(opts) diff --git a/lib/tessel/commands.js b/lib/tessel/commands.js index 24bb17ae..24afdc89 100644 --- a/lib/tessel/commands.js +++ b/lib/tessel/commands.js @@ -4,6 +4,12 @@ module.exports.readFile = function(filepath) { module.exports.scanWiFi = function() { return ['ubus', 'call', 'iwinfo', 'scan', '{"device":"wlan0"}']; }; +module.exports.getWifiInfo = function() { + return ['ubus', 'call', 'iwinfo', 'info', '{"device":"wlan0"}']; +}; +module.exports.getIPAddress = function() { + return ['ifconfig', 'wlan0']; +}; module.exports.stopRunningScript = function() { return ['/etc/init.d/tessel-app', 'stop']; }; diff --git a/lib/tessel/wifi.js b/lib/tessel/wifi.js index 37b77f12..3ed3baf1 100644 --- a/lib/tessel/wifi.js +++ b/lib/tessel/wifi.js @@ -3,6 +3,10 @@ var Tessel = require('./tessel'), logs = require('../logs'), Promise = require('bluebird'); +function logErr(d) { + logs.err(d.toString()); +} + Tessel.prototype.findAvailableNetworks = function() { var self = this; return new Promise(function(resolve, reject) { @@ -12,9 +16,7 @@ Tessel.prototype.findAvailableNetworks = function() { var resultsJSON = ''; - remoteProcess.stderr.on('data', function(d) { - logs.err(d.toString()); - }); + remoteProcess.stderr.on('data', logErr); // Gather the results remoteProcess.stdout.on('data', function(d) { @@ -56,6 +58,56 @@ Tessel.prototype.findAvailableNetworks = function() { }); }; +Tessel.prototype.getWifiInfo = function() { + var self = this; + return new Promise(function(resolve, reject) { + return self.connection.exec(commands.getWifiInfo()) + .then(function(remoteProcess) { + var resultsJSON = ''; + + remoteProcess.stdout.on('data', function(d) { + resultsJSON += d; + }); + remoteProcess.stderr.on('data', logErr); + remoteProcess.once('close', function() { + try { + var network = JSON.parse(resultsJSON); + } catch (err) { + return self.connection.end() + .then(function() { + reject(err); + }); + } + + return self.connection.exec(commands.getIPAddress()) + .then(function(rp) { + var result = ''; + + rp.stdout.on('data', function(d) { + result += d; + }); + rp.stderr.on('data', logErr); + rp.once('close', function() { + try { + network.ips = result.split('\n'); + } catch (err) { + return self.connection.end() + .then(function() { + reject(err); + }); + } + + return self.connection.end() + .then(function() { + return resolve(network); + }); + }); + }); + }); + }); + }); +}; + function compareBySignal(a, b) { if ((a.quality / a.quality_max) > (b.quality / b.quality_max)) { return -1; @@ -95,7 +147,7 @@ Tessel.prototype.connectToNetwork = function(opts) { .then(function(remoteProcess) { // Once the credentials have been comitted remoteProcess.once('close', function() { - // Restart the wifi + // Restart the wifi return self.connection.exec(commands.reconnectWifi()) .then(function(remoteProcess) { // Once the wifi restart process closes