USB Missile Launcher controlled w/ Node.js and AngularJS


@TimPietrusky


Part #1

The Journey









Why are we here?

Hauke


Christmas




  Tony Hegewald |K.Schwarz  / pixelio.de 

Nerd stuff


USB Missile Launcher





Facts

  • Real name is "Thunder Missile Launcher"
  • Produced by Dream Cheeky
  • Includes 4 foam missiles
  • Costs 34,95 € on getDigital

Arrival

Runs on Windows 


Let's go on GitHub

Alternatives

& others written in Java, C, C++, PHP, Ruby... 

No fucking way


I want

  • an awesome UIX
  • to write my frontend- and backend in JavaScript
  • that the application runs on as many systems as possible

I want to learn

 


Part #2

The Talking





Use




Find

Find USB devices

    // https://github.com/node-hid/node-hid
var HID = require('node-hid'),
    // Get all devices connected to the computer
    devices = HID.devices();

// Show all devices
console.log(devices);

Output

// Informations about the connected device 
[{ vendorId: 8483,
  productId: 4112,
  path: '0003:0006:00',
  manufacturer: 'Syntek',
  product: 'USB Missile Launcher',
  release: 1,
  interface: 0 }]

Important

vendorId + productId = unique

path = system specific



Connect

Connect to a USB device

// Options
var options = { vendorID : 8483, productID : 4112 };
// Iterate over all USB devices
devices.forEach(function(device, index) {

    // Get a specific device
    if (device.vendorId == options.vendorID 
     && device.productId == options.productID) {

      // Open a connection to the device
      console.log(new HID.HID(device.path));
    }

}, this);

Output

// The handler for the device
{ domain: null,
  _events: { newListener: [Function] },
  _maxListeners: 10,
  _raw: {},
  read: [Function],
  write: [Function],
  getFeatureReport: [Function],
  sendFeatureReport: [Function],
  setNonBlocking: [Function],
  _paused: true }



Read

Read from a USB device

// Open the device
var connectedDevice = new HID.HID(device.path);
// Read from device
connectedDevice.on("data", function(data) {
  console.log(data);
});



Write

Write to a USB device

var command = { 
  left  : [2, 4, 0, 0, 0, 0, 0, 0],
  right : [2, 8, 0, 0, 0, 0, 0, 0],
  stop  : [2, 32, 0, 0, 0, 0, 0, 0] }
connectedDevice.write(command.left); // Turn left

setTimeout(function() {
  connectedDevice.write(command.right); // Turn right

  setTimeout(function() { 
    connectedDevice.write(command.stop); // Stop
  }, 500);

}, 500);



thunder-connector


Part #3

The Controlling






Express

Express

  • Web application framework for Node.js 
  • Routing
  • Handler
  • Views

Create a webserver

var express = require('express'),
    ThunderConnector = require('thunder-connector');
// Initialize Express
var app = express();
// Handle the default route
app.get('/', function(request, response) {

  // Handle request and send a response

});
// Listen on port x for a connection
app.listen(1337);

Handle request & send response

// Display the frontend if no action is given
if (!request.param('action')) {
  response.sendfile('app/app.html');
} else {
  var result = {
    // Send 'action' as a command to the device
    'result' : ThunderConnector.command(request.param('action')),
    'action' : request.param('action')
  };

  // Send the result back to the client
  response.json(result);
}



User Interface

Sketch

100 coffees later...

  • SASS
  • Grunt

Frontend



AngularJS

AngularJS

  • Model-View-Controller framework from Google 
  • Single page web applications
  • Custom tag attributes
  • Data-binding

Basic markup

<!-- Root element of the application -->
<html ng-app="ThunderCommander">
  <body 
    <!-- Attach controller class to view -->
    ng-controller="CommandCenterController" 
    <!-- Listen to keyDown/keyUp events -->
    ng-keydown="sendKey($event)" 
    ng-keyup="sendKey($event)"
    <!-- Change class based on the connection status -->
    ng-class="{'connected': connected, 'not-connected': !connected}"
  >

Controller

// Container of the application
var ThunderCommander = angular.module('ThunderCommander', []);
// Controller to manipulate the client scope
ThunderCommander.controller('CommandCenterController', 
  ['$scope', '$http', function($scope, $http) {

    // Application logic

}]);

Application logic

// Send a command based on the pressed key
$scope.sendKey = function(event) {
    switch (event.keyCode) {
      // Left arrow
      case 37 : $scope.sendCommand('left'); break;
    }
}
// Send a command to the server
$scope.sendCommand = function(command) {
  // Send an HTTP request to the server
  $http.get('/?action='+command).success(function(data) {
    // Do something with the result
  });
};



Result



The End?




#1

Thank you all!



#2

@TimPietrusky


slid.es/timpietrusky/frankfurtjs-20140319

FrankfurtJS 20140319

By Tim Pietrusky

FrankfurtJS 20140319

  • 3,740