Arduino <-> Tessel communication

8/21/2014– Jia Huang

This document will be kept up to date on Github

This is a tutorial for how to pass data back and forth between an Arduino and a Tessel.

The data is passed via a UART bridge. Arduino has the SoftwareSerial library for UART comm and Tessel has it’s built in UART functions.

UART works through having TX (transmit) and RX (recieve) pins. A TX of one device is hooked up to the RX of another device like this:

  • Tessel TX Arduino RX
  • Tessel RX Arduino TX
  • Tessel GND Arduino GND

Step 1: Get an Arduino

The Arduino needs to operate at 3.3V. Some boards which operate at this voltage are:

Both the Seeeduino and the Crowduino can switch between 5V and 3.3V.

Arduino Uno

Arduino Unos send over signals at 5V and this will damage Tessel. If you are planning on using an Arduino Uno, you need to make a 5V to 3.3V level converter which shifts the 5V UART TX signal from the Arduino to 3.3V.

The UART TX coming from Tessel is at max 3.3V, but this will register as a digital “high” signal so it does not need to be boosted up to 5V.

Step 2: Hook up the Arduino to the Tessel

There are 3 pins that need to be hooked up, UART TX, UART RX, and Ground.

In the code example, we’re going to be using Arduino’s SoftwareSerial on pins 10 and 11.

wiring an arduino to a tessel

  • Arduino Pin 10 (orange wire) Tessel Port D, pin TX/G1
  • Arduino Pin 11 (white wire) Tessel Port D, pin RX/G2
  • Arduino Ground (brown wire) Tessel Ground

Step 3: Program the Arduino

Run this code on the Arduino

#include 
#define rxPin 10 // connect to TX of other device
#define txPin 11 // connect to RX of other device

SoftwareSerial tesselBridge =  SoftwareSerial(rxPin, txPin);

void setup()  
{
  // open serial port at 9600 baud
  Serial.begin(9600);
  Serial.println("Starting up...");
  
  // set the data rate for the SoftwareSerial port
  tesselBridge.begin(9600);
}

void loop() // run over and over
{
  if (tesselBridge.available())
    Serial.write(tesselBridge.read());
  if (Serial.available())
    tesselBridge.write(Serial.read());
}

Step 4: Program Tessel

Make a folder for the code:

mkdir arduinoBridge;
cd arduinoBridge; touch uart.js;

Put this in the uart.js file.

var tessel = require('tessel');
var led1 = tessel.led[0].output(0);
var led2 = tessel.led[1].output(0);
var i = 0;

// baudrate must match the baudrate set in the Arduino file
uartBridge = tessel.port['D'].UART({baudrate: 9600}); 

uartBridge.on('data', function(data){
  // UART data is not packetized, so you will get the data 
  // buffer as the message is sent. This means that long
  // messages will be truncated as several events.
  
  var number = parseInt(data[0]) - 48; // convert hex to ascii to int
  console.log("got data", data, number);

  if (number == 1)
    led1.toggle();

  if (number == 2)
    led2.toggle();
});

// every 3 seconds write some data over to the arduino
setInterval(function(){
  uartBridge.write("Hi there "+i+"\n");
  i++;
}, 3000);

Run the code with tessel run uart.js, or if you want this to be persistent through power cycles, tessel push uart.js.

Step 5: Test it

You should be able to go into the Arduino console and see the blue and green LEDs on Tessel change as you enter a “1” or a “2”.

terminal

This document will be kept up to date on Github

Tessel Faster Better Stronger

8/20/2014– Nathan Lintz

How do we make Tessel faster? How do we keep Tessel simple for users yet powerful enough to take on big problems? What does it take to make a bulletproof wifi connected microcontroller that can truly deliver on the promise of the Internet of Things? These were just a few of the questions which guided the projects I worked on the summer.

To solve these sorts of problems, I focused on improving the speed of Tessel by writing new firmware apis and porting the Tessel platform to other chipsets. I learned a lot about developing hardware and software platforms, so I thought I’d share some of the insights I gained along the way.


How Fast? This Fast

Moving Pixels

I was inspired to work on improving the Tessel’s performance after reading a request on our forums for an LCD screen module. I naively believed that getting the Tessel to cooperate with a screen would be as simple as porting a C graphics library to JavaScript and plugging in an LCD.

My first attempt resulted in a graphics library which could output approximately 1 pixel a second. At this rate, filing a phone screen sized display would take approximately 100 hours…bummer. I profiled the program to find what was taking so long and it turned out that making a JavaScript call per pixel was causing the library’s performance to degrade dramatically.

Not wanting to give up quite yet, I decided to dive into the firmware and see if there was any way to pump out pixels at a faster rate. I created a new hardware API for the Tessel, the SPI Batch API, which improved the performance of the graphics library I wrote by a factor of 400! With this new implementation we went from making one JS call per pixel to one JS call for the entire screen. When I tested the library, colorful pixels began pouring into the screen, proving that graphics programming is possible on the Tessel.

Developing a graphics library and a firmware API for the Tessel taught me a lot about the power and limitations of JavaScript. When it comes to event driven programming and IO bound tasks, JavaScript is great. However, when it comes to matters of raw speed, C is usually the right answer. This insight can be distilled into the following heuristic which is applicable any time you’re writing code which involves hardware and software components:

For CPU bound tasks, like pushing pixels to a buffer,write your code in C. For IO bound tasks, like reading from a file or handling HTTP requests, use a high level language like JavaScript.

Portable Tessel - Modules Everywhere

After modifying the Tessel firmware to handle graphics, I talked to the team about other ways we could improve Tessel’s performance. We realized that many of our problems could be solved by having an operating system. At the moment, Tessel doesn’t run an operating system; rather, it has a firmware layer which can run a single program. As a result, we can’t use libraries which rely on an OS. By running Tessel on a Linux board, we would have access to these sorts of libraries such as V8, Google’s JS engine, and the Linux TCP stack. This insight blossomed into the Portable Tessel Platform, a node package which emulates the Tessel API on a computer such as the Raspberry Pi or Cubieboard.


Raspberry Pi

Cubieboard

I started off this project by writing up a spec and picking node libraries that would emulate the hardware APIs for the Tessel. Our modules each use either SPI, UART, GPIO pins, I2C, or some combination thereof. After some quick searching on NPM, I found found libraries which would implement the needed protocols.

The libraries I found seemed to work, so I assumed that all I had to do was wire the boards to the modules. Unfortunately, I neglected to make sure that the hardware of the different boards was similar enough to the Tessel and that Linux fully supported all of the drivers I needed. I began testing some of our modules on the Raspberry Pi and Cubieboard, and I found that I2C on the Raspberry Pi has issues communicating with our modules, as its processor doesn’t support certain commands such as repeated start transfers. Similarly, the Cubieboard doesn’t have SPI support unless you recompile the kernel drivers.

After discovering that the boards did not support the needed protocols, I began to research how other people got them working. It took a while, but eventually I found a way to properly compile the drivers for the Cubieboard and how to fix the I2C driver for Raspberry Pi. Once I had working drivers, I just had to hook up the boards to the Tessel modules and the Portable Tessel Platform was born. Now users can build projects using our hardware modules on their own boards, opening our platform up to people who haven’t purchased a Tessel yet.

Working on the Portable Tessel Platform taught me a lot about the challenges of hardware-software integration. In pure software projects, it is easy to just swap out or modify source code to meet your needs. In hardware, planning out everything ahead is necessary as some boards not have all the features you need. I was lucky that I found new drivers for the Cubieboard and Raspberry Pi, but picking boards which have full support for SPI and I2C would have made building the Portable Tessel Platform much easier.

Next year I’ll be back at college so you won’t be hearing from me on the blog for a while. Please message me @nlintz if you get a chance to build any exciting hardware projects on the Portable Tessel Platform or graphics projects using SPI Batch.

Best,
Nathan Lintz

Evan’s Summer Internship Farewell

8/18/2014– Evan Simpson

It feels like just last week that Jon turned to me in the car and asked, “now that you’re halfway through your internship, what do you think so far?” I then pointed out to him that I had only been at Technical Machine for three weeks, and had planned on staying for two more months, so I was nowhere near halfway done. I can’t really blame Jon for thinking I’d been there longer, since I joined during the busiest time of the company’s short history, when Tessel was getting ready to ship for the first time. That being said, I’m finding it hard to believe how quickly the remaining time has gone by.

The work that I did for Technical Machine was so diverse that there was never a dull moment. I started with small module examples and README fixes, and went on to actually adding functionality to the module libraries, as well as fixing bugs. At one point I was making changes to the runtime, at another, firmware. From hardware debugging and module design to web server development, I’ve certainly had my fill of fun things to work on. Through all of this fun work, though, I did learn quite a bit in just these short months, and I’d like to share some of those things with you now.

Internships Can be Meaningful Without Gimmicks

I’ve seen and heard about too many different intern programs that will include things like field trips and fun events to make sure the interns have a good summer. While I do appreciate the intent of these activities, I feel that sometimes it is done as a way of saying “sorry the work isn’t very interesting, let’s take a break and have some fun”. Working at Technical Machine I realized that when the work itself is fun, those other perks and gimmicks don’t really seem all that special. What I wanted out of an internship was to work on something I enjoyed with other people, and to feel like my accomplishments mattered to the company. That’s exactly what I got here at Technical Machine, and I couldn’t have asked for more.

Hardware Doesn’t Have to be Hard

I’d say I had a very basic understanding of electronics and hardware development before joining Technical Machine, having only worked with Arduino on a handful of different projects. That quickly changed as I started to make changes to different module libraries. I became much more familiar with how microcontrollers load and run programs, and the different protocols devices use to talk to each other over, with or without wires. The thing that struck me the most was how simple it all was. Most of the devices we use today are all digital electronics, which coming from a background in software development, isn’t nearly as complex as I thought it all was. Putting a “digital-only” constraint on a system means that it can translate very well from the hardware domain into the software domain, where it can be abstracted and automated with ease.

If you’re a software developer looking to learn more about hardware, I’d definitely recommend reading through some of the source code for some of the Tessel module libraries. They’re all written in JavaScript, so they’re easy to understand, but they also show you how the Tessel is communicating with the different modules. This also leads me straight into my next point…

Open Source is Great

Tessel is the first open source project I’ve ever contributed to, and I love it. I think there is a lot of good that can come from open source projects, whether they be based in software, hardware, data, or otherwise. Right now there isn’t nearly as much open source hardware as there is software, but there are still some good resources out there that are invaluable when it comes to starting a new hardware project. There were a few times when I was working on one of our modules and the best resources for debugging certain problems were other open source projects using similar parts.

Now that I’m all done, it’s time for me to return to school for one more year. I had a great time out here and I plan to continue contributing to the project in my spare time, so expect to see me around on Github.

See you around,
- Evan

P.S. If you’re interested in working or interning for Technical Machine, and want to know more about what it’s like day-to-day, let me know! I’d love to share more of my experiences.

Getting the CC3000 working with JavaScript

8/15/2014– Jia Huang

When Tessel’s wifi is connected the wifi chip’s features can be accessed through Node’s net and http libraries.

However, there are a few features of the CC3000 that do not fit within Node’s API, such as the ability to connect to a network, or exposing to a user that their network connection has been dropped.

We recently introduced the ability to control Tessel’s onboard wifi connections from JavaScript. It’s done through another library called wifi-cc3000 that now comes bundled on Tessel, much like the tessel library. It allows for something like this:

var wifi = require('wifi-cc3000');

// connect to a network
function connect(){
  wifi.connect({
    security: 'wpa2'
    , ssid: '#####' // network name
    , password: '#####'
    , timeout: 30 // in seconds
  });
}

// reconnect on dropped connection
wifi.on('disconnect', function(err, data){
  console.log("disconnect emitted", err, data);
  connect(); // try to reconnect
});

A more indepth example is on Tessel’s getting started page and the full documentation is on our docs page.

How it’s implemented

The technical details behind the wifi-cc3000 library are similar to how we expose other C functions to JS, with the exception of having to also work with the CC3000 wifi chip.

TI gives out a closed source firmware binary that gets loaded on to the CC3000, along with the C libraries needed to communicate with the CC3000. This provides us the socket interface and CC3000 specific functions like network connection.

It communicates over SPI, where our Tessel MCU acts as the master and the CC3000 is the slave device. In addition to the default SPI pins (clock, data in, data out, and slave select), it also has an interrupt pin (IRQ).

An interrupt is raised by pulling the IRQ pin low, which triggers an interrupt on our main MCU. This allows our microcontroller to give the CC3000 a set of commands (like go connect to X network), and then go do other processing until the CC3000 responds with a connected or disconnected event.

A typical call on the CC3000 looks like this:

  1. We call a CC3000 driver function.
  2. The command gets translated into a SPI signal which is passed to the CC3000.
  3. The CC3000 does some processing.
  4. The CC3000 fires an interrupt.
  5. We handle the interrupt by calling a CC3000 processing function to the interrupt handler.

Some calls from the CC3000 are unsolicited, such as when we drop a wifi network. In this case the CC3000 directly fires an interrupt without us initiating the call.

The wifi-cc3000 library needs to handle both types of calls:

  1. Calls which are initiated from the user, such as .connect.
  2. Unsolicited events from the CC3000, such as a disconnected event.

In order to make this easier, we wrote some wrapper libraries.

Calls initiated by the user

Calls initiated from JS are similar to any other JS -> C exposure (like our Pin API for example). It usually follows these three steps:

  1. Bind C functions to Tessel’s VM functions. We have two locations for this, one in the runtime repo, and another in the firmware repo. The bindings on runtime relate to anything needed for Node compatibility (such as the `net` lib) while the ones in firmware relate to how Tessel specifically operates (such as Pin toggling and LEDs). Since the wifi commands we’re looking at (connect, disconnect, setting timeouts) are specific to the CC3000 and not to Node, the bindings are in the firmware repo. A typical binding looks like this:
       static int l_wifi_is_busy(lua_State* L) {
         lua_pushnumber(L, hw_net_inuse() ||  
             tessel_wifi_is_connecting() ? 1 : 0);
        
         return 1;
       }
       
       
    This pushes a `1` into the global Lua context for this function’s return value if the wifi chip is in use, otherwise it pushes a `0`.
  2. Expose VM functions through a process binding to JS. All of our firmware’s hardware functions are bound to the `luaopen_hw` context. When Tessel first boots up we push in these functions into the VM.
  3. Wrap it in a JS library. We can link to a process binding in order to access the functions exposed through `hw`. This allows us to call C functions.
       self.isBusy = function(){
         return hw.wifi_is_busy() == 1 ? true : false;
       }
       

Unsolicited calls

Unsolicited calls are more complicated since we’re going from C -> JS.

All JS is handled inside of the event loop, so in order to surface up a call from C we have to wrap our C function as if it were an event and then push it to the head of the event queue.

The process is:

  1. Create a tm_event from C. In this case it’s the disconnect event.
       tm_event wifi_disconnect_event = TM_EVENT_INIT(wifi_disconnect_callback);
       
  2. On the C callback that the CC3000 triggers, also trigger the tm_event.
       void _cc3000_cb_wifi_disconnect ()
       {
           ...
           tm_event_trigger(&wifi_disconnect_event);
       }
       
  3. This pushes the event to the head of the event queue.
       void tm_event_trigger(tm_event* event) {
        tm_events_lock();
        if (event->pending == false) {
            event->pending = true;
            event->next = 0;
            if (event_queue_head) {
                // Link it on to the end of the existing linked list
                event_queue_tail->next = event;
                event_queue_tail = event;
            } else {
                event_queue_head = event_queue_tail = event;
            }
        }
        tm_events_unlock();
       }
       
  4. Push the event message on to the VM and clean up.
       void wifi_disconnect_callback(void) {
          lua_State* L = tm_lua_state;
          if (!L) return;
    
          tm_event_unref(&wifi_disconnect_event);
    
          lua_getglobal(L, "_colony_emit");
          lua_pushstring(L, "wifi_disconnect_complete");
          lua_pushnumber(L, 0);
    
          tm_checked_call(L, 2);
       }
       
  5. Listen for the hardware process in JS.
       process.once('wifi_disconnect_complete', function(err, data){
            self.emit('disconnect', err, data);
    
            callback && callback();
          });
       

For those of you who are curious and want to see the implementation, here’s pull request #40, which has all the changes in order to get the wifi-cc3000 library functional.

Getting Started with BLE + Tessel

8/11/2014– Evan Simpson

This document will be kept up-to-date on Github.

This guide is meant to be suitable for a Bluetooth novice. If you find any part of this guide hard to understand or inaccurate, let us know! We’d love to fix that. We hope that after reading this you’ll understand what is and is not possible with BLE, as well as know when to properly refer to a BLE device as an iBeacon.

Introduction

Bluetooth Low Energy (BLE/Bluetooth 4.0/Bluetooth Smart) is the most recent incarnation of Bluetooth technology put out by the Bluetooth SIG (the organization that maintains the specification). It is designed for applications in which transferring small amounts of data at a relatively low speed makes sense, and low power consumption is necessary. It is important to understand that BLE is not at all backwards compatible with older versions of Bluetooth.

Comparison to Classic Bluetooth

The list of reasons why Bluetooth Classic (also known as Basic Rate/Enhanced Data Rate - BR/EDR) and BLE are incompatible is extensive, but we’ll try to cover some of the more fundamental differences here. This section can help you decide whether BLE is right for the application you might have in mind.

Pairing and Bonding

In Bluetooth Classic, before any data can be exchanged a few things need to happen.

First, a master device needs to find a slave device to connect to. If the master has an address for a device, it can attempt to pair directly, without even scanning for devices. Bluetooth Classic devices can be either discoverable or non-discoverable, but can still be paired with while non-discoverable. So, even if the master did scan for the device and found nothing, there is still a chance the device is in range and not-discoverable, so it might as well try pairing any way. Once the two devices have paired successfully, exchanging pin codes and security keys if necessary, then they are bonded and can initiate a connection.

Once the devices are bonded, any time they come within range of each other, they will automatically connect, if possible. When the connection has been made, the devices can exchange data wirelessly as needed.

With the introduction of BLE, there are a number of differences to the connection process. First, in order to connect to a BLE device, the target device must be advertising that it is connectable. Second, a connection can be made without pairing, with pairing being left as an optional security mode. Finally, a connection does not have to be made in order to get data from a remote device. We’ll see how this is possible later on.

Data Model

Bluetooth Classic is set up to stream data from one device to another. It can accomodate data rates high enough to support streaming audio. One of the most popular use cases for Bluetooth has historically been serial cable replacement, which is just a two-way communication stream, conveniently made wireless.

BLE, on the other hand, exchanges data through a database located on one of the connected devices. Rather than keep an open stream of data, data is only exchanged when the database is modified, or a connected device requests a value from the database. For this reason, it doesn’t really make sense to use BLE in the same way Bluetooth Classic has been used, but there are plenty of new applications involving sensors and other devices exchanging small amounts of data, which BLE was designed for.

Dual Mode Devices

There are some devices, such as cell phones and computers, which need to be able to connect to both types of devices. These devices will have Bluetooth hardware that separately supports both versions. This class of devices is referred to as dual-mode, contrary to a single-mode device, which is only compatible with same-version devices and dual-mode devices.

BLE Roles

The BLE specification allows a device to take on various roles that define the specific actions the device may be capable of. There are really two types of roles, with each device in a network fulfilling one of each type of role. The two types are central or peripheral, and client or server.

Central vs Peripheral

The central and peripheral roles describe the order of command in a BLE network. The role of the central device is similar to that of the master in Bluetooth Classic. The central device is responsible for searching for and establishing a connection with one or more peripheral devices.

The role of the peripheral device is similar to that of the slave in Bluetooth Classic. The peripheral device advertises whether or not it is connectable, as well as any services it might provide. The central can use that data to decide if it should connect to the peripheral or not.

Client vs Server

The client and server roles describe the data ownership and transmission relationship in a BLE network. In a typical network, the central device will take on the role of client - requesting and sending data from and to one or more server devices.

Peripheral devices will typically take on the role of server. Servers keep a database of attributes that a connected client can write to, and read or subscribe to changes from.

Beacons

A beacon is a specific implementation of a peripheral device that does not act as a server. All of the data a central device needs from a beacon is broadcast through the advertisement, so there is no need to connect to request the data. It is also important not to confuse any generic BLE beacon with iBeacons.

Generic Attribute Profiles

Generic Attribute Profiles (GATT Profiles) are used to define the hierarchical structure of the database a server uses to store the data it makes available to clients. A profile consists of services, each of which may contain multiple characteristics. The core specification has a small set of pre-defined profiles, however the specification does allow you to create your own.

Characteristics

A characteristic represents one data attribute that a client can access. Each characteristic can store only a single value at a time. Each characteristic can have different access permissions such as read, write, and notify.

Services

A service is used to group a category of characteristics. All characteristics must belong to a service. Usually when central devices are looking for a device to connect to, they will look to see if they support a particular service, rather than an individual characteristic.

UUIDs

Every service and every characteristic must be assigned its own Universally Unique Identifier (UUID). This UUID is how devices will look for and recognize if another device supports a particular attribute. There is a set of reserved 16-bit and 32-bit UUIDs outlined in the core specification that have a predefined or reserved use across both services and characteristics. The list of profiles linked above makes use of this reserved space. If you are looking to create your own profile, the best way to get UUIDs is through the command line tool uuidgen if you are on OS X or Linux, or through a simple online service like http://www.uuidgen.com/.

Tessel’s GATT Profile

Below, we show a portion of the Tessel’s GATT profile, which has two unique services. One service is for sharing the BLE module’s firmware version, and the other is for sending and receiving data.

The second service has a total of 12 characteristics which can be used generically for sandboxed design and prototyping of your own services.

{
  "services" : [
        {
            "uuid" : "08c8c7a06cc511e3981f0800200c9a66"
          , "description" : "Tessel Firmware Information"
          , "characteristics" : [
                {
                  "uuid" : "50888c106cc511e3981f0800200c9a66"
                , "id" : "c_tessel_firmware_version"
                , "description" : "Firmware Version"
                , "value" : "1.0.1"
              }
            ]
        }
      , {
            "uuid" : "d752c5fb13804cd5b0efcac7d72cff20"
          , "id" : "data_transceiver"
          , "description" : "Data Transceiving"
          , "characteristics" : [
              {
                  "uuid" : "883f1e6b76f64da187eb6bdbdb617888"
                , "id" : "c_trans_0"
                , "description" : "Transceiver Value 0"
                , "properties" : ["read", "write", "indicate", "notify"]
                , "length" : "255"
              }
              .
              .
              . // The full service contains 12 generic characteristics
              .
              .
              , {
                  "uuid" : "4a0efa07e1814a7fbd72094df3e97132"
                , "id" : "c_trans_11"
                , "description" : "Transceiver Value 11"
                , "properties" : ["read", "write", "indicate", "notify"]
                , "length" : "255"
                }
            ]
        }
  ]
}

You can find a JSON version of the Tessel’s entire GATT Profile, including omitted services and characteristics, in the ble-ble113a library. Please note that this is just a description of the GATT profile, which is actually defined in the firmware of the BLE module. Making changes to the GATT profile on the module requires creating a modified version of the firmware and uploading it to the module. A guide for doing this is coming soon.

Advertisements

In order to form a connection between two devices, the peripheral device must broadcast an advertisement for the central device to see. An advertisement packet contains the perihperal device’s address, as well as a device-configurable section of data that can contain various kinds of data. A scanning central device can also request a scan response from a peripheral, which has the same format as an advertisement, but can contain different, additional data. Think of a scan response as a second advertisement that can be sent upon request.

Advertising packet data

The type of data an advertisement can contain is strictly defined by the core specification and a full list of available data types can be found here. Fortunately, we have put together an npm module called bleadvertise to help you create and decode advertising data packets in a more semantic manner. Some of the more common data types to put in the advertisement are Flags (which is more or less mandatory), Incomplete List of 128-bit Service UUIDs, either Short Local Name or Complete Local Name, as well as Manufacturer Specific Data which is used in iBeacons. The maximum length an advertising data packet can be is 32 bytes, so this is an important consideration in designing what kinds of information to put in the advertisement and/or scan response.

Finding the right device

When a central device is looking for a specific device or specific type of device, it has a few options in terms of what to look for in an advertisement to determine whether or not to connect. The two most common pieces of advertising data that are examined are the device address, and the complete or incomplete list of supported services. Sometimes the address is not the best way to keep track of a device, because many devices use what is known as a random address which will change relatively frequently, and in this case, other information in the advertisement should be used to pick a device.

iBeacons

While any peripheral device can be a BLE beacon, and can beacon any data it wants to, there is now a very popular type of beacon specification created by Apple called the iBeacon. iBeacons are meant to be used for location-based applications, where high accuracy is important (i.e. inside a grocery store). The advertisement packet for an iBeacon is relatively simple consisting of a 128-bit location UUID followed by 2-Byte Major region code and 2-Byte Minor region code, marked as Manufacturer Specific Data. You can read more about the specification and licensing on Apple’s developer website.

Advertising Examples

The following example will show you how to set up a Tessel with a custom advertisement.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');
var bleadvertise = require('bleadvertise');

var packet = {
  flags: [0x02, 0x04], // Connectable, BLE only
  incompleteUUID128 : ['08c8c7a06cc511e3981f0800200c9a66'], // Tessel Firmware Version Service UUID
  shortName : 'Tessel'
}

var ad = bleadvertise.serialize(packet);

var peripheral = bleLib.use(tessel.port['A'], function(){
  peripheral.setAdvertisingData(ad, function(){
    peripheral.startAdvertising();
    console.log('Now advertising');
  });
});

That’s it! We’ll come back and add more to this later, once we learn about receiving connection events from a central device.

The example for creating an iBeacon is similar, but uses slightly different data.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');
var bleadvertise = require('bleadvertise');

var uuid = 'D9B9EC1F392543D080A91E39D4CEA95C'; // Apple's example UUID
var major = '01';
var minor = '10';

var iBeaconData = new Buffer(uuid+major+minor, 'hex'); // Create data Buffer

var packet = {
  flags: [0x04], // BLE only
  mfrData : iBeaconData
}

var ad = bleadvertise.serialize(packet);

var beacon = bleLib.use(tessel.port['A'], function(){
  beacon.setAdvertisingData(ad, function(){
    beacon.startAdvertising();
    console.log('Beaconing');
  });
});

Since beacons generally aren’t meant to connect to other devices, this is pretty much everything you need to make a beacon. Of course, if you want to beacon something besides a static value, you’ll need to make some changes, but that’s the gist of it.

Connecting

Now that we understand how peripherals let central devices know they’re available, let’s look at how the central finds them and initiates a connection.

Scan for Peripherals

The first step in discovering advertising peripherals is with a device scan. In the scanning process, the central will listen for advertisements and report when it finds one. On most platforms, there will be scanning options that let you filter discovered peripherals by the service UUIDs in their advertisements, and also prevent reporting of duplicate devices. Once you have discovered a suitable device to connect to, just send a connect command and you’re ready to start exchanging data!

Security

With BLE there are two main modes of secure data exchange - encryption and bonding, as well as three different methods for exchanging encryption keys - Just Works, Passkey Entry, and Out of Band.

Encryption and Bonding

With BLE, a connection can be encrypted with a short term key through pairing, and it can also be encrypted with a long term key through bonding. When paired, the encryption will last for the duration of the connection, and will need to be re-encrypted each time the connection is established. Through bonding, the devices will store the encryption keys, such that each time they re-connect, they will attempt to encrypt the connection. The simplest, however insecure, means of encrypting the connection is called Just Works and uses an exchanged passkey of 000000, so there is no required input from the user. The more secure options are Paskey Entry and Out of Band. To use Just Works pairing with a Tessel in the central role, call the ble.startEncryption() method after a connection has been made.

Passkey Entry

With passkey entry pairing, there is a requirement that one device be capable of displaying a passkey value (6 digits) and the other device be capable of inputting the passkey. When the passkey is displayed, it is up to the user to enter the code on the input device. Once the passkey is confirmed, the connection will be encrypted. There is no requirement that the the central or peripheral take on either display or input roles, just that both are implemented between the two devices. To enable passkey entry on a Tessel central device, call ble.setMITMProtection(true) as well as ble.setIOCapabilities() to identify the device as a display or input before scanning for devices. After connecting, once again call ble.startEncryption() to start the passkey process. In either central or peripheral mode, a Tessel can receive a 'passkeyDisplay' or 'passkeyRequest' event, and can input a displayed passkey with the ble.enterPasskey(000000) method.

Out of Band

Out of Band (OOB) pairing requires the use of another means of communication, besides BLE, to exchange encryption keys. A common example of an OOB exchange would be over NFC. Once the devices have exchanged keys over NFC, the data is relayed to the BLE controller, and the connection can be encrypted using the keys. This method is the most secure option BLE currently offers to prevent MITM attacks. Implementing OOB security on a Tessel is similar to passkey protection, however instead of needing to set the IO capabilities, you need to use ble.setOOBData(data), where data is a 16-byte string. If either one of the connecting devices has OOB data set, then the other will need to have the same data set in order for the connection to be encrypted.

Connection Examples

First let’s see what our code looks like on a Tessel acting as a central device that wants to connect to another Tessel acting as a peripheral. Let’s assume that the peripheral is advertising the same packet from our first advertisement example above.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');

var serviceUUID = ['08c8c7a06cc511e3981f0800200c9a66']; // UUID to filter for
var central = bleLib.use(tessel.port['A'], function(){
  central.startScanning(serviceUUID); // Start the scanning process
  central.on('discover', function(peripheral){ // Catch the discover event
    peripheral.connect(); // Connect to this device
  });
  central.on('connect', function(peripheral){ // Catch the connect event
    console.log('Connected to', peripheral.address.toString());
  });
});

As you can see we have two events we can listen for that let us know when a new device has been discovered or connected to.The connect event works for both central and peripheral devices, so we can go back to our advertisement example and add a listener for a connect event.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');
var bleadvertise = require('bleadvertise');

var packet = {
  flags: [0x02, 0x04], // Connectable, BLE only
  incompleteUUID128 : ['08c8c7a06cc511e3981f0800200c9a66'], // Tessel Firmware Version Service UUID
  shortName : 'Tessel'
}

var ad = bleadvertise.serialize(packet);

var peripheral = bleLib.use(tessel.port['A'], function(){
  peripheral.setAdvertisingData(ad, function(){
    peripheral.startAdvertising();
    console.log('Now advertising');
  });
  peripheral.on('connect', function(connectionId){
    console.log('Connected to central device');
  });
});

When the connection is established the central will automatically stop scanning, and the peripheral will stop advertising. Since the central can handle connections with multiple peripherals, you can start scanning again and look for another device, if needed.

Transferring Data

Once we have established a connection, we can start transferring data back and forth between our devices. This is where the terms client and server become relevant again. For this tutorial let’s assume our central will play the role of client, and the peripheral will be the server. With BLE all data is read from and written to the server’s GATT database, which is that data store who’s structure is defined by the GATT profile, discussed above.

Service Discovery

In order for a client to read and write characteristics on a remote server, it first needs to know which services and characteristics are available. To get this information, the client can request the server send over a list of all of its services and characteristics. Part of this service discovery includes a short 1-byte handle value for each characteristic. Once the client has the handle, it will use that instead of the 16-byte UUID for each exchange. This handle will be unique on different devices for characteristics with the same UUID, so it is always necessary to do a service discovery in order to get the proper handle, even if you already know the UUID.

Updating a local GATT database

Since the GATT database lives on the server, it should always have direct access to the data being exchanged. The way this is handled will vary by platform and device, but most devices that support server mode should have methods for directly updating and reading values in the GATT database.

Updating a remote GATT database

Once the client has access to the handle for the characteristic it needs to read or write to, doing so is pretty straightforward. Again, any reasonable platform should expose methods for reading/writing methods through its API. At this point it probably also important to mention that you should make sure the permissions on the characteristic you are trying to access allow your desired operation. On the Tessel, all of the Tessel-specific characteristics can be read, and all of the characteristics in the Transceiver service can be written and subscribed to, as well.

Subscribing to changes on a remote GATT database

For some applications, you don’t want to periodically check if a remote value has updated, but would rather get a notification when it has, and only then read the value. BLE allows this through two similar mechanisms. A client can set up either notifications or indications on a particular characteristic, assuming the server permissions allow it. Once a client subscribes to notifications, any time the server makes a change to the subscribed characteristic, it will let the client know, along with a short preview of the data. If the entire piece of data does not fit in the notification, the client can then send a read request for the rest. An indication works the same way, except the client must send a message back to the server, acknowledging that it received the indication.

Data Transfer Examples

Let’s go ahead and add to our earlier connection example, and make our two devices exchange data. First we’ll set up our central as a client by adding a service discovery request, looking for the first transceiver characteristic, and then subscribe to notifications.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');

var options = { serviceUUIDs : ['08c8c7a06cc511e3981f0800200c9a66'] }; // UUID to filter for
var characteristicUUID = ['883f1e6b76f64da187eb6bdbdb617888'] // Characteristic we will write to
var central = bleLib.use(tessel.port['A'], function(){
  central.startScanning(options); // Start the scanning process
  central.on('discover', function(peripheral){ // Catch the discover event
    peripheral.connect();
  });
  central.on('connect', function(peripheral){
    console.log('Connected to', peripheral.address.toString());
    peripheral.discoverCharacteristics(characteristicUUID, function(err, characteristic) {
      if (characteristic.length){
        characteristic[0].notify(true);
        characteristic[0].on('notification', function(data){
          console.log('Got notification', data.toString());
        });
      }
    });
  });
});

And now we’ll update our peripheral example with some corresponing server functionality. We’ll need to set it up to listen for when the client subscribes to a characteristic. Once that happens, we can periodically update the value and the client should automatically receive notifications.

var tessel = require('tessel');
var bleLib = require('ble-ble113a');
var bleadvertise = require('bleadvertise');

var packet = {
  flags: [0x02, 0x04], // Connectable, BLE only
  incompleteUUID128 : ['08c8c7a06cc511e3981f0800200c9a66'], // Tessel Firmware Version Service UUID
  shortName : 'Tessel'
}

var ad = bleadvertise.serialize(packet);

var peripheral = bleLib.use(tessel.port['B'], function(){
  peripheral.setAdvertisingData(ad, function(){
    peripheral.startAdvertising();
    console.log('Now advertising');
  });
  peripheral.on('connect', function(connectionId){
    console.log('Connected to central device');
  });
  peripheral.on( 'remoteNotification', function(connectionId, index){ // Catch when remote subscribes
    console.log('Notifications started');
    var count = 0;
    setInterval(function(){
      peripheral.writeLocalValue(index, new Buffer( count.toString() )); // Write to [index] transceiver value
      count++;
    }, 2000);
  });
});

Testing and Debugging

When working with BLE you might encounter an issue that you realize you have no way to resolve, especially if you are using a device which you cannot make any changes to. The following are some of the most helpful that we’ve found in working with Bluetooth.

LightBlue

LightBlue is an OS X and iOS application that allows you to see and connect to BLE devices, as well as run a service discovery, and make read/write/notify requests. This is great if you are working with a peripheral device and want to see it from the perspective of a central device.

Noble

Noble is a Node library which allows you to access the BLE capabilities of newer Mac Books as well as Linux laptops with the appropriate hardware. Noble allows you to set up your laptop as a central device, and its companion library, Bleno, allows you to set up the computer as a peripheral.

Links

This document will be kept up-to-date on Github.

Introducing the Tessel Projects Portal

8/13/2014– Kelsey Breseman

We’ve just released Tessel’s Projects Portal, a site for Tessel hackers to show off what they’ve made. It’s designed to be simple: an aggregator requiring little more than a Github link and a picture to show off a project. The simplicity is deceptive, though: there’s something important happening at the intersection of open source software and a physically modular open system.

The interaction for the Tessel projects portal lies somewhere between Instructables and Thingiverse. Since your projects might require some special setup (hardware or software), projects are given space for photos and explanation– like Instructables.

There’s also the capacity for plug-and-play interaction. For example, clap-on lights is now a solved problem. Plug the pieces together, push the code, and clap: easy as Ikea. Projects exist fully-formed, and anyone can just download the product, like on Thingiverse.

But what happens when you build something more complex? A Nest-type project for your greenhouse, for example, or a motion-tripped home security camera. It’s not exactly DIY when the interaction is plug-and-play (and clone the code). It’s more like a system of highly configurable modular appliances.

This is, I think, a step closer to the promise of consumer 3D printing. When you think of 3D printers in every home, you think of people downloading products all the time, printing out the objects they need, maybe customized for their particular application.

With current 3DP, you see a lot of excitement, but not a lot of practical purpose in the consumer sphere. It turns out that there aren’t many everyday problems that can be solved with a specifically shaped piece of weak plastic. But what if you could add brains to that piece of plastic? What if right alongside the 3D file was a link to some code and two or three simple parts that you could slot together?

This is the intersection of freely licensed software and open source hardware; this is open source products. You can get a kit, tweak it to your needs, and interact from an interface (online or off) that you control.

What’s more, you can reach in to this product at any level; nothing is proprietary, and there’s no warranty to void. If you’re a software developer, you can fork the way that data is collected, the way it’s presented, the interaction with outside libraries. If you know hardware, you can swap out your own parts in place of our modules and still run the code. This is open; this is indie; this is just plain cool.

Open source has a lot of existing community and infrastructure, but not yet one with this particular facet of digital and physical modularity. That’s why we made the Projects Portal, hoping to develop it into a testing ground for open projects and products. We seek to empower, and this is a powerful idea.

You can use our Projects Portal to gauge reactions to your projects and products. You can try to determine if an interaction holds value, seeking beta testers from our community of people who already have the parts.

If you want to test out something someone has already made, you can git clone, tessel run. It’s simple, and you don’t have to reinvent it.

There’s also the whole spectrum between: you can write a library for a component, or a node module for an interaction. You can make a piece of a project, a unitary interaction, so people can fork it or require it and build from there.

This is a whole open source ecosystem; it’s time to start building.

Check out the projects portal at projects.tessel.io.

Tessel Projects Page, New Hire, and More

8/12/2014– Updates

Tessel Projects Portal

We’d like to invite you to try our new (beta) projects portal! Check it out at projects.tessel.io. Find ideas of what to build next, get example code, show the community what you’re capable of building. We’re excited to see the things you’ve made!

Updates

In the last month, we..

  • Published a bunch of firmware updates, JS/Node compatibility fixes, and wifi improvements (see the changelogs)
  • Exposed Wifi in the JS
  • Wrote the BLE getting started guide
  • Successfully ported LuaJIT to ARM Cortex M3 on PC. We still need to get it working on Tessel itself to realize the speed improvements. Look for a timeline soon!
  • Beefed up our testing infrastructure so that we can run a suite of tests on every module with every change to the firmware or module drivers
  • Sponsored Nodebots day

We also made progress on:

  • Building out the backend infrastructure for remote code deployment. Over the next week, we need to add the firmware-level changes to accept tarballs over Wifi
  • Putting together a better internal system of engagement metrics (support, sales, sponsorship, etc.) so we can work with you more effectively
  • Rewriting our JS->Lua translator in C so that we can eventually compile on Tessel itself. This will allow the use of functions like eval() and Function()

Company-wise, we made a hire! We’re pleased to announce Ken Nierenhausen is joining our team. One of his focuses will be improving Node compatibility (near and dear to all of our hearts).

The docs repo is continually growing and changing. At the moment, the repo holds more tutorials than we link to on tessel.io/docs, so feel free to poke around. We’ll try to highlight some of these documents in upcoming blog posts.

Research and Development

Expect to see blog posts soon regarding our efforts in R&D. We’re currently looking into:

  • Potential new modules
  • A new version of Tessel
  • Tools to help you transition from a prototype to a scalable embedded system
  • Expanding the Tessel module ecosystem to other platforms (so far we have the Tessel library working on the Raspberry Pi and Cubieboard: node module [pre-production])

All of these will take some time to develop, but what we wanted to let you in on what we’re exploring. We’d love to hear from you on the Forums or via email!

See you on the forums,
Eric, Jia, Jon, Kelsey, Ken, Kevin, Tim, Evan, Nathan, and Paige

New Hire: Ken Nierenhausen

8/11/2014– Ken Nierenhausen

Hey guys!

I’m Ken. I am the first new hire that happens to not have gone to Olin. I come from San Diego, and after receiving my degree in Computer Engineering from UCSD I’m excited to be joining the team.

During my time in San Diego I focused a lot on lower level software development and design; architecture, networking, things like that. I interned at Pico Digital as well as ViaSat Inc. During my time at UCSD I became interested in the startup world due to local entrepreneurs like Brant Cooper. I decided to give it a try and started working on the early stages of my own startup with a couple buddies of mine. We called ourselves Allnighters and were focused on bringing up to date sales, deals, and discounts directly to your phone based off your location. Although we did have a taste of success thanks to San Diego’s up and coming startup scene, our team fell apart as we did not have the resources or support that we needed to continue. My failures taught me a lot, and I joined an on-campus startup incubator as a student advisor to try and help teams make it further than I did. It was a great experience that instilled in me an entrepreneurial mindset.

Before graduation, seeing that I didn’t have my own startup anymore, I accepted an offer with a big name software company.

After graduation I took a trip to San Francisco to experience where I was going to be working. This is where I managed to get ahold of Jon McKay, an old friend who had started his own company. I was interested in seeing how managing his own startup was going so I went and saw the place. It was fantastic. There was a brilliant team of software and hardware developers and I wanted to be part of it. Jon asked me to interview and after a few discussions, interviews, and a contracted project, I was lucky enough to get onboard with the visionary members of Technical Machine. I said no to the big name software company and made my way to Berkeley.

My main focus here will be on firmware and runtime. My first big project is going to be trying to get Tessel to be as node compatible as possible. In the meantime I’ll be working on improving the performance of Tessel runtime as well as incorporating some new ideas into firmware.

I’m excited to be part of the team and look forward to interacting with all of you. If you want to contact me feel free to email me at ken@technical.io

Cheers!

You Probably Don’t Need an iBeacon

8/8/2014– Evan Simpson

First, a quick background on Bluetooth

You might remember a time when the word Bluetooth was synonymous with hands-free headsets and wireless speakers. These devices gave Bluetooth a bad reputation with their poor sound quality, poor battery life, and poor interface for connecting to cell phones and computers. Since then, however, Bluetooth has come a long way, seeing huge improvements in device quality, as well as a much greater level of support in mobile and desktop operating systems.

Back in 2010, the Bluetooth Special Interest Group (SIG) put out the 4.0 specification for Bluetooth. The goal of the new specification was to enable the creation of Bluetooth devices which operate at a low data rate, have low power consumption, and have low manufacturing costs. This was a departure from the existing specification, which had been optimized over the years for always-open, high data-rate streams. This old standard was great for applications like streaming audio, but not for others such as reading data from sensors.

The new specification is designed for devices that only needed to connect occasionally to exchange small pieces of information, and can be put into a low power state in between exchanges. This mode of operation means big power savings for devices, to the extent that some Bluetooth 4.0 devices can be powered by a coin cell battery for months to years at a time, depending on the application. In the past few years, Bluetooth 4.0 has been rebranded as Bluetooth Smart by the SIG, but is now more colloquially known as Bluetooth Low Energy, or BLE.

Enter Apple

Though the specification came out over 4 years ago now, BLE has only much more recently seen mainstream adoption into connected devices. Arguably, one of the greatest contributors to BLE’s popularity has been Apple. By looking at Google search trends, we can see a surge in interest for “Bluetooth 4.0” in October of 2011, right around the time the iPhone 4S was released with support for, you guessed it, Bluetooth 4.0. In being the first big player to support the technology, Apple paved the way for other device manufacturers to support BLE, by giving them a central device to connect to. For comparison, the Android SDK didn’t have any support for BLE until late 2013 and will not have complete support for everything BLE can do until the release of Android L, and Windows Phone only began official support for BLE with this year’s 8.1 update.

Google Search trends for “Bluetooth 4.0”

Google Search trends for “Bluetooth 4.0”

More recently though, Apple has released a specification for creating location based services with BLE devices, under the brand iBeacon. iBeacons have become popular enough and we get enough questions about them that it warrants clarifying what they are, how they work, and how they are different from other BLE devices.

What is an iBeacon?

Part of the Bluetooth 4.0 specification outlines a format for an “advertising data packet” which is a small amount of data (maximum 32 bytes) that a BLE device can publicly broadcast to any other nearby devices, without needing to connect. The primary use for the advertisement is for a device to advertise the kind of services or data it provides, information on how to connect to it, or the device’s name. However, the format specification does allow for some of the data available on the device to be broadcast as well, so other devices don’t have to make a connection in order to collect sensor data. When a BLE device is designed to put all of the data other devices might need in the advertisement, it is typically called a “beacon” - all information is out-going.

At their most basic, iBeacons can be seen as a proprietary beacon, where they make use of the specification’s allowance for “Manufacturer Specific Data”, which can contain any arbitrary data that will fit. Apple defined their own format for a single location code to be contained in this section of an advertisement. Any other nearby BLE device (such as a smart phone) can then pick up the advertisement and parse out the location code.

iBeacons are deceptively simple to create, because they only require a BLE radio chip (almost any BLE radio chip will do) and don’t require any application-specific software to run on the device itself. It is up to the application running on the discovering device to know what to do with the location code pre-programmed on the iBeacon. This means that any device which implements the BLE specification can function as what Apple has trademarked an iBeacon. The actual capabilities of an iBeacon are minimal, with their utility lying in the applications people create around them.

The unfortunate side effect of the popularity of iBeacons is that they have become synonymous with BLE to many people, in much the same way that Bluetooth used to be synonymous with hands-free headsets. One thing I’ve seen all too often is products like Tile and Bean being referred to as iBeacons (although the Bean does allow you to set it up as an iBeacon, it isn’t by default). Not only has this led to a lot of confusion for people trying to get started prototyping with BLE, but it has also resulted in a sort of “bandwagon” effect, where people trying to design systems around iBeacons in order to take advantage of the brand power, but for applications where an iBeacon maybe isn’t appropriate. It means that much of what BLE is capable of is being overlooked, and that’s not to mention other means of wireless communication which might be appropriate in certain applications as well (but we can save that discussion for another time).

So how does Technical Machine’s BLE module fit in with all of this? Our BLE module allows you full control over the advertisement data, making it easy to set up an iBeacon, or design a beacon format of your own. If you’re looking into an open alternative location service format without the licensing hurdles Apple has for iBeacons, check out AltBeacon. If you want your device to be more than a beacon, the BLE module gives you access to all of the functionality outlined in the 4.0 specification, so you can interact with any other BLE device.

If you want to learn more about how BLE works, and how to get started making BLE connected devices, check out our Getting Started Guide.

Making a Tessel-style Library for Third-Party Hardware

8/7/2014– Kelsey Breseman

Find this document on Tessel’s docs repo, where it will be kept up to date.

There’s a lot of existing hardware from Seeed, Adafruit, and elsewhere that can be used with Tessel. Though it’s not that difficult to hack together a project based on the hardware API docs, making an npm module for the hardware is a nice way to interface cleanly with the hardware, and reuse a custom API across projects.

I’ve so far done this with a PIR motion detector and a pulse sensor:

This tutorial walks you through the process to go from a piece of hardware to a Tessel-style npm module.

For this tutorial, I used a PIR motion detector from Adafruit to make this npm module.

Understanding your hardware

Before you start, it would be a good idea to check out Tessel’s hardware docs and hardware api docs. These two documents will give you a good idea of Tessel’s capabilities and available interfaces. As a general rule, anything that can be used with an Arduino can also be used with a Tessel. Tessel reads in a maximum of 3.3V, so if your part outputs more than that, don’t fry the board!

Tessel can:

  • Read and write digital signals (3.3V when high; 0V when low)
  • Write PWM signals (“duty cycles”)
  • Read analog signals
  • Communicate over SPI (MISO, MOSI, and SCK)
  • Communicate over I2C (SDA and SLC)
  • Communicate over UART (TX and RX)
  • Provide 5V power* (if Tessel is powered over USB. Please see Powering Tessel)
  • Provide 3.3V power (a digital pin set to output(1) (high))

For the PIR sensor, I needed one 3.3V digital signal pin and 5V of power. It will typically say what you need on the manufacturer’s page, straight out or on a datasheet. Adafruit typically says these things in the description field of a product page, as does Seeed.

Setting up the repo

Tessel’s modules all have the same basic directory. You can see a template for Tessel modules in general on our style guide here. You might want to check out the PIR repo set up for development here.

Here are notes on some of the key files:

index.js (template)

This file is the driver for the hardware. Here’s the basic setup:

  • Require util and the event emitter, along with any other dependencies. These let you write event-driven APIs.
  • Make a constructor function that instantiates the hardware as an object. Its two arguments are “hardware” and a callback. The function should emit a “ready” event that returns the object when it is ready. For the PIR, it’s “ready” as soon as the object is instantiated. For something more complex, e.g. the Ambient module, it’s not “ready” until it verifies that it has the correct firmware version.
    • hardware specifies where the hardware is connected to Tessel. For modules, it’s a port. For external hardware, this will most likely be a port and a pin (e.g. tessel.port[‘GPIO’].pin[‘A3’]). You should probably also add error handling in case the wrong hardware type is passed in (e.g. just a port when you need a pin) or for specification of the wrong type of pin (you can see which pins are digital, analog and PWM in the examples here). You can check the PIR code for examples of this error handling.
    • callback(err, obj) should return an error if there are any errors connecting, or if there are no errors, should return the object as its second argument.
  • Functions: this is the fun part! What do you want as the API for your hardware? What’s useful? What do you want to expose? For the PIR motion detector, I only have one function, which reads the pin. Most of the useful information is better exposed as events for “movement”, “stillness”, and “change”.
  • use function: The standard require for a Tessel module is require(‘module’).use(tessel.port[‘PORT’]). The “use” function takes hardware specification and a callback, and passes them to the object constructor.
  • exports: Export the object function and the use function.

package.json (template)

Use npm init to generate most of this file.

Other items of note:

  • You do not need the tessel npm package as a dependency.
  • Add a “hardware” section. By default, Tessel pushes the entire directory so that any dependencies are included. With a “hardware” section, you can specify files and folders to ignore when pushing to embedded devices. For our modules, we list “./test” and “./examples”.

examples folder (template)

You need at least one example. This should show basic functionality of the hardware. Mine waits for a ready event, then logs a message on the emission of “movement” and “stillness” events. When you require the module, refer to ‘../’ rather than the module name.

test folder (template)

We use the node module “tinytap” for testing. Every functionality that can be tested without physical interaction should be testable with tessel run test/*.js.

README.md (template)

Your readme is your documentation. For consistency with Tessel modules, check out the template. We use the node module “marktype” to make pretty, linkable API documentation.

Connecting your hardware to Tessel

Connect your hardware based on the hardware and API documentation. Instructions for establishing SPI/UART/I2C are part of the API docs.

At the top of your README, write which pins should be connected to which between the Tessel and the external hardware. A picture of the setup would also be useful to include in the README.

Establishing communication

Set up something basic to make sure you can connect to the sensor. I like to start with example code: require Tessel, read the pin, see what kind of values we get.

If you’re working with more complex hardware, you might need to wake up the hardware with a wakeup sequence. This sort of thing will be documented in the part’s datasheet.

If there is existing Arduino code for the hardware, this can be a good starting point to poke around and get an understanding of how to interface with the device.

Writing an API

Once you’re able to connect and get some basic functionality out of the device, start writing your API.

Start with the object constructor and the use function in your index.js file. Make sure you can require the hardware and have it connect.

Now, draft up your API. How might people want to interface with this piece of hardware? How can you make it intuitive? If you’d like feedback on a proposed API, feel free to post it to the RFC category of our forums.

As a general rule, top priority is intuitive interaction. Second priority is exposing as much as you can.

Writing tests

Write tests as you go.

  • Initializing the object should callback the object, return the object, and emit the object as a ready event.
  • Super thorough tests check to make sure errors are emitted when they should be.

Writing an example

The example named <hardware>.js should be a simple “is it working” example.

Feel free to write other examples to show off different uses of the hardware and the API you’ve built!

Writing the docs

Please follow the template formatting here to write your README.

Document every method, event, and property.

Complete documentation is important! If you don’t document a method, most people will never realize that method exists.

Publishing

Publish your module to npm! If you’ve never done that, this is a good tutorial. Be sure to include ‘tessel’ in the keywords of your package.json so that people can find it!

Other places you might want to publish as well:

Find this document on Tessel’s docs repo, where it will be kept up to date.