ESP8266 WiFi Module + Nabto

The ESP8266 is a low-cost WiFi module that can be programmed directly like a microcontroller. Already thinking of your next Internet of Things project?

While an available Arduino library allows a quick start, there is still one problem to overcome: How to access your ESP8266 from outside your home network without nerve-racking router and firewall configurations or heavy and intransparent cloud services? Running the uNabto server on your ESP8266, you can establish a fast and secure Peer-to-Peer connection using only a static ID – from everywhere, no matter what is in between.

What hardware you’ll need

IMG_20160303_153803

Adafruit HUZZAH ESP8266 Breakout

IMG_20160303_153830

USB to TTL Serial Cable

This project is tested on an Adafruit ESP8266 board. It’s not the cheapest you can get, but very prototyping friendly. You can put it on a breadboard and it has a 3.3V voltage regulator onboard. Of course, you can also use a different ESP8266 module. Wikipedia provides an extensive list of available modules.

Regarding the USB to TTL Serial Cable (get it e.g. here), there are no special requirements when using the Adafruit module. If you use a different module, make sure the voltage levels match, since most boards only accept 3.3V.

Solder the pin header to your ESP8266 board and connect it to your USB to TTL adapter using 4 wires:

wiring

What software you’ll need

This project is tested on Ubuntu 15.10 but should work on any OS supported by the Arduino IDE.

We want to program the ESP8266 directly, instead of using any higher level interpreters available for the module. Adafruit provides a nice tutorial on how to setup your  Arduino IDE accordingly.

If everything is running, you should be able to compile the following simple sketch and upload it to your ESP8266. This will make the onboard LED blink every second.

const int led = BUILTIN_LED;

void setup() {
  pinMode(led, OUTPUT);
}

void loop() {
  digitalWrite(led, HIGH);
  delay(500);
  digitalWrite(led, LOW);
  delay(500);
}

How the Nabto platform works

So far, so good. But how does the Nabto platform actually work? The drawing below gives a brief overview. Your ESP8266 module represents the Device running the uNabto server. As soon as it connects to the internet it identifies itself at the Nabto Basestation, using its unique ID. If a Client wants to connect to the ESP8266, a connect request with the ID is sent to the Basestation, and a direct connection to the device is established. A client can be an HTML page running in a desktop browser extension (IE, Firefox) or the Nabto Mobile App (iOS, Android), or a custom Nabto API Client.

nabto-platform-basics

Get more information on the Nabto platform and the Client/Device SDKs on developer.nabto.com.

The uNabto Platform Adapter

The uNabto server is divided into two layers:

  • The actual uNabto framework (uNabto SDK)
  • The uNabto Platform Adapter abstraction layer between the framework and the Native Platform

unabto-platform-adapter

Hence, we only need to implement the uNabto Platform Adapter, in order to port the uNabto server to the ESP8266 module.

Implementing the Platform Adapter

The Platform Adapter acts as link between the generic uNabto framework and the Arduino platform, including the ESP8266 WiFi library. The adapter is divided into single files, as suggested in the Nabto documentation (TEN023 Writing a uNabto device application, chapter 12):

  • unabto_config.h: Basic uNabto configuration
  • unabto_platform_types.h: Define all necessary uNabto types
  • unabto_platform.h: Platform specific ad-hoc functions
  • network_adapter.cpp: Init, close, read and write functionality for network data
  • time_adapter.cpp: Time functions
  • dns_adapter.cpp: DNS resolving
  • random_adapter.cpp: Random generator
  • log.cpp: Logging

If you are interested in how the platform adapter is implemented in detail, check the adapter files in the src directory of the library on GitHub.

Using the Library

Get the Nabto ESP8266 Arduino library from https://github.com/nabto/unabto-esp8266-sdk and place it in your Arduino library directory. If you don’t know where your library directory is located, see the guide on manual installation of Arduino libraries.

After restarting your IDE the library is installed. An example sketch can be found in

File -> Examples -> Nabto-ESP8266 -> LightSwitch

The sample sketch includes the Nabto class, which encapsulates the Nabto setup. First, some settings are made. This includes the WiFi SSID and password, followed by the unique Nabto ID and preshared key of the device, as well as the pin of the onboard LED to be controlled.

#include <Nabto.h>

// Enter ssid and password of your WiFi network
const char* ssid = "...";
const char* password = "...";

// Enter device id and preshared key from developer.nabto.com
const char* nabtoId = "...";
const char* presharedKey = "...";

// Specify LED pin
const int led1_pin = BUILTIN_LED;

The setup function is used to init the LED pin and the Serial module. In line 42 you can see how the Nabto module is initialised. The begin(..) function is blocking, therefore, the following printout of the Nabto version number only takes place, if the WiFi connection was established.

void setup() {
  // Initialize built-in led
  pinMode(led1_pin, OUTPUT);
  digitalWrite(led1_pin, 1);

  // Initialize Serial
  Serial.begin(115200);

  // Initialize Nabto
  Serial.println("Init...");
  Nabto.begin(ssid, password, nabtoId, presharedKey);

  // Optionally get nabto firmware version
  char versionString[10];
  Nabto.version(versionString);
  Serial.print("Nabto v");
  Serial.print(versionString);
  Serial.println(" running...");
}

The only thing that needs to be done in the loop function is to call the tick() method of the Nabto class. This triggers the framework to check for new UDP packets and send responses. The time between ticks should be around 10 milliseconds. This is achieved by a hard delay, but you can also use the time to do application related stuff.

void loop() {
  // Check for new nabto udp packets and send response. Non-blocking
  Nabto.tick();

  // We have chosen to sleep 10 milliseconds between tics
  delay(10);
}

The following two functions provide a convenient way to set and read the LEDs, although we will only use one LED in this example.

// Set LED and return state.
// Only using ID #1 in this simple example
uint8_t setLed(uint8_t led_id, uint8_t led_on) {
  if (led_id == 1) {
    // inverted
    digitalWrite(led1_pin, !led_on);
    return !digitalRead(led1_pin);
  }
  else {
    return 0;
  }
}

// Return LED state.
// Only using ID #1 in this simple example.
uint8_t readLed(uint8_t led_id) {
  if (led_id == 1) {
    // inverted
    return !digitalRead(led1_pin);
  }
  else {
    return 0;
  }
}

The actual handling of received Nabto messages from the client is implemented in the application_event(..) function. The handler uses the message format used in the default HTML Device Driver, provided in the Nabto portal. For more information on how to create your own HTML DD, please refer to TEN024 Writing a uNabto HTML client.

application_event_result application_event(application_request* appreq, unabto_query_request* r_b, unabto_query_response* w_b) {
  switch(appreq->queryId) {
  case 1:
    {
      //  <query name="light_write.json" description="Turn light on and off" id="1">
      //    <request>
      //      <parameter name="light_id" type="uint8"/>
      //      <parameter name="light_on" type="uint8"/>
      //    </request>
      //    <response>
      //      <parameter name="light_state" type="uint8"/>
      //    </response>
      //  </query>

      uint8_t light_id;
      uint8_t light_on;
      uint8_t light_state;

      // Read parameters in request
      if (!unabto_query_read_uint8(r_b, &light_id)) return AER_REQ_TOO_SMALL;
      if (!unabto_query_read_uint8(r_b, &light_on)) return AER_REQ_TOO_SMALL;

      // Set light according to request
      light_state = setLed(light_id, light_on);

      // Write back led state
      if (!unabto_query_write_uint8(w_b, light_state)) return AER_REQ_RSP_TOO_LARGE;

      return AER_REQ_RESPONSE_READY;
    }
  case 2:
    {
      //  <query name="light_read.json" description="Read light status" id="2">
      //    <request>
      //      <parameter name="light_id" type="uint8"/>
      //    </request>
      //    <response>
      //      <parameter name="light_state" type="uint8"/>
      //    </response>
      //  </query>

      uint8_t light_id;
      uint8_t light_state;

      // Read parameters in request
      if (!unabto_query_read_uint8(r_b, &light_id)) return AER_REQ_TOO_SMALL;

      // Read light state
      light_state = readLed(light_id);

      // Write back led state
      if (!unabto_query_write_uint8(w_b, light_state)) return AER_REQ_RSP_TOO_LARGE;

      return AER_REQ_RESPONSE_READY;

    default:
      return AER_REQ_INV_QUERY_ID;
    }
  }
}

Test your device

After compiling and uploading your LightSwitch sketch to the ESP8266, it establishes a connection to your WiFi network and starts the uNabto server. In your serial monitor you should see the following printout:

Init...
Device id: 'mydeviceid.demo.nab.to'
Program Release 2.21889
Application event framework using SYNC model
SECURE ATTACH: 1, DATA: 1
NONCE_SIZE: 32, CLEAR_TEXT: 0
Nabto was successfully initialized
Nabto v2.21889 running...
SECURE ATTACH: 1, DATA: 1
NONCE_SIZE: 32, CLEAR_TEXT: 0
State change from IDLE to WAIT_DNS
Resolving dns: mydeviceid.demo.nab.to
State change from WAIT_DNS to WAIT_BS
State change from WAIT_BS to WAIT_GSP
######## U_INVITE with LARGE nonce sent, version: - URL: -
State change from WAIT_GSP to ATTACHED

When entering you device ID into your browser or Nabto App, you can see the uNabto Demo client. Using the light switch you can now turn the built-in LED on and off from everywhere!

Screenshot_2016-03-05-14-50-37

Future improvements

Currently, the WiFi SSID and password, as well as the device ID and the preshared key are stored in the ESP8266’s flash memory. This requires an update of the source code and a firmware upload on every change of these parameters. A possible solution to this problem could be a very small web server running on the ESP8266, which is accessible through a parallel running WiFi access point. The parameters entered through the web interface could then be persistently stored in the EEPROM.

7 thoughts on “ESP8266 WiFi Module + Nabto

  1. Attempted to download the .zip file called Nabto-ESP8266 from github. Arduino IDE (1.6.5) gives error “Specified folder/zip file does not contain a valid library”

    Any thoughts?

    Like

    • If you download the ZIP from github, the internal folder structure does not match the pattern expected by the Arduino IDE. Unpack the library and pack the Nabto-ESP8266 folder only (not the nabto-esp8266-library-master folder as before). Now you can add the library via Sketch -> Include Library -> Add .ZIP Library…

      Like

      • That worked. Now having trouble getting my batch of NodeMCU devkit boards working. Can’t wait to try out NABTO. Thanks for the help.

        Tim

        Like

  2. Ok, esp boards working. Now I’m stuck at entering a device id. I’m logged, and enter a device name and hit add.how do I obtain a key?

    Also I downloaded unabto_sdk but I do not see any demo folder. Is this hidden?

    Thanks

    Like

    • The key is the 32 character hex string in the 3rd column of the device table in the Nabto portal.

      You don’t need the SDK for this project since it’s already included in the library. But you can find some examples in unabto_sdk/unabto/apps/

      Like

      • Thanks! It’s showing up now, it wasn’t appearing on my PC, but showed on Safari on a Mac.

        On to the next step!

        Tim

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s