Skip to content
wwitman edited this page Dec 18, 2015 · 2 revisions

Introduction

In this tutorial we build upon the Quick Start project by adding a mock device driver to the Zetta hub. The mock driver models a simple state machine, designed to turn a mock LED on and off, as the following state machine notation shows:

LED State Machine

According to the diagram when our LED is off it can only transition to the on state, and conversely when the state is on it can only transition to off.

To keep things simple, we've written this sample device driver for you and made it available to download. In this tutorial, we'll install this sample driver and add it to the Zetta server code.

Prerequisite

This tutorial assumes you have completed the Quick Start tutorial and have the "Hello Zetta" project working.

Install the mock device driver

  1. If the Zetta server is still running, hit Ctrl-c to stop it.

  2. In the hello-zetta directory, install the mock driver using NPM:

    npm install zetta-led-mock-driver --save

    Note: By convention, Zetta device driver names follow the pattern zetta-[device name]-[platform name]-driver. In this example, we're controlling an LED device on a "mock" platform. For example, a driver that controls an LED from an Intel Edison Board might be called zetta-led-edison-driver.

  3. Open index.js in a text editor.

  4. Add this require statement to line 2:

    var LED = require('zetta-led-mock-driver');

  5. Add this use statement to line 6:

    .use(LED)

  6. Be sure the code looks like this, then save the file:

var zetta = require('zetta');
var LED = require('zetta-led-mock-driver');

zetta()
  .name('Hello Zetta')
  .use(LED)
  .listen(1337, function(){
     console.log('Zetta is running at http://127.0.0.1:1337');
});

Test the server

Now we've configured the server to use the mock LED driver. Before we look at the driver, let's test it.

  1. Start the server:

    node index.js

  2. Notice the terminal output has some new information that we didn't see before -- the LED device we added to the hub was discovered by something called a "scout". We'll discuss scouts in detail in another topic.

  Oct-23-2015 10:02:24 [scout] Device (led) f826f6e0-ebb8-430a-9e1e-6efddebc42fc was discovered
  Oct-23-2015 10:02:24 [server] Server (Hello Zetta) Hello Zetta listening on http://127.0.0.1:1337
  Zetta is running at http://127.0.0.1:1337 

Device discovery is an important Zetta concept. When Zetta discovers a device, the device information is automatically added to the API. In this case, you could write a very simple app that turns the LED on and off using this API. Let's see how that works.

Hit the API

  1. Using cURL or in a REST app like Postman or Advanced REST client, call the root URL:

    curl http://127.0.0.1:1337

  2. Then, in the response, locate the /servers/Hello%20Zetta URL and call it:

    curl http://localhost:1337/servers/Hello%20Zetta

  3. Notice that this time the entities element lists a device. This is the LED device driver we added to the server. The driver defines the current and possible state properties for the device. In the case of the LED, those properties are on and off. The current state (reflected in the properties attribute of the JSON response) is off.

{
  "class": [
    "server"
  ],
  "properties": {
    "name": "Hello Zetta"
  },
  "entities": [
    {
      "class": [
        "device",
        "led"
      ],
      "rel": [
        "http://rels.zettajs.io/device"
      ],
      "properties": {
        "id": "e6f5b480-e96e-4fdc-8718-91aeb0234c99",
        "type": "led",
        "state": "off"
      },
      "links": [
        {
          "rel": [
            "self",
            "edit"
          ],
          "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99"
        },
        {
          "rel": [
            "http://rels.zettajs.io/type",
            "describedby"
          ],
          "href": "http://localhost:1337/servers/Hello%20Zetta/meta/led"
        },
        {
          "title": "Hello Zetta",
          "rel": [
            "up",
            "http://rels.zettajs.io/server"
          ],
          "href": "http://localhost:1337/servers/Hello%20Zetta"
        }
      ]
    }
  ],
  "actions": [
    {
      "name": "query-devices",
      "method": "GET",
      "href": "http://localhost:1337/servers/Hello%20Zetta",
      "type": "application/x-www-form-urlencoded",
      "fields": [
        {
          "name": "ql",
          "type": "text"
        }
      ]
    }
  ],
  "links": [
    {
      "rel": [
        "self"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta"
    },
    {
      "rel": [
        "http://rels.zettajs.io/metadata"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta/meta"
    },
    {
      "rel": [
        "monitor"
      ],
      "href": "ws://localhost:1337/servers/Hello%20Zetta/events?topic=logs"
    }
  ]
}

##Query the device capabilities

Now, let's follow the URL to the device itself. It looks something like this:

http://127.0.0.1:1337/servers/Hello%20Zetta/devices/a3bbdd2d-67fe-4fad-97b2-3851f18aae7e

Here we can discover what actions the actual device is capable of performing. This device has a "transition" action that lets you change its state. Because the current state, as we saw previously, is off, the available action is turn-on.

{
  "class": [
    "device",
    "led"
  ],
  "properties": {
    "id": "e6f5b480-e96e-4fdc-8718-91aeb0234c99",
    "type": "led",
    "state": "off"
  },
  "actions": [
    {
      "class": [
        "transition"
      ],
      "name": "turn-on",
      "method": "POST",
      "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99",
      "fields": [
        {
          "name": "action",
          "type": "hidden",
          "value": "turn-on"
        }
      ]
    }
  ],
  "links": [
    {
      "rel": [
        "self",
        "edit"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99"
    },
    {
      "title": "Hello Zetta",
      "rel": [
        "up",
        "http://rels.zettajs.io/server"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta"
    },
    {
      "rel": [
        "http://rels.zettajs.io/type",
        "describedby"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta/meta/led"
    },
    {
      "title": "state",
      "rel": [
        "monitor",
        "http://rels.zettajs.io/object-stream"
      ],
      "href": "ws://localhost:1337/servers/Hello%20Zetta/events?topic=led%2Fe6f5b480-e96e-4fdc-8718-91aeb0234c99%2Fstate"
    },
    {
      "title": "logs",
      "rel": [
        "monitor",
        "http://rels.zettajs.io/object-stream"
      ],
      "href": "ws://localhost:1337/servers/Hello%20Zetta/events?topic=led%2Fe6f5b480-e96e-4fdc-8718-91aeb0234c99%2Flogs"
    }
  ]
}

Change the device state

You might have noticed the transition action includes an href link. The link is an HTTP POST command that you can use to change the LED's state. To "turn the light on", you simply form the correct POST request.

"actions": [
        {
            "class": [
                "transition"
            ],
            "name": "turn-on",
            "method": "POST",
            "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e511deee-a266-4431-8a42-eeef7f2412f9",
            "fields": [
                {
                    "name": "action",
                    "type": "hidden",
                    "value": "turn-on"
                }
            ]
        }
    ]

The POST request to turn on the light looks something like this (you'll need to use the link provided in your own response, which has the correct device ID):

curl -i -X POST -H http://127.0.0.1:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99 -d 'action=turn-on'

Tip: To produce nicely formatted JSON from cURL, you can pipe the cURL response to this Python command to pretty-format the response: python -m json.tool. For example:

curl -i -X POST http://127.0.0.1:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99 -d ‘action=turn-on | python -m json.tool

In the response, you can see that the state has been changed from off to on. Furthermore, the available action is changed to turn-off. To turn the light off again, follow the same pattern by POSTing to the transition URL.

{
  "class": [
    "device",
    "led"
  ],
  "properties": {
    "id": "e6f5b480-e96e-4fdc-8718-91aeb0234c99",
    "type": "led",
    "state": "on"
  },
  "actions": [
    {
      "class": [
        "transition"
      ],
      "name": "turn-off",
      "method": "POST",
      "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99",
      "fields": [
        {
          "name": "action",
          "type": "hidden",
          "value": "turn-off"
        }
      ]
    }
  ],
  "links": [
    {
      "rel": [
        "self",
        "edit"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta/devices/e6f5b480-e96e-4fdc-8718-91aeb0234c99"
    },
    {
      "title": "Hello Zetta",
      "rel": [
        "up",
        "http://rels.zettajs.io/server"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta"
    },
    {
      "rel": [
        "http://rels.zettajs.io/type",
        "describedby"
      ],
      "href": "http://localhost:1337/servers/Hello%20Zetta/meta/led"
    },
    {
      "title": "state",
      "rel": [
        "monitor",
        "http://rels.zettajs.io/object-stream"
      ],
      "href": "ws://localhost:1337/servers/Hello%20Zetta/events?topic=led%2Fe6f5b480-e96e-4fdc-8718-91aeb0234c99%2Fstate"
    },
    {
      "title": "logs",
      "rel": [
        "monitor",
        "http://rels.zettajs.io/object-stream"
      ],
      "href": "ws://localhost:1337/servers/Hello%20Zetta/events?topic=led%2Fe6f5b480-e96e-4fdc-8718-91aeb0234c99%2Flogs"
    }
  ]
}

Summary

In this topic, we added a sample "mock" device driver to a server, and then we traced the links provided in the server's JSON response to transition the state of the device.

The cool thing about Zetta APIs is that each response contains everything an app developer needs to navigate the API, discover its actions, and execute them.

Another thing to remember is that this pattern is central to Zetta development. You write the device driver for whatever device you want to access over HTTP, and Zetta provides a fully functional REST API for that device!

In the next part of the tutorial, we'll take a close look at the LED driver code.