CC3200 Two-Way Audio with Android

Texas Instrument’s CC3200 is a single-chip microcontroller unit with built-in Wi-Fi connectivity, created for the Internet of Things. It can run the FreeRTOS operating system and provides a hardware encryption engine. Sounds interesting? It did to us! So we created a demo that is capable of streaming two-way audio between the CC3200 and an Android App using our uNabto framework. Why do you need Nabto for this? Because it solves all the router and firewall hassle for you: all you need to connect to the device is a unique Device ID!

cc3200-audio-board

What you need

Just hook up the two boards as described in the Audio BoosterPack User Guide provided by TI.

How the Nabto platform works

How does the Nabto platform work exactly? The drawing below gives a brief overview. Your CC3200 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 (i.e. the Android App in this demo) wants to connect to the CC3200, a connect request with the ID is sent to the Basestation, and a direct connection to the device is established.

nabto-platform-basics

Get more information on the Nabto/AppMyProduct platform and the Client/Device SDKs at appmyproduct.com.

The uNabto Platform Adapter:

The uNabto Platform Adapter is a small component that abstracts the Native Platforms network and time functionality. The Platform Adapter is part of the uNabto server.

The uNabto server is divided into two layers:

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

unabto-platform-adapter

To run the uNabto server on the CC3200, we only need to implement the uNabto Platform Adapter (for details see the TEN023 Nabto device SDK guide). The CC3200 adapter is divided into the following files:

  • unabto_config.h: Basic uNabto configuration
  • unabto_platform_types.h: Define all necessary uNabto types
  • unabto_platform.h: Platform specific ad-hoc functions
  • unabto_adapter_network.c: Init, close, read and write functionality for network data
  • unabto_adapter_time.c: Time functions
  • unabto_adapter_dns.c: DNS resolving
  • unabto_adapter_random.c: Random generator
  • unabto_adapter_crypto.c: CC3200 hardware encryption

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

The Device Application

Info: The following describes the audio demo application (‘audio’ branch). A more generic and straightforward example of using streaming to echo data is maintained in the ‘master’ branch of our CC3200 GitHub repository.

The uNabto server is running in its own task implemented in unabto_task.c. After waiting for the network connection being established in another task, the uNabto server is initialized with basic settings as well as the unique Device ID and pre-shared encryption key from portal.appmyproduct.com.  Then, the server continuously handles incoming network events and checks for available recorded audio to send to the client.

void UNabto(void* pvParameters) {
    // device id and key from portal.appmyproduct.com
    const char* nabtoId = "<DEVICE ID>";
    const char* presharedKey = "<KEY>";

    // Initialize uNabto
    nabto_main_setup* nms = unabto_init_context();
    nms->ipAddress = g_uiIpAddress;
    nms->id = nabtoId;
    nms->secureAttach = 1;
    nms->secureData = 1;
    nms->cryptoSuite = CRYPT_W_AES_CBC_HMAC_SHA256;

    const char* p;
    unsigned char* up;
    for (p = presharedKey, up = nms->presharedKey; *p; p += 2, ++up) {
        *up = hctoi(p[0]) * 16 + hctoi(p[1]);  // hex string to byte array
    }

    while ((!IS_CONNECTED(g_ulStatus)) || (!IS_IP_ACQUIRED(g_ulStatus))) {
        osi_Sleep(500);
    }

    srand(xTaskGetTickCount());

    stream_audio_init();
    unabto_init();

    while (true) {
        wait_event();
        stream_audio_write();
    }
}

The actual audio streaming code is in stream_audio.c. The unabto_stream_event() function handles all incoming streaming events. Once a Nabto stream connection is established, the device is waiting for a stream command. In this case, there is only the command “audio”. If an unknown command is received, the device returns “-” and closes the stream. If “audio” is received from the client an acknowledgment is returned (“+”) and the actual audio streaming is started. Incoming audio data from the client is processed in lines 125-137:

    if (my_audio_stream.state == STREAM_STATE_STREAMING) {
		const uint8_t* buf;
		unabto_stream_hint hint;
		size_t readLength = unabto_stream_read(stream, &buf, &hint);
		if (readLength > 0) {
			adpcm_decode(pPlayBuffer, buf, readLength);
			if (!unabto_stream_ack(stream, buf, readLength, &hint)) {
				my_audio_stream.state = STREAM_STATE_CLOSING;
			}
		} else {
			if (hint != UNABTO_STREAM_HINT_OK) {
				my_audio_stream.state = STREAM_STATE_CLOSING;
			}
		}
}

The data is read from the stream, decoded, and written to the circular play buffer. Processed data has to be acknowledged with unabto_stream_ack(). For the audio encoding ADPCM is used (for implementation details see adpcm_audio.c). It compresses the two 16-bit stereo samples to one single byte. At 16000 samples per second, this results in a transfer bitrate of 16 kbit/s which is no problem for the CC3200, even for encrypted remote connections. If you want to have a more advanced codec like for example Speex, just replace the encoding and decoding functions.

As mentioned before, the uNabto task continuously checks for available recorded audio by calling the stream_audio_write() function. If new encoded audio is available and a stream is established, the data is sent.

void stream_audio_write() {
	if (my_audio_stream.state != STREAM_STATE_STREAMING) {
		return;
	}
	size_t encodedLen = adpcm_encode(pRecordBuffer, encodedBuf, sizeof(encodedBuf));
	if (encodedLen == 0) {
		return;
	} else {
		UNABTO_ASSERT(encodedLen == sizeof(encodedBuf));
	}

	unabto_stream_hint hint;
	size_t writeLength =
			unabto_stream_write(my_audio_stream.stream, encodedBuf, sizeof(encodedBuf), &hint);

	if (writeLength <= 0 && hint != UNABTO_STREAM_HINT_OK) {
		my_audio_stream.state = STREAM_STATE_CLOSING;
	}

	UpdateReadPtr(pRecordBuffer, writeLength * ENCODING_RATIO);
}

Using the CC3200 Code

You can get the whole CC3200 code including the described platform adapter and the audio streaming device application from the audio branch of our public CC3200 GitHub repository. Simply follow the instructions in the README to set everything up.

The Android Client

The Android audio streaming client is also published on GitHub. It uses our android client SDK available on JCenter (for source code see GitHub repository). It is included in the build.gradle with one single line:

compile ‘com.nabto.android:nabto-api:1.0.1’
}

The main App logic is implemented in MainActiviy.java. Once the unique Device ID is entered in the UI and the OPEN AUDIO STREAM button is pressed, a thread is started to establish the stream connection and send the “audio” command. Then, a recording + sending and a receiving + playing thread are started until the connection breaks or the stream is closed by the user.

android-audio-client

To run the App on your Android device, follow the README instructions in the repository. If you enter the Device ID, you should be able to establish a stream connection and hear the microphone (and line-in) input of the opposite device.

App My Pi – AppMyProduct Heat Control Demo on Your Raspberry Pi

Have you ever wanted to connect and remote control an embedded device in real-time, like for example your Raspberry Pi? Are you concerned about the security of your communication, but still want to quickly develop high-quality apps? With our IoT application platform AppMyProduct we provide the solution for you!

To give you an impression, we created a Heat Control Demo (app+device source code available on GitHub). This article describes all necessary steps to install and run the demo application on your Raspberry Pi and control it with a smartphone app for iOS/Android – and with a little experience (or some documentation digging) with both HTML5 and Cordova you can extend the demo to whatever RPI remote control purpose you can think of.

rpi-control

Also check out the demo running on a STM32 with FreeRTOS or low-cost ESP8266 WiFi module.

Setup Raspberry Pi

If you already have a Raspberry Pi with working Internet connection, you can skip this step.

Get the Raspbian operating system (lite or with PIXEL) from the official website. Copy the downloaded image to a SD card as described in the documentation.

Use an Ethernet cable to connect your Raspberry Pi to the network, or follow this guide to setup wireless networking.

Install the Heat Control Demo

The device software of our AppMyProduct Heat Control Demo is available on GitHub. The following steps walk you through installing it on your Raspberry Pi.

Build

This step requires git and cmake. I you haven’t installed them already, you should do that now:

sudo apt-get install -y git cmake

To get the source files, clone our GitHub repository and enter the directory:

git clone --recursive https://github.com/nabto/appmyproduct-device-stub.git
cd appmyproduct-device-stub

Create a build folder and enter it:

mkdir build
cd build

Build the demo application:

cmake ..
make -j3

Move the built executable to your home directory:

mv amp_device_stub ~/

Finally, go back to your home directory:

cd

Create Run Script

The demo application takes a couple of parameters, most importantly the unique device id and a licence key. You can obtain both from portal.appmyproduct.com.
You can try to run the demo with the following command (use your parameters):

sudo ./amp_device_stub -d 7pbugghs.smtth.appmyproduct.com -k 985ef2a3de0fe5328cf7c1923b13cbef -N 'RPI' -P 'Raspeberry Pi'

Abort the demo with Ctrl-C.

For a more convenient usage, we create a startup script:

nano run_amp.sh

Copy the following code into the editor (use your parameters):

#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
$DIR/amp_device_stub -d 7pbugghs.smtth.appmyproduct.com -k 985ef2a3de0fe5328cf7c1923b13cbef -N 'RPI' -P 'Raspeberry Pi'

Save and close nano with Ctrl-X and confirm with Y and Return.

Make the script executable with:

chmod +x run_amp.sh

Try to run the demo application again using the startup script:

sudo ./run_amp.sh

Run on Startup

If you want the demo to run automatically whenever the Raspberry Pi starts up, open /etc/rc.local with nano:

sudo nano /etc/rc.local

Insert the following line above “exit 0”:

stdbuf -oL /home/pi/run_amp.sh > /tmp/amp.log 2>&1 &

This runs the startup script in background and logs all outputs to /tmp/amp.log.

To test it, reboot you Raspberry Pi using:

sudo reboot

After the reboot, you should be able to see the amp_device_stub process running in the background. Check with:

ps | grep amp_device_stub

You can also see the log file using:

cat /tmp/amp.log

Example log:

11:12:19:331 unabto_common_main.c(127) Device id: '7pbugghs.smtth.appmyproduct.com'
11:12:19:331 unabto_common_main.c(128) Program Release 123.456
11:12:19:331 unabto_app_adapter.c(698) Application event framework using SYNC model
11:12:19:331 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
11:12:19:331 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
11:12:19:331 unabto_common_main.c(206) Nabto was successfully initialized
11:12:19:331 unabto_main.c(85) AppMyProduct demo stub [7pbugghs.smtth.appmyproduct.com] running!
11:12:19:331 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
11:12:19:331 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
11:12:19:331 unabto_attach.c(792) State change from IDLE to WAIT_DNS
11:12:19:331 unabto_attach.c(793) Resolving dns: 7pbugghs.smtth.appmyproduct.com
11:12:19:341 unabto_attach.c(814) State change from WAIT_DNS to WAIT_BS
11:12:19:402 unabto_attach.c(479) State change from WAIT_BS to WAIT_GSP
11:12:19:412 unabto_attach.c(266) ######## U_INVITE with LARGE nonce sent, version: - URL: -
11:12:19:453 unabto_attach.c(580) State change from WAIT_GSP to ATTACHED

Use it!

First, install the AppMyProduct Heat Control Demo on your smartphone (Apple App Store / Google Play / Android APK / Source).

Search for devices in your network. You should see your Raspberry Pi:

rpi-discover

After pairing, you can control the simulated heat pump:

rpi-control

We added a little gimmick for the Raspberry Pi: The device application controls the green on-board LED! Its blink frequency reflects the currently set target temperature. If you deactivate the heat pump, the LED is turned off. (On some Raspberry Pi versions the LED is inverted, hence the LED is permanently turned on in that case.)

Factory Reset

The Heat Control Demo application saves all settings and paired devices in a file called persistence.bin located in the same directory (your home directory in this case). In order to reset these to default, delete the file with

sudo rm persistence.bin

and restart the demo, e.g. by rebooting the Raspberry Pi:

sudo reboot

STM32F746G-DISCO Board with FreeRTOS + AppMyProduct

This is an updated version of a previous post incorporating our new AppMyProduct platform.

When working with STM32 ARM Cortex-M microcontrollers, the free embedded software STM32Cube from ST provides all necessary drivers and a collection of middleware components to reduce the initial development effort. One of the mentioned middleware components is the popular FreeRTOS real-time operating system Nabto is partnering with to create a powerful combined FreeRTOS+Nabto solution.

The launch of our new AppMyProduct application platform helps you quickly develop high-quality apps for remote control of your devices. This article explains the implementation of a demo heat-pump application using Nabto + FreeRTOS on a STM32F746G-DISCO board, which can be controller by our Heat Control Ionic starter app. (A previous blog post described the now deprecated HTML device driver approach.)

nabto+stm32

STM32F74G-DISCO board running the heat-pump demo

What you need

This demo is based and tested on the STM32F746G-DISCO board, but should be portable to similar STM32 boards.

Why Nabto and how does it work?

Have you ever thought about connecting to your STM32 device from outside your local network without nerve wracking router and firewall configurations or slow and intransparent cloud services? Running the uNabto server on your STM32 device you can establish a fast and secure Peer-to-Peer connection using only a static device ID – from everywhere, no matter what is in between.

So how does Nabto do this? The drawing below gives a brief overview. Your STM32 board 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 Device ID. If a Client (e.g. our Heat Control Ionic starter app) wants to connect to the STM32 board, a connect request with the ID is sent to the Basestation, and a direct connection to the device is established.

Screen Shot 2016-02-29 at 13.23.22

Nabto in the STM32Cube Architecture

As mentioned before, the STM32Cube provides a Hardware Abstraction Layer API and a selection of Middleware components. The uNabto server we want to implement builds on top of the STM32Cube middleware, as can be seen in the following diagram:

nabto+stm32cube-architecture.png

The uNabto server itself is divided into two layers:

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

Hence, we only need to implement the uNabto Platform Adapter, in order to port the uNabto server and the demo application to the STM32 platform.

Implementing the Platform Adapter

The Platform Adapter acts as link between the generic uNabto framework and the STM32Cube middleware layer, including the LwIP TCP/IP stack which will be used for networking. The LCD Log Utility is used to display the Nabto log output on the screen.

The adapter is divided into single files, as suggested in the Nabto documentation (TEN023 Nabto device SDK guide, chapter 12):

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

If you are interested in how the platform adapter is implemented in detail, check the adapter files in the Inc and Src directories of the demo on GitHub.

Implementing the Nabto Thread

After creating the Platform Adapter the uNabto Server is ready to use. uNabto is initialized and runs in it’s own FreeRTOS thread. The thread is defined in Src/unabto_main.c:

static void unabto_thread()
{
  const char* device_id = "<DEVICE ID>";
  const char* pre_shared_key = "<KEY>";

  // Init uNabto
  nabto_main_setup* nms = unabto_init_context();
  nms->id = strdup(device_id);

  nms->secureAttach = true;
  nms->secureData = true;
  nms->cryptoSuite = CRYPT_W_AES_CBC_HMAC_SHA256;

  if (!unabto_read_psk_from_hex(pre_shared_key, nms->presharedKey, 16)) {
    NABTO_LOG_ERROR(("Invalid cryptographic key specified", pre_shared_key));
    return;
  }

  if (!unabto_init()) {
    NABTO_LOG_FATAL(("Failed at nabto_main_init"));
  }

  // Init demo application
  demo_init(do_factory_reset);
  demo_application_set_device_name("STM32F746G-DISCO");
  demo_application_set_device_product("ACME 9002 Heatpump");
  demo_application_set_device_icon_("img/chip-small.png");

  // Main loop
  for (;;) {
    unabto_tick();
    osDelay(10);
    demo_application_tick();
  }
}

The code above initializes the server with your unique Device ID and the pre-shared encryption key from portal.appmyproduct.com (insert in highlighted lines). Then the heat-pump demo, which will be briefly described later, is initialized. Finally, an infinite loop repeatedly calls the unabto_tick() method. This triggers the framework to check for new UDP packets and send responses. The time between ticks should be around 10 milliseconds, which is achieved by a hard OS delay and some additional demo specific workload.
To start the Nabto thread we provide a unabto_start() method. It is called by the main program after initializing the TCP/IP stack and either setting a static IP address or obtaining a dynamic IP address from a DHCP server.

void unabto_start()
{
  sys_thread_new("uNabto", unabto_thread, NULL, DEFAULT_THREAD_STACKSIZE, NABTO_THREAD_PRIO);
}

The actual handling of received client requests is implemented in the application_event() callback function. The handler uses the interface definition shared with the client.

application_event_result application_event(application_request* request,
                                           unabto_query_request* query_request,
                                           unabto_query_response* query_response) {

    NABTO_LOG_INFO(("Nabto application_event: %u", request->queryId));
    debug_dump_acl();

    // handle requests as defined in interface definition shared with
    // client - for the default demo, see
    // https://github.com/nabto/ionic-starter-nabto/blob/master/www/nabto/unabto_queries.xml

    application_event_result res;

    switch (request->queryId) {
    case 10000:
        // get_public_device_info.json
        if (!write_string(query_response, device_name_)) return AER_REQ_RSP_TOO_LARGE;
        if (!write_string(query_response, device_product_)) return AER_REQ_RSP_TOO_LARGE;
        if (!write_string(query_response, device_icon_)) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_pair_allowed(request))) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_user_paired(request))) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_user_owner(request))) return AER_REQ_RSP_TOO_LARGE;
        return AER_REQ_RESPONSE_READY;

    case 10010:
        // set_device_info.json
        if (!fp_acl_is_request_allowed(request, REQUIRES_OWNER)) return AER_REQ_NO_ACCESS;
        res = copy_string(query_request, device_name_, sizeof(device_name_));
        if (res != AER_REQ_RESPONSE_READY) return res;
        if (!write_string(query_response, device_name_)) return AER_REQ_RSP_TOO_LARGE;
        return AER_REQ_RESPONSE_READY;

    case 11000:
        // get_users.json
        return fp_acl_ae_users_get(request, query_request, query_response); // implied admin priv check

    case 11010:
        // pair_with_device.json
        if (!fp_acl_is_pair_allowed(request)) return AER_REQ_NO_ACCESS;
        res = fp_acl_ae_pair_with_device(request, query_request, query_response);
        debug_dump_acl();
        return res;

        // [...]
    }
}

For more details on the Heat-Pump demo application please review the source in Src/unabto_application.c.

Hands-On!

Enough theory. Let’s try out the demo! It is available as System Workbench for STM32 (SW4STM32) project here on GitHub. Simply follow the instructions in the README.

The board should print the Nabto log on the LCD screen, as shown on the picture in the beginning of the article.

Now, connect to your device using the Heat Control Ionic starter app and see the parameters on the bottom of the LCD display change according to your app inputs. The simulated room temperature slowly converges to the target temperature. You can update the current room temperature in your app by pressing Refresh.

amp_stm32_app

The device settings are persistently stored in the STM32 flash memory. If you want to perform a “factory reset”, press the User button on the board during startup/reset. You should see FACTORY RESET printed to the display.

ESP8266 WiFi Module + AppMyProduct

This is an updated version of a previous post incorporating our new AppMyProduct platform.

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 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 16.04 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 a native app or use an abstraction framework like our Heat Control Ionic starter app used in this demo.

nabto-platform-basics

Get more information on the AppMyProduct platform and the Client/Device SDKs on portal.appmyproduct.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 Nabto device SDK guide, section 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 follow the installation instructions.

An example sketch can be found in

File -> Examples -> Nabto-ESP8266 -> HeatPump

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 Device ID and preshared key of the device obtained from portal.appmyproduct.com

// Enter ssid and password of your WiFi network
const char* WIFI_SSID = "<SSID>";
const char* WIFI_PASSWORD = "<PASSWORD>";

// Enter device id and pre-shared key from portal.appmyproduct.com
const char* DEVICE_ID = "<DEVICE ID>";
const char* PRE_SHARED_KEY = "<PRE-SHARED KEY>";

The setup function is used to init the LED pin, the Serial module, and connect to the WiFi. In line 91 you can see how the Nabto module is initialised. After the Nabto version is printed our heatpump demo is initialized.

void setup() {
    // Initialize Serial
    Serial.begin(115200);

    // Wait 2s for button press to do factory reset
    pinMode(0, INPUT_PULLUP);
    bool factory_reset = false;
    while(millis() < 2000) {
      if(digitalRead(0) == LOW) {
        Serial.println("FACTORY RESET");
        factory_reset = true;
        break;
      }
    }

    // Initialize built-in led
    pinMode(LED_PIN, OUTPUT);
    analogWrite(LED_PIN, PWMRANGE);

    // Initialize WiFi
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    Serial.print("Connecting to WiFi..");
    while (WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(500);
    }
    Serial.println("done");

    // Initialize Nabto
    Serial.println("Init Nabto...");
    Nabto.begin(DEVICE_ID, PRE_SHARED_KEY);

    // Print Nabto version
    char versionString[10];
    Nabto.version(versionString);
    Serial.print("Nabto v");
    Serial.print(versionString);
    Serial.println(" running");

    // Initialize demo application
    demo_init(factory_reset);
    demo_application_set_device_name("ESP8266");
    demo_application_set_device_product("ACME 9002 Heatpump");
    demo_application_set_device_icon_("img/chip-small.png");
}

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. For example, we use it to update the brightness of the LED and to simulate the room temperature in the demo application tick function.

void loop() {
    Nabto.tick();
    demo_application_tick();
    delay(10);
}

The actual handling of received Nabto messages from the client is implemented in the application_event(..) function. The handler uses the interface definition shared with the client.

pplication_event_result application_event(application_request* request,
                                           unabto_query_request* query_request,
                                           unabto_query_response* query_response) {

    //NABTO_LOG_INFO(("Nabto application_event: %u", request->queryId));
    //debug_dump_acl();

    // handle requests as defined in interface definition shared with
    // client - for the default demo, see
    // https://github.com/nabto/ionic-starter-nabto/blob/master/www/nabto/unabto_queries.xml

    application_event_result res;

    switch (request->queryId) {
    case 10000:
        // get_public_device_info.json
        if (!Nabto.write_string(query_response, device_name_)) return AER_REQ_RSP_TOO_LARGE;
        if (!Nabto.write_string(query_response, device_product_)) return AER_REQ_RSP_TOO_LARGE;
        if (!Nabto.write_string(query_response, device_icon_)) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_pair_allowed(request))) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_user_paired(request))) return AER_REQ_RSP_TOO_LARGE;
        if (!unabto_query_write_uint8(query_response, fp_acl_is_user_owner(request))) return AER_REQ_RSP_TOO_LARGE;
        return AER_REQ_RESPONSE_READY;

    case 10010:
        // set_device_info.json
        if (!fp_acl_is_request_allowed(request, REQUIRES_OWNER)) return AER_REQ_NO_ACCESS;
        res = Nabto.copy_string(query_request, device_name_, sizeof(device_name_));
        if (res != AER_REQ_RESPONSE_READY) return res;
        if (!Nabto.write_string(query_response, device_name_)) return AER_REQ_RSP_TOO_LARGE;
        return AER_REQ_RESPONSE_READY;

    case 11000:
        // get_users.json
        return fp_acl_ae_users_get(request, query_request, query_response); // implied admin priv check

        // [...]
    }
}

Test your device

After compiling and uploading your HeatPump 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:

Connecting to WiFi........done
Init Nabto...
Device id: 'n7j4qebq.hyr7o.appmyproduct.com'
Program Release 123.456
Application event framework using SYNC model
SECURE ATTACH: 1, DATA: 1
NONCE_SIZE: 32, CLEAR_TEXT: 0
Nabto was successfully initialized
Nabto v123.456 running
SECURE ATTACH: 1, DATA: 1
NONCE_SIZE: 32, CLEAR_TEXT: 0
State change from IDLE to WAIT_DNS
Resolving dns: esp8266test1.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

Now, connect to your device using the Heat Control Ionic starter app and see the LED change its brightness according to the target heat.

amp_esp8266_app

The Roomba (Part 2 of 2)

Please read Part 1 to read about the preliminary steps in the Roomba saga.

This part will be the fun part where we turn the Roomba into a fully fledged remote controlled vehicle fitted with realtime video feed as well!

If at any time you feel like trying this yourself, you can sign up for a free developer account or/and read more at developer.nabto.com.

In details, this part will be dealing with

  • Turn the Roomba into a remote controlled car
  • Add soundeffects
  • Add sensor data
  • Add video streaming

The RC Roomba

Turning the Roomba into a remote controlled car is really easy once the groundwork is done correctly (see Part 1).

All we need are the new opcodes given to us in the documentation:

  • Drive straight (20 cm/s)
    • Using W
    • {137, 0, 255, 128, 0}
  • Reverse (20 cm/s)
    • Using S
    • {137, 255, 0, 128, 0}
  • Rotate counterclockwise
    • Using A
    • {137, 0, 255, 0, 1}
  • Rotate clockwise
    • Using D
    • {137, 0, 255, 255, 255}

This is all we need on the device side of things.
For the html part I simply chose to create a text input field which detects when a certain character is pressed in accordance with the keys given above. Say, for example, that you press W. The Roomba will now drive in a straight line until the user sends a new command.
If a key is pressed which does not have a predefined action, then the Roomba will stop driving. I usually use space to stop.

Adding sound effects

It is possible to store melodies in the Roomba. On our specific model, 581, we can store 4 melodies with 16 notes each (that storage!). From the documentation we find the serial sequence to be

[140] [Song Number] [Song Length] [Note Number 1] [Note Duration 1] [Note Number 2] [Note Duration 2].etc.

I decided to add a reverse sound, the DSB sound and a Dixie Horn style, River Kwai March (warning: loud) sound. These were added with the following codes

  • Reverse sound
    • {140, 1, 6, 84, 32, 30, 32, 84, 32, 30, 32, 84, 32, 30, 32}
  • DSB sound
    • {140, 0, 3, 74, 40, 75, 20, 70, 32}
  • Dixie Horn sound
    • {140, 3, 12, 86,10, 83,10, 79,10, 79,10, 79,10, 81,10, 83,10, 84,10, 86,10, 86,10, 86,10, 83,10}

The songs can then be played back by this sequence [141][Song Number], like this

  • Reverse sound
    • Played when the Roomba goes in reverse
    • {141, 3}
  •  DSB
    • Using K
    • {141, 0}
  • Dixie Horn
    • Using L
    • {141, 3}

Sensor data

The Roomba has 58 different sensor data packets, which all return hex values. For this I want to query

  • Battery temperature
    • Packet ID 24
    • Data bytes: 1, signed.
    • Returns the temperature of the Roomba’s battery in degrees Celsius.
  • Battery charge
    • Packet ID 25
    • Data bytes: 2, unsigned
    • Returns the charge level in mAh
  • Battery capacity
    • Packet ID 26
    • Data bytes: 2, unsigned
    • Returns battery capacity in mAh
  • Charging state
    • Packet ID 34
    • Data bytes: 1, unsigned
    • Returns 1 if charging, 0 otherwise

We can query all these with a single sequence

[149][Number of Packets][Packet ID 1][Packet ID 2]...[Packet ID N]

which look likes this in our case

{149, 4, 24, 25, 26, 34}

Referencing the above Data bytes gives us a total sensor byte size of 6 bytes. The battery temp and charging state can be taken directly, since they only have 1 data byte. Charge and capacity need some attention since we need to bitwise left shift on the high (first) byte before we can get a decimal number. In C this is done like so

Number = [1]<<8 | [2]

We then calculate the battery level by simply doing

bat_level = 100 * (charge/capacity)

I then created a button for our html code which output charging state, battery level and battery temperature, when pressed.

Video streaming through Nabto tunnel

For this we selected to use a Raspberry Pi Camera Module since we already had one at the office. I then read about various ways of streaming the output and display it on a webserver. I tried many different approaches but eventually settled on RPi Cam Web Interface since it gave the best compromise between low latency, low bandwith usage and “high” resolution. Furthermore, these settings are fully costumisable and the user can thus change values for their needs. An extra feature is the ability to run motion detection and to take 2592 x 1944 pixel static images or 1080p @ 30fps, 720p @ 60fps  and 640x480p 60/90 video recording.

Setting up a webserver on our Pi

To get the video webserver up and running on our Pi is fairly easy when following the instructions laid out here.

sudo apt-get update
sudo apt-get dist-upgrade
git clone https://github.com/silvanmelchior/RPi_Cam_Web_Interface.git
cd RPi_Cam_Web_Interface
chmod u+x *.sh
./install.sh

The installation prompt will have some adjustable settings such as whether to run an apache or nginx webserver. Choose whatever you prefer. I chose to change the default port from 80 to 90 to avoid conflict with any other service running on our Pi. After installation a webserver should now be running. We can access it on our local network by going to pi_ip:port_chosen/html

If no video is running, try issuing ./start.sh or do an update by ./update.sh.

The default settings worked very well for me but if you happen to have a very low bandwith internet connection (or running this on one of the earlier Pi versions) you can try to adjust the bandwith settings.

Tunneling

To make our video feed available from anywhere, we will be running a Nabto tunnel on our Pi as well. Compiling a Nabto tunnel is very easy, simple issue these commands one line at a time on the Pi

cd unabto/apps/tunnel
cmake .
make

which we can execute by doing

./unabto_tunnel -d "id".demo.nab.to -s -k "key"

where the id and key are generated at developer.nabto.com

Finally we need to run the other end of the tunnel on our client machine. I will present how to do this using our simpleclient_app solution which works on Linux, Windows and Mac OSX. Furthermore I will walk through how to use the special Tunnel manager tool for Windows. All this can be downloaded from developer.nabto.com where we also need the common Nabto Client SDK Resources.

Command line

On our client machine, combine the Simple Client and Client SDK Resources such that the structure look like this
./bin/simpleclient_app and ./share/nabto/users/guest.crt and then issue

./simpleclient_app -q "id".demo.nab.to --tunnel client_port:localhost:device_port

which should output a few lines ending with either
tunnelStatus LOCAL
or
tunnelStatus REMOTE_P2P
depending on if the connection to the Pi is local or remote.

Tunnel Manager for Windows

Grab a copy of Tunnel Manager and input

"id".demo.nab.to into "Server"
127.0.0.1:client_port into "Local endpoint"
127.0.0.1:device_port into "Remote endpoint"

Which can look something like this

tunnelmanager_windows

Tunnel Manager for Windows. Change the Server name, Local endpoint and Remote endpoint to whatever you chose earlier on.

The tunnel is now up and running on the Pi and we are connected to from the client.

Let’s have some fun!

Everything is now setup. On our device side we are running a Roomba remote ./unabto_raspberry and a ./unabto_tunnel.

On the client side we are either running no tunnel (if we do not need video streaming) or either a command line ./simpleclient_app or the Tunnel Manager for Windows.

We can now finally access our uNabto Roomba webpage as we did in Part 1 where we will be greeted with this.

roomba_video_html

uNabto Roomba remote control html device driver

As stated below the image, clicking it will open a new window showing us the tunneled stream from the webserver running on the Pi.
Just below the image is a button for reading sensor data and below that I placed the input field for controlling the uNabto Roomba.

All that is left is to test it out!

If you feel like doing the same thing, please feel free to check out the code on Github and sign up for a developer account at developer.nabto.com, it is all free and you can create and manage 10 devices. This is also where you can find the SDKs and other Nabto software!

 

The Roomba (Part 1 of 2)

As some of you might have seen on twitter we had a device laying around at the Nabto headquarters with Nabto written all over it.


Today is the grand reveal of our Roomba hack!

full_roomba_tilt.jpg

I would like one hacked Roomba, please!

Like the CoffeePi this project was rather substantial so the Roomba hack will be split in two parts.

In this part we will be dealing with a common use case, namely to start a clean cycle remotely. For this we will go through

  • Hardware hacking and wiring
  • Adding the Nabto framework

Part 2 will deal with the fun stuff

  • Turn the Roomba into a remote controlled car
  • Add soundeffects
  • Add sensor data
  • Add video streaming

Hardware hacking and wiring

Roombas manufactured after October 2005, have a Serial Command Interface (SCI) for which some great documentation (here and here) is given by the company itself. Reading these revealed that everything on the Roomba is configurable through this interface and it is indeed awesome that the company itself encourages the hacking community. So why not get some Nabto running on our Roomba?
The model we have is a 5xx series. For our specific model, 581, the serial port was hidden underneath a plastic shroud which we tore right off. Underneath we locate the 7 pin SCI which look like this (from the documentation)

sci_pinout.png

We will be using pin 3, 4, 5 and 6 for communication. For this, we settled on using a 5V (!) USB serial cable. If you plan on using a 3.3V serial cable, you will need a logic level converter.

Furthermore, we want the Roomba to truly be standalone so we need some way of converting the unregulated battery voltage of 14.4 V to 5V. My simple, cheap go to solution for situations like this is an USB car charger which can be had for around 1$. They are built for variable voltage inputs of everything from 12V to 24V so they will work just fine for our Roomba project.

car_charger.png

Our 1$ USB car charger all wired up

We then fit the + wire of our USB car charger to pin 1 or 2 on the Roomba and  the + wire to pin 7 on the Roomba, for ground. In total, our wiring should look like this

roomba_wiring

Full Roomba wiring. Please note that the right hand side names and colours refer to the serial cable names. The left hand side refer to the matching colours and +, – of the USB car charger.

Adding the Nabto framework

To use the USB serial cable I wrote some small helper functions, which we will use for waking, initialising and writing/reading to/from the Roomba.

First, we need to initialise our serial connection (which we only need to do once)


char *portname = "/dev/ttyUSB0";

fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0)
{
    NABTO_LOG_INFO(("error %d opening %s: %s\n", errno, portname, strerror (errno)));
    return 0;
}
else{
    NABTO_LOG_INFO(("Opening %s: %s\n", portname, strerror (errno)));
}

    set_interface_attribs (fd, B115200, 0);  // set speed to 115,200 bps, 8n1 (no parity)
    set_blocking (fd, 0);                // set no blocking

We continue by waking up the Roomba from sleep which we do by setting the Device Detect (DD) low for say, 100ms, (as stated in the documentation). This is done by controlling the RTS line of our serial.

// Wake Roomba
setRTS(fd, 0);
usleep(100000); //0.1 sec
setRTS(fd, 1);
sleep(2);

The Roomba is then ready for commands! The code for inputting a virtual clean button press is

// Start clean cycle
char clean[] = {135};
write(fd, &clean, sizeof(clean));
usleep ((sizeof(clean)+25) * 100);

The actual command, or opcode, is 135, taken from the documentation. To stop the cleaning process, we can either issue the clean command again or put the Roomba into sleep mode. To avoid ambiguity when sending commands, I chose the latter, which has the opcode 133.

For now, this is all we need but we will explore many more (much more fun) commands in part 2 (we will update with a link here when posted).

Since we have written the helper functions in pure C, this code can be compiled for multiple devices. I tested it on my laptop running Linux Mint 17.3 Cinnamon 64-bit and on a Raspberry Pi 2 running Raspbian Jessie. It should compile just fine on at least all versions of Raspberry Pi and possibly anything else running Linux with the required libraries.

For our standalone Roomba, we of course settled on using the Pi, which we first set up for wireless network access (check an easy howto here) followed by getting the uNabto files and compiling for the Raspberry Pi. This is done by issuing the following commands one line at a time

sudo apt-get install git
sudo apt-get install cmake
git clone https://github.com/MarcusTherkildsen/unabto
cd unabto/apps/raspberry_pi_roomba
cmake .
make

We now have uNabto compiled on our Pi!
All that is left to do is to create a new device at developer.nabto.com. Simply Add Device and copy the newly created Key 

We now return to the Raspberry Pi and issue the following command for initiating the Nabto software

sudo ./unabto_raspberrypi -d "id".demo.nab.to -s -k "key"

You should see a couple of lines of output ending with

13:40:47:548 unabto_attach.c(575) State change from WAIT_GSP to ATTACHED

Which means uNabto is successfully up and running!
That’s all, we can now remotely start a cleaning cycle and stop it again by opening a browser and access id.demo.nab.to in your browser. You will be met with a log in page, simply click Guest, followed by an image like this

html_dd_screenshoot_roomba.png

uNabto Roomba html device driver

Sliding the switch to either side will now trigger the clean cycle on our Roomba, check it out!

If you suddenly got the urge to create your own IoT device using Nabto feel free to check out nabto.com and sign up for a developer account developer.nabto.com, it is all free and you can create and manage 10 devices. This is also where you can find the SDKs and other Nabto software!

The full code for this simple Roomba uNabto hack can be found at github.

Stay tuned for part 2 where we’ll have some fun!

Dartino + uNabto

The experimental open-source project Dartino enables you to write software for embedded systems using the modern Dart language and a set of libraries, that let you be highly productive. So why not add another powerful library? Thanks to  improvements to the FFI library in the latest Dartino SDK, we are now able to use the uNabto framework from within Dartino!

dartino-logo

Note: Due to remaining limitations of the Dartino FFI library this is currently only working on a local PC. Thanks to the Dartino team this might be resolved in the near future…stay tuned!

Why use uNabto in your Dartino solution?

Have you ever thought about connecting to your embedded system running Dartino from outside your local network without nerve-racking router and firewall configurations or heavy and intransparent cloud services? Running the uNabto server on your embedded system, you can establish a fast and secure Peer-to-Peer connection using only a static ID – from everywhere, no matter what is in between.

So how does Nabto do this? The drawing below gives a brief overview. Your embedded system 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 embedded system, a connect request with the ID is sent to the Basestation, and a direct connection to the device is established. A client can be a HTML page running in a desktop browser extension (IE, Firefox) or the Nabto Mobile App (iOS, Android), or a custom Nabto API Client. If you prefer Cordova also check out our recently released Nabto Cordova Plugin.

nabto-security

Get the sample application

We published a sample application including the uNabto Dartino library on GitHub. In order to set it up, follow the three steps below.

Step 1: Clone the repository

$ git clone --recursive https://github.com/nabto/unabto-dartino
$ cd unabto-dartino

Step 2: Download and unzip the latest Dartino SDK

Linux:
$ curl "https://storage.googleapis.com/dartino-archive/channels/dev/raw/0.4.0-dev.0.0/sdk/dartino-sdk-linux-x64-release.zip" -o "/tmp/dartino-sdk.zip"
$ unzip /tmp/dartino-sdk.zip

Mac OS:
$ curl "https://storage.googleapis.com/dartino-archive/channels/dev/raw/0.4.0-dev.0.0/sdk/dartino-sdk-macos-x64-release.zip" -o "/tmp/dartino-sdk.zip"
$ unzip /tmp/dartino-sdk.zip

Step 3: Build the C library

$ mkdir build
$ cd build
$ cmake ..
$ make
$ cd ..

Use the sample application

The sample application acts as an embedded device that controls a virtual living room light. To connect to the application we first need to assign a unique Device ID and a pre-shared encryption Key to it. You can get them from developer.nabto.com after adding a new Device. Both id and key are passed as strings to the constructor of the uNabto server:

main() {
  // Configure the uNabto server with a server ID and a pre-shared key obtained
  // from `developer.nabto.com`.
  var unabto = new UNabto("devicename.demo.nab.to", "35d0dca...");

You can now fire up the application on you local PC with the Dartino tool:

$ ./dartino-sdk/bin/dartino run src/app.dart

You should see a log printout similar to this:

15:18:54:118 unabto_common_main.c(127) Device id: 'devicename.demo.nab.to'
15:18:54:118 unabto_common_main.c(128) Program Release 123.456
15:18:54:118 unabto_app_adapter.c(698) Application event framework using SYNC model
15:18:54:118 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
15:18:54:118 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
15:18:54:118 unabto_common_main.c(206) Nabto was successfully initialized
15:18:54:118 unabto_context.c(55) SECURE ATTACH: 1, DATA: 1
15:18:54:118 unabto_context.c(63) NONCE_SIZE: 32, CLEAR_TEXT: 0
15:18:54:118 unabto_attach.c(787) State change from IDLE to WAIT_DNS
15:18:54:118 unabto_attach.c(788) Resolving dns: devicename.demo.nab.to
uNabto version 123.456.
15:18:54:330 unabto_attach.c(809) State change from WAIT_DNS to WAIT_BS
15:18:54:353 unabto_attach.c(474) State change from WAIT_BS to WAIT_GSP
15:18:54:364 unabto_attach.c(266) ######## U_INVITE with LARGE nonce sent, version: - URL: -
15:18:54:375 unabto_attach.c(575) State change from WAIT_GSP to ATTACHED

The uNabto server is now ready and you can connect to it from any client. 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 virtual living room light on and off from everywhere!

dartino-firefox

Light 1 turned ON!
Light 1 turned OFF!

For demonstration purposes, the example application closes the server connection after ~10 seconds.

The sample application in detail

The sample application is quite straightforward since all complicated interfacing to the native C library is done in the uNabto library. We only need to include it with

import 'unabto.dart';

In the main() function we construct the uNabto server object by passing the Device ID and the pre-shared Key as parameters. However, the server is started later with the init() function. You also might want to check if there were any errors doing that.

  var unabto = new UNabto("devicename.demo.nab.to", "35d0dca...");

  // Get version information.
  print("uNabto version ${unabto.version}.");

  // Attempt to init and start the server.
  int result = unabto.init();
  if (result != 0) {
    print("Init error: $result.");
  } else {

To handle incoming events from the client we register handler functions for every query ID. We’ll come back to the handlers later on.

    // Register two event handlers for the `light_write.json` and
    // `light_read.json` queries.
    unabto.registerReceiver(1, onLightWrite);
    unabto.registerReceiver(2, onLightRead);

You can now do other stuff. The sample application just sleeps for 10 seconds to demonstrate how to close the uNabto server in the end.

    // This is where the main app code would usually run.
    // In this sample we just sleep a bit.
    sleep(10000);

    // Clean-up: Deallocate foreign memory and functions.
    unabto.close();

The following handler takes care of the query with ID #1. It reads the light’s ID and the light’s new state from the incoming readBuffer. The new state is applied to the virtual light. Afterwards, it returns the new state to the client by writing it to the outgoing writeBuffer.

void onLightWrite(UNabtoRequest appRequest, UNabtoReadBuffer readBuffer,
    UNabtoWriteBuffer writeBuffer) {
  // Read the request parameters.
  int lightId = readBuffer.readUint8();
  int lightOn = readBuffer.readUint8();

  // Set the light state.
  int lightState = setLight(lightId, lightOn);

  // Write the response parameter.
  writeBuffer.writeUint8(lightState);
}

The following handler takes care of the query with ID #2. It reads requested light’s ID from the incoming readBuffer, retrieves the state of the virtual light and returns the light’s state to the client by writing it to the outgoing writeBuffer.

void onLightRead(UNabtoRequest appRequest, UNabtoReadBuffer readBuffer,
    UNabtoWriteBuffer writeBuffer) {
  // Read the request parameters.
  int lightId = readBuffer.readUint8();
  int lightState = readLight(lightId);

  // Write the response parameter.
  writeBuffer.writeUint8(lightState);
}

Diving deeper

If you want to explore the whole available interface of the uNabto library have a look at it on GitHub. It also demonstrates how to use the Dartino FFI library to access a foreign library and work with its structures and byte arrays.

Finally, if you want to modify the underlying uNabto C library checkout the files in this directory. For example, In the unabto_config.h you can turn off the logging or disable remote connections.

ESP8266 WiFi Module + Nabto

This post is outdated. Please have a look at the updated version incorporating our new AppMyProduct platform.

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/tree/v1.1 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.

Raspberry Pi 3 IoT, perfect for Nabto

A few days ago (29/2-2016) the new Raspberry Pi 3 was announced. Of course we were all excited here at the Nabto headquarters and quickly bought a few.

Since they are reviewed as the perfect platform for IoT we wanted to check out if it is perfect for Nabto as well. Spoiler alert: it is !

Setting up the Pi 3

The fastest way to get wifi and Nabto up and running on your Pi 3 is to burn an image to your sd card (for this post we are using Raspbian Jessie Lite). After doing that, hook up your Pi3 by wire to your local network. You can now access the Pi, either directly by HDMI and a keyboard or over SSH.

One of the main features of the new Pi3 is the onboard wifi module so the first thing to do is to search for available networks and make the Pi autoconnect to the one we want. This is most easily done by issuing the following commands one line at a time

wpa_cli
scan
scan_results
add_network
set_network 0 ssid "ssid_name"
set_network 0 psk "password_stuff"
enable_network 0
save_config
quit

Where you should, of course, replace ssid_name and password_stuff with the SSID and password of the network you are trying to connect to.
After that you can reboot the Pi and remove the wire and you have a Raspberry Pi 3 ready for IoT!

Setting up Nabto

Setting up Nabto is as easy as setting up the wifi. First of we need to get the necessary tools for getting the uNabto files and compiling for the Raspberry Pi. This is done by issuing the following commands one line at a time

sudo apt-get install git
sudo apt-get install cmake
git clone https://github.com/nabto/unabto.git
cd unabto/apps/raspberry_pi
cmake .
make

We now have Nabto compiled on our Pi!
All that is left to do is to create a new device at portal.nabto.com. Simply Add Device and copy the newly created Key 

We now return to the Raspberry Pi and issue the following command for initiating the Nabto software

sudo ./unabto_raspberrypi -d "id".demo.nab.to -s -k "key"

You should see a couple of lines of output ending with

13:40:47:548 unabto_attach.c(575) State change from WAIT_GSP to ATTACHED

Which means Nabto is successfully up and running!

Trying out Nabto

Now that everything is up and running the final thing to do is to access id.demo.nab.to in your browser. You will be met with a log in page, simply click Guest, followed by an image like this

html_dd

The uNabto demo is up and running!

Sliding the switch to either side will now trigger the onboard activity light on your Raspberry Pi, check it out!

For a more in depth introduction on how to write your own functionality into the Nabto framework, please refer to this blog post The SunPi control center.

The CoffeePi (Part 1 of 2)

When I asked if I could hack the 1300$ (8800 dkk) coffee machine at the Nabto headquarters the responses varied from “no way” to “I’ll give it 30 % chance of success”. Eventually they surrendered to my request, so let’s see if it all worked out!

Since this project was rather substantial, the coffee machine saga will be split in two (possibly three later on) parts.

In this part we will be dealing with

  • Disassembling the coffee machine and finding points of interest
  • Figure out the what is needed to control the buttons
  • Brew an actual cop of coffee using SSH.

Part 2 will deal with

  • Figure out how to wire up and emulate the rotary knob
  • Adding the Nabto framework
  • Making the full menu available
  • Order a cup of coffee in London, get it seconds later in Denmark

Disassembling the coffee machine

before_dismantling.png

The starting point, a shiny functioning Siemens EQ 7 Plus coffee machine

The starting point was the Siemens EQ 7 (TE712201RW) coffee machine, as seen in its standard form in the image above.

First of I had to decide whether to try and access the three pin service port or to rip the machine apart and make some proper hacking. Since I found no information about this service port online I decided on the latter (plus it sounded like a lot more fun).

Machines like these are built with as few screws as possible and thus all side panels are hold in place by small plastic pins. Furthermore the machine is made such that to get to the main board you have to remove the back panel, then the side panels and finally the front panel. In total, dismantling the coffee machine was not easy but I did it MANY times in the process because of broken soldering or crushed wires.

20160218_120943

E-waste or successful hack?

With the front finally of it was time to have a look at the main board.

20160218_121202

The main board inclosure

We see 6 buttons and a rotary knob in the middle. Now we just need to check out what is underneath.

Controlling the buttons

20160218_121542 - marked.jpg

The main board of the coffee machine.

Using a multimeter I began by figuring out any common connections indicated by the blue lines in the above image.

When one of the buttons are pushed a connection is made between the blue and yellow side of the button. We want to be able to create artificial button pushes and thus we need to solder on wires at every yellow line in the above picture and a common blue wire.

20160223_194222.jpg

Strapped up for the party

We can now imitate a button push by simply shortening common with any of the buttons.
To control this programmatically I went with optocouplers, specifically Fairchild 817 chosen because it has a high CTR min. meaning that we can directly activate them using the 3.3V digital pins from a Raspberry Pi, as seen below.

20160222_165956.jpg

Using an optocoupler directly from the 3.3V pins from the Raspberry Pi.

I chose optocouplers since they are basically “light relays” as my colleague said.

opto

Cross-section through an optocoupler.[wiki] As can be seen the red LED is electronically isolated from the green sensor. Thus the two sides can have very different voltage levels without damaging anything.

This turned out to be a good choice since the logic of the coffee machine runs at 5V and the Raspberry digital pins run at 3.3V, as mentioned earlier.

All that is left is then to hook up the main board again and follow the on screen instructions:

20160218_145749

Please close the door!

After “closing the door” we need to mark the wires such that we know what they do.

20160218_155624

Almost assembled and soon labeled.

I simply shorted each wire with the common wire (see above) to figure out the function of each wire.

20160218_181952.jpg

Wires from coffee machine ready to rock

As seen above the wires are now coming out of the coffee machine in a nice little bundle. We now simply need to wire up alle the optocouplers to the raspberry pi and when that is done connect everything together.

20160222_161923

Heating the soldering iron.

Since I did not have any connectors lying around I had to create some using a bit of soldering.

20160222_172341

The optocouplers all wired up.

To avoid damaging the optocouplers (and RPi) I inserted a 270Ω resistor alongside each. The “red” wire above is common ground and the numbered “green” wires are the wires we can digitally set high/low. When we set an optocoupler high it means that power is allowed to flow through on the right hand side in the image above, i.e. a button on the coffee machine is pushed.

Have a cuppa

We can now finally wire everything together such that we can click any of the six buttons by issuing a simple command over SSH:

gpio write 10 1
gpio write 10 0

This basically emitates pushing the button in (first line) and then releasing it again (second line).

So far we still have to manually scroll to the desired item in the menu, but when we are there we can programmatically push the button, as seen below:

20160222_184911

The first cup of coffee ordered remotely (i.e. 5 meters away at my computer)

Great success! 

Issues

As mentioned, we still have to manually scroll to the desired menu item before we can programmatically push a button.

The next part will be dealing with this problem as well as a few others:

  • Figure out how to wire up and emulate the rotary knob
  • Adding the Nabto framework
  • Making the full menu available
  • Order a cup of coffee in London, get it seconds later in Denmark