Driving Yoctopuce modules the hard way

Driving Yoctopuce modules the hard way

It may happen that, one day, for a given application, you must do without our high level programming libraries. For example because you must drive the modules in a language we do not support (yet), or because you don't want to bother about object programming. It's quite possible, and here are the keys to success.



At the lowest level, communication with the Yoctopuce modules is done using HID type USB packets. It's unlikely that you would want to go that low, but if you are interested in details on our HID protocol, have a look in the ydef.h file, which you'll find in the yapi directory of the C++ or Objective-C library.

At a more interesting level, in the USB packets we transfer mostly traffic in the HTTP format, the protocol used by all web servers. Each of our modules behaves like a small web server, which you can read from and which you can update the state of using predefined URLs. Therefore, to talk to our modules directly, you must
1) know how to send HTTP requests on our USB channel
2) know how the URLs of our modules are organized in order to access a specific function
3) know which format we use to return descriptive data

To send an HTTP request on our USB channel, there are two possibilities. The simplest is to use the VirtualHub, which in fact is a simple TCP to USB gateway. It enables the web server embedded on each module to be available on the network. This allows you to use any HTTP client library to talk with connected modules, including in languages without any low-level support. The second possibility consists in sending a request directly in USB, with the help of our yapiHTTPRequest function, available in the yapi.dll (yapi.so for UNIX) library. How to use it is explained below.

To organize the URLs of our modules, we use a REST type architecture: the URL hierarchical organization directly follows the logical organization of the module, its functions, and its attributes. Therefore, you can simply explore with a web browser our REST API to find in a few moments which URL allows you to access a given relay or sensor. To do so, run the VirtualHub, click on the serial number of the module you are interested in, and open the Open API browser link.

Link to open the REST API, a good starting point for experimentation
Link to open the REST API, a good starting point for experimentation



For instance, you'll see that to commute the relay 1 of a module to active state, you only need to access the URL:

/api/relay1?state=1


Likewise, to read the value in Lux of a light sensor, you only need to read the content of the URL

/api/lightSensor/currentValue


If you want to access a device with its serial number, just add the serial number in the path:

/bySerial/RELAYHI1-00044/api/relay1?state=1


You can also use logical names: a device named MyYoctoDevice can be accessed like this:

/byName/MyYoctoDevice/api/relay1



To read the state of all the sensors of a module in a single request, you can load the highest URL directly. But in this case, the result is a data structure which you'll need to parse to find the different sensors. The selection of the format of the structured representation is done through the extension provided in the URL. For example:
/api.json returns a structure describing the whole module, coded in JSON.
/api.xml returns the same structure, but coded in XML.
/api.txt returns the same structure, but as simple text.



Changing a relay state with the virtual hub and a HTTP request
Changing a relay state with the virtual hub and a HTTP request



The attribute list for each module is explained in the module user manual, at the beginning of programming chapter.

If you want to see an example of a rather extensive use of this technique, you can see the Yocto-Meteo project on blogspot done in Java by one of our users, using his own version of the objects to communicate with the modules using the REST API (ours should follow soon...) and to geolocalize them.

Let's now have a look at the functions that we provide to directly access our HTTP channel without using the VirtualHub. They are located in our yapi library. Its source code is available in C++ and Objective-C library, and the dynamic pre-compiled libraries are present, for instance, in the C#, VisualBasic, and Delphi libraries.

The first function to call once (and only once) is yapiInitAPI:

int yapiInitAPI(int connection_type, char *errmsg);


Pass value 1 to the connection_type parameter to use USB.
Pass a 255 character buffer to the errmsg parameter for the API to return an error message if there is a problem. You can pass a null pointer if you don't want an error message.
The function returns a negative integer in case of error, or zero if everything went well.

The second function, to call at least once (and periodically if you want hot-plug support ), is yapiUpdateDeviceList:

int yapiUpdateDeviceList(int forceupdate, char *errmsg);


Pass value 1 to the forceupdate parameter to force a hardware scan.
Pass a 255 character buffer to the errmsg parameter for the API to return an error message if there is a problem. You can pass a null pointer if you don't want an error message.
The function returns a negative integer in case of error, or zero if everything went well.

Then you can simply call yapiHTTPRequest to talk to the module:

int yapiHTTPRequest(char *device, char *request, char* buffer,int buffsize,
                    int *fullsize, char *errmsg);


Pass the serial number or the logical name of the chosen module to the device parameter.
Pass the full HTTP request (including terminal line feeds) to the request parameter.
Pass to the buffer parameter a buffer large enough to receive the response, and provide its size in the buffsize parameter.
Pass a pointer to an integer to the fullsize parameter for the API to be able to return the effective size of the response. You can pass a null pointer if you don't want to know the size of the response. In any case, you can trust that the response ends with a null character.
Pass a 255 character buffer to the errmsg parameter for the API to return an error message if there is a problem. You can pass a null pointer if you don't want an error message.
The function returns a negative integer in case of error, or zero if everything went well.

Here is a short example in vanilla C to commute a relay:

#include <stdio.h>
#include "yapi.h"

int main(int argc, char *argv)
{
   char errmsg[256];
   char buffer[256];

   if(yapiInitAPI(1, errmsg) < 0 || yapiUpdateDeviceList(1, errmsg) < 0) {
      fprintf("init error: %s\n", errmsg);
      return 1;
   }

   if(yapiHTTPRequest("RELAYLOH1-000001",
                      "GET /api/relay1.json?state=0 HTTP/1.1\r\n\r\n",
                      buffer, sizeof(buffer), NULL, errmsg) < 0) {
      fprintf("communication error: %s\n", errmsg);
      return 1;
   }
   return 0;
}



There are numerous other functions in the low level interface, providing non-blocking access, callbacks, and so on. To know more, simply open the yapi.h file: useful functions are normally reasonably well commented. If this is not enough, leave a comment on this article or send us an email at support@yoctopuce.com.




1 - camillo777 Thursday,june 20,2013 9H52

Hi all, I am a little bit confused... with the YoctoEthernet and YoctoWireless modules is it possible to retrieve with a single HTTP REST call from a remote PC for example the value of the current temperature from a YoctoTemperature module?

This would be cool for Nagios monitoring software for example to create a simple script (in PHP or bash) to make a simple HTTP call to retrieve and save values without having the VirtualHub installed.

You are saying that each Yoctopuce module has natively an HTTP server on board?

Thank you!

Best regards,
Camillo

2 - mvuilleu (Yocto-Team)Thursday,june 20,2013 9H57

Yes, if you plug any Yoctopuce module on a YoctoHub-Ethernet or YoctoHub-Wireless, you can access the current measure of the module with a simple REST query.

When we say that each Yoctopuce module has an HTTP server on board, it means indeed that all our sensors have the internal logic of an HTTP REST api. The only thing that most modules miss is the network interface, so they expose the HTTP REST api over the USB interface by default. But when you plug then on a YoctoHub-Ethernet, then they can talk directly to the network, without the need for a VirtualHub.

3 - ajay7904 Monday,march 01,2021 12H10

What is the purpose of this functions yapiGetAllDevices()

is this function serves the same purpose as yapiUpdateDeviceList() ?

4 - seb (Yocto-Team)Monday,march 01,2021 14H38

@ajay7904 : This function is used to enumerate detected Yoctopuce Device. It fills an array of YAPI_DEVICE. Then you need to call yapiGetDeviceInfo for each YAPI_DEVICE of this array.

You can have a look at this code:
https://gist.github.com/yoctopuce/3b3e05ed7f3b5c39e4869d23350060ac

Yoctopuce, get your stuff connected.