You've set up an internet-enabled development board with Adafruit IO Wippersnapper. But, upon glancing at the component picker, you don't see the component you need for your IoT project. Let's get your favorite input, output, or sensor added to Adafruit IO WipperSnapper so it can be used by projects designed by you and others!

The process for adding components varies with difficulty depending on what type of component you're adding:

  • If you're adding a "pin component", such as a digital output (i.e.: an LED), analog input (i.e.: potentiometer or light sensor), or digital input (i.e.: push-button or PIR sensor) - adding a new component is easy. It involves writing a small amount of descriptive JSON and adding an image!
  • If you're adding an "i2c component" which is currently any I2C input-only device (i.e.: any I2C sensor) - adding a new i2c component is a little bit trickier. The process involves writing a small amount of JSON, adding an image, and writing some C++ code. 

Adding a new component to Adafruit IO WipperSnapper means your component will show up in this list on Adafruit IO WipperSnapper, for everyone:

It will also automatically generate a web-form like this:

Your component will have its current state either monitored or controlled by the device interface.

Once created, a WipperSnapper component can work seamlessly with the rest of IO, including Dashboards and Triggers!

This guide assumes you already have a GitHub account and have installed Git.

Fork the WipperSnapper_Components Repository

We'll start by creating a fork of the WipperSnapper Components repository on your account. Sign in to your GitHub account and navigate to the WipperSnapper_Components repository.

Click the "Fork" button on the upper-right-hand corner of the website.

Your fork should take a few seconds to complete, once done, let's move on to adding the component type you want.

As an example, the following adds the Flat Vibration Switch sold in the Adafruit store to WipperSnapper.

Flat Vibration Switch with Breadboard friendly pins
This is a low sensitivity, directional vibration-induced trigger switch. Inside is a very soft spring coiled around a long metal pin. When the switch...
$0.95
In Stock

First, identify what type of pin component this switch is. You can learn this by understanding how the switch works.

When the vibration switch gets bumped, it acts as a closed switch. In order to get the state of the switch, a microcontroller needs to configure the switch as a digital input as it only reports two states: when the switch is either open ('0') or closed ('1').

So, we'll be creating a digital input switch as we'll want the vibration switch to send data to WipperSnapper if it's bumped.

Add Component JSON

This page assumes you've followed the instructions on the Get Setup page and have the WipperSnapper_Components repository forked and locally cloned.

First, create a Git branch to work within. In this case, name it add-flat-vibration-switch.

Next, navigate to the Wippersnapper_Components/components/pin directory and make a copy of a component with similar functionality. The toggle switch component and the vibration switch both operate the same way and send the same values if they're toggled.

Create a copy of the toggle_switch folder.

Component folder names should use underscores and the name should be lower case (i.e: my_component).

Rename the toggle_switch copy folder to flat_vibration_switch.

Modify Component Definition JSON File

The definition.json file within this folder is known as the definition file, it defines the pin-based WipperSnapper component for use in Adafruit IO. 

Using a text editor, open the toggle switch's definition.json file.

{
  "displayName": "Toggle Switch",
  "published": true,
  "autoSelectString": "toggle",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30,
  "visualization": {
    "type": "switch",
    "offLabel": "Off",
    "offIcon": "fa6:regular:light-switch-off",
    "onLabel": "On",
    "onIcon": "fa6:solid:light-switch-on"
  }
}

JSON files are written as pairs of keys and values, separated by a semicolon.

The first key/value pair in the JSON definition is the displayName, which is the human-friendly name of a component. This field is required.

We'll start by changing the displayName from "Toggle Switch" to "Flat Vibration Switch". You should change the displayName to reflect the component you're adding.

At this point, the definition.json file looks like the following.

{
  "displayName": "Flat Vibration Switch",
  "autoSelectString": "toggle",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30
}

Next, set the required pin mode field. This field may either be ANALOG or DIGITAL. Since the microcontroller reading a vibration switch will either read a digital 1 or a digital 0 value, its mode is digital.

At this point, the definition.json file looks like the following.

{
  "displayName": "Flat Vibration Switch",
  "autoSelectString": "toggle",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30
}

Finally, the last of the required fields is the pin's direction which may be either INPUT or OUTPUT. Data from the vibration switch will be read into the board, so  define an INPUT direction.

{
  "displayName": "Flat Vibration Switch",
  "autoSelectString": "toggle",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30
}

The optional autoSelectString field is a hint for automatically looking up pin names. For example, an LED component will automatically select a pin labeled "LED" if the pin exists. 

In the vibration switch case, this field is not required so it can be removed.

{
  "displayName": "Flat Vibration Switch",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30
}

The defaultPeriod field describes the default value of the Period field on the "Component Settings" form on WipperSnapper (in seconds). You may leave this as-is.

However, some sensors may take a longer amount of time than the 30-second default to gather readings and this time period may need to be adjusted.

{
  "displayName": "Flat Vibration Switch",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30
}

(Optional) Add Component Visualization 

You may (optionally) add some text to the definition file to describe its "look" on the Adafruit IO device interface. 

While optional, a component with visualization not only makes it visually prettier - it adds function! Adafruit IO component visualization includes icons and labels to explain what the component does.

For example, this is a LED switch component without a defined visualization:

And this is a vibration switch component on Adafruit IO with a visualization defined in its definition file.

Adding the following visualization object to your component's definition.json will define its look and feel:

"visualization": {
    "type": "switch",
    "offLabel": "Still",
    "offIcon": "fa6:regular:bell-slash",
    "onLabel": "Bzzz",
    "onIcon": "fa6:solid:bell-on"
  }

The components visualization type may be either a switch or a button (we're working on adding more component types). Each type is omnidirectional, meaning it may be used as either an output or an input.

The off/onLabel and off/onIcons are specific to the switch component type.

The component's labels (onLabel and offLabel) correspond to its physical state. For example, a vibration sensor when "off" is still (reflected by the offLabel above). When the vibration sensor is activated (by movement or touch), we'll change the onLabel to "Touched".

The component's icons, onIcon and offIcon, correspond to the component's on and off state.

For example, the onIcon is defined as:

"onIcon": "fa6:solid:bell-on"

bell-on is the name of the icon, with a bunch of namespaces in front of it. Let's break it down:

  • fa6 means we are using a set of icons called Font Awesome 6
  • solid is the style of the icon. There are 4 icon styles to pick from - light, thin, regular and solid.
  • bell-on is the name of the icon. 

To find an icon, visit https://fontawesome.com/icons to search for an icon you like. 

Clicking on an icon will show you the various icon styles.

Once you've completed adding the visualization object to the component's definition, you're finished editing its definition. A complete definition.json file should look something like the following.

{
  "displayName": "Toggle Switch",
  "published": true,
  "autoSelectString": "toggle",
  "mode": "DIGITAL",
  "direction": "INPUT",
  "defaultPeriod": 30,
  "visualization": {
    "type": "switch",
    "offLabel": "Off",
    "offIcon": "fa6:regular:light-switch-off",
    "onLabel": "On",
    "onIcon": "fa6:solid:light-switch-on"
  }
}

Add Component Image

Next, you'll need to add an image of your component. It's best to get a photo of the component from the manufacturer's website.

First, make sure your image adheres to the following specifications: 

  • Image file's extension can be any one of: jpg, jpeg, gif, png, svg
  • Image file's dimensions must be 300px x 300px
  • Image file's size must be at least 3kb and must not exceed 100kb

For the flat vibration switch, it is the first image from the Adafruit Store product page. Next, this image must be resized. Using a web-based tool such as https://picresize.com is suggested and ensuring the final image is 300px by 300px. 

Add the resized image to the flat_vibration_switch folder and rename it image.png. You may need to delete the existing file, there should only be one file named image.EXTENSION in this folder.

You may also delete the optional animation.gif file within this folder if you are not planning to add one.

(Optional) Add Component Animation

This step is optional due to the amount of work required to produce an animation. The Ruiz brothers have a video on how to create a spinning board animation below:

The optional animation.gif file also must adhere to the following specifications:

  • File must ALWAYS be .gif
  • File dimensions must be 300px x 300px
  • File is between 5kb and 700kb

Commit Your Changes and Push

Next, let's add all these changes to your fork. Add your components using the git add command.

Typing git status shows the files you're about to add.

Then, commit the files by typing git commit -m "adding new component"

And push to your forked repository, git push yourRepo add-component-name

Submit a Pull Request

Finally, it's time to submit a pull request to add the component to WipperSnapper!

After you've pushed the updated files to your branch, navigate to https://github.com/adafruit/Wippersnapper_Components/pulls and click "Compare & pull request".

Give your pull request a name and a description. Make it as descriptive as possible!

Click "Create pull request".

The repository will run checks on these files. If the checks pass, Adafruit will review the files. 

Testing your Pin Component

As part of our review process, we'll make your component appear under the component picker as "in development". This allows you to test the component before giving us (Adafruit) the final OK.

On your Adafruit IO Device page, open the component picker. Click the "Show Dev" checkbox.

You should see the pin component you just added.

Make sure everything on the form looks okay. Then, create your component and test it out with a device.

Once you've fully tested your component and are satisfied with how it works, let us know in the Pull Request and we'll make it live on Adafruit IO!

I2C is a popular protocol that uses two wires to communicate with sensors (often called I2C devices). If you need a quick overview (or refresher!) of how I2C works, read through this guide page.

The following page(s) will go over the process of adding your favorite I2C sensor.

You will need to follow this page first, then the "Adding an I2C Component Driver" page after.

The process of adding I2C components is more involved than adding a pin component and you'll be asked to write some C++ code. If you haven't written C++ before - don't worry - this guide will walk you through the process and provide examples.

As an example, the following uses the MCP9808 High Accuracy I2C Temperature Sensor Breakout for this guide since it's a simple breakout that only reports temperature data.

Keep in mind that some I2C breakouts have multiple sensors which report multiple types of data (such as temperature, humidity, altitude, etc.). The more types of data reported by a sensor, the more involved its I2C component driver code will be.

Add Component JSON Definition

This page assumes you've followed the instructions on the Get Setup page and have the WipperSnapper_Components repository forked and locally cloned.

First, create a branch to work within. In our case, we'll name it add-mcp9808.

Next, navigate to the Wippersnapper_Components/components/i2c directory. Create a new folder named mcp9808.

Within the mcp9808 folder, add a new file named definition.json. This will hold the definition of the physical sensor for the WipperSnapper website.

JSON files are written as pairs of keys and values, separated by a semicolon.

The first key/value pair in the JSON definition is the displayName, which is the human-friendly name of a component. This field is required

{
    "displayName": "MCP9808",
}

Each I2C device has a unique address to identify it by. We have a list of I2C addresses on this page. If it's not on that page, check the sensor's datasheet. 

According to its documentation, the Adafruit MCP9808's I2C addresses can range from 0x18 to 0x1C.

These addresses are listed within the i2cAddresses field in the JSON definition:

{
    "displayName": "MCP9808",
    "i2cAddresses": [ "0x18", "0x19", "0x1A", "0x1C" ],
}

Next, add the list of subcomponents. These are all the sensors on the I2C device.

The MCP9808 breakout only has an ambient temperature sensor. There are two types of ambient temperature sensors on the list of sensor types - "ambient-temp" and "ambient-temp-fahrenheit". The ambient-temp sensor type tells Adafruit IO that a sensor on this breakout will send ambient temperature data back in degree Celsius. Adding ambient-temp-fahrenheit to the list of subcomponents will allow a user on Adafruit IO to select between having the sensor return the temperature in either degree Celsius or degree Fahrenheit. 

The final .JSON file for this sensor is below (and here it is on GitHub)

{
  "displayName": "MCP9808",
  "i2cAddresses": [ "0x18", "0x19", "0x1A", "0x1C" ],
  "subcomponents": [ "ambient-temp", "ambient-temp-fahrenheit" ]
}

Add Component Image

Next, you'll need to add an image of your component. It is recommended you get a photo of the component from the manufacturer's website.

First, make sure your image adheres to the following specifications: 

  • Image file's extension can be any one of: jpg, jpeg, gif, png, svg
  • Image file's dimensions must be 300px by 300px
  • Image file's size must be at least 3kb and must not exceed 100kb

Below is the first image from the Adafruit Store product page.

Next, this image must be resized. It is suggested using a web-based tool such as https://picresize.com and ensuring the final image is 300px by 300px. 

Add the resized image to the mcp9808 folder and rename it image.EXTENSION. You may need to delete the existing file, there should only be one file named image.EXTENSION in this folder.

You may also delete the optional animation.gif file within this folder if you are not planning to add one.

(Optional) Add Component Animation

This step is optional due to the amount of work required to produce an animation. The Ruiz brothers have a video on how to create a spinning board animation below:

The optional animation.gif file also must adhere to the following specifications:

  • File must ALWAYS be .gif
  • File dimensions must be 300px by 300px
  • File is between 5kb and 700kb

Commit Your Changes and Push

Next, add all these changes to your fork. Add your components using the git add command.

Typing git status shows the files you're about to add.

Then, commit the files by typing git commit -m "adding new component"

And push to your forked repository, git push yourRepo add-component-name

Submit a Pull Request

Finally, to submit a pull request to add the component to WipperSnapper!

After you've pushed the updated files to your branch, navigate to https://github.com/adafruit/Wippersnapper_Components/pulls and click "Compare & pull request".

Give your pull request a name and a description. Make it as descriptive as possible and click "Create pull request".

The repository will run checks on these files. If the checks pass, Adafruit) will review the files. 

When approved, they'll be automatically added to WipperSnapper and available under the component picker along with the form options you added to the definition.json file.

Expanding the capabilities of the WipperSnapper Arduino library requires you to have some familiarity with C++. The example below involves creating and editing some code that helps WipperSnapper interface with an I2C sensor.

If you get stuck or need help, post up on the #help-with-adafruit-io channel in the Adafruit Discord server and we'll try to assist!

Get Setup

This guide assumes you've installed the Arduino IDE and have successfully programmed a WipperSnapper-compatible development board with it. 

Start by making a local fork of the WipperSnapper_Arduino repository to your GitHub account. Next, you'll need to clone this forked repository to your computer's Arduino library folder (we have a guide on how to locate this folder here)

Open up the Arduino IDE. Then, open the WipperSnapper demo sketch located in File->Tools->Adafruit WipperSnapper->Wippersnapper_demo.

Since the WipperSnapper library was installed manually and not from the Arduino Library Manager, it's required dependencies will not be automatically installed. 

Open the library.properties file for this library. Underneath the depends field is a list of all the libraries required. You'll need to manually install each dependency using the Arduino Library Manager (Sketch->Include Libraries->Manage Libraries).

Once you've manually installed the dependencies, select the board you're using and click "Verify".

If you successfully compiled the sketch, you're ready to add a new component to Adafruit IO WipperSnapper.

Adding an I2C Component Driver

As an example, we'll be creating a new WipperSnapper I2C component for the MCP9808 sensor. You will need to modify the instructions below to reflect the sensor you're adding.

Before digging into the code, find and install an Arduino library that already contains driver code for your sensor. Adafruit WipperSnapper interfaces with existing libraries, low-level sensor code within the I2C drivers is not accepted. Low-level code should already be wrapped into an Arduino library which is listed on the Arduino Library Manager.

The sensor used here is an Adafruit MCP9808 Breakout. The Arduino library for this is listed on the Arduino Library Manager and publicly available on GitHub.

During this process, only files within the Adafruit_Wippersnapper_Arduino/src/components/i2c directory will be modified. Open your file browser, or code editor, to this folder.

Next, create a new file under the Adafruit_Wippersnapper_Arduino/src/components/i2c/drivers directory named WipperSnapper_I2C_Driver_MCP9808.h. This file will contain the code that tells WipperSnapper how to communicate with the MCP9808 sensor.

Next is to fill it with code that references the MCP9808 Arduino library linked above. To begin, start with the following template.

#ifndef WipperSnapper_I2C_Driver_MCP9808_H
#define WipperSnapper_I2C_Driver_MCP9808_H

#include "WipperSnapper_I2C_Driver.h"
#include <Adafruit_MCP9808.h>

/**************************************************************************/
/*!
    @brief  Class that provides a driver interface for a MCP9808 sensor.
*/
/**************************************************************************/
class WipperSnapper_I2C_Driver_MCP9808 : public WipperSnapper_I2C_Driver {
public:
  /*******************************************************************************/
  /*!
      @brief    Constructor for a MCP9808 sensor.
      @param    i2c
                The I2C interface.
      @param    sensorAddress
                7-bit device address.
  */
  /*******************************************************************************/
  WipperSnapper_I2C_Driver_MCP9808(TwoWire *i2c, uint16_t sensorAddress)
      : WipperSnapper_I2C_Driver(i2c, sensorAddress) {
    _i2c = i2c;
    _sensorAddress = sensorAddress;
  }

  /*******************************************************************************/
  /*!
      @brief    Destructor for an MCP9808 sensor.
  */
  /*******************************************************************************/
  ~WipperSnapper_I2C_Driver_MCP9808() {
    // Called when a MCP9808 component is deleted.
    delete _mcp9808;
  }

  /*******************************************************************************/
  /*!
      @brief    Initializes the MCP9808 sensor and begins I2C.
      @returns  True if initialized successfully, False otherwise.
  */
  /*******************************************************************************/
  bool begin() {
    // Place initialization code here!
  }


protected:
  Adafruit_MCP9808 *_mcp9808; ///< Pointer to MCP9808 temperature sensor object
};

#endif // WipperSnapper_I2C_Driver_MCP9808

At the top of the code are include guards which prevent the compiler from including multiple instances of this class. 

Next are #includes which include WipperSnapper_I2C_Driver.h, the base class containing generic implementations for the I2C_Driver, and the MCP9808 sensor driver - Adafruit_MCP9808.h. You will want to include the correct library for your I2C sensor here.

The constructor (WipperSnapper_I2C_Driver_MCP9808()) and destructor (~WipperSnapper_I2C_Driver_MCP9808()) are called when the component is either initialized or deleted via the WipperSnapper website. The constructor is passed the I2C object and the sensor address from the new component form.

At the bottom, underneath protected, you'll need to create a pointer (_mcp9808) to a MCP9808 sensor object. 

Next, within begin(), initialize the sensor and begin I2C communication. This can be copied from an example Arduino sketch's setup() function.

At this point, your code should look like the following.

#ifndef WipperSnapper_I2C_Driver_MCP9808_H
#define WipperSnapper_I2C_Driver_MCP9808_H

#include "WipperSnapper_I2C_Driver.h"
#include <Adafruit_MCP9808.h>

/**************************************************************************/
/*!
    @brief  Class that provides a driver interface for a MCP9808 sensor.
*/
/**************************************************************************/
class WipperSnapper_I2C_Driver_MCP9808 : public WipperSnapper_I2C_Driver {
public:
  /*******************************************************************************/
  /*!
      @brief    Constructor for a MCP9808 sensor.
      @param    i2c
                The I2C interface.
      @param    sensorAddress
                7-bit device address.
  */
  /*******************************************************************************/
  WipperSnapper_I2C_Driver_MCP9808(TwoWire *i2c, uint16_t sensorAddress)
      : WipperSnapper_I2C_Driver(i2c, sensorAddress) {
    _i2c = i2c;
    _sensorAddress = sensorAddress;
  }

  /*******************************************************************************/
  /*!
      @brief    Destructor for an MCP9808 sensor.
  */
  /*******************************************************************************/
  ~WipperSnapper_I2C_Driver_MCP9808() {
    // Called when a MCP9808 component is deleted.
    delete _mcp9808;
  }

  /*******************************************************************************/
  /*!
      @brief    Initializes the MCP9808 sensor and begins I2C.
      @returns  True if initialized successfully, False otherwise.
  */
  /*******************************************************************************/
  bool begin() {
    _mcp9808 = new Adafruit_MCP9808();
    bool isInit = _mcp9808->begin((uint8_t)_sensorAddress, _i2c);
    return isInit;
  }


protected:
  Adafruit_MCP9808 *_mcp9808; ///< Pointer to MCP9808 temperature sensor object
};

#endif // WipperSnapper_I2C_Driver_MCP9808

Getting the Temperature

The MCP9808 contains an ambient temperature sensor. A function needs to be added to read the value of the ambient temperature sensor, called getEventAmbientTemperature().

The WipperSnapper I2C component utilizes the Adafruit Unified Sensor Driver to handle reading sensors. This driver reduces all data to a single sensors_event_t structure and uses standardized SI units for every type of sensor.

Within the getEventAmbientTemperature function, read from the MCP9808 sensor (_mcp9808->readTempC();) and set the sensors_event_t struct's temperature field to the SI value of the temperature sensor (tempEvent->temperature = _mcp9808->readTempC());

#ifndef WipperSnapper_I2C_Driver_MCP9808_H
#define WipperSnapper_I2C_Driver_MCP9808_H

#include "WipperSnapper_I2C_Driver.h"
#include <Adafruit_MCP9808.h>

class WipperSnapper_I2C_Driver_MCP9808 : public WipperSnapper_I2C_Driver {
public:
  WipperSnapper_I2C_Driver_MCP9808(TwoWire *_i2c, uint16_t sensorAddress) : WipperSnapper_I2C_Driver(_i2c, sensorAddress) {
    // Called when a MCP9808 component is created
    setI2CAddress(sensorAddress); // sets the driver's I2C address
    _mcp9808 = new Adafruit_MCP9808();
    _isInitialized = _mcp9808->begin();
  }

  ~WipperSnapper_I2C_Driver_MCP9808() {
      // Called when a MCP9808 component is deleted.
      delete _mcp9808;
  }

  bool getEventAmbientTemperature(sensors_event_t *tempEvent) {
    tempEvent->temperature = _mcp9808->readTempC();
    return true;
  }

protected:
  Adafruit_MCP9808 *_mcp9808; ///< Pointer to MCP9808 temperature sensor object
};

#endif // WipperSnapper_I2C_Driver_MCP9808

Wait - My I2C breakout has more than one sensor!

WipperSnapper uses the Adafruit Unified Sensor Driver to handle reading sensors and enforces standardized SI units for every type of sensor. In WipperSnapper_I2C_Driver.h, there are functions for each predefined sensor type within the Adafruit Unified Sensor Driver.

For each sensor value you'd like to read - the driver code should implement the Arduino Library's function for obtaining the value within a new getEventSensorType() function and pack it into a sensors_event_t field. 

NOTE - If you're adding a sensor that does not yet have a predefined sensor_type, please add a new issue to Adafruit_Sensor.

Add the Sensor Driver to the I2C Component

With the sensor driver WipperSnapper_I2C_Driver_MCP9808.h complete,  add it to the I2C Component (components/i2c/WipperSnapper_I2C.*).

Open components/i2c/WipperSnapper_I2C.h in a code editor. At the top of the file, include the MCP9808 driver just created.

...
#include "drivers/WipperSnapper_I2C_Driver_DPS310.h"
#include "drivers/WipperSnapper_I2C_Driver_SCD30.h"
#include "drivers/WipperSnapper_I2C_Driver_MCP9808.h"

Towards the bottom of this file, add a new pointer to the MCP9808 class:

..
  WipperSnapper_I2C_Driver_SCD30   *_scd30 = nullptr;
  WipperSnapper_I2C_Driver_BME280  *_bme280 = nullptr;
  WipperSnapper_I2C_Driver_MCP9808 *_mcp9808 = nullptr;
 ..

Finally, add code to components/i2c/WipperSnapper_I2C.cpp in order to detect and initialize the MCP9808 sensor.

bool WipperSnapper_Component_I2C::initI2CDevice(
    wippersnapper_i2c_v1_I2CDeviceInitRequest *msgDeviceInitReq) {
  ...
  } else if (strcmp("mcp9808", msgDeviceInitReq->i2c_device_name) == 0) {
    _mcp9808 = new WipperSnapper_I2C_Driver_MCP9808(this->_i2c, i2cAddress);
    if (!_mcp9808->begin()) {
      WS_DEBUG_PRINTLN("ERROR: Failed to initialize MCP9808!");
      _busStatusResponse =
          wippersnapper_i2c_v1_BusResponse_BUS_RESPONSE_DEVICE_INIT_FAIL;
      return false;
    }
    _scd30->configureDriver(msgDeviceInitReq);
    drivers.push_back(_mcp9808);
    WS_DEBUG_PRINTLN("MCP9808 Initialized Successfully!");
  }
  ...
}

Testing your new Sensor

In the Arduino IDE, open File->Examples->Adafruit_WipperSnapper_Arduino->Wippersnapper_demo and compile the sketch.

If the sketch compiles with no errors, upload the sketch to your development board.

Open the Arduino Serial Monitor at 115200 baud to monitor the WipperSnapper session.

After the board successfully connects to WipperSnapper, you should see the following debug output stating the application is running.

On the WipperSnapper device page, click + New Component.

As part of our review process, we'll make your component appear under the component picker as "in development". This allows you to test the component before giving us (Adafruit) final approval to make it live.

On your Adafruit IO Device page, open the component picker. Then, click the "Show Dev" checkbox.

On the Arduino Serial monitor, you should see an I2C Scan command being executed on the Feather.

On the WipperSnapper website, configure your component and click Create Component.

On the Arduino Serial Monitor, you should see the MCP9808 sensor initialize. After 30 seconds, it should read the temperature value and PUBLISH it to WipperSnapper.

You should see the new value appear on your WipperSnapper device page.

Almost done - let's finally add a pull request to the Adafruit WipperSnapper library so others can use this sensor.

Create a Pull Request to WipperSnapper Arduino

First, read over the Doxygen page on this guide and run Doxygen on your code. Then, format your code using clang-format.

Once you've run Doxygen and linted using clang-format, you're ready to submit a pull request adding the sensor to the WipperSnapper Arduino library.

Commit and push your files to a branch on local your fork of Adafruit_WipperSnapper_Arduino and open a new pull request on the Adafruit_WipperSnapper_Arduino repository.

Adafruit has an example of a "perfect" pull request here.

Once reviewed and accepted, Adafruit will include support for your sensor in the latest version of the Adafruit IO Wippersnapper library. We will also remove the "in-development" flag from the component to make it live on Adafruit IO.

What about SPI or UART Components?

WipperSnapper does not currently support components that communicate over SPI or UART. It may in the future, though!

What about I2C components that I can control, like an OLED display

We have future plans for I2C output components - but they are currently not implemented in WipperSnapper.

What about an analog output like a PWM LED or a Servo?

WipperSnapper does not currently support analog output components. It only supports analog inputs.

I do not feel comfortable writing or editing C++ code but want an I2C sensor component added to WipperSnapper

You may request a component to be added to WipperSnapper by navigating to the WipperSnapper_Components GitHub page and filing a request for a component type. Please be descriptive as possible, and include any libraries/documentation/URLs you may have. Requests have no ETA regarding when they will be implemented into WipperSnapper.

This guide was first published on Mar 10, 2022. It was last updated on Mar 10, 2022.