For the very impatient demanding "action" right away go directly to an example application.
This document describes what it takes to get started writing your own uNabto based applications. Read the Overview to get an idea of the big picture or see Application Development for details.
If you have any questions to the starter kit or comments in general, please feel free to post in the uNabto community forum or write an email directly to us on support@nabto.com.
uNabto Overview
uNabto (micro-Nabto) is the Nabto product line targeted at low resource devices - see http://www.nabto.com for solutions for more resource rich platforms.
uNabto basically allows direct interaction with tiny devices through a browser interface by installing a browser plugin to handle nabto:// URLs. The user is given the impression of interacting with a full-blown web-application, while actually only exchanging a few bytes with the remote device - the actual HTML response is generated in-browser.
The platform consists of four major components:
-
HTML Device Driver (supplied by vendor): Description of device requests/responses and content for HTML layout. May be retreived from a central repository by the Nabto Plugin or installed manually.
-
Nabto Plugin (supplied by Nabto): Handles nabto:// requests in browser, retrieves HTML Device Driver, forwards requests to device, retrieves response and populates HTML templates
-
uNabto Adapter (supplied by Nabto and/or vendor): Interfaces device, communicates with browser through a simple UDP based protocol, registers with base station
-
Base Station (supplied by Nabto): Mediates among Nabto Plugin, device (uNabto Adapter) and device drivers.
Base Station
The uNabto base station is the central facility that mediates connections between client and server and provides the client with the URL of an appropriate HTML device driver. Note that in this uNabto starter kit version, the base station’s role is limited, see Current Limitations for details.
HTML Device Driver
The HTML "device driver" describes how information is mapped between the low level representation on the remote device and the HTML user interface generated by the Nabto Plugin. It consists of a zip file with layout material and a description of the data sent between browser and device:
-
Graphics: GIF, JPG, PNG etc.
-
Style sheets
-
Javascript
-
Static HTML pages
-
HTML templates
-
Request Mapping - HTTP request to compact UDP based protocol
-
Response Mapping - compact UDP based protocol to template parameters
The vendor (application developer - the reader of this document) packages such a bundle, suitable for the device in question. The bundle is deployed in a location reachable by the browser through file:// or http:// requests. See sections Model Description and Device Driver Packaging and Deployment for details.
Nabto Plugin
The plugin is registered in the browser to serve nabto:// requests: It retrieves an HTML device driver based on information from the base station (if not already installed and uptodate). By combining the browser request with information in the the driver bundle, the plugin formats and sends a request to the remote embedded device and receives a response using the compact UDP protocol.
An HTML page is rendered using the received data, metadata and templates in the HTML device driver bundle.
From the HTML template developer’s perspective, the Nabto Plugin acts as an MVC controller similar to a front controller component in regular web server applications; it receives and validates user input, invokes the remote device and populates a model, accessible from the HTML template.
The Nabto Plugin can be downloaded from http://download.nabto.com.
uNabto Adapter
The uNabto Adapter software installed on the device receives requests from the Nabto Plugin through the compact UDP protocol. It decodes the request and invokes appropriate system software on the embedded device. Finally a response is sent back in an UDP packet to the browser.
Nabto supplies source code for adapters to the following platforms.
-
Linux
-
Windows
-
Mac
-
Microchip PIC18 and PIC32
-
Arduino
If we are not currently supporting your platform the section Create your own adapter gives an overview of what nabto requires.
Detailed Interaction Among Components
Consider a scenario where the user wants to retrieve the temperature from a house-sensor that has been assigned the uNabto hostname "foo.u.nabto.net". For simplicity, browser and device are co-located on the same network, allowing use of a simple local communications scheme not involving the base station for NAT traversal:
-
User enters URL http://foo.u.nabto.net/house_temperature in browser (or clicks a link)
-
foo.u.nabto.net resolves to the DNS host name of a uNabto base station that has a web server running, answering the http:// request. If it cannot detect a Nabto browser plugin, it guides the user through the plugin installation. Once the plugin is installed, the user is redirected to nabto://foo.u.nabto.net/house_temperature.
-
The Nabto Plugin handles this request and examines if a valid HTML device driver is installed for the host foo.u.nabto.net. If necessary, it queries the base station to get a URL and installs the HTML device driver.
-
The Nabto Plugin shows the view template from the HTML Device Driver associated with the "house_temperature" request.
-
The user enters any necessary input data (e.g., a sensor id) and submits the request.
-
The Nabto Plugin tries to locate the foo.u.nabto.net uNabto device - in the starter kit version this means a simple UDP broadcast on the local network with a discovery message containing the requested hostname.
-
The uNabto Adapter software on the device assigned the name foo.u.nabto.net answers the request by sending back its IP address to the Nabto Plugin.
-
The Nabto Plugin encodes the user’s input parameters according the metadata in the HTML device driver and sends the parameters along with the "house_temperature" opcode to the device.
-
The uNabto Adapter receives and decodes the request and samples the temperature through the specified sensor. The temperature is encoded and sent back to the Nabto Plugin.
-
The Nabto Plugin inserts the received response value into the symbol table for the "house_temperature" layout template and shows the full HTML page to the user.
Current Limitations
The current starter kit version of uNabto supports the most basic functionality to demonstrate key aspects. This includes rendering rich responses using the HTML device driver approach and communication between devices. Certificate based authentication and encryption is not supported in this version.
A simple convention is used to decide if a request is a uNabto request: All uNabto devices must be named within the .u.nabto.net subdomain to be accessible by the plugin. The HTML device driver bundle is retrieved from a web server assumed to be running on a host with a DNS hostname as assigned to the device.
Application Development
Model Description
The uNabto application developer must describe the queries handled by a specific device in a query model for the device, represented as a simple XML file (consider it similar to a simple SOAP WSDL or RPC metadata). The Nabto Plugin uses this model directly to encode requests sent to the device and parse the response received from the device. The populated model is accessible from the HTML view templates.
The uNabto Adapter software must similarly adhere to the model (decode requests, encode responses according to it). However, given the limited resources of the device, it is unlikely it can use the metadata directly. With the present uNabto release, the application developer will then have to manually implement the adapter to adhere to the model. Nabto will later supply a code generation tool to generate marshalling stubs.
The query model schema have been supplied with this document (query_model.xsd) and is downloadable from http://www.nabto.com/unabto/query_model.xsd.
An example query model file:
<unabto_queries
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="query_model.xsd">
<query name="house_temperature" description="Measure House Temperature" id="1">
<request>
<parameter name="sensor_id" type="uint32"/>
</request>
<response>
<parameter name="temperature" type="int32"/>
</response>
</query>
</unabto_queries>
This model describes a query named "house_temperature", with a single input (request) parameter and a single output (response) parameter. The supported parameter types are as of writing signed and unsigned 8-, 16- and 32-bit integers and IEEE754 floats and doubles (uint8, uint16, uint32, int8, int16, int32, float, double).
The mandatory name attribute on the query tag is used for looking up the query from the path information in the user specified URL. In the example, the URL nabto://foo.u.nabto.net/house_temperature will match the query. The name must be unique within each query model file.
The mandatory query id attribute is a compact identification of the query in question, used as opcode when sending requests to the device (see the protocol description below for details).
The optional description attribute is a user friendly name for the query.
HTML Views
Templates
The Nabto Plugin currently supports TPT based templates. Support for XSLT templates will be added in a future release.
A TPT template looks as follows:
<html>
<body>
<h1>Temperature Measurement</h1>
<img src="/gfx/logo.png"/>
<p>
Temperature is ${temperature}.
</p>
<a href="/help/temperature.html">Online Help</a>
</body>
</html>
The parameters in the response model are accessible in the template using the ${} syntax. For instance, ${temperature} is populated by the plugin with the value returned by the sensor in the house_temperature example.
The following special parameters are populated by the plugin:
| Parameter | Content |
|---|---|
${_query} |
The name of this query (the name attribute of the model’s query node), e.g. "house_temperature". |
${_description} |
A more descriptive name of this query (the description attribute of the query node), e.g. "House temperature measurement". |
${_self} |
The full URL currently being handled (e.g., nabto://foo.u.nabto.net/house_temperature?sensor_id=123) |
${_self_no_query} |
The full URL currently being handled - without the query part. A template associated with URL nabto://foo.u.nabto.net/house_temperature?sensor_id=123 will see ${_self_no_query} = nabto://foo.u.nabto.net/house_temperature |
${_host} |
Host part of the URL currently being handled (e.g., foo.u.nabto.net) |
${_REQUEST} |
A map with all input parameters, accessible e.g. as ${_REQUEST.sensor_id}. |
${_RESPONSE} |
A map with all response parameters, accessible e.g. as ${_RESPONSE.temperature}. |
See the TPT documentation for further information, e.g. on conditional parsing (@if/@else) and loop constructs (@foreach) - the latter could be used with the ${_REQUEST} and ${_RESPONSE} special parameters.
Static data in the HTML device driver bundle may be referenced with relative URLs as seen with the <img src="/gfx/logo.png"/> and <a href="/help/temperature.html"> tags.
See section Device Driver Packaging and Deployment for details on how to package templates and static data into a HTML device driver bundle.
Activation By Plugin
The Nabto Plugin acts as a controller that receives requests, delegates to device if necessary and serves an HTML template to the user. The template file name is derived from the query name (value of query’s name attribute in the query model with .tpt suffix appended). A custom name may also be set explicitly with the optional template attribute. All templates in an HTML device driver bundle reside in the nabto sub directory.
If the plugin is invoked as the action target of an HTML form (ie., corresponding to a web server CGI-script being invoked), it is assumed that a request should be sent to a device and a response HTML template rendered with the response (with all response parameters and the ${_RESPONSE} map set). The plugin decides this is the case, if the current request is a POST request or is a GET request with a query string (eg., nabto://foo.u.nabto.net/house_temperature?sensor_id=123).
If the plugin is not invoked as an action target, ie. if the current request is a GET request with no query part (such as nabto://foo.u.nabto.net/house_temperature), the template is simply shown with all parameters from the model set to empty strings. If a query is defined in the model with this name but no template present in the device driver bundle, an auto-generated form is shown, based on the model (handy for quick testing during device adapter development). This auto-generated form can be forcibly shown with nabto://foo.u.nabto.net/house_temperature?_show_form.
- nabto://foo.u.nabto.net/house_temperature
-
Shows the house_temperature.tpt template with all parameters from the query model set to empty strings (including values of parameter entries in the $_{REQUEST} and $_{RESPONSE} maps).
- nabto://foo.u.nabto.net/house_temperature?sensor_id=123
-
Invokes the house_temperature request on the device, populates the $_{REQUEST} map with a sensor_id value of 123 and assigns the ${temperature} parameter the value received from the device (also sets the temperature entry in $_{RESPONSE}).
- nabto://foo.u.nabto.net/help/general.html
-
Retrieves the "help/general.html" page from the static part of the HTML device driver bundle (see packaging).
HTML Device Driver Packaging and Deployment
The HTML device driver bundle contains model file, templates and static data necessary to perform requests and render views for a specific uNabto host. The host specific bundle is a zip file with the following structure:
- ./nabto
-
A flat directory with all uNabto specific contents - the model file for the host in question (unabto_queries.xml) and all template files to be used for rendering views.
- ./static
-
Data that may be served as is. May contain child directory hierarchies. URLs that do not map to requests are used to locate static data in this directory. For instance, the plugin will serve the static HTML file ./static/help/general.html in response to URL nabto://foo.u.nabto.net/help/general.html.
On the client machines, bundles are installed in per-host directories in the html_dd sub-directory of the Nabto base directory. The Nabto base directory is ~/.nabto on Linux and OS X, %APPDATA%/Nabto on Windows XP and %USERPROFILE%/AppData/LocalLow/Nabto on Windows Vista and Windows 7.
Sample bundle installations after installing HTML device drivers for both devices foo.u.nabto.net and bar.u.nabto.net thus look like:
~/.nabto/html_dd/foo.u.nabto.net/nabto/unabto_queries.xml ~/.nabto/html_dd/foo.u.nabto.net/nabto/house_temperature.tpt ~/.nabto/html_dd/foo.u.nabto.net/static/help/general.html ~/.nabto/html_dd/foo.u.nabto.net/static/gfx/logo.png ~/.nabto/html_dd/bar.u.nabto.net/nabto/unabto_queries.xml ~/.nabto/html_dd/bar.u.nabto.net/nabto/wind_speed.tpt ~/.nabto/html_dd/bar.u.nabto.net/static/gfx/gauge.png
As of writing, the following simple rules describe how the plugin retrieves a bundle for installation:
-
If a bundle is already installed, nothing is done per default (ie., no check is performed to see if a newer version is available). To overcome this, either remove the existing bundle or set the forceDeviceDriverInstall configuration option in the Nabto plugin configuration file (nabto_config.ini in the Nabto base directory).
-
If a file named html_device_driver.zip exists in the host specific html device driver directory, this file is used. If for instance the file ~/.nabto/html_dd/foo.u.nabto.net/html_device_driver.zip exists, this file is simply unpacked. Useful for development purposes.
-
Else, a bundle is retrieved from the URL http://<host-name>/html_device_driver.zip, where <host-name> is the host name specified by user in the nabto:// URL. For instance, the URL nabto://foo.u.nabto.net/house_temperature triggers a download of http://foo.u.nabto.net/html_device_driver.zip. Using wildcard DNS records and e.g. an appropriate Apache virtual host configuration, this may be used to setup HTML device drivers shared among multiple devices. A sample HTML device driver bundle matching the examples in this document has been deployed on the Nabto web server to handle *.u.nabto.net requests.
Local UDP Protocol Between Device and Browser
This section contains a short overview of the local uNabto Protocol – mostly intended for implementers of the uNabto Adapter, the server software running on the host device. The local protocol has no authentication or encryption.
The protocol connecting the Nabto browser plugin and a uNabto Adapter on a local subnet is a simple request-response protocol, carried as data in UDP packets: A request is a single UDP packet from the browser plugin to the uNabto Adapter and the response is a single UDP packet in the opposite direction.
With the simple local version of the protocol, the uNabto Adapter opens a UDP socket on port 5570 (or a non-default port that matches the uDevicePort value in the Nabto Plugin’s configuration file). The socket must be able to receive packets being broadcast on the connection. The broadcast is used by the Nabto browser plugin to discover the IP-address of a named uNabto server.
The Protocol
When an incoming request is received on the UDP socket, it is validated and if valid, the response is sent to the sender of the request, ie. to the IP-address and port from which the particular packet was received. The local protocol creates no dependencies between successive packets, no matter whether they originate from different clients or from the same client.
The Request
| Byte no. | Field | Description/remarks |
|---|---|---|
0 |
Header.version |
0 |
1 |
Header.flags |
0 |
2 |
Header.rsvd |
0 |
3 |
Header.op |
Message type (0: application, 1: address discovery) |
4-7 |
Identifer |
Opaque identifier, must be copied from request to response |
8-11 |
Reserved |
Reserved field, must be copied from request to response |
12-15 |
Opcode |
Used when Header.op is 0 (application): Identification of the request type (opcode) - the value of the id attribute in the query model. |
16- |
Appl. Data |
Request parameters in the order listed in the query model, integers encoded in network byte order |
12- |
Protocol Data |
Used when Header.op is not 0 |
The Response
| Byte no. | Field | Description/remarks |
|---|---|---|
0 |
Header.version |
0 |
1 |
Header.flags |
0x80 (response-flag) 0x40 (error-flag when proper answer cannot be generated) |
2 |
Header.rsvd |
0 |
3 |
Header.op |
Message type, must be copied from request to response |
4-7 |
Identifier |
Opaque identifier, must be copied from request to response |
8-11 |
Reserved |
Reserved field, must be copied from request to response |
12- |
Data |
Response parameters in the order listed in the query model, encoded in network byte order (or the Response Protocol Data when Header.op isn’t 0) |
The length of the Data field may be pre-calculated from the model description or determined from the length of the UDP data:
The Request data is 16 bytes shorter than the UDP data field and the Response data is 12 bytes shorter than the UDP data field.
The Protocol data and the Response Protocol Data is 12 bytes shorter than the UDP data field.
The Discovery Message
The Message type (1) is used for IP-address discovery by the Nabto Plugin to find the IP-address of a named uNabto enabled server:
The Request Protocol data is the name of the uNabto server (zero-terminated string of chars).
The Response Protocol Data holds a 4-byte Data field with the IPv4 address (network byte order).
Implementing your own uNabto adapter.
This section will guide you through the implementation of a unabto adapter on a device where nabto isn’t supported yet. Throughout this section the name of the new device will be newdevice.
First we will have to add definitions which are used throughout uNabto. This is made in the file ./src/app/unabto/server/unabto_env_base.h.
We have to define a identifier for the new device in the source, add an entry like the one below and assign it to an unused number e.g. 5.
#define NABTO_DEVICE_NEWDEVICE 5 /**< Arduino board with an wiznet w5100 */
If you dont want to specify -DNABTO_DEVICE=NABTO_DEVICE_NEWDEVICE when you compile the uNabto code for your new device you can change the default device to the new device as shown below.
/** Define default device. */ #ifndef NABTO_DEVICE #define NABTO_DEVICE NABTO_DEVICE_NEWDEVICE #endif
Add an inclusion of a file which defines the device specific types for your platform.
#if NABTO_DEVICE == NABTO_DEVICE_UNABTO_APP # include "devices/unabto_app/unabto_env_base_app.h" #elif NABTO_DEVICE == NABTO_DEVICE_PC # include "devices/pc/unabto_env_base_pc.h" #elif NABTO_DEVICE == NABTO_DEVICE_MICROCHIP # include "devices/microchip/unabto_env_base_mchip.h" #elif NABTO_DEVICE == NABTO_DEVICE_ARDUINO # include "devices/arduino/unabto_env_base_arduino.h" #elif NABTO_DEVICE == NABTO_DEVICE_NEWDEVICE # include "devices/newdevice/unabto_env_base_newdevice.h" #endif
Add the folder ./src/app/unabto/server/devices/newdevice in this folder create a file called unabto_env_base_newdevice.h this is the file you included above. This file should atleast have the following type definitions.
typedef TYPE_OF_SOCKETS_IN_NEWDEVICE nabto_socket_t; typedef TYPE_OF_TIMESTAMPS_IN_NEWDEVICE nabto_stamp_t; #define nabtoGetStamp() function_which_returns_a_timestamp_in_newdevice() #define nabtoMsec2Stamp(msec) function_which_convert_a_timestamp_to_milliseconds_in_newdevice(msec)
Now the basic types are set, which means we only need to implement a few functions before the newdevice is nabto enabled. The functions which needs to be implemented is described in ./src/app/unabto/server/unabto_external_environment.h the file is included below to give an overview.
#ifndef UNABTO_EXTERNAL_ENVIRONMENT_H
#define UNABTO_EXTERNAL_ENVIRONMENT_H
#include "unabto_env_base.h"
/**
* Fill buffer with random content.
* @param buf the buffer
* @param len the length of the buffer
*/
void nabto_random(uint8_t* buf, size_t len);
/******************************************************************************/
/**
* Initialise a udp socket. This function is called for every socket
* uNabto creates, this will normally be two times. One for local
* connections and one for remote connections.
*
* @param localAddr The local address to bind to.
* @param localPort The local port to bind to.
* A port number of 0 gives a random port.
* @param socket To return the created socket descriptor.
* @return true iff successfull
*/
bool nabto_init_socket(uint32_t localAddr, uint16_t* localPort, nabto_socket_t* socket);
/**
* Close a socket.
* Close can be called on already closed sockets. And should tolerate this behavior.
*
* @param socketDescriptor the socket to be closed
*/
void nabto_close_socket(nabto_socket_t* socketDescriptor);
/******************************************************************************/
/**
* Read message from network (non-blocking).
* Memory management is handled by the callee.
*
* @param socket the UDP socket
* @param buf destination of the received bytes
* @param len length of destination buffer
* @param addr the senders IP address (host byte order)
* @param port the senders UDP port (host byte order)
* @return the number of bytes received
*/
ssize_t nabto_read(nabto_socket_t socket,
uint8_t* buf,
size_t len,
uint32_t* addr,
uint16_t* port);
/******************************************************************************/
/**
* Write message to network (blocking) The memory allocation and
* deallocation for the buffer is handled by the callee.
*
* @param socket the UDP socket
* @param buf the bytes to be sent
* @param len number of bytes to be sent
* @param addr the receivers IP address (host byte order)
* @param port the receivers UDP port (host byte order)
* @return true when success
*/
ssize_t nabto_write(nabto_socket_t socket,
const uint8_t* buf,
size_t len,
uint32_t addr,
uint16_t port);
/******************************************************************************/
/**
* Init the platform. This is called once when the platform is
* initialised. This can be used to initialise platform specific behavior.
* The function is called before first socket operations.
* @return true if success.
*/
bool nabto_init_platform();
/*****************************************************************************/
/**
* Close the platform. This is called once when the platform is
* closed.
* When this function is called no further socket invocations will occur. This
* can be used to make cleanup on the platform.
*/
void nabto_close_platform();
#endif /* UNABTO_EXTERNAL_ENVIRONMENT_H */
When these seven functions are implemented uNabto is ported to your device. What remains is to implement applications which uses nabto on your device.
Implement an application which uses nabto.
Below is a simple uNabto main program with an implementation of unabto events which simply echo all request back in the response.
#include "unabto_common_main.h"
int main(int argc, char* argv[]) {
/**
* Create a context for the uNabto instance, and initialise it to
* default values
*/
nabto_main_context_t nmc;
nabto_init_default_values(&nmc);
/**
* Set the local ip address to listen on and the server id to use.
*/
#define MY_LOCAL_IP "192.168.70.3"
nmc.nms.localAddr = htonl(inet_addr(MY_LOCAL_IP));
nmc.nms.id = "foo.u.nabto.net";
/**
* Initialise nabto. This will open the sockets needed by uNabto
*/
nabto_main_init(&nmc);
/**
* Running the main loop
*/
while ( true ) {
nabto_main_tick(&nmc);
// sleep some time.
}
nabto_main_close(&nmc);
}
/**
* This implements the user application.
* This application is a simple echo service.
*/
int application_event(uint32_t query_id, buffer_read_t* r_b, buffer_write_t* w_b) {
switch(query_id) {
case 1:
uint32_t value;
buffer_read_uint32(r_b, &value);
buffer_write_uint32(w_b, value);
return 0;
}
return -1;
}
Example Application
The full source code for a stub-based test application has been supplied with this document with key excerpts shown below. The device adapter (and the embedded device stub) can be built with Visual Studio 2005+ on Windows, GCC on Unix platforms and Microchip MPLAB for PIC18 and PIC32 microcontrollers (and is possible to deploy on other platforms with minor adjustments). A compiled win32 version can be downloaded from http://download.nabto.com/unabto.exe.
The example server answers requests for foo.u.nabto.net, unless specified otherwise on the command line when running the server. Screenshot of session:
Running the PC Example Application
-
Install Nabto Plugin from http://download.nabto.com
-
Build the test application through Visual Studio or using make on a Unix platform (or download a win32 executable)
-
Start the test application: ./unabto <ip address to bind to> on the "device"
-
Enter the URL nabto://foo.u.nabto.net/house_temperature in your browser on the "client"
These steps will install an HTML device driver bundle corresponding to the example, automatically retrieved by the plugin from the public Nabto test web server answering on http://foo.u.nabto.net. You may install alternative bundles, e.g. with your own customizations.
If the device should be available for non-local clients, i.e. if it should support NAT traversal, it is necessary to specify which base station the device should use.
-
Start the test application: ./unabto <ip address to bind to> <device name> -A <basestation ip> on the "device". e.g. ./unabto <ip address to bind to> foo.u.nabto.net -A 195.249.159.159
The basestation IP is the address of the basestation associated with the given device name, but has to be explicitly specified as the demo application currently does not support DNS lookups. The 195.249.159.159 base station is available for tests with this starter-kit.
Nabto starterkit naming convention
When naming a nabto device two things has to be considered. Which HTML device driver should the browser use and naming collision with other devices, this is due to current limitations in the uNabto starter-kit.
Currently we have two HTML device drivers available one for the weather station example and one for the PICDEM.net 2 Development Board.
If devices are named as <something>.picdem.u.nabto.net e.g 1.picdem.u.nabto.net then the browser will use the HTML device driver designed for the PICDEM.net 2 Development Board. If alternatively the device is named as <something>.weather.u.nabto.net e.g. 1.weather.u.nabto.net the browser vil use the HTML device driver designed for the weather example.
The other aspect of device names is, every device has to use a name of the form <something>.u.nabto.net when using NAT traversal. To minimize the risk of name collisions a name like <devicename>.<company>.<html device driver>.u.nabto.net is preferred, e.g. device10.foocompany.weather.u.nabto.net.
In a production setting device names could be <serialnumber>.<devicetype>.<company>.net
Model Definition
The example model defines two queries:
<?xml version="1.0"?>
<unabto_queries
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://www.nabto.com/unabto/query_model.xsd">
<query name="house_temperature" description="Measure House Temperature" id="1">
<request>
<parameter name="sensor_id" type="uint32"/>
</request>
<response>
<parameter name="temperature" type="int32"/>
</response>
</query>
<query name="wind_speed" description="Measure Wind Speed" id="2">
<request>
</request>
<response>
<parameter name="speed_m_s" type="uint32"/>
</response>
</query>
</unabto_queries>
Layout Template
The layout template for the house_temperature request looks as follows (the wind_speed template has been omitted here):
@set(title, ${_description})
@include("header.tpt")
<h1>${title}</h1>
<div class="boxc">
<form action="${_self_noquery}" method="post">
<fieldset>
<div class="inputs inputsTemplate">
<table>
<tr>
<td>
<label class="labelTemplate" for="sensor_id">Sensor ID</label>
</td>
<td>
<input type="text" value="${_REQUEST.sensor_id}" name="sensor_id" class="inputTemplate"/>
</td>
</tr>
<tr>
<td>
<b>Measured Temperature</b>
</td>
<td>
<b>${temperature}</b>
</td>
</tr>
</table>
</div>
<div class="buttons">
<input type="submit" class="submit submitTemplate" value="Measure"/>
</div>
</fieldset>
</form>
</div>
@include("footer.tpt")
Recall that a layout template is not mandatory - a rudimentary template auto-generated from the query model is used if no template is included in HTML device driver bundle, useful during early device adapter- and model-development.
Device Implementation
Structure of the source files.
Device specific source files:
- ./src/app/unabto/server
-
This is the base for the unabto server example it contains common files for all platforms.
- ./src/app/unabto/server/devices/
-
Device specific source. At the moment there are source files for unix/win32 and Microchip PIC18 targetted the PICDEM.net 2 Development board.
The device adapter handles 2 application level messages, corresponding to above model definition:
| Request data | Response data | ||||
|---|---|---|---|---|---|
Request |
ReqId |
Length |
Content1 |
Length |
Content1 |
house_temperature |
1 |
4 |
sensor id |
4 |
temperature |
wind_speed |
2 |
0 |
4 |
windspeed |
|
1: integers in network byte order.
This is the main loop of the device. It calls nabto_main_init from unabto_common_main.c and has a mainloop which calls nabto_do_one_main() once each iteration.
This handles either local events coming from the LAN or remote events coming from the base station. If a packet is an application event, application_event is called to handle the packet.
This defines the method which should be implemented to handle application logic.
int application_event(uint32_t request_id, buffer_read_t* read_buffer, buffer_write_t* write_buffer)
{
switch (request_id) {
case 1:
/*
* <query name="house_temperature" id="1"
* template="house_temperature_template_overrule.tpt">
* <request>
* <parameter name="sensor_id" type="uint32"/>
* </request>
* <response>
* <parameter name="temperature" type="int32"/>
* </response>
* </query>
*/
{
int32_t temp;
uint32_t ix;
// read 4 bytes from the input buffer
if (!buffer_read_uint32(read_buffer, &ix)) return -1;
// write 4 bytes to the output buffer
temp = getTemperature(ix);
if (!buffer_write_uint32(write_buffer, temp)) return -1;
return 0;
}
case 2:
/*
* <query name="wind_speed" id="2">
* <request>
* </request>
* <response>
* <parameter name="speed_m_s" type="uint32"/>
* </response>
* </query>
*/
if (!buffer_write_uint32(write_buffer, getWindSpeed())) return -1;
return 0;
case 4: {
return 0;
}
}
/**
* if no opcode matched return it as an error
*/
{
const char* msg = "Unknown opCode";
NABTO_ERROR(msg << ": " << request_id);
if (!buffer_write_str(write_buffer, msg)) return -1;
return -1;
}
}
Running the Microchip Example Application
The Microchip example application is designed for use with the Microchip PICDEM.net 2 development board or the ethernet starter kit development board. Experimenting with the platform requires MPLAB IDE, MPLAB C18 or MPLAB C32 and the Microchip TCPIP Stack.
Development boards for uNabto
The uNabto Microchip demo is primarily targetted for the PICDEM.net 2 development http://www.microchip.com/picdemnet2. It also runs on the PIC32 Ethernet Starter-kit but temperature readings and potentiometer readings isn’t working properly since the platform hasn’t such things. http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2615&dDocName=en545713
Network configurations where the PICDEM.net 2 demo works.
We try to support as many network configurations as possible to give the best user experience.
It’s important to use the network interface closest to the onboard LCD since we use the integrated ethernet controller, NOT the onboard ENC28J60.
The easiest network setup is to give the PICDEM.net 2 board internet access through a router. The client pc also needs internet access eg. through the same router as the board is conencted to.
We support other configurations eg. where the board is directly connected to the client using local link addresses.
For all configurations is it an requirement that the client has internet access the first time it tries to connect to the PICDEM.net 2 unabto demo.
MPLAB IDE:
Version 8.73, 8.63 and 8.66 is known to work with uNabto.
Download and install MPLAB IDE from http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002
MPLAB C18:
We recommend MPLAB C18 version 3.36 or version 3.40, since we have noticed version 3.37 and 3.37.01 doesn’t work with uNabto. http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010014
Download, unpack and install the program in the archive.
MPLAB C32
We use MPLAB C32 v2.0 http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2615&dDocName=en532454
Microchip TCPIP Stack:
As of 3/8 2011 support for microchip TCPIP Stack version 5.25 and 5.31 is dropped. we use version 5.36.
The downloaded stack is an archive with an installer after installing the package the default location for the TCPIP Stack is c:\Microchip Solutions v2011-07-14\Microchip, if the TCP/IP Stack is located elsewhere you will have to manually reflect this in the suplied MPLAB project files.
uNabto:
The MPLAB IDE specific project files can be found in ./build/microchip/mplab/ currently we have project files for MPLAB C18 and MPLAB C32 the former for development on the PICDEM.NET 2 development board and the latter for the Microchip Ethernet starter kit development board.
In ./src/app/unabto/server/devices/microchip/unabto_config_mchip.c is the MAC address and device name set. The MAC address should be set to the number located under the PICDEM.NET 2 evaluation board.
#include "unabto_config_mchip.h" /** * The server_id should be set to the desired address If the server_id * is set to foo.picdem.u.nabto.net then the device can be accessed * as nabto://foo.picdem.u.nabto.net in your browser. * * It's important to choose a unique server id to prevent collisions. * * The last part of the server id decides which Device Driver the * browser downloads for a device. For the PICDEM.NET 2 evaluation * board the server_id should always end with * ``.picdem.u.nabto.net'' to get the correct Device Driver. */ const char* server_id = "foo.picdem.u.nabto.net"; /** * high_mac_addr defines the highest 24 bits of the mac address (OUI) * for PICDEM.net 2 boards this is 0x00 0x04 0xA3 */ const uint32_t high_mac_addr = 0x0004a3; /** * low_mac_addr defines the lowest 24 bits of the MAC address (NIC * specific). On the bottom of the PICDEM.NET 2 evaluation board there * are two labels stating "ADDRESS" which is the MAC addresses which * is assigned to the NICs. */ const uint32_t low_mac_addr = 0; /** * Remove the following line after configuring mac_addr and server_id to the appropriate values. */ #error REMEMBER TO SET SERVER_ID AND MAC_ADDR SETTINGS IN src/app/unabto/server/devices/microchip/unabto_config_mchip.c
The uNabto Microchip specific Main is located in ./src/app/unabto/server/devices/microchip/unabto_main_mchip.c
Since we use co-operative multitasking in the microchip example, we call nabto_main_tick() once for each iteration of the mainloop.
while(true) {
....
nabto_main_tick(&nmc);
....
}
A Note about device names, device applications and HTML device drivers.
To get the desired operation of the uNabto starterkit it’s important that device names, HTML device drivers and device applications match.
Currently there we have two public available HTML devide drivers, one which is targetted the PICDEM.NET 2 board and one which is targetted the simulated weather station.
If you name your server id matches *.microchip.u.nabto.net then the PICDEM.NET 2 device driver will be loaded in the browser, alternatively if you name the device *.weather.u.nabto.net the the Weater station HTML device driver will be loaded.
We have two uNabto applications, one for the weather station which simulates a weather station. The other uNabto application is for the PICDEM.NET 2 evaluation board. It supports toogling the 8 leds, reading a potentiometer and reading the buttons.
In the Weather Station application we use the application_event implementation found in ./src/app/unabto/server/applications/unabto_weather_station.c and for the PICDEM.NET 2 application we use the implementation of application_event from ./src/app/unabto/server/applications/unabto_picdemnet2.c
Using the uNabto arduino starter-kit.
The starter-kit includes uNabto for the Arduino prototyping platform.
Requirements
-
An Arduino board we have testet uNabto with the Duemilanove board with an Atmega328p mcu and the Arduino Uno.
-
An Arduino Ethernet shield.
-
The arduino software http://arduino.cc/en/Main/Software
Installation
-
From the starter-kit copy The folder ./arduino/Nabto folder to the libraries folder in the folder where you installed the arduino software.
Usage of the nabto example.
-
Open arduino.
-
Open Files → Examples → Nabto → Demo.
-
Type in the MAC-Address located on the bottom of the ethernet shield.
-
Specify a local ip for the ethernet shield.
-
Specify an unique ID for your arduino demo, e.g <macaddress>.weather.u.nabto.net.
The example is a weather station which can measure the temperature if a temperature sensor is attached to one of the analog inputs.
Limitations
The uNabto Arduino starter-kit comes without DNS or DHCP support. This means you have to specify the address of the Nabto Base Station and the local address of your device in the initialisation of uNabto. DNS and DHCP can be added using third-party libraries.