• Making a Tessel-style Library for Third-Party Hardware

    Thursday, August 7, 2014

    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.


    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.

    #tessel #adafruit #kelsey breseman #technical machine #seeed #pir #pulse #infrared #diy #hardware #wires

August 2018

January 2018

July 2017

February 2017

November 2016

October 2016

September 2016

August 2016

July 2016

June 2016

April 2016

March 2016

February 2016

November 2015

September 2015

August 2015

July 2015

June 2015

May 2015

March 2015

February 2015

January 2015

December 2014

November 2014

October 2014

September 2014

August 2014

July 2014

June 2014

May 2014

April 2014

March 2014

February 2014

January 2014

December 2013

November 2013

October 2013

September 2013

August 2013

July 2013