View on GitHub

Nobel (code-generator) creates a REST API for your Arduino board, based on a RAML definition.

Download this project as a .zip file Download this project as a tar.gz file

Donate

Bitcoins: 38Le7UzvozGQoJvWywcbShVTZ1G5CH1DyU
38Le7UzvozGQoJvWywcbShVTZ1G5CH1DyU

NPM version NPM Downloads

Nobel (code-generator) creates a REST API for your Arduino board, based on a SWAGGER or RAML definition.

Description

Nobel scaffolds an Arduino application that exposes a REST API. Then, you can write the logic for interacting with your physical devices inside methods that will be executed when the corresponding URL is invoked.

Example

Considering the following Swagger code:

swagger: "2.0"
info:
  version: "0.0.1"
  title: NobelTestingAPI
paths:
  /servo:
    post:
      description: |
        Moves the servo to the specified angle.
      parameters:
        - name: angle 
          in: body
          description: angle object
          required: true
          schema:
            $ref: '#/definitions/Angle'
      responses:
        200:
          description: Successful response
          schema:
            $ref: '#/definitions/Angle'
    put:
      description: |
        Moves the servo buy Adding the specified angle (could be negative)
      parameters:
        - name: angle 
          in: body
          description: angle object
          required: true
          schema:
            $ref: '#/definitions/Angle'
      responses:
        200:
          description: Successful response
          schema:
            $ref: '#/definitions/Angle'
    get:
      description: |
       Returns the current servo angle
      responses:
        200:
          description: Successful response
          schema:
            $ref: '#/definitions/Angle'
definitions:
  Angle:
    description: Task object
    properties:
      angle:
        type: integer
        description: task object name
    required:
      - angle

or the following RAML code

#%RAML 0.8
title: NobelTestingAPI
/servo:
  post:
    description: |
      Moves the servo to the specified angle.
    body:
      application/json:
        example: |
          {"angle": 71}
  put:
    description: |
      Moves the servo buy Adding the specified angle (could be negative)
    body:
      application/json:
        example: |
          {"angle": -10}
  get:
    description: |
      Returns the current servo angle
    responses:
      200:
        body:
          application/json:
            example: |
              { "angle": 71 }

Nobel generates a project with several files (following the Arduino specs for splitting a program). One of the files contains the Handlers, where you can write your own code. Associated to the RAML example:

// Handlers

void servoHandler(WebServer &server, WebServer::ConnectionType verb, String uriParams, String queryParams) {
  switch (verb)
    {

    case WebServer::POST:
        server.httpSuccess();
        break;

    case WebServer::PUT:
        server.httpSuccess();
        break;

    case WebServer::GET:
        server.httpSuccess();
        break;

    default:
        server.httpFail();
    }
}

Installation

Pre-requisites

Install Nobel

Installing Nobel is really simple.

... That's all you need.

Usage

Nobel is a Command Line Interface (CLI), which means that you will be executing it from a terminal/command line (I don't see a clear value on building a GUI for this).

nobel -s [your_swagger_or_raml_file] -n [your_project_name]

The line above shows the minimum parameters set you need to specify in order to scaffold an Arduino Application using Nobel. The result is:

.
└── myArduinoRobot
    ├── A_functions.ino
    ├── B_definitions.ino
    ├── C_handlers.ino
    ├── D_initialization.ino
    └── myArduinoRobot.ino

You can find a description of each file in the following sections.

Arguments

Argument Required Description
-s --source YES The Swagger or RAML file describing the API to implement on the Arduino program.
-n --name YES The name of your project. Nobel will create a folder with this name, and one main project file inside named like this.
-t --target NO The target directory where the project will be placed. If not specified, the project will be created on the folder where you are running Nobel.
-il --installLibraries NO If specified, it installs the required Arduino libraries on the folder you specify. Click here to figure out where this folder is.
-h --help NO Really? Yes, the user manual will be printed in the terminal/command line

Once your app is there

Files

Coding in Arduino is really a lot of fun (despite of/becouse of/but/your choice) it presents some challenges. The main one here: Memory. There could be better ways of implementing the code Nobel creates, but I haven't found it yet (feel free of making your own suggestions. That won't hurt my feelings at all). Because of this, I needed to hardcode some values (yes, shame on me). You only need to worry about it if you need to manually add new resources. If not:

Seeing the example is the best way of understanding how to code. Note: The scaffolded application will use DHCP. You can find the code to change this in the D_Initialization.ino file (setup function)

Manually Adding new resources

Sorry! I'll try to improve this, but this far, for an MVP, it is what it is!

Don't bother reading this if you are NOT manually adding new resources.

A_Functions.ino

 FLASH_STRING_ARRAY(resources,
      PSTR("/resourceA/"),
      PSTR("/resourceB/"),
      PSTR("/resourceC/"),
      PSTR("/resourceD/"),
      PSTR("/resourceE/")
      // add more if needed
  );

When adding one, you will also need to add the proper Handler in D_Initialization.ino

D_Initialization.ino

void registerHandlers() {
handlers[0].method = &resourceAHandler;
handlers[1].method = &resourceBlHandler;
handlers[2].method = &resourceCHandler;
handlers[3].method = &resourceDHandler;
handlers[4].method = &resourceEHandler;
}

Important: The order is the way of matching a resource with it handler!!! It's much more efficient and doable than trying to do some kind of "reflection". So, make sure of adding the handlers in the same order than the resources on the previous step. Now, a handler, is basically a pointer to a function (Nobel places these functions on C_Handlers.ino). So, if you have &resourceAHandler, you will need:

C_Handlers.ino

void resourceAHandler(WebServer &server, WebServer::ConnectionType verb, String uriParams, String queryParams) {
  // Your code here (generally, start with a switch)
}

Hands On Example

Create the API definition file.

You can choose to define your API by using Swagger or RAML. It's up to you ;)

Swagger

swagger: "2.0"
info:
  version: "0.0.1"
  title: NobelExampleAPI
paths:
  /led:
    post:
      description: |
        Turns the light on
      responses:
        200:
          description: Successful response
    delete:
      description: |
        Turns the light off
      responses:
        200:
          description: Successful response

RAML

#%RAML 0.8
title: NobelExampleAPI
/led:
  post:
    description: Turns the light on
  delete:
    description: Turns the light off

and save it (the example asumes that it will be called swaggerExample.yaml or ramlExample.raml)

Scaffold the application

For Swagger

nobel -s swaggerExample.yaml -n ledController

For RAML

nobel -s ramlExample.raml -n ledController

or

For Swagger

nobel -s nobelExample.raml -n ledController -il [path_to_your_arduino_libraries_directory]

For RAML

nobel -s nobelExample.raml -n ledController -il [path_to_your_arduino_libraries_directory]

if you haven't ever installed the required libraries.

Put your own code

B_Definitions.ino

Add this line:

byte ledPin = 9; // It's a good practice to use a variable to semantically represent your Arduino output.

D_Initialization.ino

Add this line in the void setup() function

pinMode(ledPin, OUTPUT); // We are specifying that the pin 9 will be used as an output.

The function code should look like this:

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  ethStart();
  registerHandlers();
  webserver.setFailureCommand(&dispatch);
  webserver.begin();
}

C_Handlers

digitalWrite(ledPin, HIGH); // Turns the led on
digitalWrite(ledPin, LOW); // Turns the led off

Let's add both calls to the POST and DELETE methods, and the final code should look like this:

void ledHandler(WebServer &server, WebServer::ConnectionType verb, String uriParams, String queryParams) {
  switch (verb)
    {

    case WebServer::POST:
        digitalWrite(ledPin, HIGH);
        server.httpSuccess();
        break;

    case WebServer::DELETE:
        digitalWrite(ledPin, LOW);
        server.httpSuccess();
        break;

    default:
        server.httpFail();
    }
}

Compile and deploy

By default, the generated code will make Arduino take an IP by using DHCP. Open a Serial Monitor to see the assigned IP. In order to test the app, use any program capable of sending HTTP messages via network. Postman extension for chrome is my favorite.

Contributing to this code

Credits