Yocto-pressure : user's guide

Yocto-Pressure : User's guide

1. Introduction
1.1 Safety Information
1.2 Environmental conditions
2. Presentation
2.1 Common elements
2.2 Specific elements
2.3 Optional accessories
3. First steps
3.1 Prerequisites
3.2 Testing USB connectivity
3.3 Localization
3.4 Test of the module
3.5 Configuration
4. Assembly and connections
4.1 Fixing
4.2 Connecting to a tube
4.3 Moving the sensor away
4.4 USB power distribution
4.5 Electromagnetic compatibility (EMI)
5. Programming, general concepts
5.1 Programming paradigm
5.2 The Yocto-Pressure module
5.3 Module control interface
5.4 Pressure function interface
5.5 Temperature function interface
5.6 DataLogger function interface
5.7 What interface: Native, DLL or Service ?
5.8 Programming, where to start?
6. Using the Yocto-Pressure in command line
6.1 Installing
6.2 Use: general description
6.3 Control of the Pressure function
6.4 Control of the module part
6.5 Limitations
7. Using Yocto-Pressure with JavaScript / EcmaScript
7.1 Blocking I/O versus Asynchronous I/O in JavaScript
7.2 Using Yoctopuce library for JavaScript / EcmaScript 2017
7.3 Control of the Pressure function
7.4 Control of the module part
7.5 Error handling
8. Using Yocto-Pressure with PHP
8.1 Getting ready
8.2 Control of the Pressure function
8.3 Control of the module part
8.4 HTTP callback API and NAT filters
8.5 Error handling
9. Using Yocto-Pressure with C++
9.1 Control of the Pressure function
9.2 Control of the module part
9.3 Error handling
9.4 Integration variants for the C++ Yoctopuce library
10. Using Yocto-Pressure with Objective-C
10.1 Control of the Pressure function
10.2 Control of the module part
10.3 Error handling
11. Using Yocto-Pressure with Visual Basic .NET
11.1 Installation
11.2 Using the Yoctopuce API in a Visual Basic project
11.3 Control of the Pressure function
11.4 Control of the module part
11.5 Error handling
12. Using Yocto-Pressure with C#
12.1 Installation
12.2 Using the Yoctopuce API in a Visual C# project
12.3 Control of the Pressure function
12.4 Control of the module part
12.5 Error handling
13. Using the Yocto-Pressure with Universal Windows Platform
13.1 Blocking and asynchronous functions
13.2 Installation
13.3 Using the Yoctopuce API in a Visual Studio project
13.4 Control of the Pressure function
13.5 A real example
13.6 Control of the module part
13.7 Error handling
14. Using Yocto-Pressure with Delphi
14.1 Preparation
14.2 Control of the Pressure function
14.3 Control of the module part
14.4 Error handling
15. Using the Yocto-Pressure with Python
15.1 Source files
15.2 Dynamic library
15.3 Control of the Pressure function
15.4 Control of the module part
15.5 Error handling
16. Using the Yocto-Pressure with Java
16.1 Getting ready
16.2 Control of the Pressure function
16.3 Control of the module part
16.4 Error handling
17. Using the Yocto-Pressure with Android
17.1 Native access and VirtualHub
17.2 Getting ready
17.3 Compatibility
17.4 Activating the USB port under Android
17.5 Control of the Pressure function
17.6 Control of the module part
17.7 Error handling
18. Using the Yocto-Pressure in command line
18.1 Installing
18.2 Use: general description
18.3 Control of the Temperature function
18.4 Control of the module part
18.5 Limitations
19. Using Yocto-Pressure with JavaScript / EcmaScript
19.1 Blocking I/O versus Asynchronous I/O in JavaScript
19.2 Using Yoctopuce library for JavaScript / EcmaScript 2017
19.3 Control of the Temperature function
19.4 Control of the module part
19.5 Error handling
20. Using Yocto-Pressure with PHP
20.1 Getting ready
20.2 Control of the Temperature function
20.3 Control of the module part
20.4 HTTP callback API and NAT filters
20.5 Error handling
21. Using Yocto-Pressure with C++
21.1 Control of the Temperature function
21.2 Control of the module part
21.3 Error handling
21.4 Integration variants for the C++ Yoctopuce library
22. Using Yocto-Pressure with Objective-C
22.1 Control of the Temperature function
22.2 Control of the module part
22.3 Error handling
23. Using Yocto-Pressure with Visual Basic .NET
23.1 Installation
23.2 Using the Yoctopuce API in a Visual Basic project
23.3 Control of the Temperature function
23.4 Control of the module part
23.5 Error handling
24. Using Yocto-Pressure with C#
24.1 Installation
24.2 Using the Yoctopuce API in a Visual C# project
24.3 Control of the Temperature function
24.4 Control of the module part
24.5 Error handling
25. Using the Yocto-Pressure with Universal Windows Platform
25.1 Blocking and asynchronous functions
25.2 Installation
25.3 Using the Yoctopuce API in a Visual Studio project
25.4 Control of the Temperature function
25.5 A real example
25.6 Control of the module part
25.7 Error handling
26. Using Yocto-Pressure with Delphi
26.1 Preparation
26.2 Control of the Temperature function
26.3 Control of the module part
26.4 Error handling
27. Using the Yocto-Pressure with Python
27.1 Source files
27.2 Dynamic library
27.3 Control of the Temperature function
27.4 Control of the module part
27.5 Error handling
28. Using the Yocto-Pressure with Java
28.1 Getting ready
28.2 Control of the Temperature function
28.3 Control of the module part
28.4 Error handling
29. Using the Yocto-Pressure with Android
29.1 Native access and VirtualHub
29.2 Getting ready
29.3 Compatibility
29.4 Activating the USB port under Android
29.5 Control of the Temperature function
29.6 Control of the module part
29.7 Error handling
30. Advanced programming
30.1 Event programming
30.2 The data logger
30.3 Sensor calibration
31. Firmware Update
31.1 The VirtualHub or the YoctoHub
31.2 The command line library
31.3 The Android application Yocto-Firmware
31.4 Updating the firmware with the programming library
31.5 The "update" mode
32. Using with unsupported languages
32.1 Command line
32.2 VirtualHub and HTTP GET
32.3 Using dynamic libraries
32.4 Porting the high level library
33. High-level API Reference
33.1 General functions
33.2 Module control interface
33.3 Pressure function interface
33.4 Temperature function interface
33.5 DataLogger function interface
33.6 Recorded data sequence
33.7 Measured value
34. Troubleshooting
34.1 Where to start?
34.2 Programming examples don't seem to work
34.3 Linux and USB
34.4 ARM Platforms: HF and EL
34.5 Powered module but invisible for the OS
34.6 Another process named xxx is already using yAPI
34.7 Disconnections, erratic behavior
34.8 Damaged device
35. Characteristics
36. Index

1. Introduction

The Yocto-Pressure is a 60x20mm electronic module enabling you to perform by USB the measure of a pressure up to 10 bars. It has a 100mbar accuracy. It is equipped with a quick coupler enabling you to connect a 4mm diameter tube. It can measure gas as well as liquids. Incidentally, the Yocto-Pressure also provides a temperature measure.


The Yocto-Pressure module

The Yocto-Pressure is not in itself a complete product. It is a component intended to be integrated into a solution used in laboratory equipments, or in industrial process-control equipments, or for similar applications in domestic and commercial environments. In order to use it, you must at least install it in a protective enclosure and connect it to a host computer.

Yoctopuce thanks you for buying this Yocto-Pressure and sincerely hopes that you will be satisfied with it. The Yoctopuce engineers have put a large amount of effort to ensure that your Yocto-Pressure is easy to install anywhere and easy to drive from a maximum of programming languages. If you are nevertheless disappointed with this module, or if you need additional information, do not hesitate to contact Yoctopuce support:

E-mail address:support@yoctopuce.com
Web site:www.yoctopuce.com
Postal address:Chemin des Journaliers, 1
ZIP code, city:1236 Cartigny
Country:Switzerland

1.1. Safety Information

The Yocto-Pressure is designed to meet the requirements of IEC 61010-1:2010 safety standard. It does not create any serious hazards to the operator and surrounding area, even in single fault condition, as long as it is integrated and used according to the instructions contained in this documentation, and in this section in particular.

Protective enclosure

The Yocto-Pressure should not be used without a protective enclosure, because of the accessible bare electronic components. For optimal safety, it should be put into a non-metallic, non-inflammable enclosure, resistant to a mechanical stress level of 5 J. For instance, use a polycarbonate (e.g. LEXAN) enclosure rated IK08 with a IEC 60695-11-10 flammability rating of V-1 or better. Using a lower quality enclosure may require specific warnings for the operator and/or compromise conformity with the safety standard.

Maintenance

If a damage is observed on the electronic board or on the enclosure, it should be replaced in order to ensure continued safety of the equipment, and to prevent damaging other parts of the system due to overload that a short circuit could cause.

Identification

In order to ease the maintenance and the identification of risks during maintenance, you should affixate the water-resistant identification label provided together with the electronic board as close as possible to the device. If the device is put in a dedicated enclosure, the identification label should be affixated on the outside of the enclosure.

Application

The safety standard applied is intended to cover laboratory equipment, industrial process-control equipment and similar applications in residential or commercial environment. If you intend to use the Yocto-Pressure for another kind of application, you should check the safety regulations according to the standard applicable to your application.

In particular, the Yocto-Pressure is not certified for use in medical environments or for life-support applications.

Environment

The Yocto-Pressure is not certified for use in hazardous locations, explosive environments, or life-threatening applications. Environmental ratings are provided below.

1.2. Environmental conditions

Yoctopuce devices have been designed for indoor use in a standard office or laboratory environment (IEC 60664 pollution degree 2): air pollution is expected to be limited and mainly non-conductive. Relative humidity is expected to be between 10% and 90% RH, non condensing. Use in environments with significant solid pollution or conductive pollution requires a protection from such pollution using an IP67 or IP68 enclosure. The products are designed for use up to altitude 2000m.

All Yoctopuce devices are warranted to perform according to their documentation and technical specifications under normal temperature conditions according to IEC61010-1, i.e. 5C to 40C. In addition, most devices can also be used on an extended temperature range, where some limitations may apply from case to case.

The extended operating temperature range for the Yocto-Pressure is -20...85C. This temperature range has been determined based on components manufacturer recommendations, and on controlled environment tests performed during a limited duration (1h). If you plan to use the Yocto-Pressure in harsh environments for a long period of time, we strongly advise you to run extensive tests before going to production.

2. Presentation


1:Micro-B USB socket 4:Picoflex header slots
2:Yocto-button 5:1.27mm pads
3:Yocto-led 6:Pressure sensor

2.1. Common elements

All Yocto-modules share a number of common functionalities.

USB connector

Yoctopuce modules all come with a USB 2.0 micro-B socket. Warning: the USB connector is simply soldered in surface and can be pulled out if the USB plug acts as a lever. In this case, if the tracks stayed in position, the connector can be soldered back with a good iron and using flux to avoid bridges. Alternatively, you can solder a USB cable directly in the 1.27mm-spaced holes near the connector.

If you plan to use a power source other then a standard USB host port to power the device through the USB connector, that power source must respect the assigned values of USB 2.0 specifications:

A higher voltage is likely to destroy the device. THe behaviour with a lower voltage is not specified, but it can result firmware corruption.

Yocto-button

The Yocto-button has two functionalities. First, it can activate the Yocto-beacon mode (see below under Yocto-led). Second, if you plug in a Yocto-module while keeping this button pressed, you can then reprogram its firmware with a new version. Note that there is a simpler UI-based method to update the firmware, but this one works even in case of severely damaged firmware.

Yocto-led

Normally, the Yocto-led is used to indicate that the module is working smoothly. The Yocto-led then emits a low blue light which varies slowly, mimicking breathing. The Yocto-led stops breathing when the module is not communicating any more, as for instance when powered by a USB hub which is disconnected from any active computer.

When you press the Yocto-button, the Yocto-led switches to Yocto-beacon mode. It starts flashing faster with a stronger light, in order to facilitate the localization of a module when you have several identical ones. It is indeed possible to trigger off the Yocto-beacon by software, as it is possible to detect by software that a Yocto-beacon is on.

The Yocto-led has a third functionality, which is less pleasant: when the internal software which controls the module encounters a fatal error, the Yocto-led starts emitting an SOS in morse 1. If this happens, unplug and re-plug the module. If it happens again, check that the module contains the latest version of the firmware, and, if it is the case, contact Yoctopuce support2.

Current sensor

Each Yocto-module is able to measure its own current consumption on the USB bus. Current supply on a USB bus being quite critical, this functionality can be of great help. You can only view the current consumption of a module by software.

Serial number

Each Yocto-module has a unique serial number assigned to it at the factory. For Yocto-Pressure modules, this number starts with PRESSMK1. The module can be software driven using this serial number. The serial number cannot be modified.

Logical name

The logical name is similar to the serial number: it is a supposedly unique character string which allows you to reference your module by software. However, in the opposite of the serial number, the logical name can be modified at will. The benefit is to enable you to build several copies of the same project without needing to modify the driving software. You only need to program the same logical name in each copy. Warning: the behavior of a project becomes unpredictable when it contains several modules with the same logical name and when the driving software tries to access one of these modules through its logical name. When leaving the factory, modules do not have an assigned logical name. It is yours to define.

2.2. Specific elements

The sensor

The pressure sensor is the MS5837-30BA manufactured by TE connectivity. An SMC KQH04-M6A quick coupler is mounted on the sensor to ease the connection to the pressurized circuit to be measured. Therefore, the technical characteristics of the whole result from both the sensor and the SMC coupler.

The MS5837-30BA sensor itself can measure a pressure from 0 to 30 bars, but the fixing device securing the quick coupler is guarantied only up to 10 bars. As a safety measure, we checked that the fixing device supports an accidental overpressure of 20 bars during 48 hours. Likewise, the MS5837-30BA sensor itself can work between -20 and +85C, but the quick coupler is specified only from -5C to 60C for air, and from 0C to 40C (without ice) for water.

On the standard temperature range, between 5 and 40C, the absolute accuracy of the sensor is of 0.05 bar between 0 and 6 bar, and 0.1 bar up to 10 bars.

In the extended temperature range from -20C and 85C, the accuracy is of 0.1 bar between 0 and 6 bar, and of 0.2 bar up to 20 bars. But pay attention to the information above about the quick coupler if you go outside of the standard temperature range.

This sensor measures the absolute pressure, which means that if it measures the pressure of a pneumatic circuit which is not under pressure, it does not return zero, but the value of the local atmospheric pressure, that is about 1000 mbars at sea level.

Beware: this MS5837-30BA sensor is very fragile, it is made of a small ceramic square on which is glued a small metal cylinder containing a gel which serves as interface between the electronics of the sensor and the substance to be measured. This little cylinder can be very easily ripped off. The quick coupler mounting system consolidates the whole, but we nevertheless recommend you not to drop the module and not to dismantle it. To avoid the temptation of dismantling it to satisfy your curiosity, you can find below an exploded view of the sensor part.


Exploded view of the sensor part

2.3. Optional accessories

The accessories below are not necessary to use the Yocto-Pressure module but might be useful depending on your project. These are mostly common products that you can buy from your favorite hacking store. To save you the tedious job of looking for them, most of them are also available on the Yoctopuce shop.

Screws and spacers

In order to mount the Yocto-Pressure module, you can put small screws in the 2.5mm assembly holes, with a screw head no larger than 4.5mm. The best way is to use threaded spacers, which you can then mount wherever you want. You can find more details on this topic in the chapter about assembly and connections.

Micro-USB hub

If you intend to put several Yoctopuce modules in a very small space, you can connect them directly to a micro-USB hub. Yoctopuce builds a USB hub particularly small for this purpose (down to 20mmx36mm), on which you can directly solder a USB cable instead of using a USB plug. For more details, see the micro-USB hub information sheet.

YoctoHub-Ethernet, YoctoHub-Wireless and YoctoHub-GSM

You can add network connectivity to your Yocto-Pressure, thanks to the YoctoHub-Ethernet, the YoctoHub-Wireless and the YoctoHub-GSM which provides repectiveley Ethernet, WiFi and GSM connectivity. All of them can drive up to three devices and behave exactly like a regular computer running a VirtualHub.

1.27mm (or 1.25mm) connectors

In case you wish to connect your Yocto-Pressure to a Micro-hub USB or a YoctoHub without using a bulky USB connector, you can use the four 1.27mm pads just behind the USB connector. There are two options.

You can mount the Yocto-Pressure directly on the hub using screw and spacers, and connect it using 1.27mm board-to-board connectors. To prevent shortcuts, it is best to solder the female connector on the hub and the male connector on the Yocto-Pressure.

You can also use a small 4-wires cable with a 1.27mm connector. 1.25mm works as well, it does not make a difference for 4 pins. This makes it possible to move the device a few inches away. Don't put it too far away if you use that type of cable, because as the cable is not shielded, it may cause undesirable electromagnetic emissions.

Enclosure

Your Yocto-Pressure has been designed to be installed as is in your project. Nevertheless, Yoctopuce sells enclosures specifically designed for Yoctopuce devices. These enclosures have removable mounting brackets and magnets allowing them to stick on ferromagnetic surfaces. More details are available on the Yoctopuce web site 3. The suggested enclosure model for your Yocto-Pressure is the YoctoBox-Long-Thick-Press.


You can install your Yocto-Pressure in an optional enclosure

Picoflex connectors and flexible ribbon cable

If you want to move away the sensor part of the Yocto-Pressure module with a plug connector, you need 4-wire flexible ribbon cable of 1.27mm pitch and Picoflex connectors. 4 You can find more details on this topic in the chapter about assembly and connections.

3. First steps

By design, all Yoctopuce modules are driven the same way. Therefore, user's guides for all the modules of the range are very similar. If you have already carefully read through the user's guide of another Yoctopuce module, you can jump directly to the description of the module functions.

3.1. Prerequisites

In order to use your Yocto-Pressure module, you should have the following items at hand.

A computer

Yoctopuce modules are intended to be driven by a computer (or possibly an embedded microprocessor). You will write the control software yourself, according to your needs, using the information provided in this manual.

Yoctopuce provides software libraries to drive its modules for the following operating systems: Windows, macOS X, Linux, and Android. Yoctopuce modules do not require installing any specific system driver, as they leverage the standard HID driver5 provided with every operating system.

Windows versions currently supported are: Windows XP, Windows 2003, Windows Vista, Windows 7, Windows 8 and Windows 10. Both 32 bit and 64 bit versions are supported. The programming library is also available for the Universal Windows Platform (UWP), which is supported by all flavors of Windows 10, including Windows 10 IoT. Yoctopuce is frequently testing its modules on Windows 7 and Windows 10.

MacOS versions currently supported are: Mac OS X 10.9 (Maverick), 10.10 (Yosemite), 10.11 (El Capitan), macOS 10.12 (Sierra), macOS 10.13 (High Sierra) and macOS 10.14 (Mojave). Yoctopuce is frequently testing its modules on macOS 10.14.

Linux kernels currently supported are the 2.6 branch, the 3.x branch and the 4.x branch. Other versions of the Linux kernel, and even other UNIX variants, are very likely to work as well, as Linux support is implemented through the standard libusb API. Yoctopuce is frequently testing its modules on Linux kernel 4.15 (Ubuntu 18.04 LTS).

Android versions currently supported are: Android 3.1 and later. Moreover, it is necessary for the tablet or phone to support the Host USB mode. Yoctopuce is frequently testing its modules on Android 7.x on a Samsung Galaxy A6 with the Java for Android library.

A USB 2.0 cable, type A-micro B

USB 2.0 connectors exist in three sizes: the "standard" size that you probably use to connect your printer, the very common mini size to connect small devices, and finally the micro size often used to connect mobile phones, as long as they do not exhibit an apple logo. All USB modules manufactured by Yoctopuce use micro size connectors.


The most common USB 2.0 connectors: A, B, Mini B, Micro A, Micro B6

To connect your Yocto-Pressure module to a computer, you need a USB 2.0 cable of type A-micro B. The price of this cable may vary a lot depending on the source, look for it under the name USB 2.0 A to micro B Data cable. Make sure not to buy a simple USB charging cable without data connectivity. The correct type of cable is available on the Yoctopuce shop.


You must plug in your Yocto-Pressure module with a USB 2.0 cable of type A - micro B

If you insert a USB hub between the computer and the Yocto-Pressure module, make sure to take into account the USB current limits. If you do not, be prepared to face unstable behaviors and unpredictable failures. You can find more details on this topic in the chapter about assembly and connections.

3.2. Testing USB connectivity

At this point, your Yocto-Pressure should be connected to your computer, which should have recognized it. It is time to make it work.

Go to the Yoctopuce web site and download the Virtual Hub software7. It is available for Windows, Linux, and Mac OS X. Normally, the Virtual Hub software serves as an abstraction layer for languages which cannot access the hardware layers of your computer. However, it also offers a succinct interface to configure your modules and to test their basic functions. You access this interface with a simple web browser8. Start the Virtual Hub software in a command line, open your preferred web browser and enter the URL http://127.0.0.1:4444. The list of the Yoctopuce modules connected to your computer is displayed.


Module list as displayed in your web bowser

3.3. Localization

You can then physically localize each of the displayed modules by clicking on the beacon button. This puts the Yocto-led of the corresponding module in Yocto-beacon mode. It starts flashing, which allows you to easily localize it. The second effect is to display a little blue circle on the screen. You obtain the same behavior when pressing the Yocto-button of the module.

3.4. Test of the module

The first item to check is that your module is working well: click on the serial number corresponding to your module. This displays a window summarizing the properties of your Yocto-Pressure.


Properties of the Yocto-Pressure module

This window allows you, among other things, to play with your module to check how it works, as the pressure and temperature values are displayed in real time.

3.5. Configuration

When, in the module list, you click on the configure button corresponding to your module, the configuration window is displayed.


Yocto-Pressure module configuration.

Firmware

The module firmware can easily be updated with the help of the interface. Firmware destined for Yoctopuce modules are available as .byn files and can be downloaded from the Yoctopuce web site.

To update a firmware, simply click on the upgrade button on the configuration window and follow the instructions. If the update fails for one reason or another, unplug and re-plug the module and start the update process again. This solves the issue in most cases. If the module was unplugged while it was being reprogrammed, it does probably not work anymore and is not listed in the interface. However, it is always possible to reprogram the module correctly by using the Virtual Hub software 9 in command line 10.

Logical name of the module

The logical name is a name that you choose, which allows you to access your module, in the same way a file name allows you to access its content. A logical name has a maximum length of 19 characters. Authorized characters are A..Z, a..z, 0..9, _, and -. If you assign the same logical name to two modules connected to the same computer and you try to access one of them through this logical name, behavior is undetermined: you have no way of knowing which of the two modules answers.

Luminosity

This parameter allows you to act on the maximal intensity of the leds of the module. This enables you, if necessary, to make it a little more discreet, while limiting its power consumption. Note that this parameter acts on all the signposting leds of the module, including the Yocto-led. If you connect a module and no led turns on, it may mean that its luminosity was set to zero.

Logical names of functions

Each Yoctopuce module has a serial number and a logical name. In the same way, each function on each Yoctopuce module has a hardware name and a logical name, the latter can be freely chosen by the user. Using logical names for functions provides a greater flexibility when programming modules.

The only two functions provided by the Yocto-Pressure module are the "pressure" and "temperature" functions. Simply click on the corresponding "rename" button to assign them a new logical name.

4. Assembly and connections

This chapter provides important information regarding the use of the Yocto-Pressure module in real-world situations. Make sure to read it carefully before going too far into your project if you want to avoid pitfalls.

4.1. Fixing

While developing your project, you can simply let the module hang at the end of its cable. Check only that it does not come in contact with any conducting material (such as your tools). When your project is almost at an end, you need to find a way for your modules to stop moving around.


Examples of assembly on supports

The Yocto-Pressure module contains 2.5mm assembly holes. You can use these holes for screws. The screw head diameter must not be larger than 4.5mm or they will damage the module circuits. Make sure that the lower surface of the module is not in contact with the support. We recommend using spacers, but other methods are possible. Nothing prevents you from fixing the module with a glue gun; it will not be good-looking, but it will hold.

If your intend to screw your module directly against a conducting part, for example a metallic frame, insert an isolating layer in between. Otherwise you are bound to induce a short circuit: there are naked pads under your module. Simple insulating tape should be enough.

4.2. Connecting to a tube

The Yocto-Pressure is equipped with a 4mm quick coupler to very easily connect a polyethylene tube, such as widely used in pneumatic techniques, but any tube with a 4mm external diameter will do. To connect the tube to the Yocto-Pressure, simply push the tube in the quick coupler of the Yocto-Pressure. To disconnect the tube, do not forcibly remove it:

  1. Make sure the tube is not under pressure
  2. Press on the quick coupler ring
  3. Remove the tube


Do not force to disconnect the tube

4.3. Moving the sensor away

The Yocto-Pressure module is designed so that you can split it into two parts, allowing you to move away the sensors from the command sub-module. You can split the module by simply breaking the circuit. However, you will obtain better results if you use a good pincer, or cutting pliers. When you have split the sub-modules, you can sandpaper the protruding parts without risk.


Wiring under the sub-modules once separated.

Once the module is split into two, you must rewire the sub-modules. Several solutions are available. You can connect the sub-modules by soldering simple electric wires, but you will obtain a better result with 1.27 pitch ribbon cable. Consider using solid copper cables, rather than threaded ones: solid copper cables are somewhat less flexible, but much easier to solder.


Moving the sensors away with a simple ribbon cable.

You can also use a ribbon cable equipped with Picoflex connectors. You will obtain a slightly bigger system, but Picoflex headers are much easier to solder than ribbon cable. Moreover, the result can be disassembled.


Moving the sensors away with Picoflex connectors.

Warning, divisible Yoctopuce modules very often have very similar connection systems. Nevertheless, sub-modules from different models are not all compatible. If you connect your Yocto-Pressure sub-module to another type of module such as a Yocto-Meteo for instance, it will not work, and you run a high risk of damaging your equipment.

4.4. USB power distribution

Although USB means Universal Serial BUS, USB devices are not physically organized as a flat bus but as a tree, using point-to-point connections. This has consequences on power distribution: to make it simple, every USB port must supply power to all devices directly or indirectly connected to it. And USB puts some limits.

In theory, a USB port provides 100mA, and may provide up to 500mA if available and requested by the device. In the case of a hub without external power supply, 100mA are available for the hub itself, and the hub should distribute no more than 100mA to each of its ports. This is it, and this is not much. In particular, it means that in theory, it is not possible to connect USB devices through two cascaded hubs without external power supply. In order to cascade hubs, it is necessary to use self-powered USB hubs, that provide a full 500mA to each subport.

In practice, USB would not have been as successful if it was really so picky about power distribution. As it happens, most USB hub manufacturers have been doing savings by not implementing current limitation on ports: they simply connect the computer power supply to every port, and declare themselves as self-powered hub even when they are taking all their power from the USB bus (in order to prevent any power consumption check in the operating system). This looks a bit dirty, but given the fact that computer USB ports are usually well protected by a hardware current limitation around 2000mA, it actually works in every day life, and seldom makes hardware damage.

What you should remember: if you connect Yoctopuce modules through one, or more, USB hub without external power supply, you have no safe-guard and you depend entirely on your computer manufacturer attention to provide as much current as possible on the USB ports, and to detect overloads before they lead to problems or to hardware damages. When modules are not provided enough current, they may work erratically and create unpredictable bugs. If you want to prevent any risk, do not cascade hubs without external power supply, and do not connect peripherals requiring more than 100mA behind a bus-powered hub.

In order to help you controlling and planning overall power consumption for your project, all Yoctopuce modules include a built-in current sensor that indicates (with 5mA precision) the consumption of the module on the USB bus.

Note also that the USB cable itself may also cause power supply issues, in particular when the wires are too thin or when the cable is too long 11. Good cables are usually made using AWG 26 or AWG 28 wires for data lines and AWG 24 wires for power.

4.5. Electromagnetic compatibility (EMI)

Connection methods to integrate the Yocto-Pressure obviously have an impact on the system overall electromagnetic emissions, and therefore also impact the conformity with international standards.

When we perform reference measurements to validate the conformity of our products with IEC CISPR 11, we do not use any enclosure but connect the devices using a shielded USB cable, compliant with USB 2.0 specifications: the cable shield is connected to both connector shells, and the total resistance from shell to shell is under 0.6Ω. The USB cable length is 3m, in order to expose one meter horizontally, one meter vertically and keep the last meter close to the host computer within a ferrite bead.

If you use a non-shielded USB cable, or an improperly shielded cable, your system will work perfectly well but you may not remain in conformity with the emission standard. If you are building a system made of multiple devices connected using 1.27mm pitch connectors, or with a sensor moved away from the device CPU, you can generally recover the conformity by using a metallic enclosure acting as an external shield.

Still on the topic of electromagnetic compatibility, the maximum supported length of the USB cable is 3m. In addition to the voltage drop issue mentionned above, using longer wires would require to run extra tests to assert compatibility with the electromagnetic immunity standards.

5. Programming, general concepts

The Yoctopuce API was designed to be at the same time simple to use and sufficiently generic for the concepts used to be valid for all the modules in the Yoctopuce range, and this in all the available programming languages. Therefore, when you have understood how to drive your Yocto-Pressure with your favorite programming language, learning to use another module, even with a different language, will most likely take you only a minimum of time.

5.1. Programming paradigm

The Yoctopuce API is object oriented. However, for simplicity's sake, only the basics of object programming were used. Even if you are not familiar with object programming, it is unlikely that this will be a hinderance for using Yoctopuce products. Note that you will never need to allocate or deallocate an object linked to the Yoctopuce API: it is automatically managed.

There is one class per Yoctopuce function type. The name of these classes always starts with a Y followed by the name of the function, for example YTemperature, YRelay, YPressure, etc.. There is also a YModule class, dedicated to managing the modules themselves, and finally there is the static YAPI class, that supervises the global workings of the API and manages low level communications.


Structure of the Yoctopuce API.

The YSensor class

Each Yoctopuce sensor function has its dedicated class: YTemperature to measure the temperature, YVoltage to measure a voltage, YRelay to drive a relay, etc. However there is a special class that can do more: YSensor.

The YSensor class is the parent class for all Yoctopuce sensors, and can provide access to any sensor, regardless of its type. It includes methods to access all common functions. This makes it easier to create applications that use many different sensors. Moreover, if you create an application based on YSensor, it will work with all Yoctopuce sensors, even those which do no yet exist.

Programmation

In the Yoctopuce API, priority was put on the ease of access to the module functions by offering the possibility to make abstractions of the modules implementing them. Therefore, it is quite possible to work with a set of functions without ever knowing exactly which module are hosting them at the hardware level. This tremendously simplifies programming projects with a large number of modules.

From the programming stand point, your Yocto-Pressure is viewed as a module hosting a given number of functions. In the API, these functions are objects which can be found independently, in several ways.

Access to the functions of a module

Access by logical name

Each function can be assigned an arbitrary and persistent logical name: this logical name is stored in the flash memory of the module, even if this module is disconnected. An object corresponding to an Xxx function to which a logical name has been assigned can then be directly found with this logical name and the YXxx.FindXxx method. Note however that a logical name must be unique among all the connected modules.

Access by enumeration

You can enumerate all the functions of the same type on all the connected modules with the help of the classic enumeration functions FirstXxx and nextXxxx available for each YXxx class.

Access by hardware name

Each module function has a hardware name, assigned at the factory and which cannot be modified. The functions of a module can also be found directly with this hardware name and the YXxx.FindXxx function of the corresponding class.

Difference between Find and First

The YXxx.FindXxxx and YXxx.FirstXxxx methods do not work exactly the same way. If there is no available module, YXxx.FirstXxxx returns a null value. On the opposite, even if there is no corresponding module, YXxx.FindXxxx returns a valid object, which is not online but which could become so if the corresponding module is later connected.

Function handling

When the object corresponding to a function is found, its methods are available in a classic way. Note that most of these subfunctions require the module hosting the function to be connected in order to be handled. This is generally not guaranteed, as a USB module can be disconnected after the control software has started. The isOnline method, available in all the classes, is then very helpful.

Access to the modules

Even if it is perfectly possible to build a complete project while making a total abstraction of which function is hosted on which module, the modules themselves are also accessible from the API. In fact, they can be handled in a way quite similar to the functions. They are assigned a serial number at the factory which allows you to find the corresponding object with YModule.Find(). You can also assign arbitrary logical names to the modules to make finding them easier. Finally, the YModule class contains the YModule.FirstModule() and nextModule() enumeration methods allowing you to list the connected modules.

Functions/Module interaction

From the API standpoint, the modules and their functions are strongly uncorrelated by design. Nevertheless, the API provides the possibility to go from one to the other. Thus, the get_module() method, available for each function class, allows you to find the object corresponding to the module hosting this function. Inversely, the YModule class provides several methods allowing you to enumerate the functions available on a module.

5.2. The Yocto-Pressure module

The Yocto-Pressure device provides one instance of the Altitude function, corresponding to the estimated altitude, with a sensitivity of about 0.25m. It also provides the measured atmospheric pressure and temperature.

module : Module

attributetypemodifiable ?
productName  String  read-only
serialNumber  String  read-only
logicalName  String  modifiable
productId  Hexadecimal number  read-only
productRelease  Hexadecimal number  read-only
firmwareRelease  String  read-only
persistentSettings  Enumerated  modifiable
luminosity  0..100%  modifiable
beacon  On/Off  modifiable
upTime  Time  read-only
usbCurrent  Used current (mA)  read-only
rebootCountdown  Integer  modifiable
userVar  Integer  modifiable

pressure : Pressure
attributetypemodifiable ?
logicalName  String  modifiable
advertisedValue  String  modifiable
unit  String  read-only
currentValue  Fixed-point number  read-only
lowestValue  Fixed-point number  modifiable
highestValue  Fixed-point number  modifiable
currentRawValue  Fixed-point number  read-only
logFrequency  Frequency  modifiable
reportFrequency  Frequency  modifiable
advMode  Enumerated  modifiable
calibrationParam  Calibration parameters  modifiable
resolution  Fixed-point number  modifiable
sensorState  Integer  read-only

temperature : Temperature
attributetypemodifiable ?
logicalName  String  modifiable
advertisedValue  String  modifiable
unit  String  modifiable
currentValue  Fixed-point number  read-only
lowestValue  Fixed-point number  modifiable
highestValue  Fixed-point number  modifiable
currentRawValue  Fixed-point number  read-only
logFrequency  Frequency  modifiable
reportFrequency  Frequency  modifiable
advMode  Enumerated  modifiable
calibrationParam  Calibration parameters  modifiable
resolution  Fixed-point number  modifiable
sensorState  Integer  read-only
sensorType  Enumerated  modifiable
signalValue  Fixed-point number  read-only
signalUnit  String  read-only
command  String  modifiable

dataLogger : DataLogger
attributetypemodifiable ?
logicalName  String  modifiable
advertisedValue  String  modifiable
currentRunIndex  Integer  read-only
timeUTC  UTC time  modifiable
recording  Enumerated  modifiable
autoStart  On/Off  modifiable
beaconDriven  On/Off  modifiable
usage  0..100%  read-only
clearHistory  Boolean  modifiable

5.3. Module control interface

This interface is identical for all Yoctopuce USB modules. It can be used to control the module global parameters, and to enumerate the functions provided by each module.

productName

Character string containing the commercial name of the module, as set by the factory.

serialNumber

Character string containing the serial number, unique and programmed at the factory. For a Yocto-Pressure module, this serial number always starts with PRESSMK1. You can use the serial number to access a given module by software.

logicalName

Character string containing the logical name of the module, initially empty. This attribute can be modified at will by the user. Once initialized to an non-empty value, it can be used to access a given module. If two modules with the same logical name are in the same project, there is no way to determine which one answers when one tries accessing by logical name. The logical name is limited to 19 characters among A..Z,a..z,0..9,_, and -.

productId

USB device identifier of the module, preprogrammed to 117 at the factory.

productRelease

Release number of the module hardware, preprogrammed at the factory.

firmwareRelease

Release version of the embedded firmware, changes each time the embedded software is updated.

persistentSettings

State of persistent module settings: loaded from flash memory, modified by the user or saved to flash memory.

luminosity

Lighting strength of the informative leds (e.g. the Yocto-Led) contained in the module. It is an integer value which varies between 0 (LEDs turned off) and 100 (maximum led intensity). The default value is 50. To change the strength of the module LEDs, or to turn them off completely, you only need to change this value.

beacon

Activity of the localization beacon of the module.

upTime

Time elapsed since the last time the module was powered on.

usbCurrent

Current consumed by the module on the USB bus, in milli-amps.

rebootCountdown

Countdown to use for triggering a reboot of the module.

userVar

32bit integer variable available for user storage.

5.4. Pressure function interface

The Yoctopuce class YPressure allows you to read and configure Yoctopuce pressure sensors. It inherits from YSensor class the core functions to read measurements, to register callback functions, to access the autonomous datalogger.

logicalName

Character string containing the logical name of the pressure sensor, initially empty. This attribute can be modified at will by the user. Once initialized to an non-empty value, it can be used to access the pressure sensor directly. If two pressure sensors with the same logical name are used in the same project, there is no way to determine which one answers when one tries accessing by logical name. The logical name is limited to 19 characters among A..Z,a..z,0..9,_, and -.

advertisedValue

Short character string summarizing the current state of the pressure sensor, that is automatically advertised up to the parent hub. For a pressure sensor, the advertised value is the current value of the pressure.

unit

Short character string representing the measuring unit for the pressure.

currentValue

Current value of the pressure, in millibar (hPa), as a floating point number.

lowestValue

Minimal value of the pressure, in millibar (hPa), as a floating point number.

highestValue

Maximal value of the pressure, in millibar (hPa), as a floating point number.

currentRawValue

Uncalibrated, unrounded raw value returned by the sensor, as a floating point number.

logFrequency

Datalogger recording frequency, or "OFF" when measures should not be stored in the data logger flash memory.

reportFrequency

Timed value notification frequency, or "OFF" when timed value notifications are disabled for this function.

advMode

Measuring mode for the advertised value pushed to the parent hub.

calibrationParam

Extra calibration parameters (for instance to compensate for the effects of an enclosure), as an array of 16 bit words.

resolution

Measure resolution (i.e. precision of the numeric representation, not necessarily of the measure itself).

sensorState

Sensor health state (zero when a current measure is available).

5.5. Temperature function interface

The Yoctopuce class YTemperature allows you to read and configure Yoctopuce temperature sensors. It inherits from YSensor class the core functions to read measurements, to register callback functions, to access the autonomous datalogger. This class adds the ability to configure some specific parameters for some sensors (connection type, temperature mapping table).

logicalName

Character string containing the logical name of the temperature sensor, initially empty. This attribute can be modified at will by the user. Once initialized to an non-empty value, it can be used to access the temperature sensor directly. If two temperature sensors with the same logical name are used in the same project, there is no way to determine which one answers when one tries accessing by logical name. The logical name is limited to 19 characters among A..Z,a..z,0..9,_, and -.

advertisedValue

Short character string summarizing the current state of the temperature sensor, that is automatically advertised up to the parent hub. For a temperature sensor, the advertised value is the current value of the temperature.

unit

Short character string representing the measuring unit for the temperature.

currentValue

Current value of the temperature, in Celsius, as a floating point number.

lowestValue

Minimal value of the temperature, in Celsius, as a floating point number.

highestValue

Maximal value of the temperature, in Celsius, as a floating point number.

currentRawValue

Uncalibrated, unrounded raw value returned by the sensor, as a floating point number.

logFrequency

Datalogger recording frequency, or "OFF" when measures should not be stored in the data logger flash memory.

reportFrequency

Timed value notification frequency, or "OFF" when timed value notifications are disabled for this function.

advMode

Measuring mode for the advertised value pushed to the parent hub.

calibrationParam

Extra calibration parameters (for instance to compensate for the effects of an enclosure), as an array of 16 bit words.

resolution

Measure resolution (i.e. precision of the numeric representation, not necessarily of the measure itself).

sensorState

Sensor health state (zero when a current measure is available).

sensorType

Thermal sensor type used in the device, this can be a digital sensor, a specific type for a thermocouple, a PT100, a thermistor or a IR sensor

signalValue

Current value of the electrical signal measured by the sensor (except for digital sensors) as a floating point number.

signalUnit

Short character string representing the measuring unit of the electrical signal used by the sensor.

command

Magic attribute used to setup physical sensor parameters.

5.6. DataLogger function interface

Yoctopuce sensors include a non-volatile memory capable of storing ongoing measured data automatically, without requiring a permanent connection to a computer. The DataLogger function controls the global parameters of the internal data logger. Recording control (start/stop) as well as data retreival is done at sensor objects level.

logicalName

Character string containing the logical name of the data logger, initially empty. This attribute can be modified at will by the user. Once initialized to an non-empty value, it can be used to access the data logger directly. If two data loggers with the same logical name are used in the same project, there is no way to determine which one answers when one tries accessing by logical name. The logical name is limited to 19 characters among A..Z,a..z,0..9,_, and -.

advertisedValue

Short character string summarizing the current state of the data logger, that is automatically advertised up to the parent hub. For a data logger, the advertised value is its recording state (ON or OFF).

currentRunIndex

Current run number, corresponding to the number of time the module was powered on with the dataLogger enabled at some point.

timeUTC

Current UTC time, in case it is desirable to bind an absolute time reference to the data stored by the data logger. This time must be set up by software.

recording

Activation state of the data logger. The data logger can be enabled and disabled at will, using this attribute, but its state on power on is determined by the autoStart persistent attribute. When the datalogger is enabled but not yet ready to record data, its state is set to PENDING.

autoStart

Automatic start of the data logger on power on. Setting this attribute ensures that the data logger is always turned on when the device is powered up, without need for a software command. Note: if the device doesn't have any time source at his disposal, it will wait for ~8 seconds before automatically starting to record.

beaconDriven

Synchronize the sate of the localization beacon and the state of the data logger. If this attribute is set, it is possible to start the recording with the Yocto-button or the attribute beacon of the function YModule. In the same way, if the attribute recording is changed, the sate of the localization beacon is updated. Note: when this attribute is set the localization beacon pulses slower than usual.

usage

Percentage of datalogger memory in use.

clearHistory

Attribute that can be set to true to clear recorded data.

5.7. What interface: Native, DLL or Service ?

There are several methods to control you Yoctopuce module by software.

Native control

In this case, the software driving your project is compiled directly with a library which provides control of the modules. Objectively, it is the simplest and most elegant solution for the end user. The end user then only needs to plug the USB cable and run your software for everything to work. Unfortunately, this method is not always available or even possible.


The application uses the native library to control the locally connected module

Native control by DLL

Here, the main part of the code controlling the modules is located in a DLL. The software is compiled with a small library which provides control of the DLL. It is the fastest method to code module support in a given language. Indeed, the "useful" part of the control code is located in the DLL which is the same for all languages: the effort to support a new language is limited to coding the small library which controls the DLL. From the end user stand point, there are few differences: one must simply make sure that the DLL is installed on the end user's computer at the same time as the main software.


The application uses the DLL to natively control the locally connected module

Control by service

Some languages do simply not allow you to easily gain access to the hardware layers of the machine. It is the case for Javascript, for instance. To deal with this case, Yoctopuce provides a solution in the form of a small piece of software called VirtualHub12. It can access the modules, and your application only needs to use a library which offers all necessary functions to control the modules via this VirtualHub. The end users will have to start the VirtualHub before running the project control software itself, unless they decide to install the hub as a service/deamon, in which case the VirtualHub starts automatically when the machine starts up.


The application connects itself to the VirtualHub to gain access to the module

The service control method comes with a non-negligible advantage: the application does not need to run on the machine on which the modules are connected. The application can very well be located on another machine which connects itself to the service to drive the modules. Moreover, the native libraries and DLL mentioned above are also able to connect themselves remotely to one or several machines running VirtualHub.


When a VirtualHub is used, the control application does not need to reside on the same machine as the module.

Whatever the selected programming language and the control paradigm used, programming itself stays strictly identical. From one language to another, functions bear exactly the same name, and have the same parameters. The only differences are linked to the constraints of the languages themselves.

Language Native  Native with DLL  Virtual hub 
C++
Objective-C -
Delphi -
Python -
VisualBasic .Net -
C# .Net -
C# UWP -
EcmaScript / JavaScript - -
PHP - -
Java -
Java for Android -
Command line -

Support methods for different languages

Limitations of the Yoctopuce libraries

Natives et DLL libraries have a technical limitation. On the same computer, you cannot concurrently run several applications accessing Yoctopuce devices directly. If you want to run several projects on the same computer, make sure your control applications use Yoctopuce devices through a VirtualHub software. The modification is trivial: it is just a matter of parameter change in the yRegisterHub() call.

5.8. Programming, where to start?

At this point of the user's guide, you should know the main theoretical points of your Yocto-Pressure. It is now time to practice. You must download the Yoctopuce library for your favorite programming language from the Yoctopuce web site13. Then skip directly to the chapter corresponding to the chosen programming language.

All the examples described in this guide are available in the programming libraries. For some languages, the libraries also include some complete graphical applications, with their source code.

When you have mastered the basic programming of your module, you can turn to the chapter on advanced programming that describes some techniques that will help you make the most of your Yocto-Pressure.

6. Using the Yocto-Pressure in command line

When you want to perform a punctual operation on your Yocto-Pressure, such as reading a value, assigning a logical name, and so on, you can obviously use the Virtual Hub, but there is a simpler, faster, and more efficient method: the command line API.

The command line API is a set of executables, one by type of functionality offered by the range of Yoctopuce products. These executables are provided pre-compiled for all the Yoctopuce officially supported platforms/OS. Naturally, the executable sources are also provided14.

6.1. Installing

Download the command line API15. You do not need to run any setup, simply copy the executables corresponding to your platform/OS in a directory of your choice. You may add this directory to your PATH variable to be able to access these executables from anywhere. You are all set, you only need to connect your Yocto-Pressure, open a shell, and start working by typing for example:

C:\>YPressure any get_currentValue

To use the command API on Linux, you need either have root privileges or to define an udev rule for your system. See the Troubleshooting chapter for more details.

6.2. Use: general description

All the command line API executables work on the same principle. They must be called the following way


C:\>Executable [options] [target] command [parameter]

[options] manage the global workings of the commands, they allow you, for instance, to pilot a module remotely through the network, or to force the module to save its configuration after executing the command.

[target] is the name of the module or of the function to which the command applies. Some very generic commands do not need a target. You can also use the aliases "any" and "all", or a list of names separated by comas without space.

command is the command you want to run. Almost all the functions available in the classic programming APIs are available as commands. You need to respect neither the case nor the underlined characters in the command name.

[parameters] logically are the parameters needed by the command.

At any time, the command line API executables can provide a rather detailed help. Use for instance:


C:\>executable /help

to know the list of available commands for a given command line API executable, or even:


C:\>executable command /help

to obtain a detailed description of the parameters of a command.

6.3. Control of the Pressure function

To control the Pressure function of your Yocto-Pressure, you need the YPressure executable file.

For instance, you can launch:

C:\>YPressure any get_currentValue

This example uses the "any" target to indicate that we want to work on the first Pressure function found among all those available on the connected Yoctopuce modules when running. This prevents you from having to know the exact names of your function and of your module.

But you can use logical names as well, as long as you have configured them beforehand. Let us imagine a Yocto-Pressure module with the PRESSMK1-123456 serial number which you have called "MyModule", and its pressure function which you have renamed "MyFunction". The five following calls are strictly equivalent (as long as MyFunction is defined only once, to avoid any ambiguity).


C:\>YPressure PRESSMK1-123456.pressure describe

C:\>YPressure PRESSMK1-123456.MyFunction describe

C:\>YPressure MyModule.pressure describe

C:\>YPressure MyModule.MyFunction describe

C:\>YPressure MyFunction describe

To work on all the Pressure functions at the same time, use the "all" target.


C:\>YPressure all describe

For more details on the possibilities of the YPressure executable, use:


C:\>YPressure /help

6.4. Control of the module part

Each module can be controlled in a similar way with the help of the YModule executable. For example, to obtain the list of all the connected modules, use:


C:\>YModule inventory

You can also use the following command to obtain an even more detailed list of the connected modules:


C:\>YModule all describe

Each xxx property of the module can be obtained thanks to a command of the get_xxxx() type, and the properties which are not read only can be modified with the set_xxx() command. For example:


C:\>YModule PRESSMK1-12346 set_logicalName MonPremierModule

C:\>YModule PRESSMK1-12346 get_logicalName

Changing the settings of the module

When you want to change the settings of a module, simply use the corresponding set_xxx command. However, this change happens only in the module RAM: if the module restarts, the changes are lost. To store them permanently, you must tell the module to save its current configuration in its nonvolatile memory. To do so, use the saveToFlash command. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash method. For example:


C:\>YModule PRESSMK1-12346 set_logicalName MonPremierModule
C:\>YModule PRESSMK1-12346 saveToFlash

Note that you can do the same thing in a single command with the -s option.


C:\>YModule -s  PRESSMK1-12346 set_logicalName MonPremierModule

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

6.5. Limitations

The command line API has the same limitation than the other APIs: there can be only one application at a given time which can access the modules natively. By default, the command line API works in native mode.

You can easily work around this limitation by using a Virtual Hub: run the VirtualHub16 on the concerned machine, and use the executables of the command line API with the -r option. For example, if you use:


C:\>YModule  inventory

you obtain a list of the modules connected by USB, using a native access. If another command which accesses the modules natively is already running, this does not work. But if you run a Virtual Hub, and you give your command in the form:


C:\>YModule -r 127.0.0.1 inventory

it works because the command is not executed natively anymore, but through the Virtual Hub. Note that the Virtual Hub counts as a native application.

7. Using Yocto-Pressure with JavaScript / EcmaScript

EcmaScript is the official name of the standardized version of the web-oriented programming language commonly referred to as JavaScript. This Yoctopuce library take advantages of advanced features introduced in EcmaScript 2017. It has therefore been named Library for JavaScript / EcmaScript 2017 to differentiate it from the previous Library for JavaScript, now deprecated in favor of this new version.

This library provides access to Yoctopuce devices for modern JavaScript engines. It can be used within a browser as well as with Node.js. The library will automatically detect upon initialization whether the runtime environment is a browser or a Node.js virtual machine, and use the most appropriate system libraries accordingly.

Asynchronous communication with the devices is handled across the whole library using Promise objects, leveraging the new EcmaScript 2017 async / await non-blocking syntax for asynchronous I/O (see below). This syntax is now available out-of-the-box in most Javascript engines. No transpilation is needed: no Babel, no jspm, just plain Javascript. Here is your favorite engines minimum version needed to run this code. All of them are officially released at the time we write this document.

If you need backward-compatibility with older releases, you can always run Babel to transpile your code and the library to older standards, as described a few paragraphs below.

We don't suggest using jspm 0.17 anymore since that tool is still in Beta after 18 month, and having to use an extra tool to implement our library is pointless now that async / await are part of the standard.

7.1. Blocking I/O versus Asynchronous I/O in JavaScript

JavaScript is single-threaded by design. That means, if a program is actively waiting for the result of a network-based operation such as reading from a sensor, the whole program is blocked. In browser environments, this can even completely freeze the user interface. For this reason, the use of blocking I/O in JavaScript is strongly discouraged nowadays, and blocking network APIs are getting deprecated everywhere.

Instead of using parallel threads, JavaScript relies on asynchronous I/O to handle operations with a possible long timeout: whenever a long I/O call needs to be performed, it is only triggered and but then the code execution flow is terminated. The JavaScript engine is therefore free to handle other pending tasks, such as UI. Whenever the pending I/O call is completed, the system invokes a callback function with the result of the I/O call to resume execution of the original execution flow.

When used with plain callback functions, as pervasive in Node.js libraries, asynchronous I/O tend to produce code with poor readability, as the execution flow is broken into many disconnected callback functions. Fortunately, new methods have emerged recently to improve that situation. In particular, the use of Promise objects to abstract and work with asynchronous tasks helps a lot. Any function that makes a long I/O operation can return a Promise, which can be used by the caller to chain subsequent operations in the same flow. Promises are part of EcmaScript 2015 standard.

Promise objects are good, but what makes them even better is the new async / await keywords to handle asynchronous I/O:

Long story made short, async and await make it possible to write EcmaScript code with all benefits of asynchronous I/O, but without breaking the code flow. It is almost like multi-threaded execution, except that control switch between pending tasks only happens at places where the await keyword appears.

We have therefore chosen to write our new EcmaScript library using Promises and async functions, so that you can use the friendly await syntax. To keep it easy to remember, all public methods of the EcmaScript library are async, i.e. return a Promise object, except:

7.2. Using Yoctopuce library for JavaScript / EcmaScript 2017

JavaScript is one of those languages which do not generally allow you to directly access the hardware layers of your computer. Therefore the library can only be used to access network-enabled devices (connected through a YoctoHub), or USB devices accessible through Yoctopuce TCP/IP to USB gateway, named VirtualHub.

Go to the Yoctopuce web site and download the following items:

Extract the library files in a folder of your choice, you will find many of examples in it. Connect your modules and start the VirtualHub software. You do not need to install any driver.

Using the official Yoctopuce library for node.js

Start by installing the latest Node.js version (v7.6 or later) on your system. It is very easy. You can download it from the official web site: http://nodejs.org. Make sure to install it fully, including npm, and add it to the system path.

To give it a try, go into one of the example directory (for instance example_nodejs/Doc-Inventory). You will see that it include an application description file (package.json) and a source file (demo.js). To download and setup the libraries needed by this example, just run:


npm install

Once done, you can start the example file using:


node demo.js

Using a local copy of the Yoctopuce library with node.js

If for some reason you need to make changes to the Yoctopuce library, you can easily configure your project to use the local copy in the lib/ subdirectory rather than the official npm package. In order to do so, simply type the following command in your project directory:


npm link ../../lib

Using the Yoctopuce library within a browser (HTML)

For HTML examples, it is even simpler: there is nothing to install. Each example is a single HTML file that you can open in a browser to try it. In this context, loading the Yoctopuce library is no different from any standard HTML script include tag.

Using the Yoctoluce library on older JavaScript engines

If you need to run this library on older JavaScript engines, you can use Babel19 to transpile your code and the library into older JavaScript standards. To install Babel with typical settings, simply use:


npm instal -g babel-cli
npm instal babel-preset-env

You would typically ask Babel to put the transpiled files in another directory, named compat for instance. Your files and all files of the Yoctopuce library should be transpiled, as follow:


babel --presets env demo.js --out-dir compat/
babel --presets env ../../lib --out-dir compat/

Although this approach is based on node.js toolchain, it actually works as well for transpiling JavaScript files for use in a browser. The only thing that you cannot do so easily is transpiling JavaScript code embedded directly in an HTML page. You have to use an external script file for using EcmaScript 2017 syntax with Babel.

Babel has many smart features, such as a watch mode that will automatically refresh transpiled files whenever the source file is changed, but this is beyond the scope of this note. You will find more in Babel documentation.

Backward-compatibility with the old JavaScript library

This new library is not fully backward-compatible with the old JavaScript library, because there is no way to transparently map the old blocking API to the new asynchronous API. The method names however are the same, and old synchronous code can easily be made asynchronous just by adding the proper await keywords before the method calls. For instance, simply replace:


beaconState = module.get_beacon();

by


beaconState = await module.get_beacon();

Apart from a few exceptions, most XXX_async redundant methods have been removed as well, as they would have introduced confusion on the proper way of handling asynchronous behaviors. It is however very simple to get an async method to invoke a callback upon completion, using the returned Promise object. For instance, you can replace:


module.get_beacon_async(callback, myContext);

by


module.get_beacon().then(function(res) { callback(myContext, module, res); });

In some cases, it might be desirable to get a sensor value using a method identical to the old synchronous methods (without using Promises), even if it returns a slightly outdated cached value since I/O is not possible. For this purpose, the EcmaScript library introduce new classes called synchronous proxies. A synchronous proxy is an object that mirrors the most recent state of the connected class, but can be read using regular synchronous function calls. For instance, instead of writing:


async function logInfo(module)
{
    console.log('Name: '+await module.get_logicalName());
    console.log('Beacon: '+await module.get_beacon());
}

...
logInfo(myModule);
...

you can use:


function logInfoProxy(moduleSyncProxy)
{
    console.log('Name: '+moduleProxy.get_logicalName());
    console.log('Beacon: '+moduleProxy.get_beacon());
}

logInfoSync(await myModule.get_syncProxy());

You can also rewrite this last asynchronous call as:


myModule.get_syncProxy().then(logInfoProxy);

7.3. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a JavaScript code snipplet to use the Pressure function.


// For Node.js, we use function require()
// For HTML, we would use <script src="...">
require('yoctolib-es2017/yocto_api.js');
require('yoctolib-es2017/yocto_pressure.js');

// Get access to your device, through the VirtualHub running locally
await YAPI.RegisterHub('127.0.0.1');
var pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");

// Check that the module is online to handle hot-plug
if(await pressure.isOnline())
{
    // Use pressure.get_currentValue()
    [...]
}

Let us look at these lines in more details.

yocto_api and yocto_pressure import

These two import provide access to functions allowing you to manage Yoctopuce modules. yocto_api is always needed, yocto_pressure is necessary to manage modules containing a pressure sensor, such as Yocto-Pressure. Other imports can be useful in other cases, such as YModule which can let you enumerate any type of Yoctopuce device.

YAPI.RegisterHub

The RegisterHub method allows you to indicate on which machine the Yoctopuce modules are located, more precisely on which machine the VirtualHub software is running. In our case, the 127.0.0.1:4444 address indicates the local machine, port 4444 (the standard port used by Yoctopuce). You can very well modify this address, and enter the address of another machine on which the VirtualHub software is running, or of a YoctoHub. If the host cannot be reached, this function will trigger an exception.

YPressure.FindPressure

The FindPressure method allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can also use logical names, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure")
pressure = YPressure.FindPressure("PRESSMK1-123456.MaFonction")
pressure = YPressure.FindPressure("MonModule.pressure")
pressure = YPressure.FindPressure("MonModule.MaFonction")
pressure = YPressure.FindPressure("MaFonction")

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example, for Node.js

Open a command window (a terminal, a shell...) and go into the directory example_nodejs/Doc-GettingStarted-Yocto-Pressure within Yoctopuce library for JavaScript / EcmaScript 2017. In there, you will find a file named demo.js with the sample code below, which uses the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

If your Yocto-Pressure is not connected on the host running the browser, replace in the example the address 127.0.0.1 by the IP address of the host on which the Yocto-Pressure is connected and where you run the VirtualHub.

"use strict";

require('yoctolib-es2017/yocto_api.js');
require('yoctolib-es2017/yocto_pressure.js');

let press;

async function startDemo()
{
    await YAPI.LogUnhandledPromiseRejections();
    await YAPI.DisableExceptions();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }

    // Select specified device, or use first available one
    let serial = process.argv[process.argv.length-1];
    if(serial[8] != '-') {
        // by default use any connected module suitable for the demo
        let anysensor = YPressure.FirstPressure();
        if(anysensor) {
            let module = await anysensor.module();
            serial = await module.get_serialNumber();
        } else {
            console.log('No matching sensor connected, check cable !');
            return;
        }
    }
    console.log('Using device '+serial);
    press = YPressure.FindPressure(serial+".pressure");

    refresh();
}

async function refresh()
{
    if (await press.isOnline()) {
        console.log('Pressure : '+(await press.get_currentValue()) + (await press.get_unit()));
    } else {
        console.log('Module not connected');
    }
    setTimeout(refresh, 500);
}

startDemo();
 

As explained at the beginning of this chapter, you need to have Node.js v7.6 or later installed to try this example. When done, you can type the following two commands to automatically download and install the dependencies for building this example:


npm install
You can the start the sample code within Node.js using the following command, replacing the [...] by the arguments that you want to pass to the demo code:

node demo.js [...]

Same example, but this time running in a browser

If you want to see how to use the library within a browser rather than with Node.js, switch to the directory example_html/Doc-GettingStarted-Yocto-Pressure. You will find there a single HTML file, with a JavaScript section similar to the code above, but with a few changes since it has to interact through an HTML page rather than through the JavaScript console.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Hello World</title>
  <script src="../../lib/yocto_api.js"></script>
  <script src="../../lib/yocto_pressure.js"></script>
  <script>
    async function startDemo()
    {
      await YAPI.LogUnhandledPromiseRejections();
      await YAPI.DisableExceptions();

      // Setup the API to use the VirtualHub on local machine
      let errmsg = new YErrorMsg();
      if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        alert('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
      }
      refresh();
    }

    async function refresh()
    {
      let serial = document.getElementById('serial').value;
      if(serial == '') {
        // by default use any connected module suitable for the demo
        let anysensor = YPressure.FirstPressure();
        if(anysensor) {
          let module = await anysensor.module();
          serial = await module.get_serialNumber();
          document.getElementById('serial').value = serial;
        }
      }
      let press = YPressure.FindPressure(serial+".pressure");

      if (await press.isOnline()) {
        document.getElementById('msg').value = '';
        document.getElementById("press").value = (await press.get_currentValue()) + (await press.get_unit());
      } else {
        document.getElementById('msg').value = 'Module not connected';
      }
      setTimeout(refresh, 500);
    }

    startDemo();
  </script>
</head>
<body>
Module to use: <input id='serial'>
<input id='msg' style='color:red;border:none;' readonly><br>
pressure : <input id='press' readonly><br>
</body>
</html>
 

No installation is needed to run this example, all you have to do is open the HTML file using a web browser,

7.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo(args)
{
    await YAPI.LogUnhandledPromiseRejections();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }

    // Select the relay to use
    let module = YModule.FindModule(args[0]);
    if(await module.isOnline()) {
        if(args.length > 1) {
            if(args[1] == 'ON') {
                await module.set_beacon(YModule.BEACON_ON);
            } else {
                await module.set_beacon(YModule.BEACON_OFF);
            }
        }
        console.log('serial:       '+await module.get_serialNumber());
        console.log('logical name: '+await module.get_logicalName());
        console.log('luminosity:   '+await module.get_luminosity()+'%');
        console.log('beacon:       '+(await module.get_beacon()==YModule.BEACON_ON?'ON':'OFF'));
        console.log('upTime:       '+parseInt(await module.get_upTime()/1000)+' sec');
        console.log('USB current:  '+await module.get_usbCurrent()+' mA');
        console.log('logs:');
        console.log(await module.get_lastLogs());
    } else {
        console.log("Module not connected (check identification and USB cable)\n");
    }
    await YAPI.FreeAPI();
}

if(process.argv.length < 2) {
    console.log("usage: node demo.js <serial or logicalname> [ ON | OFF ]");
} else {
    startDemo(process.argv.slice(2));
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo(args)
{
    await YAPI.LogUnhandledPromiseRejections();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }
   
    // Select the relay to use
    let module = YModule.FindModule(args[0]);
    if(await module.isOnline()) {
        if(args.length > 1) {
            let newname = args[1];
            if (!await YAPI.CheckLogicalName(newname)) {
                console.log("Invalid name (" + newname + ")");
                process.exit(1);
            }
            await module.set_logicalName(newname);
            await module.saveToFlash();
        }
        console.log('Current name: '+await module.get_logicalName());
    } else {
        console.log("Module not connected (check identification and USB cable)\n");
    }
    await YAPI.FreeAPI();
}

if(process.argv.length < 2) {
    console.log("usage: node demo.js <serial> [newLogicalName]");
} else {
    startDemo(process.argv.slice(2));
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.FirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo()
{
    await YAPI.LogUnhandledPromiseRejections();
    await YAPI.DisableExceptions();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if (await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1');
        return;
    }
    refresh();
}

async function refresh()
{
    try {
        let errmsg = new YErrorMsg();
        await YAPI.UpdateDeviceList(errmsg);

        let module = YModule.FirstModule();
        while(module) {
            let line = await module.get_serialNumber();
            line += '(' + (await module.get_productName()) + ')';
            console.log(line);
            module = module.nextModule();
        }
        setTimeout(refresh, 500);
    } catch(e) {
        console.log(e);
    }
}

try {
    startDemo();
} catch(e) {
    console.log(e);
}
 

7.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

8. Using Yocto-Pressure with PHP

PHP is, like Javascript, an atypical language when interfacing with hardware is at stakes. Nevertheless, using PHP with Yoctopuce modules provides you with the opportunity to very easily create web sites which are able to interact with their physical environment, and this is not available to every web server. This technique has a direct application in home automation: a few Yoctopuce modules, a PHP server, and you can interact with your home from anywhere on the planet, as long as you have an internet connection.

PHP is one of those languages which do not allow you to directly access the hardware layers of your computer. Therefore you need to run a virtual hub on the machine on which your modules are connected.

To start your tests with PHP, you need a PHP 5.3 (or more) server20, preferably locally on you machine. If you wish to use the PHP server of your internet provider, it is possible, but you will probably need to configure your ADSL router for it to accept and forward TCP request on the 4444 port.

8.1. Getting ready

Go to the Yoctopuce web site and download the following items:

Decompress the library files in a folder of your choice accessible to your web server, connect your modules, run the VirtualHub software, and you are ready to start your first tests. You do not need to install any driver.

8.2. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a PHP code snipplet to use the Pressure function.


include('yocto_api.php');
include('yocto_pressure.php');

// Get access to your device, through the VirtualHub running locally
yRegisterHub('http://127.0.0.1:4444/',$errmsg);
$pressure = yFindPressure("PRESSMK1-123456.pressure");

// Check that the module is online to handle hot-plug
if(pressure->isOnline())
{
    // Use pressure->get_currentValue(), ...
}

Let's look at these lines in more details.

yocto_api.php and yocto_pressure.php

These two PHP includes provides access to the functions allowing you to manage Yoctopuce modules. yocto_api.php must always be included, yocto_pressure.php is necessary to manage modules containing a pressure sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function allows you to indicate on which machine the Yoctopuce modules are located, more precisely on which machine the VirtualHub software is running. In our case, the 127.0.0.1:4444 address indicates the local machine, port 4444 (the standard port used by Yoctopuce). You can very well modify this address, and enter the address of another machine on which the VirtualHub software is running.

yFindPressure

The yFindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


$pressure = yFindPressure("PRESSMK1-123456.pressure");
$pressure = yFindPressure("PRESSMK1-123456.MyFunction");
$pressure = yFindPressure("MyModule.pressure");
$pressure = yFindPressure("MyModule.MyFunction");
$pressure = yFindPressure("MyFunction");

yFindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by yFindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Open your preferred text editor23, copy the code sample below, save it with the Yoctopuce library files in a location which is accessible to you web server, then use your preferred web browser to access this page. The code is also provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

<HTML>
<HEAD>
 <TITLE>Hello World</TITLE>
</HEAD>
<BODY>
<?php
  include('yocto_api.php');
  include('yocto_pressure.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1");
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $press = yFindPressure("$serial.pressure");
      if (!$press->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $press = yFirstPressure();
      if(is_null($press)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $press->module()->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  $pvalue = $press->get_currentValue();
  Print("Pressure: $pvalue mbar<br>");
  yFreeAPI();

  // trigger auto-refresh after one second
  Print("<script language='javascript1.5' type='text/JavaScript'>\n");
  Print("setTimeout('window.location.reload()',1000);");
  Print("</script>\n");
?>
</BODY>
</HTML>
 

8.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

<HTML>
<HEAD>
 <TITLE>Module Control</TITLE>
</HEAD>
<BODY>
<FORM method='get'>
<?php
  include('yocto_api.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1 : ".$errmsg);
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $module = yFindModule("$serial");
      if (!$module->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $module = yFirstModule();
      if($module) { // skip VirtualHub
          $module = $module->nextModule();
      }
      if(is_null($module)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $module->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  if (isset($_GET['beacon'])) {
      if ($_GET['beacon']=='ON')
          $module->set_beacon(Y_BEACON_ON);
      else
          $module->set_beacon(Y_BEACON_OFF);
  }
  printf('serial: %s<br>',$module->get_serialNumber());
  printf('logical name: %s<br>',$module->get_logicalName());
  printf('luminosity: %s<br>',$module->get_luminosity());
  print('beacon: ');
  if($module->get_beacon() == Y_BEACON_ON) {
      printf("<input type='radio' name='beacon' value='ON' checked>ON ");
      printf("<input type='radio' name='beacon' value='OFF'>OFF<br>");
  } else {
      printf("<input type='radio' name='beacon' value='ON'>ON ");
      printf("<input type='radio' name='beacon' value='OFF' checked>OFF<br>");
  }
  printf('upTime: %s sec<br>',intVal($module->get_upTime()/1000));
  printf('USB current: %smA<br>',$module->get_usbCurrent());
  printf('logs:<br><pre>%s</pre>',$module->get_lastLogs());
  yFreeAPI();
?>
<input type='submit' value='refresh'>
</FORM>
</BODY>
</HTML>
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

<HTML>
<HEAD>
 <TITLE>save settings</TITLE>
<BODY>
<FORM method='get'>
<?php
  include('yocto_api.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1");
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $module = yFindModule("$serial");
      if (!$module->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $module = yFirstModule();
      if($module) { // skip VirtualHub
          $module = $module->nextModule();
      }
      if(is_null($module)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $module->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  if (isset($_GET['newname'])){
      $newname = $_GET['newname'];
      if (!yCheckLogicalName($newname))
          die('Invalid name');
      $module->set_logicalName($newname);
      $module->saveToFlash();
  }
  printf("Current name: %s<br>", $module->get_logicalName());
  print("New name: <input name='newname' value='' maxlength=19><br>");
  yFreeAPI();
?>
<input type='submit'>
</FORM>
</BODY>
</HTML>
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

<HTML>
<HEAD>
 <TITLE>inventory</TITLE>
</HEAD>
<BODY>
<H1>Device list</H1>
<TT>
<?php
    include('yocto_api.php');
    yRegisterHub("http://127.0.0.1:4444/");
    $module   = yFirstModule();
    while (!is_null($module)) {
        printf("%s (%s)<br>", $module->get_serialNumber(),
               $module->get_productName());
        $module=$module->nextModule();
    }
    yFreeAPI();
?>
</TT>
</BODY>
</HTML>
 

8.4. HTTP callback API and NAT filters

The PHP library is able to work in a specific mode called HTTP callback Yocto-API. With this mode, you can control Yoctopuce devices installed behind a NAT filter, such as a DSL router for example, and this without needing to open a port. The typical application is to control Yoctopuce devices, located on a private network, from a public web site.

The NAT filter: advantages and disadvantages

A DSL router which translates network addresses (NAT) works somewhat like a private phone switchboard (a PBX): internal extensions can call each other and call the outside; but seen from the outside, there is only one official phone number, that of the switchboard itself. You cannot reach the internal extensions from the outside.


Typical DSL configuration: LAN machines are isolated from the outside by the DSL router

Transposed to the network, we have the following: appliances connected to your home automation network can communicate with one another using a local IP address (of the 192.168.xxx.yyy type), and contact Internet servers through their public address. However, seen from the outside, you have only one official IP address, assigned to the DSL router only, and you cannot reach your network appliances directly from the outside. It is rather restrictive, but it is a relatively efficient protection against intrusions.


Responses from request from LAN machines are routed.


But requests from the outside are blocked.

Seeing Internet without being seen provides an enormous security advantage. However, this signifies that you cannot, a priori, set up your own web server at home to control a home automation installation from the outside. A solution to this problem, advised by numerous home automation system dealers, consists in providing outside visibility to your home automation server itself, by adding a routing rule in the NAT configuration of the DSL router. The issue of this solution is that it exposes the home automation server to external attacks.

The HTTP callback API solves this issue without having to modify the DSL router configuration. The module control script is located on an external site, and it is the VirtualHub which is in charge of calling it a regular intervals.


The HTTP callback API uses the VirtualHub which initiates the requests.

Configuration

The callback API thus uses the VirtualHub as a gateway. All the communications are initiated by the VirtualHub. They are thus outgoing communications and therefore perfectly authorized by the DSL router.

You must configure the VirtualHub so that it calls the PHP script on a regular basis. To do so:

  1. Launch a VirtualHub
  2. Access its interface, usually 127.0.0.1:4444
  3. Click on the configure button of the line corresponding to the VirtualHub itself
  4. Click on the edit button of the Outgoing callbacks section


Click on the "configure" button on the first line


Click on the "edit" button of the "Outgoing callbacks" section


And select "Yocto-API callback".

You then only need to define the URL of the PHP script and, if need be, the user name and password to access this URL. Supported authentication methods are basic and digest. The second method is safer than the first one because it does not allow transfer of the password on the network.

Usage

From the programmer standpoint, the only difference is at the level of the yRegisterHub function call. Instead of using an IP address, you must use the callback string (or http://callback which is equivalent).


include("yocto_api.php");
yRegisterHub("callback");

The remainder of the code stays strictly identical. On the VirtualHub interface, at the bottom of the configuration window for the HTTP callback API , there is a button allowing you to test the call to the PHP script.

Be aware that the PHP script controlling the modules remotely through the HTTP callback API can be called only by the VirtualHub. Indeed, it requires the information posted by the VirtualHub to function. To code a web site which controls Yoctopuce modules interactively, you must create a user interface which stores in a file or in a database the actions to be performed on the Yoctopuce modules. These actions are then read and run by the control script.

Common issues

For the HTTP callback API to work, the PHP option allow_url_fopen must be set. Some web site hosts do not set it by default. The problem then manifests itself with the following error:

error: URL file-access is disabled in the server configuration

To set this option, you must create, in the repertory where the control PHP script is located, an .htaccess file containing the following line:
php_flag "allow_url_fopen" "On"
Depending on the security policies of the host, it is sometimes impossible to authorize this option at the root of the web site, or even to install PHP scripts receiving data from a POST HTTP. In this case, place the PHP script in a subdirectory.

Limitations

This method that allows you to go through NAT filters cheaply has nevertheless a price. Communications being initiated by the VirtualHub at a more or less regular interval, reaction time to an event is clearly longer than if the Yoctopuce modules were driven directly. You can configure the reaction time in the specific window of the VirtualHub, but it is at least of a few seconds in the best case.

The HTTP callback Yocto-API mode is currently available in PHP, EcmaScript (Node.JS) and Java only.

8.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

9. Using Yocto-Pressure with C++

C++ is not the simplest language to master. However, if you take care to limit yourself to its essential functionalities, this language can very well be used for short programs quickly coded, and it has the advantage of being easily ported from one operating system to another. Under Windows, all the examples and the project models are tested with Microsoft Visual Studio 2010 Express, freely available on the Microsoft web site24. Under Mac OS X, all the examples and project models are tested with XCode 4, available on the App Store. Moreover, under Max OS X and under Linux, you can compile the examples using a command line with GCC using the provided GNUmakefile. In the same manner under Windows, a Makefile allows you to compile examples using a command line, fully knowing the compilation and linking arguments.

Yoctopuce C++ libraries25 are integrally provided as source files. A section of the low-level library is written in pure C, but you should not need to interact directly with it: everything was done to ensure the simplest possible interaction from C++. The library is naturally also available as binary files, so that you can link it directly if you prefer.

You will soon notice that the C++ API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface. You will find in the last section of this chapter all the information needed to create a wholly new project linked with the Yoctopuce libraries.

9.1. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C++ code snipplet to use the Pressure function.


#include "yocto_api.h"
#include "yocto_pressure.h"

[...]
String  errmsg;
YPressure *pressure;

// Get access to your device, connected locally on USB for instance
yRegisterHub("usb", errmsg);
pressure = yFindPressure("PRESSMK1-123456.pressure");

// Hot-plug is easy: just check that the device is online
if(pressure->isOnline())
{
    // Use pressure->get_currentValue(), ...
}

Let's look at these lines in more details.

yocto_api.h et yocto_pressure.h

These two include files provide access to the functions allowing you to manage Yoctopuce modules. yocto_api.h must always be used, yocto_pressure.h is necessary to manage modules containing a pressure sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindPressure

The yFindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


YPressure *pressure = yFindPressure("PRESSMK1-123456.pressure");
YPressure *pressure = yFindPressure("PRESSMK1-123456.MyFunction");
YPressure *pressure = yFindPressure("MyModule.pressure");
YPressure *pressure = yFindPressure("MyModule.MyFunction");
YPressure *pressure = yFindPressure("MyFunction");

yFindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by yFindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Launch your C++ environment and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library. If you prefer to work with your favorite text editor, open the file main.cpp, and type make to build the example when you are done.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

#include "yocto_api.h"
#include "yocto_pressure.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

static void usage(void)
{
  cout << "usage: demo <serial_number> " << endl;
  cout << "       demo <logical_name>" << endl;
  cout << "       demo any" << endl;
  u64 now = yGetTickCount();
  while (yGetTickCount() - now < 3000) {
    // wait 3 sec to show the message
  }
  exit(1);
}

int main(int argc, const char * argv[])
{
  string errmsg, target;
  YPressure *psensor;

  if (argc < 2) {
    usage();
  }
  target = (string) argv[1];

  // Setup the API to use local USB devices
  if (yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if (target == "any") {
    psensor = yFirstPressure();
    if (psensor == NULL) {
      cout << "No module connected (check USB cable)" << endl;
      return 1;
    }
  } else {
    psensor = yFindPressure(target + ".pressure");
  }

  while (1) {
    if (!psensor->isOnline()) {
      cout << "Module not connected (check identification and USB cable)";
      break;
    }
    cout << "Current pressure: " << psensor->get_currentValue() << " mbar" << endl;
    cout << "  (press Ctrl-C to exit)" << endl;
    ySleep(1000, errmsg);
  };
  yFreeAPI();

  return 0;
}
 

9.2. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#include <iostream>
#include <stdlib.h>

#include "yocto_api.h"

using namespace std;

static void usage(const char *exe)
{
  cout << "usage: " << exe << " <serial or logical name> [ON/OFF]" << endl;
  exit(1);
}


int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if(argc < 2)
    usage(argv[0]);

  YModule *module = yFindModule(argv[1]);  // use serial or logical name

  if (module->isOnline()) {
    if (argc > 2) {
      if (string(argv[2]) == "ON")
        module->set_beacon(Y_BEACON_ON);
      else
        module->set_beacon(Y_BEACON_OFF);
    }
    cout << "serial:       " << module->get_serialNumber() << endl;
    cout << "logical name: " << module->get_logicalName() << endl;
    cout << "luminosity:   " << module->get_luminosity() << endl;
    cout << "beacon:       ";
    if (module->get_beacon() == Y_BEACON_ON)
      cout << "ON" << endl;
    else
      cout << "OFF" << endl;
    cout << "upTime:       " << module->get_upTime() / 1000 << " sec" << endl;
    cout << "USB current:  " << module->get_usbCurrent() << " mA" << endl;
    cout << "Logs:" << endl << module->get_lastLogs() << endl;
  } else {
    cout << argv[1] << " not connected (check identification and USB cable)"
         << endl;
  }
  yFreeAPI();
  return 0;
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

#include <iostream>
#include <stdlib.h>

#include "yocto_api.h"

using namespace std;

static void usage(const char *exe)
{
  cerr << "usage: " << exe << " <serial> <newLogicalName>" << endl;
  exit(1);
}

int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if(argc < 2)
    usage(argv[0]);

  YModule *module = yFindModule(argv[1]);  // use serial or logical name

  if (module->isOnline()) {
    if (argc >= 3) {
      string newname =  argv[2];
      if (!yCheckLogicalName(newname)) {
        cerr << "Invalid name (" << newname << ")" << endl;
        usage(argv[0]);
      }
      module->set_logicalName(newname);
      module->saveToFlash();
    }
    cout << "Current name: " << module->get_logicalName() << endl;
  } else {
    cout << argv[1] << " not connected (check identification and USB cable)"
         << endl;
  }
  yFreeAPI();
  return 0;
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

#include <iostream>

#include "yocto_api.h"

using namespace std;

int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(YAPI::RegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  cout << "Device list: " << endl;

  YModule *module = YModule::FirstModule();
  while (module != NULL) {
    cout << module->get_serialNumber() << " ";
    cout << module->get_productName()  << endl;
    module = module->nextModule();
  }
  yFreeAPI();
  return 0;
}
 

9.3. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

9.4. Integration variants for the C++ Yoctopuce library

Depending on your needs and on your preferences, you can integrate the library into your projects in several distinct manners. This section explains how to implement the different options.

Integration in source format

Integrating all the sources of the library into your projects has several advantages:

To integrate the source code, the easiest way is to simply include the Sources directory of your Yoctopuce library into your IncludePath, and to add all the files of this directory (including the sub-directory yapi) to your project.

For your project to build correctly, you need to link with your project the prerequisite system libraries, that is:

Integration as a static library

Integration of the Yoctopuce library as a static library is a simpler manner to build a small executable which uses Yoctopuce modules. You can quickly compile the program with a single command. You do not need to install a dynamic library specific to Yoctopuce, everything is in the executable.

To integrate the static Yoctopuce library to your project, you must include the Sources directory of the Yoctopuce library into your IncludePath, and add the sub-directory Binaries/... corresponding to your operating system into your libPath.

Then, for you project to build correctly, you need to link with your project the Yoctopuce library and the prerequisite system libraries:

Note, under Linux, if you wish to compile in command line with GCC, it is generally advisable to link system libraries as dynamic libraries, rather than as static ones. To mix static and dynamic libraries on the same command line, you must pass the following arguments:

gcc (...) -Wl,-Bstatic -lyocto-static -Wl,-Bdynamic -lm -lpthread -lusb-1.0 -lstdc++

Integration as a dynamic library

Integration of the Yoctopuce library as a dynamic library allows you to produce an executable smaller than with the two previous methods, and to possibly update this library, if a patch reveals itself necessary, without needing to recompile the source code of the application. On the other hand, it is an integration mode which systematically requires you to copy the dynamic library on the target machine where the application will run (yocto.dll for Windows, libyocto.so.1.0.1 for Mac OS X and Linux).

To integrate the dynamic Yoctopuce library to your project, you must include the Sources directory of the Yoctopuce library into your IncludePath, and add the sub-directory Binaries/... corresponding to your operating system into your LibPath.

Then, for you project to build correctly, you need to link with your project the dynamic Yoctopuce library and the prerequisite system libraries:

With GCC, the command line to compile is simply:

gcc (...) -lyocto -lm -lpthread -lusb-1.0 -lstdc++

10. Using Yocto-Pressure with Objective-C

Objective-C is language of choice for programming on Mac OS X, due to its integration with the Cocoa framework. In order to use the Objective-C library, you need XCode version 4.2 (earlier versions will not work), available freely when you run Lion. If you are still under Snow Leopard, you need to be registered as Apple developer to be able to download XCode 4.2. The Yoctopuce library is ARC compatible. You can therefore implement your projects either using the traditional retain / release method, or using the Automatic Reference Counting.

Yoctopuce Objective-C libraries26 are integrally provided as source files. A section of the low-level library is written in pure C, but you should not need to interact directly with it: everything was done to ensure the simplest possible interaction from Objective-C.

You will soon notice that the Objective-C API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface. You can find on Yoctopuce blog a detailed example27 with video shots showing how to integrate the library into your projects.

10.1. Control of the Pressure function

Launch Xcode 4.2 and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

#import <Foundation/Foundation.h>
#import "yocto_api.h"
#import "yocto_pressure.h"

static void usage(void)
{
  NSLog(@"usage: demo <serial_number> ");
  NSLog(@"       demo <logical_name>");
  NSLog(@"       demo any                 (use any discovered device)");
  exit(1);
}

int main(int argc, const char * argv[])
{
  NSError *error;

  if (argc < 2) {
    usage();
  }

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb": &error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }
    NSString     *target = [NSString stringWithUTF8String:argv[1]];
    YPressure *psensor;
    if ([target isEqualToString:@"any"]) {
      psensor = [YPressure FirstPressure];
      if (psensor == NULL) {
        NSLog(@"No module connected (check USB cable)");
        return 1;
      }
    } else {
      psensor = [YPressure FindPressure:[target stringByAppendingString:@".pressure"]];
    }

    while(1) {
      if(![psensor isOnline]) {
        NSLog(@"Module not connected (check identification and USB cable)\n");
        break;
      }

      NSLog(@"Current pressure: %f C\n", [psensor get_currentValue]);
      NSLog(@"  (press Ctrl-C to exit)\n");
      [YAPI Sleep:1000:NULL];
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

There are only a few really important lines in this example. We will look at them in details.

yocto_api.h et yocto_pressure.h

These two import files provide access to the functions allowing you to manage Yoctopuce modules. yocto_api.h must always be used, yocto_pressure.h is necessary to manage modules containing a pressure sensor, such as Yocto-Pressure.

[YAPI RegisterHub]

The [YAPI RegisterHub] function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter @"usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

[Pressure FindPressure]

The [Pressure FindPressure] function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


YPressure *pressure = [Pressure FindPressure:@"PRESSMK1-123456.pressure"];
YPressure *pressure = [Pressure FindPressure:@"PRESSMK1-123456.MyFunction"];
YPressure *pressure = [Pressure FindPressure:@"MyModule.pressure"];
YPressure *pressure = [Pressure FindPressure:@"MyModule.MyFunction"];
YPressure *pressure = [Pressure FindPressure:@"MyFunction"];

[Pressure FindPressure] returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline method of the object returned by [Pressure FindPressure] allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

10.2. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

static void usage(const char *exe)
{
  NSLog(@"usage: %s <serial or logical name> [ON/OFF]\n", exe);
  exit(1);
}


int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb": &error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }
    if(argc < 2)
      usage(argv[0]);
    NSString *serial_or_name = [NSString stringWithUTF8String:argv[1]];
    // use serial or logical name
    YModule *module = [YModule FindModule:serial_or_name];
    if ([module isOnline]) {
      if (argc > 2) {
        if (strcmp(argv[2], "ON") == 0)
          [module setBeacon:Y_BEACON_ON];
        else
          [module setBeacon:Y_BEACON_OFF];
      }
      NSLog(@"serial:       %@\n", [module serialNumber]);
      NSLog(@"logical name: %@\n", [module logicalName]);
      NSLog(@"luminosity:   %d\n", [module luminosity]);
      NSLog(@"beacon:       ");
      if ([module beacon] == Y_BEACON_ON)
        NSLog(@"ON\n");
      else
        NSLog(@"OFF\n");
      NSLog(@"upTime:       %ld sec\n", [module upTime] / 1000);
      NSLog(@"USB current:  %d mA\n",  [module usbCurrent]);
      NSLog(@"logs:  %@\n",  [module get_lastLogs]);
    } else {
      NSLog(@"%@ not connected (check identification and USB cable)\n",
            serial_or_name);
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx, and properties which are not read-only can be modified with the help of the set_xxx: method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx: function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash method. The short example below allows you to modify the logical name of a module.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

static void usage(const char *exe)
{
  NSLog(@"usage: %s <serial> <newLogicalName>\n", exe);
  exit(1);
}


int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb" :&error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }

    if(argc < 2)
      usage(argv[0]);

    NSString *serial_or_name = [NSString stringWithUTF8String:argv[1]];
    // use serial or logical name
    YModule *module = [YModule FindModule:serial_or_name];

    if (module.isOnline) {
      if (argc >= 3) {
        NSString *newname =  [NSString stringWithUTF8String:argv[2]];
        if (![YAPI CheckLogicalName:newname]) {
          NSLog(@"Invalid name (%@)\n", newname);
          usage(argv[0]);
        }
        module.logicalName = newname;
        [module saveToFlash];
      }
      NSLog(@"Current name: %@\n", module.logicalName);
    } else {
      NSLog(@"%@ not connected (check identification and USB cable)\n",
            serial_or_name);
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb" :&error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@\n", [error localizedDescription]);
      return 1;
    }

    NSLog(@"Device list:\n");

    YModule *module = [YModule FirstModule];
    while (module != nil) {
      NSLog(@"%@ %@", module.serialNumber, module.productName);
      module = [module nextModule];
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

10.3. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

11. Using Yocto-Pressure with Visual Basic .NET

VisualBasic has long been the most favored entrance path to the Microsoft world. Therefore, we had to provide our library for this language, even if the new trend is shifting to C#. All the examples and the project models are tested with Microsoft VisualBasic 2010 Express, freely available on the Microsoft web site28.

11.1. Installation

Download the Visual Basic Yoctopuce library from the Yoctopuce web site29. There is no setup program, simply copy the content of the zip file into the directory of your choice. You mostly need the content of the Sources directory. The other directories contain the documentation and a few sample programs. All sample projects are Visual Basic 2010, projects, if you are using a previous version, you may have to recreate the projects structure from scratch.

11.2. Using the Yoctopuce API in a Visual Basic project

The Visual Basic.NET Yoctopuce library is composed of a DLL and of source files in Visual Basic. The DLL is not a .NET DLL, but a classic DLL, written in C, which manages the low level communications with the modules30. The source files in Visual Basic manage the high level part of the API. Therefore, your need both this DLL and the .vb files of the sources directory to create a project managing Yoctopuce modules.

Configuring a Visual Basic project

The following indications are provided for Visual Studio Express 2010, but the process is similar for other versions. Start by creating your project. Then, on the Solution Explorer panel, right click on your project, and select "Add" and then "Add an existing item".

A file selection window opens. Select the yocto_api.vb file and the files corresponding to the functions of the Yoctopuce modules that your project is going to manage. If in doubt, select all the files.

You then have the choice between simply adding these files to your project, or to add them as links (the Add button is in fact a scroll-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply keeps a link on the original files. We recommend you to use links, which makes updates of the library much easier.

Then add in the same manner the yapi.dll DLL, located in the Sources/dll directory31. Then, from the Solution Explorer window, right click on the DLL, select Properties and in the Properties panel, set the Copy to output folder to always. You are now ready to use your Yoctopuce modules from Visual Studio.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

11.3. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Visual Basic code snipplet to use the Pressure function.


[...]
Dim errmsg As String errmsg
Dim pressure As YPressure
 
REM Get access to your device, connected locally on USB for instance
yRegisterHub("usb", errmsg)
pressure = yFindPressure("PRESSMK1-123456.pressure")

REM Hot-plug is easy: just check that the device is online
If (pressure.isOnline()) Then
   REM Use pressure.get_currentValue(), ...
End If

Let's look at these lines in more details.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindPressure

The yFindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = yFindPressure("PRESSMK1-123456.pressure")
pressure = yFindPressure("PRESSMK1-123456.MyFunction")
pressure = yFindPressure("MyModule.pressure")
pressure = yFindPressure("MyModule.MyFunction")
pressure = yFindPressure("MyFunction")

yFindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by yFindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Launch Microsoft VisualBasic and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

Module Module1

  Private Sub Usage()
    Dim execname = System.AppDomain.CurrentDomain.FriendlyName
    Console.WriteLine("Usage:")
    Console.WriteLine(execname + " <serial_number>")
    Console.WriteLine(execname + " <logical_name>")
    Console.WriteLine(execname + " any  ")
    System.Threading.Thread.Sleep(2500)

    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim target As String

    Dim psensor As YPressure

    If argv.Length < 2 Then Usage()

    target = argv(1)

    REM Setup the API to use local USB devices
    If (yRegisterHub("usb", errmsg) <> YAPI_SUCCESS) Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    If target = "any" Then
      psensor = yFirstPressure()

      If psensor Is Nothing Then
        Console.WriteLine("No module connected (check USB cable) ")
        End
      End If
    Else
      psensor = yFindPressure(target + ".pressure")
    End If

    While (True)
      If Not (psensor.isOnline()) Then
        Console.WriteLine("Module not connected (check identification and USB cable)")
        End
      End If
      Console.WriteLine("Current pressure: " + Str(psensor.get_currentValue()) _
                        + " mbar")
      Console.WriteLine("  (press Ctrl-C to exit)")
      ySleep(1000, errmsg)
    End While
    yFreeAPI()
  End Sub

End Module
 

11.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.


Imports System.IO
Imports System.Environment

Module Module1

  Sub usage()
    Console.WriteLine("usage: demo <serial or logical name> [ON/OFF]")
    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim m As ymodule

    If (yRegisterHub("usb", errmsg) <> YAPI_SUCCESS) Then
      Console.WriteLine("RegisterHub error:" + errmsg)
      End
    End If

    If argv.Length < 2 Then usage()

    m = yFindModule(argv(1)) REM use serial or logical name
    If (m.isOnline()) Then
      If argv.Length > 2 Then
        If argv(2) = "ON" Then m.set_beacon(Y_BEACON_ON)
        If argv(2) = "OFF" Then m.set_beacon(Y_BEACON_OFF)
      End If
      Console.WriteLine("serial:       " + m.get_serialNumber())
      Console.WriteLine("logical name: " + m.get_logicalName())
      Console.WriteLine("luminosity:   " + Str(m.get_luminosity()))
      Console.Write("beacon:       ")
      If (m.get_beacon() = Y_BEACON_ON) Then
        Console.WriteLine("ON")
      Else
        Console.WriteLine("OFF")
      End If
      Console.WriteLine("upTime:       " + Str(m.get_upTime() / 1000) + " sec")
      Console.WriteLine("USB current:  " + Str(m.get_usbCurrent()) + " mA")
      Console.WriteLine("Logs:")
      Console.WriteLine(m.get_lastLogs())
    Else
      Console.WriteLine(argv(1) + " not connected (check identification and USB cable)")
    End If
    yFreeAPI()
  End Sub

End Module
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

Module Module1


  Sub usage()

    Console.WriteLine("usage: demo <serial or logical name> <new logical name>")
    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim newname As String
    Dim m As YModule

    If (argv.Length <> 3) Then usage()

    REM Setup the API to use local USB devices
    If yRegisterHub("usb", errmsg) <> YAPI_SUCCESS Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    m = yFindModule(argv(1)) REM use serial or logical name
    If m.isOnline() Then
      newname = argv(2)
      If (Not yCheckLogicalName(newname)) Then
        Console.WriteLine("Invalid name (" + newname + ")")
        End
      End If
      m.set_logicalName(newname)
      m.saveToFlash() REM do not forget this
      Console.Write("Module: serial= " + m.get_serialNumber)
      Console.Write(" / name= " + m.get_logicalName())
    Else
      Console.Write("not connected (check identification and USB cable")
    End If
    yFreeAPI()

  End Sub

End Module
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not Nothing. Below a short example listing the connected modules.

Module Module1

  Sub Main()
    Dim M As ymodule
    Dim errmsg As String = ""

    REM Setup the API to use local USB devices
    If yRegisterHub("usb", errmsg) <> YAPI_SUCCESS Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    Console.WriteLine("Device list")
    M = yFirstModule()
    While M IsNot Nothing
      Console.WriteLine(M.get_serialNumber() + " (" + M.get_productName() + ")")
      M = M.nextModule()
    End While
    yFreeAPI()
  End Sub

End Module
 

11.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

12. Using Yocto-Pressure with C#

C# (pronounced C-Sharp) is an object-oriented programming language promoted by Microsoft, it is somewhat similar to Java. Like Visual-Basic and Delphi, it allows you to create Windows applications quite easily. All the examples and the project models are tested with Microsoft C# 2010 Express, freely available on the Microsoft web site32.

Our programming library is also compatible with Mono, the open source version of C# that also works on Linux and MacOS. You will find on our web site various articles that describe how to configure Mono to use our library.

12.1. Installation

Download the Visual C# Yoctopuce library from the Yoctopuce web site33. There is no setup program, simply copy the content of the zip file into the directory of your choice. You mostly need the content of the Sources directory. The other directories contain the documentation and a few sample programs. All sample projects are Visual C# 2010, projects, if you are using a previous version, you may have to recreate the projects structure from scratch.

12.2. Using the Yoctopuce API in a Visual C# project

The Visual C#.NET Yoctopuce library is composed of a DLL and of source files in Visual C#. The DLL is not a .NET DLL, but a classic DLL, written in C, which manages the low level communications with the modules34. The source files in Visual C# manage the high level part of the API. Therefore, your need both this DLL and the .cs files of the sources directory to create a project managing Yoctopuce modules.

Configuring a Visual C# project

The following indications are provided for Visual Studio Express 2010, but the process is similar for other versions. Start by creating your project. Then, on the Solution Explorer panel, right click on your project, and select "Add" and then "Add an existing item".

A file selection window opens. Select the yocto_api.cs file and the files corresponding to the functions of the Yoctopuce modules that your project is going to manage. If in doubt, select all the files.

You then have the choice between simply adding these files to your project, or to add them as links (the Add button is in fact a scroll-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply keeps a link on the original files. We recommend you to use links, which makes updates of the library much easier.

Then add in the same manner the yapi.dll DLL, located in the Sources/dll directory35. Then, from the Solution Explorer window, right click on the DLL, select Properties and in the Properties panel, set the Copy to output folder to always. You are now ready to use your Yoctopuce modules from Visual Studio.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

12.3. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C# code snipplet to use the Pressure function.


[...]
string errmsg ="";
YPressure pressure;
 
// Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("usb", errmsg);
pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");

// Hot-plug is easy: just check that the device is online
if (pressure.isOnline())
 {  // Use pressure.get_currentValue(); ...
 }

Let's look at these lines in more details.

YAPI.RegisterHub

The YAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI.SUCCESS and errmsg contains the error message.

YPressure.FindPressure

The YPressure.FindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");
pressure = YPressure.FindPressure("PRESSMK1-123456.MyFunction");
pressure = YPressure.FindPressure("MyModule.pressure");
pressure = YPressure.FindPressure("MyModule.MyFunction");
pressure = YPressure.FindPressure("MyFunction");

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by YPressure.FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch Microsoft Visual C# and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine(execname + " <serial_number>");
      Console.WriteLine(execname + " <logical_name>");
      Console.WriteLine(execname + " any  ");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      string errmsg = "";
      string target;

      YPressure psensor;

      if (args.Length < 1) usage();
      target = args[0].ToUpper();

      // Setup the API to use local USB devices
      if (YAPI.RegisterHub("usb", ref errmsg) != YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      if (target == "ANY") {
        psensor = YPressure.FirstPressure();

        if (psensor == null) {
          Console.WriteLine("No module connected (check USB cable) ");
          Environment.Exit(0);
        }
      } else {
        psensor = YPressure.FindPressure(target + ".pressure");
      }

      if (!psensor.isOnline()) {
        Console.WriteLine("Module not connected");
        Console.WriteLine("check identification and USB cable");
        Environment.Exit(0);
      }

      while (psensor.isOnline()) {
        Console.WriteLine("Current pressure: " + psensor.get_currentValue().ToString()
                          + " mbar");
        Console.WriteLine("  (press Ctrl-C to exit)");

        YAPI.Sleep(1000, ref errmsg);
      }
      YAPI.FreeAPI();
    }
  }
}

12.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine(execname + " <serial or logical name> [ON/OFF]");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }


      if (args.Length < 1)  usage();

      m = YModule.FindModule(args[0]); // use serial or logical name

      if (m.isOnline()) {
        if (args.Length >= 2) {
          if (args[1].ToUpper() == "ON") {
            m.set_beacon(YModule.BEACON_ON);
          }
          if (args[1].ToUpper() == "OFF") {
            m.set_beacon(YModule.BEACON_OFF);
          }
        }

        Console.WriteLine("serial:       " + m.get_serialNumber());
        Console.WriteLine("logical name: " + m.get_logicalName());
        Console.WriteLine("luminosity:   " + m.get_luminosity().ToString());
        Console.Write("beacon:       ");
        if (m.get_beacon() == YModule.BEACON_ON)
          Console.WriteLine("ON");
        else
          Console.WriteLine("OFF");
        Console.WriteLine("upTime:       " + (m.get_upTime() / 1000 ).ToString() + " sec");
        Console.WriteLine("USB current:  " + m.get_usbCurrent().ToString() + " mA");
        Console.WriteLine("Logs:\r\n" + m.get_lastLogs());

      } else {
        Console.WriteLine(args[0] + " not connected (check identification and USB cable)");
      }
      YAPI.FreeAPI();
    }
  }
}
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine("usage: demo <serial or logical name> <new logical name>");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";
      string newname;

      if (args.Length != 2) usage();

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      m = YModule.FindModule(args[0]); // use serial or logical name

      if (m.isOnline()) {
        newname = args[1];
        if (!YAPI.CheckLogicalName(newname)) {
          Console.WriteLine("Invalid name (" + newname + ")");
          Environment.Exit(0);
        }

        m.set_logicalName(newname);
        m.saveToFlash(); // do not forget this

        Console.Write("Module: serial= " + m.get_serialNumber());
        Console.WriteLine(" / name= " + m.get_logicalName());
      } else {
        Console.Write("not connected (check identification and USB cable");
      }
      YAPI.FreeAPI();
    }
  }
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      Console.WriteLine("Device list");
      m = YModule.FirstModule();
      while (m != null) {
        Console.WriteLine(m.get_serialNumber() + " (" + m.get_productName() + ")");
        m = m.nextModule();
      }
      YAPI.FreeAPI();
    }
  }
}
 

12.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

13. Using the Yocto-Pressure with Universal Windows Platform

Universal Windows Platform (UWP) is not a language per say, but a software platform created by Microsoft. This platform allows you to run a new type of applications: the universal Windows applications. These applications can work on all machines running under Windows 10. This includes computers, tablets, smart phones, XBox One, and also Windows IoT Core.

The Yoctopuce UWP library allows you to use Yoctopuce modules in a universal Windows application and is written in C# in its entirety. You can add it to a Visual Studio 201736 project.

13.1. Blocking and asynchronous functions

The Universal Windows Platform does not use the Win32 API but only the Windows Runtime API which is available on all the versions of Windows 10 and for any architecture. Thanks to this library, you can use UWP on all the Windows 10 versions, including Windows 10 IoT Core.

However, using the new UWP API has some consequences: the Windows Runtime API to access the USB ports is asynchronous, and therefore the Yoctopuce library must be asynchronous as well. Concretely, the asynchronous methods do not return a result directly but a Task or Task<> object and the result can be obtained later. Fortunately, the C# language, version 6, supports the async and await keywords, which simplifies using these functions enormously. You can thus use asynchronous functions in the same way as traditional functions as long as you respect the following two rules:

Example:

async Task<int> MyFunction(int  val)
{
    // do some long computation
    ...

    return result;
}

int res = await MyFunction(1234);
Our library follows these two rules and can therefore use the await notation.

For you not to have to wonder wether a function is asynchronous or not, there is the following convention: all the public methods of the UWP library are asynchronous, that is that you must call them with the await keyword, except:

13.2. Installation

Download the Yoctopuce library for Universal Windows Platform from the Yoctopuce web site37. There is no installation software, simply copy the content of the zip file in a directory of your choice. You essentially need the content of the Sources directory. The other directories contain documentation and a few sample programs. Sample projects are Visual Studio 2017 projects. Visual Studio 2017 is available on the Microsoft web site38.

13.3. Using the Yoctopuce API in a Visual Studio project

Start by creating your project. Then, from the Solution Explorer panel right click on your project and select Add then Existing element .

A file chooser opens: select all the files in the library Sources directory.

You then have the choice between simply adding the files to your project or adding them as a link (the Add button is actually a drop-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply creates a link to the original files. We recommend to use links, as a potential library update is thus much easier.

The Package.appxmanifest file

By default a Universal Windows application doesn't have access rights to the USB ports. If you want to access USB devices, you must imperatively declare it in the Package.appxmanifest file.

Unfortunately, the edition window of this file doesn't allow this operation and you must modify the Package.appxmanifest file by hand. In the "Solution Explorer" panel, right click on the Package.appxmanifest and select "View Code".

In this XML file, we must add a DeviceCapability node in the Capabilities node. This node must have a "Name" attribute with a "humaninterfacedevice" value.

Inside this node, you must declare all the modules that can be used. Concretely, for each module, you must add a "Device" node with an "Id" attribute, which has for value a character string "vidpid:USB_VENDORID USB_DEVICE_ID". The Yoctopuce USB_VENDORID is 24e0 and you can find the USB_DEVICE_ID of each Yoctopuce device in the documentation in the "Characteristics" section. Finally, the "Device" node must contain a "Function" node with the "Type" attribute with a value of "usage:ff00 0001".

For the Yocto-Pressure, here is what you must add in the "Capabilities" node:


  <DeviceCapability Name="humaninterfacedevice">
      <!-- Yocto-Pressure -->
      <Device Id="vidpid:24e0 0075">
        <Function Type="usage:ff00 0001" />
      </Device>
    </DeviceCapability>

Unfortunately, it's not possible to write a rule authorizing all Yoctopuce modules. Therefore, you must imperatively add each module that you want to use.

13.4. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C# code snippet to use the Pressure function.


[...]

await YAPI.RegisterHub("usb");
pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");

//To manage hot-plug, we check that the module is here
if (await pressure.isOnline()) {
        //Use pressure.get_currentValue()
     ...
}

[...]

Let us look at these lines in more details.

YAPI.RegisterHub

The YAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. The parameter is the address of the virtual hub able to see the devices. If the string "usb" is passed as parameter, the API works with modules locally connected to the machine. If the initialization does not succeed, an exception is thrown.

YPressure.FindPressure

The YPressure.FindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");
pressure = YPressure.FindPressure("PRESSMK1-123456.MaFonction");
pressure = YPressure.FindPressure("MonModule.pressure");
pressure = YPressure.FindPressure("MonModule.MaFonction");
pressure = YPressure.FindPressure("MaFonction");

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by YPressure.FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

13.5. A real example

Launch Visual Studio and open the corresponding project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

Visual Studio projects contain numerous files, and most of them are not linked to the use of the Yoctopuce library. To simplify reading the code, we regrouped all the code that uses the library in the Demo class, located in the demo.cs file. Properties of this class correspond to the different fields displayed on the screen, and the Run() method contains the code which is run when the "Start" button is pushed.

In this example, you can recognize the functions explained above, but this time used with all the side materials needed to make it work nicely as a small demo.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {
    public string HubURL { get; set; }
    public string Target { get; set; }

    public override async Task<int> Run()
    {
      try {
        await YAPI.RegisterHub(HubURL);

        YPressure psensor;

        if (Target.ToLower() == "any") {
          psensor = YPressure.FirstPressure();

          if (psensor == null) {
            WriteLine("No module connected (check USB cable) ");
            return -1;
          }
        } else {
          psensor = YPressure.FindPressure(Target + ".pressure");
        }

        while (await psensor.isOnline()) {
          WriteLine("Pressure: " + await psensor.get_currentValue() + " mbar");
          await YAPI.Sleep(1000);
        }

        WriteLine("Module not connected (check identification and USB cable)");
      } catch (YAPI_Exception ex) {
        WriteLine("error: " + ex.Message);
      }

      YAPI.FreeAPI();
      return 0;
    }
  }
}

13.6. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {

    public string HubURL { get; set; }
    public string Target { get; set; }
    public bool Beacon { get; set; }

    public override async Task<int> Run()
    {
      YModule m;
      string errmsg = "";

      if (await YAPI.RegisterHub(HubURL) != YAPI.SUCCESS) {
        WriteLine("RegisterHub error: " + errmsg);
        return -1;
      }
      m = YModule.FindModule(Target + ".module"); // use serial or logical name
      if (await m.isOnline()) {
        if (Beacon) {
          await m.set_beacon(YModule.BEACON_ON);
        } else {
          await m.set_beacon(YModule.BEACON_OFF);
        }

        WriteLine("serial: " + await m.get_serialNumber());
        WriteLine("logical name: " + await m.get_logicalName());
        WriteLine("luminosity: " + await m.get_luminosity());
        Write("beacon: ");
        if (await m.get_beacon() == YModule.BEACON_ON)
          WriteLine("ON");
        else
          WriteLine("OFF");
        WriteLine("upTime: " + (await m.get_upTime() / 1000) + " sec");
        WriteLine("USB current: " + await m.get_usbCurrent() + " mA");
        WriteLine("Logs:\r\n" + await m.get_lastLogs());
      } else {
        WriteLine(Target + " not connected  on" + HubURL +
                  "(check identification and USB cable)");
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {

    public string HubURL { get; set; }
    public string Target { get; set; }
    public string LogicalName { get; set; }

    public override async Task<int> Run()
    {
      try {
        YModule m;

        await YAPI.RegisterHub(HubURL);

        m = YModule.FindModule(Target); // use serial or logical name
        if (await m.isOnline()) {
          if (!YAPI.CheckLogicalName(LogicalName)) {
            WriteLine("Invalid name (" + LogicalName + ")");
            return -1;
          }

          await m.set_logicalName(LogicalName);
          await m.saveToFlash(); // do not forget this
          Write("Module: serial= " + await m.get_serialNumber());
          WriteLine(" / name= " + await m.get_logicalName());
        } else {
          Write("not connected (check identification and USB cable");
        }
      } catch (YAPI_Exception ex) {
        WriteLine("RegisterHub error: " + ex.Message);
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {
    public string HubURL { get; set; }

    public override async Task<int> Run()
    {
      YModule m;
      try {
        await YAPI.RegisterHub(HubURL);

        WriteLine("Device list");
        m = YModule.FirstModule();
        while (m != null) {
          WriteLine(await m.get_serialNumber()
                    + " (" + await m.get_productName() + ")");
          m = m.nextModule();
        }
      } catch (YAPI_Exception ex) {
        WriteLine("Error:" + ex.Message);
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

13.7. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software.

In the Universal Windows Platform library, error handling is implemented with exceptions. You must therefore intercept and correctly handle these exceptions if you want to have a reliable project which does not crash as soon as you disconnect a module.

Library thrown exceptions are always of the YAPI_Exception type, so you can easily separate them from other exceptions in a try{...} catch{...} block.

Example:


try {
        ....
} catch (YAPI_Exception ex) {
        Debug.WriteLine("Exception from Yoctopuce lib:" + ex.Message);
} catch (Exception ex) {
        Debug.WriteLine("Other exceptions :" + ex.Message);
}

14. Using Yocto-Pressure with Delphi

Delphi is a descendent of Turbo-Pascal. Originally, Delphi was produced by Borland, Embarcadero now edits it. The strength of this language resides in its ease of use, as anyone with some notions of the Pascal language can develop a Windows application in next to no time. Its only disadvantage is to cost something39.

Delphi libraries are provided not as VCL components, but directly as source files. These files are compatible with most Delphi versions. 40

To keep them simple, all the examples provided in this documentation are console applications. Obviously, the libraries work in a strictly identical way with VCL applications.

You will soon notice that the Delphi API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

14.1. Preparation

Go to the Yoctopuce web site and download the Yoctopuce Delphi libraries41. Uncompress everything in a directory of your choice, add the subdirectory sources in the list of directories of Delphi libraries.42

By default, the Yoctopuce Delphi library uses the yapi.dll DLL, all the applications you will create with Delphi must have access to this DLL. The simplest way to ensure this is to make sure yapi.dll is located in the same directory as the executable file of your application.

14.2. Control of the Pressure function

Launch your Delphi environment, copy the yapi.dll DLL in a directory, create a new console application in the same directory, and copy-paste the piece of code below:

program helloworld;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Windows,
  yocto_api,
  yocto_pressure;

Procedure  Usage();
  var
    exe : string;
  begin
    exe:= ExtractFileName(paramstr(0));
    WriteLn(exe+' <serial_number>');
    WriteLn(exe+' <logical_name>');
    WriteLn(exe+' any');
    halt;
  End;

var
  sensor : TYTemperature;
  errmsg : string;
  done   : boolean;

begin

  if (paramcount<1) then usage();

  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  if paramstr(1)='any' then
    begin
      // try to find  the first pressure sensor available
      sensor := yFirstPressure();
      if sensor=nil then
         begin
           writeln('No module connected (check USB cable)');
           halt;
         end
       end
   else  // or use the one specified on the commande line
    sensor:= yFindPressure(paramstr(1)+'.pressure');

  // let's poll
  done := false;
  repeat
    if (sensor.isOnline()) then
     begin
       Write('Current pressure: '+FloatToStr(sensor.get_currentValue())+' mbar');
       Writeln('   (press Ctrl-C to exit)');
       Sleep(1000);
     end
    else
     begin
       Writeln('Module not connected (check identification and USB cable)');
       done := true;
     end;
  until done;
  yFreeAPI();
end.

There are only a few really important lines in this sample example. We will look at them in details.

yocto_api and yocto_pressure

These two units provide access to the functions allowing you to manage Yoctopuce modules. yocto_api must always be used, yocto_pressure is necessary to manage modules containing a pressure sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and specifies where the modules should be looked for. When used with the parameter 'usb', it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindPressure

The yFindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can also use logical names, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure := yFindPressure("PRESSMK1-123456.pressure");
pressure := yFindPressure("PRESSMK1-123456.MyFunction");
pressure := yFindPressure("MyModule.pressure");
pressure := yFindPressure("MyModule.MyFunction");
pressure := yFindPressure("MyFunction");

yFindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by yFindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

14.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

program modulecontrol;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

const
  serial = 'PRESSMK1-123456'; // use serial number or logical name

procedure refresh(module:Tymodule) ;
  begin
    if (module.isOnline())  then
     begin
       Writeln('');
       Writeln('Serial       : ' + module.get_serialNumber());
       Writeln('Logical name : ' + module.get_logicalName());
       Writeln('Luminosity   : ' + intToStr(module.get_luminosity()));
       Write('Beacon    :');
       if  (module.get_beacon()=Y_BEACON_ON) then Writeln('on')
                                             else Writeln('off');
       Writeln('uptime       : ' + intToStr(module.get_upTime() div 1000)+'s');
       Writeln('USB current  : ' + intToStr(module.get_usbCurrent())+'mA');
       Writeln('Logs         : ');
       Writeln(module.get_lastlogs());
       Writeln('');
       Writeln('r : refresh / b:beacon ON / space : beacon off');
     end
    else Writeln('Module not connected (check identification and USB cable)');
  end;


procedure beacon(module:Tymodule;state:integer);
  begin
    module.set_beacon(state);
    refresh(module);
  end;

var
  module : TYModule;
  c      : char;
  errmsg : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  module := yFindModule(serial);
  refresh(module);

  repeat
    read(c);
    case c of
     'r': refresh(module);
     'b': beacon(module,Y_BEACON_ON);
     ' ': beacon(module,Y_BEACON_OFF);
    end;
  until  c = 'x';
  yFreeAPI();
end.

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

program savesettings;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

const
  serial = 'PRESSMK1-123456'; // use serial number or logical name

var
  module  : TYModule;
  errmsg  : string;
  newname : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  module := yFindModule(serial);
  if (not(module.isOnline)) then
   begin
     writeln('Module not connected (check identification and USB cable)');
     exit;
   end;

  Writeln('Current logical name : '+module.get_logicalName());
  Write('Enter new name : ');
  Readln(newname);
  if (not(yCheckLogicalName(newname))) then
   begin
     Writeln('invalid logical name');
     exit;
   end;
  module.set_logicalName(newname);
  module.saveToFlash();
  yFreeAPI();
  Writeln('logical name is now : '+module.get_logicalName());
end.
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not nil. Below a short example listing the connected modules.

program inventory;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

var
  module : TYModule;
  errmsg : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  Writeln('Device list');

  module := yFirstModule();
  while module<>nil  do
   begin
     Writeln( module.get_serialNumber()+' ('+module.get_productName()+')');
     module := module.nextModule();
   end;
  yFreeAPI();

end.

14.4. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

15. Using the Yocto-Pressure with Python

Python is an interpreted object oriented language developed by Guido van Rossum. Among its advantages is the fact that it is free, and the fact that it is available for most platforms, Windows as well as UNIX. It is an ideal language to write small scripts on a napkin. The Yoctopuce library is compatible with Python 2.6+ and 3+. It works under Windows, Mac OS X, and Linux, Intel as well as ARM. The library was tested with Python 2.6 and Python 3.2. Python interpreters are available on the Python web site43.

15.1. Source files

The Yoctopuce library classes44 for Python that you will use are provided as source files. Copy all the content of the Sources directory in the directory of your choice and add this directory to the PYTHONPATH environment variable. If you use an IDE to program in Python, refer to its documentation to configure it so that it automatically finds the API source files.

15.2. Dynamic library

A section of the low-level library is written in C, but you should not need to interact directly with it: it is provided as a DLL under Windows, as a .so files under UNIX, and as a .dylib file under Mac OS X. Everything was done to ensure the simplest possible interaction from Python: the distinct versions of the dynamic library corresponding to the distinct operating systems and architectures are stored in the cdll directory. The API automatically loads the correct file during its initialization. You should not have to worry about it.

If you ever need to recompile the dynamic library, its complete source code is located in the Yoctopuce C++ library.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

15.3. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Python code snipplet to use the Pressure function.


[...]

errmsg=YRefParam()
#Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("usb",errmsg)
pressure = YPressure.FindPressure("PRESSMK1-123456.pressure")

# Hot-plug is easy: just check that the device is online
if pressure.isOnline():
    #Use pressure.get_currentValue()
    ...
   
[...]    

Let's look at these lines in more details.

YAPI.RegisterHub

The yAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI.SUCCESS and errmsg contains the error message.

YPressure.FindPressure

The YPressure.FindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure")
pressure = YPressure.FindPressure("PRESSMK1-123456.MyFunction")
pressure = YPressure.FindPressure("MyModule.pressure")
pressure = YPressure.FindPressure("MyModule.MyFunction")
pressure = YPressure.FindPressure("MyFunction")

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by YPressure.FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch Python and open the corresponding sample script provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *
from yocto_pressure import *


def usage():
    scriptname = os.path.basename(sys.argv[0])
    print("Usage:")
    print(scriptname + ' <serial_number>')
    print(scriptname + ' <logical_name>')
    print(scriptname + ' any  ')
    sys.exit()


def die(msg):
    sys.exit(msg + ' (check USB cable)')


errmsg = YRefParam()

if len(sys.argv) < 2:
    usage()

target = sys.argv[1]

# Setup the API to use local USB devices
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("init error" + errmsg.value)

if target == 'any':
    # retreive any pressure sensor
    sensor = YPressure.FirstPressure()
    if sensor is None:
        die('No module connected')
else:
    sensor = YPressure.FindPressure(target + '.pressure')

if not (sensor.isOnline()):
    die('device not connected')

while sensor.isOnline():
    print("Pressure :  " + "%2.1f" % sensor.get_currentValue() + "mbar (Ctrl-C to stop)")
    YAPI.Sleep(1000)
YAPI.FreeAPI()
 

15.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *


def usage():
    sys.exit("usage: demo <serial or logical name> [ON/OFF]")


errmsg = YRefParam()
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("RegisterHub error: " + str(errmsg))

if len(sys.argv) < 2:
    usage()

m = YModule.FindModule(sys.argv[1])  # # use serial or logical name

if m.isOnline():
    if len(sys.argv) > 2:
        if sys.argv[2].upper() == "ON":
            m.set_beacon(YModule.BEACON_ON)
        if sys.argv[2].upper() == "OFF":
            m.set_beacon(YModule.BEACON_OFF)

    print("serial:       " + m.get_serialNumber())
    print("logical name: " + m.get_logicalName())
    print("luminosity:   " + str(m.get_luminosity()))
    if m.get_beacon() == YModule.BEACON_ON:
        print("beacon:       ON")
    else:
        print("beacon:       OFF")
    print("upTime:       " + str(m.get_upTime() / 1000) + " sec")
    print("USB current:  " + str(m.get_usbCurrent()) + " mA")
    print("logs:\n" + m.get_lastLogs())
else:
    print(sys.argv[1] + " not connected (check identification and USB cable)")
YAPI.FreeAPI()
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *


def usage():
    sys.exit("usage: demo <serial or logical name> <new logical name>")


if len(sys.argv) != 3:
    usage()

errmsg = YRefParam()
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("RegisterHub error: " + str(errmsg))

m = YModule.FindModule(sys.argv[1])  # use serial or logical name
if m.isOnline():
    newname = sys.argv[2]
    if not YAPI.CheckLogicalName(newname):
        sys.exit("Invalid name (" + newname + ")")
    m.set_logicalName(newname)
    m.saveToFlash()  # do not forget this
    print("Module: serial= " + m.get_serialNumber() + " / name= " + m.get_logicalName())
else:
    sys.exit("not connected (check identification and USB cable")
YAPI.FreeAPI()

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys


from yocto_api import *

errmsg = YRefParam()

# Setup the API to use local USB devices
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("init error" + str(errmsg))

print('Device list')

module = YModule.FirstModule()
while module is not None:
    print(module.get_serialNumber() + ' (' + module.get_productName() + ')')
    module = module.nextModule()
YAPI.FreeAPI()

15.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

16. Using the Yocto-Pressure with Java

Java is an object oriented language created by Sun Microsystem. Beside being free, its main strength is its portability. Unfortunately, this portability has an excruciating price. In Java, hardware abstraction is so high that it is almost impossible to work directly with the hardware. Therefore, the Yoctopuce API does not support native mode in regular Java. The Java API needs a Virtual Hub to communicate with Yoctopuce devices.

16.1. Getting ready

Go to the Yoctopuce web site and download the following items:

The library is available as source files as well as a jar file. Decompress the library files in a folder of your choice, connect your modules, run the VirtualHub software, and you are ready to start your first tests. You do not need to install any driver.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

16.2. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Java code snippet to use the Pressure function.


[...]

// Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("127.0.0.1");
pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");

// Hot-plug is easy: just check that the device is online
if (pressure.isOnline())
{    
    // Use pressure.get_currentValue()
    [...]
}

[...]

Let us look at these lines in more details.

YAPI.RegisterHub

The yAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. The parameter is the address of the Virtual Hub able to see the devices. If the initialization does not succeed, an exception is thrown.

YPressure.FindPressure

The YPressure.FindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure")
pressure = YPressure.FindPressure("PRESSMK1-123456.MyFunction")
pressure = YPressure.FindPressure("MyModule.pressure")
pressure = YPressure.FindPressure("MyModule.MyFunction")
pressure = YPressure.FindPressure("MyFunction")

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by YPressure.FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch you Java environment and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all the side materials needed to make it work nicely as a small demo.

import com.yoctopuce.YoctoAPI.*;

public class Demo {

    public static void main(String[] args)   {
        try {
            // setup the API to use local VirtualHub
            YAPI.RegisterHub("127.0.0.1");
        } catch (YAPI_Exception ex) {
            System.out.println("Cannot contact VirtualHub on 127.0.0.1 (" + ex.getLocalizedMessage() + ")");
            System.out.println("Ensure that the VirtualHub application is running");
            System.exit(1);
        }
        YPressure psensor;

        if (args.length == 0) {
            psensor = YPressure.FirstPressure();
            if (psensor == null) {
                System.out.println("No module connected (check USB cable)");
                System.exit(1);
            }
        } else {
            psensor = YPressure.FindPressure(args[0] + ".pressure");
        }

        while (true) {
            try {
                System.out.println("Current pressure: " + psensor.get_currentValue() + " mbar");
                System.out.println("  (press Ctrl-C to exit)");
                YAPI.Sleep(1000);
            } catch (YAPI_Exception ex) {
                System.out.println("Module not connected (check identification and USB cable)");
                break;
            }
        }

        YAPI.FreeAPI();
    }
}
 

16.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.


import com.yoctopuce.YoctoAPI.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Demo {

    public static void main(String[] args)
    {
        try {
            // setup the API to use local VirtualHub
            YAPI.RegisterHub("127.0.0.1");
        } catch (YAPI_Exception ex) {
            System.out.println("Cannot contact VirtualHub on 127.0.0.1 (" + ex.getLocalizedMessage() + ")");
            System.out.println("Ensure that the VirtualHub application is running");
            System.exit(1);
        }
        System.out.println("usage: demo [serial or logical name] [ON/OFF]");

        YModule module;
        if (args.length == 0) {
            module = YModule.FirstModule();
            if (module == null) {
                System.out.println("No module connected (check USB cable)");
                System.exit(1);
            }
        } else {
            module = YModule.FindModule(args[0]);  // use serial or logical name
        }

        try {
            if (args.length > 1) {
                if (args[1].equalsIgnoreCase("ON")) {
                    module.setBeacon(YModule.BEACON_ON);
                } else {
                    module.setBeacon(YModule.BEACON_OFF);
                }
            }
            System.out.println("serial:       " + module.get_serialNumber());
            System.out.println("logical name: " + module.get_logicalName());
            System.out.println("luminosity:   " + module.get_luminosity());
            if (module.get_beacon() == YModule.BEACON_ON) {
                System.out.println("beacon:       ON");
            } else {
                System.out.println("beacon:       OFF");
            }
            System.out.println("upTime:       " + module.get_upTime() / 1000 + " sec");
            System.out.println("USB current:  " + module.get_usbCurrent() + " mA");
            System.out.println("logs:\n" + module.get_lastLogs());
        } catch (YAPI_Exception ex) {
            System.out.println(args[1] + " not connected (check identification and USB cable)");
        }
        YAPI.FreeAPI();
    }
}
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

import com.yoctopuce.YoctoAPI.*;

public class Demo {

    public static void main(String[] args)
    {
        try {
            // setup the API to use local VirtualHub
            YAPI.RegisterHub("127.0.0.1");
        } catch (YAPI_Exception ex) {
            System.out.println("Cannot contact VirtualHub on 127.0.0.1 (" + ex.getLocalizedMessage() + ")");
            System.out.println("Ensure that the VirtualHub application is running");
            System.exit(1);
        }

        if (args.length != 2) {
            System.out.println("usage: demo <serial or logical name> <new logical name>");
            System.exit(1);
        }

        YModule m;
        String newname;

        m = YModule.FindModule(args[0]); // use serial or logical name

        try {
            newname = args[1];
            if (!YAPI.CheckLogicalName(newname))
                {
                    System.out.println("Invalid name (" + newname + ")");
                    System.exit(1);
                }

            m.set_logicalName(newname);
            m.saveToFlash(); // do not forget this

            System.out.println("Module: serial= " + m.get_serialNumber());
            System.out.println(" / name= " + m.get_logicalName());
        } catch (YAPI_Exception ex) {
            System.out.println("Module " + args[0] + "not connected (check identification and USB cable)");
            System.out.println(ex.getMessage());
            System.exit(1);
        }

        YAPI.FreeAPI();
    }
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

import com.yoctopuce.YoctoAPI.*;

public class Demo {

    public static void main(String[] args)
    {
        try {
            // setup the API to use local VirtualHub
            YAPI.RegisterHub("127.0.0.1");
        } catch (YAPI_Exception ex) {
            System.out.println("Cannot contact VirtualHub on 127.0.0.1 (" + ex.getLocalizedMessage() + ")");
            System.out.println("Ensure that the VirtualHub application is running");
            System.exit(1);
        }

        System.out.println("Device list");
        YModule module = YModule.FirstModule();
        while (module != null) {
            try {
                System.out.println(module.get_serialNumber() + " (" + module.get_productName() + ")");
            } catch (YAPI_Exception ex) {
                break;
            }
            module = module.nextModule();
        }
        YAPI.FreeAPI();
    }
}
 

16.4. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software.

In the Java API, error handling is implemented with exceptions. Therefore you must catch and handle correctly all exceptions that might be thrown by the API if you do not want your software to crash as soon as you unplug a device.

17. Using the Yocto-Pressure with Android

To tell the truth, Android is not a programming language, it is an operating system developed by Google for mobile appliances such as smart phones and tablets. But it so happens that under Android everything is programmed with the same programming language: Java. Nevertheless, the programming paradigms and the possibilities to access the hardware are slightly different from classical Java, and this justifies a separate chapter on Android programming.

17.1. Native access and VirtualHub

In the opposite to the classical Java API, the Java for Android API can access USB modules natively. However, as there is no VirtualHub running under Android, it is not possible to remotely control Yoctopuce modules connected to a machine under Android. Naturally, the Java for Android API remains perfectly able to connect itself to a VirtualHub running on another OS.

17.2. Getting ready

Go to the Yoctopuce web site and download the Java for Android programming library47. The library is available as source files, and also as a jar file. Connect your modules, decompress the library files in the directory of your choice, and configure your Android programming environment so that it can find them.

To keep them simple, all the examples provided in this documentation are snippets of Android applications. You must integrate them in your own Android applications to make them work. However, your can find complete applications in the examples provided with the Java for Android library.

17.3. Compatibility

In an ideal world, you would only need to have a smart phone running under Android to be able to make Yoctopuce modules work. Unfortunately, it is not quite so in the real world. A machine running under Android must fulfil to a few requirements to be able to manage Yoctopuce USB modules natively.

Android 4.x

Android 4.0 (api 14) and following are officially supported. Theoretically, support of USB host functions since Android 3.1. But be aware that the Yoctopuce Java for Android API is regularly tested only from Android 4 onwards.

USB host support

Naturally, not only must your machine have a USB port, this port must also be able to run in host mode. In host mode, the machine literally takes control of the devices which are connected to it. The USB ports of a desktop computer, for example, work in host mode. The opposite of the host mode is the device mode. USB keys, for instance, work in device mode: they must be controlled by a host. Some USB ports are able to work in both modes, they are OTG (On The Go) ports. It so happens that many mobile devices can only work in device mode: they are designed to be connected to a charger or a desktop computer, and nothing else. It is therefore highly recommended to pay careful attention to the technical specifications of a product working under Android before hoping to make Yoctopuce modules work with it.

Unfortunately, having a correct version of Android and USB ports working in host mode is not enough to guaranty that Yoctopuce modules will work well under Android. Indeed, some manufacturers configure their Android image so that devices other than keyboard and mass storage are ignored, and this configuration is hard to detect. As things currently stand, the best way to know if a given Android machine works with Yoctopuce modules consists in trying.

Supported hardware

The library is tested and validated on the following machines:

If your Android machine is not able to control Yoctopuce modules natively, you still have the possibility to remotely control modules driven by a VirtualHub on another OS, or a YoctoHub 48.

17.4. Activating the USB port under Android

By default, Android does not allow an application to access the devices connected to the USB port. To enable your application to interact with a Yoctopuce module directly connected on your tablet on a USB port, a few additional steps are required. If you intend to interact only with modules connected on another machine through the network, you can ignore this section.

In your AndroidManifest.xml, you must declare using the "USB Host" functionality by adding the <uses-feature android:name="android.hardware.usb.host" /> tag in the manifest section.


<manifest ...>
    ...
    <uses-feature android:name="android.hardware.usb.host" />;
    ...
</manifest>

When first accessing a Yoctopuce module, Android opens a window to inform the user that the application is going to access the connected module. The user can deny or authorize access to the device. If the user authorizes the access, the application can access the connected device as long as it stays connected. To enable the Yoctopuce library to correctly manage these authorizations, your must provide a pointer on the application context by calling the EnableUSBHost method of the YAPI class before the first USB access. This function takes as arguments an object of the android.content.Context class (or of a subclass). As the Activity class is a subclass of Context, it is simpler to call YAPI.EnableUSBHost(this); in the method onCreate of your application. If the object passed as parameter is not of the correct type, a YAPI_Exception exception is generated.


...
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
                // Pass the application Context to the Yoctopuce Library
        YAPI.EnableUSBHost(this);
        } catch (YAPI_Exception e) {
                Log.e("Yocto",e.getLocalizedMessage());
        }
}
...

Autorun

It is possible to register your application as a default application for a USB module. In this case, as soon as a module is connected to the system, the application is automatically launched. You must add <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/> in the section <intent-filter> of the main activity. The section <activity> must have a pointer to an XML file containing the list of USB modules which can run the application.


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <uses-feature android:name="android.hardware.usb.host" />
    ...
    <application ... >
        <activity
            android:name=".MainActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
        </activity>
    </application>

</manifest>

The XML file containing the list of modules allowed to run the application must be saved in the res/xml directory. This file contains a list of USB vendorId and deviceID in decimal. The following example runs the application as soon as a Yocto-Relay or a YoctoPowerRelay is connected. You can find the vendorID and the deviceID of Yoctopuce modules in the characteristics section of the documentation.


<?xml version="1.0" encoding="utf-8"?>

<resources>
    <usb-device vendor-id="9440" product-id="12" />
    <usb-device vendor-id="9440" product-id="13" />
</resources>

17.5. Control of the Pressure function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Java code snippet to use the Pressure function.


[...]

// Retrieving the object representing the module (connected here locally by USB)
YAPI.EnableUSBHost(this);
YAPI.RegisterHub("usb");
pressure = YPressure.FindPressure("PRESSMK1-123456.pressure");

// Hot-plug is easy: just check that the device is online
if (pressure.isOnline())
   { //Use pressure.get_currentValue()
     ...
   }

[...]

Let us look at these lines in more details.

YAPI.EnableUSBHost

The YAPI.EnableUSBHost function initializes the API with the Context of the current application. This function takes as argument an object of the android.content.Context class (or of a subclass). If you intend to connect your application only to other machines through the network, this function is facultative.

YAPI.RegisterHub

The yAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. The parameter is the address of the virtual hub able to see the devices. If the string "usb" is passed as parameter, the API works with modules locally connected to the machine. If the initialization does not succeed, an exception is thrown.

YPressure.FindPressure

The YPressure.FindPressure function allows you to find a pressure sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the pressure function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


pressure = YPressure.FindPressure("PRESSMK1-123456.pressure")
pressure = YPressure.FindPressure("PRESSMK1-123456.MyFunction")
pressure = YPressure.FindPressure("MyModule.pressure")
pressure = YPressure.FindPressure("MyModule.MyFunction")
pressure = YPressure.FindPressure("MyFunction")

YPressure.FindPressure returns an object which you can then use at will to control the pressure sensor.

isOnline

The isOnline() method of the object returned by YPressure.FindPressure allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch you Java environment and open the corresponding sample project provided in the directory Examples//Doc-Examples of the Yoctopuce library.

In this example, you can recognize the functions explained above, but this time used with all the side materials needed to make it work nicely as a small demo.

package com.yoctopuce.doc_examples;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import com.yoctopuce.YoctoAPI.YAPI;
import com.yoctopuce.YoctoAPI.YAPI_Exception;
import com.yoctopuce.YoctoAPI.YModule;
import com.yoctopuce.YoctoAPI.YPressure;

public class GettingStarted_Yocto_Temperature extends Activity implements OnItemSelectedListener
{

    private ArrayAdapter<String> aa;
    private String serial = "";
    private Handler handler = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gettingstarted_yocto_temperature);
        Spinner my_spin = (Spinner) findViewById(R.id.spinner1);
        my_spin.setOnItemSelectedListener(this);
        aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        my_spin.setAdapter(aa);
        handler = new Handler();
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        try {
            aa.clear();
            YAPI.EnableUSBHost(this);
            YAPI.RegisterHub("usb");
            YModule module = YModule.FirstModule();
            while (module != null) {
                if (module.get_productName().equals("Yocto-Pressure")) {
                    String serial = module.get_serialNumber();
                    aa.add(serial);
                }
                module = module.nextModule();
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
        aa.notifyDataSetChanged();
        handler.postDelayed(r, 500);
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        handler.removeCallbacks(r);
        YAPI.FreeAPI();
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
    {
        serial = parent.getItemAtPosition(pos).toString();
    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0)
    {
    }

    final Runnable r = new Runnable()
    {
        public void run()
        {
            if (serial != null) {
                YPressure temp_sensor = YPressure.FindPressure(serial + ".pressure");
                try {
                    TextView view = (TextView) findViewById(R.id.tempfield);
                    view.setText(String.format("%.1f %s", temp_sensor.getCurrentValue(), temp_sensor.getUnit()));
                } catch (YAPI_Exception e) {
                    e.printStackTrace();

                }
            }
            handler.postDelayed(this, 1000);
        }
    };

}
 

17.6. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

package com.yoctopuce.doc_examples;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Switch;
import android.widget.TextView;

import com.yoctopuce.YoctoAPI.YAPI;
import com.yoctopuce.YoctoAPI.YAPI_Exception;
import com.yoctopuce.YoctoAPI.YModule;

public class ModuleControl extends Activity implements OnItemSelectedListener
{

    private ArrayAdapter<String> aa;
    private YModule module = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.modulecontrol);
        Spinner my_spin = (Spinner) findViewById(R.id.spinner1);
        my_spin.setOnItemSelectedListener(this);
        aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        my_spin.setAdapter(aa);
    }

    @Override
    protected void onStart()
    {
        super.onStart();

        try {
            aa.clear();
            YAPI.EnableUSBHost(this);
            YAPI.RegisterHub("usb");
            YModule r = YModule.FirstModule();
            while (r != null) {
                String hwid = r.get_hardwareId();
                aa.add(hwid);
                r = r.nextModule();
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
        // refresh Spinner with detected relay
        aa.notifyDataSetChanged();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        YAPI.FreeAPI();
    }

    private void DisplayModuleInfo()
    {
        TextView field;
        if (module == null)
            return;
        try {
            field = (TextView) findViewById(R.id.serialfield);
            field.setText(module.getSerialNumber());
            field = (TextView) findViewById(R.id.logicalnamefield);
            field.setText(module.getLogicalName());
            field = (TextView) findViewById(R.id.luminosityfield);
            field.setText(String.format("%d%%", module.getLuminosity()));
            field = (TextView) findViewById(R.id.uptimefield);
            field.setText(module.getUpTime() / 1000 + " sec");
            field = (TextView) findViewById(R.id.usbcurrentfield);
            field.setText(module.getUsbCurrent() + " mA");
            Switch sw = (Switch) findViewById(R.id.beaconswitch);
            sw.setChecked(module.getBeacon() == YModule.BEACON_ON);
            field = (TextView) findViewById(R.id.logs);
            field.setText(module.get_lastLogs());

        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
    {
        String hwid = parent.getItemAtPosition(pos).toString();
        module = YModule.FindModule(hwid);
        DisplayModuleInfo();
    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0)
    {
    }

    public void refreshInfo(View view)
    {
        DisplayModuleInfo();
    }

    public void toggleBeacon(View view)
    {
        if (module == null)
            return;
        boolean on = ((Switch) view).isChecked();

        try {
            if (on) {
                module.setBeacon(YModule.BEACON_ON);
            } else {
                module.setBeacon(YModule.BEACON_OFF);
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
    }
}
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

package com.yoctopuce.doc_examples;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.yoctopuce.YoctoAPI.YAPI;
import com.yoctopuce.YoctoAPI.YAPI_Exception;
import com.yoctopuce.YoctoAPI.YModule;

public class SaveSettings extends Activity implements OnItemSelectedListener
{

    private ArrayAdapter<String> aa;
    private YModule module = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.savesettings);
        Spinner my_spin = (Spinner) findViewById(R.id.spinner1);
        my_spin.setOnItemSelectedListener(this);
        aa = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        my_spin.setAdapter(aa);
    }

    @Override
    protected void onStart()
    {
        super.onStart();

        try {
            aa.clear();
            YAPI.EnableUSBHost(this);
            YAPI.RegisterHub("usb");
            YModule r = YModule.FirstModule();
            while (r != null) {
                String hwid = r.get_hardwareId();
                aa.add(hwid);
                r = r.nextModule();
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
        // refresh Spinner with detected relay
        aa.notifyDataSetChanged();
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        YAPI.FreeAPI();
    }

    private void DisplayModuleInfo()
    {
        TextView field;
        if (module == null)
            return;
        try {
            YAPI.UpdateDeviceList();// fixme
            field = (TextView) findViewById(R.id.logicalnamefield);
            field.setText(module.getLogicalName());
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
    {
        String hwid = parent.getItemAtPosition(pos).toString();
        module = YModule.FindModule(hwid);
        DisplayModuleInfo();
    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0)
    {
    }

    public void saveName(View view)
    {
        if (module == null)
            return;

        EditText edit = (EditText) findViewById(R.id.newname);
        String newname = edit.getText().toString();
        try {
            if (!YAPI.CheckLogicalName(newname)) {
                Toast.makeText(getApplicationContext(), "Invalid name (" + newname + ")", Toast.LENGTH_LONG).show();
                return;
            }
            module.set_logicalName(newname);
            module.saveToFlash(); // do not forget this
            edit.setText("");
        } catch (YAPI_Exception ex) {
            ex.printStackTrace();
        }
        DisplayModuleInfo();
    }

}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

package com.yoctopuce.doc_examples;

import android.app.Activity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.yoctopuce.YoctoAPI.YAPI;
import com.yoctopuce.YoctoAPI.YAPI_Exception;
import com.yoctopuce.YoctoAPI.YModule;

public class Inventory extends Activity
{

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.inventory);
    }

    public void refreshInventory(View view)
    {
        LinearLayout layout = (LinearLayout) findViewById(R.id.inventoryList);
        layout.removeAllViews();

        try {
            YAPI.UpdateDeviceList();
            YModule module = YModule.FirstModule();
            while (module != null) {
                String line = module.get_serialNumber() + " (" + module.get_productName() + ")";
                TextView tx = new TextView(this);
                tx.setText(line);
                tx.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
                layout.addView(tx);
                module = module.nextModule();
            }
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStart()
    {
        super.onStart();
        try {
            YAPI.EnableUSBHost(this);
            YAPI.RegisterHub("usb");
        } catch (YAPI_Exception e) {
            e.printStackTrace();
        }
        refreshInventory(null);
    }

    @Override
    protected void onStop()
    {
        super.onStop();
        YAPI.FreeAPI();
    }

}
 

17.7. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software.

In the Java API for Android, error handling is implemented with exceptions. Therefore you must catch and handle correctly all exceptions that might be thrown by the API if you do not want your software to crash soon as you unplug a device.

18. Using the Yocto-Pressure in command line

When you want to perform a punctual operation on your Yocto-Pressure, such as reading a value, assigning a logical name, and so on, you can obviously use the Virtual Hub, but there is a simpler, faster, and more efficient method: the command line API.

The command line API is a set of executables, one by type of functionality offered by the range of Yoctopuce products. These executables are provided pre-compiled for all the Yoctopuce officially supported platforms/OS. Naturally, the executable sources are also provided49.

18.1. Installing

Download the command line API50. You do not need to run any setup, simply copy the executables corresponding to your platform/OS in a directory of your choice. You may add this directory to your PATH variable to be able to access these executables from anywhere. You are all set, you only need to connect your Yocto-Pressure, open a shell, and start working by typing for example:

C:\>YPressure any get_currentValue

To use the command API on Linux, you need either have root privileges or to define an udev rule for your system. See the Troubleshooting chapter for more details.

18.2. Use: general description

All the command line API executables work on the same principle. They must be called the following way


C:\>Executable [options] [target] command [parameter]

[options] manage the global workings of the commands, they allow you, for instance, to pilot a module remotely through the network, or to force the module to save its configuration after executing the command.

[target] is the name of the module or of the function to which the command applies. Some very generic commands do not need a target. You can also use the aliases "any" and "all", or a list of names separated by comas without space.

command is the command you want to run. Almost all the functions available in the classic programming APIs are available as commands. You need to respect neither the case nor the underlined characters in the command name.

[parameters] logically are the parameters needed by the command.

At any time, the command line API executables can provide a rather detailed help. Use for instance:


C:\>executable /help

to know the list of available commands for a given command line API executable, or even:


C:\>executable command /help

to obtain a detailed description of the parameters of a command.

18.3. Control of the Temperature function

To control the Temperature function of your Yocto-Pressure, you need the YTemperature executable file.

For instance, you can launch:

C:\>YPressure any get_currentValue

This example uses the "any" target to indicate that we want to work on the first Temperature function found among all those available on the connected Yoctopuce modules when running. This prevents you from having to know the exact names of your function and of your module.

But you can use logical names as well, as long as you have configured them beforehand. Let us imagine a Yocto-Pressure module with the PRESSMK1-123456 serial number which you have called "MyModule", and its temperature function which you have renamed "MyFunction". The five following calls are strictly equivalent (as long as MyFunction is defined only once, to avoid any ambiguity).


C:\>YTemperature PRESSMK1-123456.temperature describe

C:\>YTemperature PRESSMK1-123456.MyFunction describe

C:\>YTemperature MyModule.temperature describe

C:\>YTemperature MyModule.MyFunction describe

C:\>YTemperature MyFunction describe

To work on all the Temperature functions at the same time, use the "all" target.


C:\>YTemperature all describe

For more details on the possibilities of the YTemperature executable, use:


C:\>YTemperature /help

18.4. Control of the module part

Each module can be controlled in a similar way with the help of the YModule executable. For example, to obtain the list of all the connected modules, use:


C:\>YModule inventory

You can also use the following command to obtain an even more detailed list of the connected modules:


C:\>YModule all describe

Each xxx property of the module can be obtained thanks to a command of the get_xxxx() type, and the properties which are not read only can be modified with the set_xxx() command. For example:


C:\>YModule PRESSMK1-12346 set_logicalName MonPremierModule

C:\>YModule PRESSMK1-12346 get_logicalName

Changing the settings of the module

When you want to change the settings of a module, simply use the corresponding set_xxx command. However, this change happens only in the module RAM: if the module restarts, the changes are lost. To store them permanently, you must tell the module to save its current configuration in its nonvolatile memory. To do so, use the saveToFlash command. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash method. For example:


C:\>YModule PRESSMK1-12346 set_logicalName MonPremierModule
C:\>YModule PRESSMK1-12346 saveToFlash

Note that you can do the same thing in a single command with the -s option.


C:\>YModule -s  PRESSMK1-12346 set_logicalName MonPremierModule

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

18.5. Limitations

The command line API has the same limitation than the other APIs: there can be only one application at a given time which can access the modules natively. By default, the command line API works in native mode.

You can easily work around this limitation by using a Virtual Hub: run the VirtualHub51 on the concerned machine, and use the executables of the command line API with the -r option. For example, if you use:


C:\>YModule  inventory

you obtain a list of the modules connected by USB, using a native access. If another command which accesses the modules natively is already running, this does not work. But if you run a Virtual Hub, and you give your command in the form:


C:\>YModule -r 127.0.0.1 inventory

it works because the command is not executed natively anymore, but through the Virtual Hub. Note that the Virtual Hub counts as a native application.

19. Using Yocto-Pressure with JavaScript / EcmaScript

EcmaScript is the official name of the standardized version of the web-oriented programming language commonly referred to as JavaScript. This Yoctopuce library take advantages of advanced features introduced in EcmaScript 2017. It has therefore been named Library for JavaScript / EcmaScript 2017 to differentiate it from the previous Library for JavaScript, now deprecated in favor of this new version.

This library provides access to Yoctopuce devices for modern JavaScript engines. It can be used within a browser as well as with Node.js. The library will automatically detect upon initialization whether the runtime environment is a browser or a Node.js virtual machine, and use the most appropriate system libraries accordingly.

Asynchronous communication with the devices is handled across the whole library using Promise objects, leveraging the new EcmaScript 2017 async / await non-blocking syntax for asynchronous I/O (see below). This syntax is now available out-of-the-box in most Javascript engines. No transpilation is needed: no Babel, no jspm, just plain Javascript. Here is your favorite engines minimum version needed to run this code. All of them are officially released at the time we write this document.

If you need backward-compatibility with older releases, you can always run Babel to transpile your code and the library to older standards, as described a few paragraphs below.

We don't suggest using jspm 0.17 anymore since that tool is still in Beta after 18 month, and having to use an extra tool to implement our library is pointless now that async / await are part of the standard.

19.1. Blocking I/O versus Asynchronous I/O in JavaScript

JavaScript is single-threaded by design. That means, if a program is actively waiting for the result of a network-based operation such as reading from a sensor, the whole program is blocked. In browser environments, this can even completely freeze the user interface. For this reason, the use of blocking I/O in JavaScript is strongly discouraged nowadays, and blocking network APIs are getting deprecated everywhere.

Instead of using parallel threads, JavaScript relies on asynchronous I/O to handle operations with a possible long timeout: whenever a long I/O call needs to be performed, it is only triggered and but then the code execution flow is terminated. The JavaScript engine is therefore free to handle other pending tasks, such as UI. Whenever the pending I/O call is completed, the system invokes a callback function with the result of the I/O call to resume execution of the original execution flow.

When used with plain callback functions, as pervasive in Node.js libraries, asynchronous I/O tend to produce code with poor readability, as the execution flow is broken into many disconnected callback functions. Fortunately, new methods have emerged recently to improve that situation. In particular, the use of Promise objects to abstract and work with asynchronous tasks helps a lot. Any function that makes a long I/O operation can return a Promise, which can be used by the caller to chain subsequent operations in the same flow. Promises are part of EcmaScript 2015 standard.

Promise objects are good, but what makes them even better is the new async / await keywords to handle asynchronous I/O:

Long story made short, async and await make it possible to write EcmaScript code with all benefits of asynchronous I/O, but without breaking the code flow. It is almost like multi-threaded execution, except that control switch between pending tasks only happens at places where the await keyword appears.

We have therefore chosen to write our new EcmaScript library using Promises and async functions, so that you can use the friendly await syntax. To keep it easy to remember, all public methods of the EcmaScript library are async, i.e. return a Promise object, except:

19.2. Using Yoctopuce library for JavaScript / EcmaScript 2017

JavaScript is one of those languages which do not generally allow you to directly access the hardware layers of your computer. Therefore the library can only be used to access network-enabled devices (connected through a YoctoHub), or USB devices accessible through Yoctopuce TCP/IP to USB gateway, named VirtualHub.

Go to the Yoctopuce web site and download the following items:

Extract the library files in a folder of your choice, you will find many of examples in it. Connect your modules and start the VirtualHub software. You do not need to install any driver.

Using the official Yoctopuce library for node.js

Start by installing the latest Node.js version (v7.6 or later) on your system. It is very easy. You can download it from the official web site: http://nodejs.org. Make sure to install it fully, including npm, and add it to the system path.

To give it a try, go into one of the example directory (for instance example_nodejs/Doc-Inventory). You will see that it include an application description file (package.json) and a source file (demo.js). To download and setup the libraries needed by this example, just run:


npm install

Once done, you can start the example file using:


node demo.js

Using a local copy of the Yoctopuce library with node.js

If for some reason you need to make changes to the Yoctopuce library, you can easily configure your project to use the local copy in the lib/ subdirectory rather than the official npm package. In order to do so, simply type the following command in your project directory:


npm link ../../lib

Using the Yoctopuce library within a browser (HTML)

For HTML examples, it is even simpler: there is nothing to install. Each example is a single HTML file that you can open in a browser to try it. In this context, loading the Yoctopuce library is no different from any standard HTML script include tag.

Using the Yoctoluce library on older JavaScript engines

If you need to run this library on older JavaScript engines, you can use Babel54 to transpile your code and the library into older JavaScript standards. To install Babel with typical settings, simply use:


npm instal -g babel-cli
npm instal babel-preset-env

You would typically ask Babel to put the transpiled files in another directory, named compat for instance. Your files and all files of the Yoctopuce library should be transpiled, as follow:


babel --presets env demo.js --out-dir compat/
babel --presets env ../../lib --out-dir compat/

Although this approach is based on node.js toolchain, it actually works as well for transpiling JavaScript files for use in a browser. The only thing that you cannot do so easily is transpiling JavaScript code embedded directly in an HTML page. You have to use an external script file for using EcmaScript 2017 syntax with Babel.

Babel has many smart features, such as a watch mode that will automatically refresh transpiled files whenever the source file is changed, but this is beyond the scope of this note. You will find more in Babel documentation.

Backward-compatibility with the old JavaScript library

This new library is not fully backward-compatible with the old JavaScript library, because there is no way to transparently map the old blocking API to the new asynchronous API. The method names however are the same, and old synchronous code can easily be made asynchronous just by adding the proper await keywords before the method calls. For instance, simply replace:


beaconState = module.get_beacon();

by


beaconState = await module.get_beacon();

Apart from a few exceptions, most XXX_async redundant methods have been removed as well, as they would have introduced confusion on the proper way of handling asynchronous behaviors. It is however very simple to get an async method to invoke a callback upon completion, using the returned Promise object. For instance, you can replace:


module.get_beacon_async(callback, myContext);

by


module.get_beacon().then(function(res) { callback(myContext, module, res); });

In some cases, it might be desirable to get a sensor value using a method identical to the old synchronous methods (without using Promises), even if it returns a slightly outdated cached value since I/O is not possible. For this purpose, the EcmaScript library introduce new classes called synchronous proxies. A synchronous proxy is an object that mirrors the most recent state of the connected class, but can be read using regular synchronous function calls. For instance, instead of writing:


async function logInfo(module)
{
    console.log('Name: '+await module.get_logicalName());
    console.log('Beacon: '+await module.get_beacon());
}

...
logInfo(myModule);
...

you can use:


function logInfoProxy(moduleSyncProxy)
{
    console.log('Name: '+moduleProxy.get_logicalName());
    console.log('Beacon: '+moduleProxy.get_beacon());
}

logInfoSync(await myModule.get_syncProxy());

You can also rewrite this last asynchronous call as:


myModule.get_syncProxy().then(logInfoProxy);

19.3. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a JavaScript code snipplet to use the Temperature function.


// For Node.js, we use function require()
// For HTML, we would use &lt;script src="..."&gt;
require('yoctolib-es2017/yocto_api.js');
require('yoctolib-es2017/yocto_temperature.js');

// Get access to your device, through the VirtualHub running locally
await YAPI.RegisterHub('127.0.0.1');
var temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");

// Check that the module is online to handle hot-plug
if(await temperature.isOnline())
{
    // Use temperature.get_currentValue()
    [...]
}

Let us look at these lines in more details.

yocto_api and yocto_temperature import

These two import provide access to functions allowing you to manage Yoctopuce modules. yocto_api is always needed, yocto_temperature is necessary to manage modules containing a temperature sensor, such as Yocto-Pressure. Other imports can be useful in other cases, such as YModule which can let you enumerate any type of Yoctopuce device.

YAPI.RegisterHub

The RegisterHub method allows you to indicate on which machine the Yoctopuce modules are located, more precisely on which machine the VirtualHub software is running. In our case, the 127.0.0.1:4444 address indicates the local machine, port 4444 (the standard port used by Yoctopuce). You can very well modify this address, and enter the address of another machine on which the VirtualHub software is running, or of a YoctoHub. If the host cannot be reached, this function will trigger an exception.

YTemperature.FindTemperature

The FindTemperature method allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can also use logical names, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature")
temperature = YTemperature.FindTemperature("PRESSMK1-123456.MaFonction")
temperature = YTemperature.FindTemperature("MonModule.temperature")
temperature = YTemperature.FindTemperature("MonModule.MaFonction")
temperature = YTemperature.FindTemperature("MaFonction")

YTemperature.FindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by FindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example, for Node.js

Open a command window (a terminal, a shell...) and go into the directory example_nodejs/Doc-GettingStarted-Yocto-Pressure within Yoctopuce library for JavaScript / EcmaScript 2017. In there, you will find a file named demo.js with the sample code below, which uses the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

If your Yocto-Pressure is not connected on the host running the browser, replace in the example the address 127.0.0.1 by the IP address of the host on which the Yocto-Pressure is connected and where you run the VirtualHub.

"use strict";

require('yoctolib-es2017/yocto_api.js');
require('yoctolib-es2017/yocto_pressure.js');

let press;

async function startDemo()
{
    await YAPI.LogUnhandledPromiseRejections();
    await YAPI.DisableExceptions();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }

    // Select specified device, or use first available one
    let serial = process.argv[process.argv.length-1];
    if(serial[8] != '-') {
        // by default use any connected module suitable for the demo
        let anysensor = YPressure.FirstPressure();
        if(anysensor) {
            let module = await anysensor.module();
            serial = await module.get_serialNumber();
        } else {
            console.log('No matching sensor connected, check cable !');
            return;
        }
    }
    console.log('Using device '+serial);
    press = YPressure.FindPressure(serial+".pressure");

    refresh();
}

async function refresh()
{
    if (await press.isOnline()) {
        console.log('Pressure : '+(await press.get_currentValue()) + (await press.get_unit()));
    } else {
        console.log('Module not connected');
    }
    setTimeout(refresh, 500);
}

startDemo();
 

As explained at the beginning of this chapter, you need to have Node.js v7.6 or later installed to try this example. When done, you can type the following two commands to automatically download and install the dependencies for building this example:


npm install
You can the start the sample code within Node.js using the following command, replacing the [...] by the arguments that you want to pass to the demo code:

node demo.js [...]

Same example, but this time running in a browser

If you want to see how to use the library within a browser rather than with Node.js, switch to the directory example_html/Doc-GettingStarted-Yocto-Pressure. You will find there a single HTML file, with a JavaScript section similar to the code above, but with a few changes since it has to interact through an HTML page rather than through the JavaScript console.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Hello World</title>
  <script src="../../lib/yocto_api.js"></script>
  <script src="../../lib/yocto_pressure.js"></script>
  <script>
    async function startDemo()
    {
      await YAPI.LogUnhandledPromiseRejections();
      await YAPI.DisableExceptions();

      // Setup the API to use the VirtualHub on local machine
      let errmsg = new YErrorMsg();
      if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        alert('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
      }
      refresh();
    }

    async function refresh()
    {
      let serial = document.getElementById('serial').value;
      if(serial == '') {
        // by default use any connected module suitable for the demo
        let anysensor = YPressure.FirstPressure();
        if(anysensor) {
          let module = await anysensor.module();
          serial = await module.get_serialNumber();
          document.getElementById('serial').value = serial;
        }
      }
      let press = YPressure.FindPressure(serial+".pressure");

      if (await press.isOnline()) {
        document.getElementById('msg').value = '';
        document.getElementById("press").value = (await press.get_currentValue()) + (await press.get_unit());
      } else {
        document.getElementById('msg').value = 'Module not connected';
      }
      setTimeout(refresh, 500);
    }

    startDemo();
  </script>
</head>
<body>
Module to use: <input id='serial'>
<input id='msg' style='color:red;border:none;' readonly><br>
pressure : <input id='press' readonly><br>
</body>
</html>
 

No installation is needed to run this example, all you have to do is open the HTML file using a web browser,

19.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo(args)
{
    await YAPI.LogUnhandledPromiseRejections();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }

    // Select the relay to use
    let module = YModule.FindModule(args[0]);
    if(await module.isOnline()) {
        if(args.length > 1) {
            if(args[1] == 'ON') {
                await module.set_beacon(YModule.BEACON_ON);
            } else {
                await module.set_beacon(YModule.BEACON_OFF);
            }
        }
        console.log('serial:       '+await module.get_serialNumber());
        console.log('logical name: '+await module.get_logicalName());
        console.log('luminosity:   '+await module.get_luminosity()+'%');
        console.log('beacon:       '+(await module.get_beacon()==YModule.BEACON_ON?'ON':'OFF'));
        console.log('upTime:       '+parseInt(await module.get_upTime()/1000)+' sec');
        console.log('USB current:  '+await module.get_usbCurrent()+' mA');
        console.log('logs:');
        console.log(await module.get_lastLogs());
    } else {
        console.log("Module not connected (check identification and USB cable)\n");
    }
    await YAPI.FreeAPI();
}

if(process.argv.length < 2) {
    console.log("usage: node demo.js <serial or logicalname> [ ON | OFF ]");
} else {
    startDemo(process.argv.slice(2));
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo(args)
{
    await YAPI.LogUnhandledPromiseRejections();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if(await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1: '+errmsg.msg);
        return;
    }
   
    // Select the relay to use
    let module = YModule.FindModule(args[0]);
    if(await module.isOnline()) {
        if(args.length > 1) {
            let newname = args[1];
            if (!await YAPI.CheckLogicalName(newname)) {
                console.log("Invalid name (" + newname + ")");
                process.exit(1);
            }
            await module.set_logicalName(newname);
            await module.saveToFlash();
        }
        console.log('Current name: '+await module.get_logicalName());
    } else {
        console.log("Module not connected (check identification and USB cable)\n");
    }
    await YAPI.FreeAPI();
}

if(process.argv.length < 2) {
    console.log("usage: node demo.js <serial> [newLogicalName]");
} else {
    startDemo(process.argv.slice(2));
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.FirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

"use strict";

require('yoctolib-es2017/yocto_api.js');

async function startDemo()
{
    await YAPI.LogUnhandledPromiseRejections();
    await YAPI.DisableExceptions();

    // Setup the API to use the VirtualHub on local machine
    let errmsg = new YErrorMsg();
    if (await YAPI.RegisterHub('127.0.0.1', errmsg) != YAPI.SUCCESS) {
        console.log('Cannot contact VirtualHub on 127.0.0.1');
        return;
    }
    refresh();
}

async function refresh()
{
    try {
        let errmsg = new YErrorMsg();
        await YAPI.UpdateDeviceList(errmsg);

        let module = YModule.FirstModule();
        while(module) {
            let line = await module.get_serialNumber();
            line += '(' + (await module.get_productName()) + ')';
            console.log(line);
            module = module.nextModule();
        }
        setTimeout(refresh, 500);
    } catch(e) {
        console.log(e);
    }
}

try {
    startDemo();
} catch(e) {
    console.log(e);
}
 

19.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

20. Using Yocto-Pressure with PHP

PHP is, like Javascript, an atypical language when interfacing with hardware is at stakes. Nevertheless, using PHP with Yoctopuce modules provides you with the opportunity to very easily create web sites which are able to interact with their physical environment, and this is not available to every web server. This technique has a direct application in home automation: a few Yoctopuce modules, a PHP server, and you can interact with your home from anywhere on the planet, as long as you have an internet connection.

PHP is one of those languages which do not allow you to directly access the hardware layers of your computer. Therefore you need to run a virtual hub on the machine on which your modules are connected.

To start your tests with PHP, you need a PHP 5.3 (or more) server55, preferably locally on you machine. If you wish to use the PHP server of your internet provider, it is possible, but you will probably need to configure your ADSL router for it to accept and forward TCP request on the 4444 port.

20.1. Getting ready

Go to the Yoctopuce web site and download the following items:

Decompress the library files in a folder of your choice accessible to your web server, connect your modules, run the VirtualHub software, and you are ready to start your first tests. You do not need to install any driver.

20.2. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a PHP code snipplet to use the Temperature function.


include('yocto_api.php');
include('yocto_temperature.php');

// Get access to your device, through the VirtualHub running locally
yRegisterHub('http://127.0.0.1:4444/',$errmsg);
$temperature = yFindTemperature("PRESSMK1-123456.temperature");

// Check that the module is online to handle hot-plug
if(temperature->isOnline())
{
    // Use temperature->get_currentValue(), ...
}

Let's look at these lines in more details.

yocto_api.php and yocto_temperature.php

These two PHP includes provides access to the functions allowing you to manage Yoctopuce modules. yocto_api.php must always be included, yocto_temperature.php is necessary to manage modules containing a temperature sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function allows you to indicate on which machine the Yoctopuce modules are located, more precisely on which machine the VirtualHub software is running. In our case, the 127.0.0.1:4444 address indicates the local machine, port 4444 (the standard port used by Yoctopuce). You can very well modify this address, and enter the address of another machine on which the VirtualHub software is running.

yFindTemperature

The yFindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


$temperature = yFindTemperature("PRESSMK1-123456.temperature");
$temperature = yFindTemperature("PRESSMK1-123456.MyFunction");
$temperature = yFindTemperature("MyModule.temperature");
$temperature = yFindTemperature("MyModule.MyFunction");
$temperature = yFindTemperature("MyFunction");

yFindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by yFindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Open your preferred text editor58, copy the code sample below, save it with the Yoctopuce library files in a location which is accessible to you web server, then use your preferred web browser to access this page. The code is also provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

<HTML>
<HEAD>
 <TITLE>Hello World</TITLE>
</HEAD>
<BODY>
<?php
  include('yocto_api.php');
  include('yocto_pressure.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1");
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $press = yFindPressure("$serial.pressure");
      if (!$press->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $press = yFirstPressure();
      if(is_null($press)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $press->module()->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  $pvalue = $press->get_currentValue();
  Print("Pressure: $pvalue mbar<br>");
  yFreeAPI();

  // trigger auto-refresh after one second
  Print("<script language='javascript1.5' type='text/JavaScript'>\n");
  Print("setTimeout('window.location.reload()',1000);");
  Print("</script>\n");
?>
</BODY>
</HTML>
 

20.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

<HTML>
<HEAD>
 <TITLE>Module Control</TITLE>
</HEAD>
<BODY>
<FORM method='get'>
<?php
  include('yocto_api.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1 : ".$errmsg);
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $module = yFindModule("$serial");
      if (!$module->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $module = yFirstModule();
      if($module) { // skip VirtualHub
          $module = $module->nextModule();
      }
      if(is_null($module)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $module->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  if (isset($_GET['beacon'])) {
      if ($_GET['beacon']=='ON')
          $module->set_beacon(Y_BEACON_ON);
      else
          $module->set_beacon(Y_BEACON_OFF);
  }
  printf('serial: %s<br>',$module->get_serialNumber());
  printf('logical name: %s<br>',$module->get_logicalName());
  printf('luminosity: %s<br>',$module->get_luminosity());
  print('beacon: ');
  if($module->get_beacon() == Y_BEACON_ON) {
      printf("<input type='radio' name='beacon' value='ON' checked>ON ");
      printf("<input type='radio' name='beacon' value='OFF'>OFF<br>");
  } else {
      printf("<input type='radio' name='beacon' value='ON'>ON ");
      printf("<input type='radio' name='beacon' value='OFF' checked>OFF<br>");
  }
  printf('upTime: %s sec<br>',intVal($module->get_upTime()/1000));
  printf('USB current: %smA<br>',$module->get_usbCurrent());
  printf('logs:<br><pre>%s</pre>',$module->get_lastLogs());
  yFreeAPI();
?>
<input type='submit' value='refresh'>
</FORM>
</BODY>
</HTML>
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

<HTML>
<HEAD>
 <TITLE>save settings</TITLE>
<BODY>
<FORM method='get'>
<?php
  include('yocto_api.php');

  // Use explicit error handling rather than exceptions
  yDisableExceptions();

  // Setup the API to use the VirtualHub on local machine
  if(yRegisterHub('http://127.0.0.1:4444/',$errmsg) != YAPI_SUCCESS) {
      die("Cannot contact VirtualHub on 127.0.0.1");
  }

  @$serial = $_GET['serial'];
  if ($serial != '') {
      // Check if a specified module is available online
      $module = yFindModule("$serial");
      if (!$module->isOnline()) {
          die("Module not connected (check serial and USB cable)");
      }
  } else {
      // or use any connected module suitable for the demo
      $module = yFirstModule();
      if($module) { // skip VirtualHub
          $module = $module->nextModule();
      }
      if(is_null($module)) {
          die("No module connected (check USB cable)");
      } else {
          $serial = $module->get_serialnumber();
      }
  }
  Print("Module to use: <input name='serial' value='$serial'><br>");

  if (isset($_GET['newname'])){
      $newname = $_GET['newname'];
      if (!yCheckLogicalName($newname))
          die('Invalid name');
      $module->set_logicalName($newname);
      $module->saveToFlash();
  }
  printf("Current name: %s<br>", $module->get_logicalName());
  print("New name: <input name='newname' value='' maxlength=19><br>");
  yFreeAPI();
?>
<input type='submit'>
</FORM>
</BODY>
</HTML>
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

<HTML>
<HEAD>
 <TITLE>inventory</TITLE>
</HEAD>
<BODY>
<H1>Device list</H1>
<TT>
<?php
    include('yocto_api.php');
    yRegisterHub("http://127.0.0.1:4444/");
    $module   = yFirstModule();
    while (!is_null($module)) {
        printf("%s (%s)<br>", $module->get_serialNumber(),
               $module->get_productName());
        $module=$module->nextModule();
    }
    yFreeAPI();
?>
</TT>
</BODY>
</HTML>
 

20.4. HTTP callback API and NAT filters

The PHP library is able to work in a specific mode called HTTP callback Yocto-API. With this mode, you can control Yoctopuce devices installed behind a NAT filter, such as a DSL router for example, and this without needing to open a port. The typical application is to control Yoctopuce devices, located on a private network, from a public web site.

The NAT filter: advantages and disadvantages

A DSL router which translates network addresses (NAT) works somewhat like a private phone switchboard (a PBX): internal extensions can call each other and call the outside; but seen from the outside, there is only one official phone number, that of the switchboard itself. You cannot reach the internal extensions from the outside.


Typical DSL configuration: LAN machines are isolated from the outside by the DSL router

Transposed to the network, we have the following: appliances connected to your home automation network can communicate with one another using a local IP address (of the 192.168.xxx.yyy type), and contact Internet servers through their public address. However, seen from the outside, you have only one official IP address, assigned to the DSL router only, and you cannot reach your network appliances directly from the outside. It is rather restrictive, but it is a relatively efficient protection against intrusions.


Responses from request from LAN machines are routed.


But requests from the outside are blocked.

Seeing Internet without being seen provides an enormous security advantage. However, this signifies that you cannot, a priori, set up your own web server at home to control a home automation installation from the outside. A solution to this problem, advised by numerous home automation system dealers, consists in providing outside visibility to your home automation server itself, by adding a routing rule in the NAT configuration of the DSL router. The issue of this solution is that it exposes the home automation server to external attacks.

The HTTP callback API solves this issue without having to modify the DSL router configuration. The module control script is located on an external site, and it is the VirtualHub which is in charge of calling it a regular intervals.


The HTTP callback API uses the VirtualHub which initiates the requests.

Configuration

The callback API thus uses the VirtualHub as a gateway. All the communications are initiated by the VirtualHub. They are thus outgoing communications and therefore perfectly authorized by the DSL router.

You must configure the VirtualHub so that it calls the PHP script on a regular basis. To do so:

  1. Launch a VirtualHub
  2. Access its interface, usually 127.0.0.1:4444
  3. Click on the configure button of the line corresponding to the VirtualHub itself
  4. Click on the edit button of the Outgoing callbacks section


Click on the "configure" button on the first line


Click on the "edit" button of the "Outgoing callbacks" section


And select "Yocto-API callback".

You then only need to define the URL of the PHP script and, if need be, the user name and password to access this URL. Supported authentication methods are basic and digest. The second method is safer than the first one because it does not allow transfer of the password on the network.

Usage

From the programmer standpoint, the only difference is at the level of the yRegisterHub function call. Instead of using an IP address, you must use the callback string (or http://callback which is equivalent).


include("yocto_api.php");
yRegisterHub("callback");

The remainder of the code stays strictly identical. On the VirtualHub interface, at the bottom of the configuration window for the HTTP callback API , there is a button allowing you to test the call to the PHP script.

Be aware that the PHP script controlling the modules remotely through the HTTP callback API can be called only by the VirtualHub. Indeed, it requires the information posted by the VirtualHub to function. To code a web site which controls Yoctopuce modules interactively, you must create a user interface which stores in a file or in a database the actions to be performed on the Yoctopuce modules. These actions are then read and run by the control script.

Common issues

For the HTTP callback API to work, the PHP option allow_url_fopen must be set. Some web site hosts do not set it by default. The problem then manifests itself with the following error:

error: URL file-access is disabled in the server configuration

To set this option, you must create, in the repertory where the control PHP script is located, an .htaccess file containing the following line:
php_flag "allow_url_fopen" "On"
Depending on the security policies of the host, it is sometimes impossible to authorize this option at the root of the web site, or even to install PHP scripts receiving data from a POST HTTP. In this case, place the PHP script in a subdirectory.

Limitations

This method that allows you to go through NAT filters cheaply has nevertheless a price. Communications being initiated by the VirtualHub at a more or less regular interval, reaction time to an event is clearly longer than if the Yoctopuce modules were driven directly. You can configure the reaction time in the specific window of the VirtualHub, but it is at least of a few seconds in the best case.

The HTTP callback Yocto-API mode is currently available in PHP, EcmaScript (Node.JS) and Java only.

20.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

21. Using Yocto-Pressure with C++

C++ is not the simplest language to master. However, if you take care to limit yourself to its essential functionalities, this language can very well be used for short programs quickly coded, and it has the advantage of being easily ported from one operating system to another. Under Windows, all the examples and the project models are tested with Microsoft Visual Studio 2010 Express, freely available on the Microsoft web site59. Under Mac OS X, all the examples and project models are tested with XCode 4, available on the App Store. Moreover, under Max OS X and under Linux, you can compile the examples using a command line with GCC using the provided GNUmakefile. In the same manner under Windows, a Makefile allows you to compile examples using a command line, fully knowing the compilation and linking arguments.

Yoctopuce C++ libraries60 are integrally provided as source files. A section of the low-level library is written in pure C, but you should not need to interact directly with it: everything was done to ensure the simplest possible interaction from C++. The library is naturally also available as binary files, so that you can link it directly if you prefer.

You will soon notice that the C++ API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface. You will find in the last section of this chapter all the information needed to create a wholly new project linked with the Yoctopuce libraries.

21.1. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C++ code snipplet to use the Temperature function.


#include "yocto_api.h"
#include "yocto_temperature.h"

[...]
String  errmsg;
YTemperature *temperature;

// Get access to your device, connected locally on USB for instance
yRegisterHub("usb", errmsg);
temperature = yFindTemperature("PRESSMK1-123456.temperature");

// Hot-plug is easy: just check that the device is online
if(temperature->isOnline())
{
    // Use temperature->get_currentValue(), ...
}

Let's look at these lines in more details.

yocto_api.h et yocto_temperature.h

These two include files provide access to the functions allowing you to manage Yoctopuce modules. yocto_api.h must always be used, yocto_temperature.h is necessary to manage modules containing a temperature sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindTemperature

The yFindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


YTemperature *temperature = yFindTemperature("PRESSMK1-123456.temperature");
YTemperature *temperature = yFindTemperature("PRESSMK1-123456.MyFunction");
YTemperature *temperature = yFindTemperature("MyModule.temperature");
YTemperature *temperature = yFindTemperature("MyModule.MyFunction");
YTemperature *temperature = yFindTemperature("MyFunction");

yFindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by yFindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Launch your C++ environment and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library. If you prefer to work with your favorite text editor, open the file main.cpp, and type make to build the example when you are done.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

#include "yocto_api.h"
#include "yocto_pressure.h"
#include <iostream>
#include <stdlib.h>

using namespace std;

static void usage(void)
{
  cout << "usage: demo <serial_number> " << endl;
  cout << "       demo <logical_name>" << endl;
  cout << "       demo any" << endl;
  u64 now = yGetTickCount();
  while (yGetTickCount() - now < 3000) {
    // wait 3 sec to show the message
  }
  exit(1);
}

int main(int argc, const char * argv[])
{
  string errmsg, target;
  YPressure *psensor;

  if (argc < 2) {
    usage();
  }
  target = (string) argv[1];

  // Setup the API to use local USB devices
  if (yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if (target == "any") {
    psensor = yFirstPressure();
    if (psensor == NULL) {
      cout << "No module connected (check USB cable)" << endl;
      return 1;
    }
  } else {
    psensor = yFindPressure(target + ".pressure");
  }

  while (1) {
    if (!psensor->isOnline()) {
      cout << "Module not connected (check identification and USB cable)";
      break;
    }
    cout << "Current pressure: " << psensor->get_currentValue() << " mbar" << endl;
    cout << "  (press Ctrl-C to exit)" << endl;
    ySleep(1000, errmsg);
  };
  yFreeAPI();

  return 0;
}
 

21.2. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#include <iostream>
#include <stdlib.h>

#include "yocto_api.h"

using namespace std;

static void usage(const char *exe)
{
  cout << "usage: " << exe << " <serial or logical name> [ON/OFF]" << endl;
  exit(1);
}


int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if(argc < 2)
    usage(argv[0]);

  YModule *module = yFindModule(argv[1]);  // use serial or logical name

  if (module->isOnline()) {
    if (argc > 2) {
      if (string(argv[2]) == "ON")
        module->set_beacon(Y_BEACON_ON);
      else
        module->set_beacon(Y_BEACON_OFF);
    }
    cout << "serial:       " << module->get_serialNumber() << endl;
    cout << "logical name: " << module->get_logicalName() << endl;
    cout << "luminosity:   " << module->get_luminosity() << endl;
    cout << "beacon:       ";
    if (module->get_beacon() == Y_BEACON_ON)
      cout << "ON" << endl;
    else
      cout << "OFF" << endl;
    cout << "upTime:       " << module->get_upTime() / 1000 << " sec" << endl;
    cout << "USB current:  " << module->get_usbCurrent() << " mA" << endl;
    cout << "Logs:" << endl << module->get_lastLogs() << endl;
  } else {
    cout << argv[1] << " not connected (check identification and USB cable)"
         << endl;
  }
  yFreeAPI();
  return 0;
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

#include <iostream>
#include <stdlib.h>

#include "yocto_api.h"

using namespace std;

static void usage(const char *exe)
{
  cerr << "usage: " << exe << " <serial> <newLogicalName>" << endl;
  exit(1);
}

int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(yRegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  if(argc < 2)
    usage(argv[0]);

  YModule *module = yFindModule(argv[1]);  // use serial or logical name

  if (module->isOnline()) {
    if (argc >= 3) {
      string newname =  argv[2];
      if (!yCheckLogicalName(newname)) {
        cerr << "Invalid name (" << newname << ")" << endl;
        usage(argv[0]);
      }
      module->set_logicalName(newname);
      module->saveToFlash();
    }
    cout << "Current name: " << module->get_logicalName() << endl;
  } else {
    cout << argv[1] << " not connected (check identification and USB cable)"
         << endl;
  }
  yFreeAPI();
  return 0;
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

#include <iostream>

#include "yocto_api.h"

using namespace std;

int main(int argc, const char * argv[])
{
  string      errmsg;

  // Setup the API to use local USB devices
  if(YAPI::RegisterHub("usb", errmsg) != YAPI_SUCCESS) {
    cerr << "RegisterHub error: " << errmsg << endl;
    return 1;
  }

  cout << "Device list: " << endl;

  YModule *module = YModule::FirstModule();
  while (module != NULL) {
    cout << module->get_serialNumber() << " ";
    cout << module->get_productName()  << endl;
    module = module->nextModule();
  }
  yFreeAPI();
  return 0;
}
 

21.3. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

21.4. Integration variants for the C++ Yoctopuce library

Depending on your needs and on your preferences, you can integrate the library into your projects in several distinct manners. This section explains how to implement the different options.

Integration in source format

Integrating all the sources of the library into your projects has several advantages:

To integrate the source code, the easiest way is to simply include the Sources directory of your Yoctopuce library into your IncludePath, and to add all the files of this directory (including the sub-directory yapi) to your project.

For your project to build correctly, you need to link with your project the prerequisite system libraries, that is:

Integration as a static library

Integration of the Yoctopuce library as a static library is a simpler manner to build a small executable which uses Yoctopuce modules. You can quickly compile the program with a single command. You do not need to install a dynamic library specific to Yoctopuce, everything is in the executable.

To integrate the static Yoctopuce library to your project, you must include the Sources directory of the Yoctopuce library into your IncludePath, and add the sub-directory Binaries/... corresponding to your operating system into your libPath.

Then, for you project to build correctly, you need to link with your project the Yoctopuce library and the prerequisite system libraries:

Note, under Linux, if you wish to compile in command line with GCC, it is generally advisable to link system libraries as dynamic libraries, rather than as static ones. To mix static and dynamic libraries on the same command line, you must pass the following arguments:

gcc (...) -Wl,-Bstatic -lyocto-static -Wl,-Bdynamic -lm -lpthread -lusb-1.0 -lstdc++

Integration as a dynamic library

Integration of the Yoctopuce library as a dynamic library allows you to produce an executable smaller than with the two previous methods, and to possibly update this library, if a patch reveals itself necessary, without needing to recompile the source code of the application. On the other hand, it is an integration mode which systematically requires you to copy the dynamic library on the target machine where the application will run (yocto.dll for Windows, libyocto.so.1.0.1 for Mac OS X and Linux).

To integrate the dynamic Yoctopuce library to your project, you must include the Sources directory of the Yoctopuce library into your IncludePath, and add the sub-directory Binaries/... corresponding to your operating system into your LibPath.

Then, for you project to build correctly, you need to link with your project the dynamic Yoctopuce library and the prerequisite system libraries:

With GCC, the command line to compile is simply:

gcc (...) -lyocto -lm -lpthread -lusb-1.0 -lstdc++

22. Using Yocto-Pressure with Objective-C

Objective-C is language of choice for programming on Mac OS X, due to its integration with the Cocoa framework. In order to use the Objective-C library, you need XCode version 4.2 (earlier versions will not work), available freely when you run Lion. If you are still under Snow Leopard, you need to be registered as Apple developer to be able to download XCode 4.2. The Yoctopuce library is ARC compatible. You can therefore implement your projects either using the traditional retain / release method, or using the Automatic Reference Counting.

Yoctopuce Objective-C libraries61 are integrally provided as source files. A section of the low-level library is written in pure C, but you should not need to interact directly with it: everything was done to ensure the simplest possible interaction from Objective-C.

You will soon notice that the Objective-C API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface. You can find on Yoctopuce blog a detailed example62 with video shots showing how to integrate the library into your projects.

22.1. Control of the Temperature function

Launch Xcode 4.2 and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

#import <Foundation/Foundation.h>
#import "yocto_api.h"
#import "yocto_pressure.h"

static void usage(void)
{
  NSLog(@"usage: demo <serial_number> ");
  NSLog(@"       demo <logical_name>");
  NSLog(@"       demo any                 (use any discovered device)");
  exit(1);
}

int main(int argc, const char * argv[])
{
  NSError *error;

  if (argc < 2) {
    usage();
  }

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb": &error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }
    NSString     *target = [NSString stringWithUTF8String:argv[1]];
    YPressure *psensor;
    if ([target isEqualToString:@"any"]) {
      psensor = [YPressure FirstPressure];
      if (psensor == NULL) {
        NSLog(@"No module connected (check USB cable)");
        return 1;
      }
    } else {
      psensor = [YPressure FindPressure:[target stringByAppendingString:@".pressure"]];
    }

    while(1) {
      if(![psensor isOnline]) {
        NSLog(@"Module not connected (check identification and USB cable)\n");
        break;
      }

      NSLog(@"Current pressure: %f C\n", [psensor get_currentValue]);
      NSLog(@"  (press Ctrl-C to exit)\n");
      [YAPI Sleep:1000:NULL];
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

There are only a few really important lines in this example. We will look at them in details.

yocto_api.h et yocto_temperature.h

These two import files provide access to the functions allowing you to manage Yoctopuce modules. yocto_api.h must always be used, yocto_temperature.h is necessary to manage modules containing a temperature sensor, such as Yocto-Pressure.

[YAPI RegisterHub]

The [YAPI RegisterHub] function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter @"usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

[Temperature FindTemperature]

The [Temperature FindTemperature] function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


YTemperature *temperature = [Temperature FindTemperature:@"PRESSMK1-123456.temperature"];
YTemperature *temperature = [Temperature FindTemperature:@"PRESSMK1-123456.MyFunction"];
YTemperature *temperature = [Temperature FindTemperature:@"MyModule.temperature"];
YTemperature *temperature = [Temperature FindTemperature:@"MyModule.MyFunction"];
YTemperature *temperature = [Temperature FindTemperature:@"MyFunction"];

[Temperature FindTemperature] returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline method of the object returned by [Temperature FindTemperature] allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

22.2. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

static void usage(const char *exe)
{
  NSLog(@"usage: %s <serial or logical name> [ON/OFF]\n", exe);
  exit(1);
}


int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb": &error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }
    if(argc < 2)
      usage(argv[0]);
    NSString *serial_or_name = [NSString stringWithUTF8String:argv[1]];
    // use serial or logical name
    YModule *module = [YModule FindModule:serial_or_name];
    if ([module isOnline]) {
      if (argc > 2) {
        if (strcmp(argv[2], "ON") == 0)
          [module setBeacon:Y_BEACON_ON];
        else
          [module setBeacon:Y_BEACON_OFF];
      }
      NSLog(@"serial:       %@\n", [module serialNumber]);
      NSLog(@"logical name: %@\n", [module logicalName]);
      NSLog(@"luminosity:   %d\n", [module luminosity]);
      NSLog(@"beacon:       ");
      if ([module beacon] == Y_BEACON_ON)
        NSLog(@"ON\n");
      else
        NSLog(@"OFF\n");
      NSLog(@"upTime:       %ld sec\n", [module upTime] / 1000);
      NSLog(@"USB current:  %d mA\n",  [module usbCurrent]);
      NSLog(@"logs:  %@\n",  [module get_lastLogs]);
    } else {
      NSLog(@"%@ not connected (check identification and USB cable)\n",
            serial_or_name);
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

Each property xxx of the module can be read thanks to a method of type get_xxxx, and properties which are not read-only can be modified with the help of the set_xxx: method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx: function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash method. The short example below allows you to modify the logical name of a module.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

static void usage(const char *exe)
{
  NSLog(@"usage: %s <serial> <newLogicalName>\n", exe);
  exit(1);
}


int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb" :&error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@", [error localizedDescription]);
      return 1;
    }

    if(argc < 2)
      usage(argv[0]);

    NSString *serial_or_name = [NSString stringWithUTF8String:argv[1]];
    // use serial or logical name
    YModule *module = [YModule FindModule:serial_or_name];

    if (module.isOnline) {
      if (argc >= 3) {
        NSString *newname =  [NSString stringWithUTF8String:argv[2]];
        if (![YAPI CheckLogicalName:newname]) {
          NSLog(@"Invalid name (%@)\n", newname);
          usage(argv[0]);
        }
        module.logicalName = newname;
        [module saveToFlash];
      }
      NSLog(@"Current name: %@\n", module.logicalName);
    } else {
      NSLog(@"%@ not connected (check identification and USB cable)\n",
            serial_or_name);
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not NULL. Below a short example listing the connected modules.

#import <Foundation/Foundation.h>
#import "yocto_api.h"

int main (int argc, const char * argv[])
{
  NSError *error;

  @autoreleasepool {
    // Setup the API to use local USB devices
    if([YAPI RegisterHub:@"usb" :&error] != YAPI_SUCCESS) {
      NSLog(@"RegisterHub error: %@\n", [error localizedDescription]);
      return 1;
    }

    NSLog(@"Device list:\n");

    YModule *module = [YModule FirstModule];
    while (module != nil) {
      NSLog(@"%@ %@", module.serialNumber, module.productName);
      module = [module nextModule];
    }
    [YAPI FreeAPI];
  }
  return 0;
}
 

22.3. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

23. Using Yocto-Pressure with Visual Basic .NET

VisualBasic has long been the most favored entrance path to the Microsoft world. Therefore, we had to provide our library for this language, even if the new trend is shifting to C#. All the examples and the project models are tested with Microsoft VisualBasic 2010 Express, freely available on the Microsoft web site63.

23.1. Installation

Download the Visual Basic Yoctopuce library from the Yoctopuce web site64. There is no setup program, simply copy the content of the zip file into the directory of your choice. You mostly need the content of the Sources directory. The other directories contain the documentation and a few sample programs. All sample projects are Visual Basic 2010, projects, if you are using a previous version, you may have to recreate the projects structure from scratch.

23.2. Using the Yoctopuce API in a Visual Basic project

The Visual Basic.NET Yoctopuce library is composed of a DLL and of source files in Visual Basic. The DLL is not a .NET DLL, but a classic DLL, written in C, which manages the low level communications with the modules65. The source files in Visual Basic manage the high level part of the API. Therefore, your need both this DLL and the .vb files of the sources directory to create a project managing Yoctopuce modules.

Configuring a Visual Basic project

The following indications are provided for Visual Studio Express 2010, but the process is similar for other versions. Start by creating your project. Then, on the Solution Explorer panel, right click on your project, and select "Add" and then "Add an existing item".

A file selection window opens. Select the yocto_api.vb file and the files corresponding to the functions of the Yoctopuce modules that your project is going to manage. If in doubt, select all the files.

You then have the choice between simply adding these files to your project, or to add them as links (the Add button is in fact a scroll-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply keeps a link on the original files. We recommend you to use links, which makes updates of the library much easier.

Then add in the same manner the yapi.dll DLL, located in the Sources/dll directory66. Then, from the Solution Explorer window, right click on the DLL, select Properties and in the Properties panel, set the Copy to output folder to always. You are now ready to use your Yoctopuce modules from Visual Studio.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

23.3. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Visual Basic code snipplet to use the Temperature function.


[...]
Dim errmsg As String errmsg
Dim temperature As YTemperature
 
REM Get access to your device, connected locally on USB for instance
yRegisterHub("usb", errmsg)
temperature = yFindTemperature("PRESSMK1-123456.temperature")

REM Hot-plug is easy: just check that the device is online
If (temperature.isOnline()) Then
   REM Use temperature.get_currentValue(), ...
End If

Let's look at these lines in more details.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindTemperature

The yFindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = yFindTemperature("PRESSMK1-123456.temperature")
temperature = yFindTemperature("PRESSMK1-123456.MyFunction")
temperature = yFindTemperature("MyModule.temperature")
temperature = yFindTemperature("MyModule.MyFunction")
temperature = yFindTemperature("MyFunction")

yFindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by yFindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

A real example

Launch Microsoft VisualBasic and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

Module Module1

  Private Sub Usage()
    Dim execname = System.AppDomain.CurrentDomain.FriendlyName
    Console.WriteLine("Usage:")
    Console.WriteLine(execname + " <serial_number>")
    Console.WriteLine(execname + " <logical_name>")
    Console.WriteLine(execname + " any  ")
    System.Threading.Thread.Sleep(2500)

    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim target As String

    Dim psensor As YPressure

    If argv.Length < 2 Then Usage()

    target = argv(1)

    REM Setup the API to use local USB devices
    If (yRegisterHub("usb", errmsg) <> YAPI_SUCCESS) Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    If target = "any" Then
      psensor = yFirstPressure()

      If psensor Is Nothing Then
        Console.WriteLine("No module connected (check USB cable) ")
        End
      End If
    Else
      psensor = yFindPressure(target + ".pressure")
    End If

    While (True)
      If Not (psensor.isOnline()) Then
        Console.WriteLine("Module not connected (check identification and USB cable)")
        End
      End If
      Console.WriteLine("Current pressure: " + Str(psensor.get_currentValue()) _
                        + " mbar")
      Console.WriteLine("  (press Ctrl-C to exit)")
      ySleep(1000, errmsg)
    End While
    yFreeAPI()
  End Sub

End Module
 

23.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.


Imports System.IO
Imports System.Environment

Module Module1

  Sub usage()
    Console.WriteLine("usage: demo <serial or logical name> [ON/OFF]")
    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim m As ymodule

    If (yRegisterHub("usb", errmsg) <> YAPI_SUCCESS) Then
      Console.WriteLine("RegisterHub error:" + errmsg)
      End
    End If

    If argv.Length < 2 Then usage()

    m = yFindModule(argv(1)) REM use serial or logical name
    If (m.isOnline()) Then
      If argv.Length > 2 Then
        If argv(2) = "ON" Then m.set_beacon(Y_BEACON_ON)
        If argv(2) = "OFF" Then m.set_beacon(Y_BEACON_OFF)
      End If
      Console.WriteLine("serial:       " + m.get_serialNumber())
      Console.WriteLine("logical name: " + m.get_logicalName())
      Console.WriteLine("luminosity:   " + Str(m.get_luminosity()))
      Console.Write("beacon:       ")
      If (m.get_beacon() = Y_BEACON_ON) Then
        Console.WriteLine("ON")
      Else
        Console.WriteLine("OFF")
      End If
      Console.WriteLine("upTime:       " + Str(m.get_upTime() / 1000) + " sec")
      Console.WriteLine("USB current:  " + Str(m.get_usbCurrent()) + " mA")
      Console.WriteLine("Logs:")
      Console.WriteLine(m.get_lastLogs())
    Else
      Console.WriteLine(argv(1) + " not connected (check identification and USB cable)")
    End If
    yFreeAPI()
  End Sub

End Module
 

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

Module Module1


  Sub usage()

    Console.WriteLine("usage: demo <serial or logical name> <new logical name>")
    End
  End Sub

  Sub Main()
    Dim argv() As String = System.Environment.GetCommandLineArgs()
    Dim errmsg As String = ""
    Dim newname As String
    Dim m As YModule

    If (argv.Length <> 3) Then usage()

    REM Setup the API to use local USB devices
    If yRegisterHub("usb", errmsg) <> YAPI_SUCCESS Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    m = yFindModule(argv(1)) REM use serial or logical name
    If m.isOnline() Then
      newname = argv(2)
      If (Not yCheckLogicalName(newname)) Then
        Console.WriteLine("Invalid name (" + newname + ")")
        End
      End If
      m.set_logicalName(newname)
      m.saveToFlash() REM do not forget this
      Console.Write("Module: serial= " + m.get_serialNumber)
      Console.Write(" / name= " + m.get_logicalName())
    Else
      Console.Write("not connected (check identification and USB cable")
    End If
    yFreeAPI()

  End Sub

End Module
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not Nothing. Below a short example listing the connected modules.

Module Module1

  Sub Main()
    Dim M As ymodule
    Dim errmsg As String = ""

    REM Setup the API to use local USB devices
    If yRegisterHub("usb", errmsg) <> YAPI_SUCCESS Then
      Console.WriteLine("RegisterHub error: " + errmsg)
      End
    End If

    Console.WriteLine("Device list")
    M = yFirstModule()
    While M IsNot Nothing
      Console.WriteLine(M.get_serialNumber() + " (" + M.get_productName() + ")")
      M = M.nextModule()
    End While
    yFreeAPI()
  End Sub

End Module
 

23.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

24. Using Yocto-Pressure with C#

C# (pronounced C-Sharp) is an object-oriented programming language promoted by Microsoft, it is somewhat similar to Java. Like Visual-Basic and Delphi, it allows you to create Windows applications quite easily. All the examples and the project models are tested with Microsoft C# 2010 Express, freely available on the Microsoft web site67.

Our programming library is also compatible with Mono, the open source version of C# that also works on Linux and MacOS. You will find on our web site various articles that describe how to configure Mono to use our library.

24.1. Installation

Download the Visual C# Yoctopuce library from the Yoctopuce web site68. There is no setup program, simply copy the content of the zip file into the directory of your choice. You mostly need the content of the Sources directory. The other directories contain the documentation and a few sample programs. All sample projects are Visual C# 2010, projects, if you are using a previous version, you may have to recreate the projects structure from scratch.

24.2. Using the Yoctopuce API in a Visual C# project

The Visual C#.NET Yoctopuce library is composed of a DLL and of source files in Visual C#. The DLL is not a .NET DLL, but a classic DLL, written in C, which manages the low level communications with the modules69. The source files in Visual C# manage the high level part of the API. Therefore, your need both this DLL and the .cs files of the sources directory to create a project managing Yoctopuce modules.

Configuring a Visual C# project

The following indications are provided for Visual Studio Express 2010, but the process is similar for other versions. Start by creating your project. Then, on the Solution Explorer panel, right click on your project, and select "Add" and then "Add an existing item".

A file selection window opens. Select the yocto_api.cs file and the files corresponding to the functions of the Yoctopuce modules that your project is going to manage. If in doubt, select all the files.

You then have the choice between simply adding these files to your project, or to add them as links (the Add button is in fact a scroll-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply keeps a link on the original files. We recommend you to use links, which makes updates of the library much easier.

Then add in the same manner the yapi.dll DLL, located in the Sources/dll directory70. Then, from the Solution Explorer window, right click on the DLL, select Properties and in the Properties panel, set the Copy to output folder to always. You are now ready to use your Yoctopuce modules from Visual Studio.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

24.3. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C# code snipplet to use the Temperature function.


[...]
string errmsg ="";
YTemperature temperature;
 
// Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("usb", errmsg);
temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");

// Hot-plug is easy: just check that the device is online
if (temperature.isOnline())
 {  // Use temperature.get_currentValue(); ...
 }

Let's look at these lines in more details.

YAPI.RegisterHub

The YAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI.SUCCESS and errmsg contains the error message.

YTemperature.FindTemperature

The YTemperature.FindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");
temperature = YTemperature.FindTemperature("PRESSMK1-123456.MyFunction");
temperature = YTemperature.FindTemperature("MyModule.temperature");
temperature = YTemperature.FindTemperature("MyModule.MyFunction");
temperature = YTemperature.FindTemperature("MyFunction");

YTemperature.FindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by YTemperature.FindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch Microsoft Visual C# and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine(execname + " <serial_number>");
      Console.WriteLine(execname + " <logical_name>");
      Console.WriteLine(execname + " any  ");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      string errmsg = "";
      string target;

      YPressure psensor;

      if (args.Length < 1) usage();
      target = args[0].ToUpper();

      // Setup the API to use local USB devices
      if (YAPI.RegisterHub("usb", ref errmsg) != YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      if (target == "ANY") {
        psensor = YPressure.FirstPressure();

        if (psensor == null) {
          Console.WriteLine("No module connected (check USB cable) ");
          Environment.Exit(0);
        }
      } else {
        psensor = YPressure.FindPressure(target + ".pressure");
      }

      if (!psensor.isOnline()) {
        Console.WriteLine("Module not connected");
        Console.WriteLine("check identification and USB cable");
        Environment.Exit(0);
      }

      while (psensor.isOnline()) {
        Console.WriteLine("Current pressure: " + psensor.get_currentValue().ToString()
                          + " mbar");
        Console.WriteLine("  (press Ctrl-C to exit)");

        YAPI.Sleep(1000, ref errmsg);
      }
      YAPI.FreeAPI();
    }
  }
}

24.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine(execname + " <serial or logical name> [ON/OFF]");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }


      if (args.Length < 1)  usage();

      m = YModule.FindModule(args[0]); // use serial or logical name

      if (m.isOnline()) {
        if (args.Length >= 2) {
          if (args[1].ToUpper() == "ON") {
            m.set_beacon(YModule.BEACON_ON);
          }
          if (args[1].ToUpper() == "OFF") {
            m.set_beacon(YModule.BEACON_OFF);
          }
        }

        Console.WriteLine("serial:       " + m.get_serialNumber());
        Console.WriteLine("logical name: " + m.get_logicalName());
        Console.WriteLine("luminosity:   " + m.get_luminosity().ToString());
        Console.Write("beacon:       ");
        if (m.get_beacon() == YModule.BEACON_ON)
          Console.WriteLine("ON");
        else
          Console.WriteLine("OFF");
        Console.WriteLine("upTime:       " + (m.get_upTime() / 1000 ).ToString() + " sec");
        Console.WriteLine("USB current:  " + m.get_usbCurrent().ToString() + " mA");
        Console.WriteLine("Logs:\r\n" + m.get_lastLogs());

      } else {
        Console.WriteLine(args[0] + " not connected (check identification and USB cable)");
      }
      YAPI.FreeAPI();
    }
  }
}
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void usage()
    {
      string execname = System.AppDomain.CurrentDomain.FriendlyName;
      Console.WriteLine("Usage:");
      Console.WriteLine("usage: demo <serial or logical name> <new logical name>");
      System.Threading.Thread.Sleep(2500);
      Environment.Exit(0);
    }

    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";
      string newname;

      if (args.Length != 2) usage();

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      m = YModule.FindModule(args[0]); // use serial or logical name

      if (m.isOnline()) {
        newname = args[1];
        if (!YAPI.CheckLogicalName(newname)) {
          Console.WriteLine("Invalid name (" + newname + ")");
          Environment.Exit(0);
        }

        m.set_logicalName(newname);
        m.saveToFlash(); // do not forget this

        Console.Write("Module: serial= " + m.get_serialNumber());
        Console.WriteLine(" / name= " + m.get_logicalName());
      } else {
        Console.Write("not connected (check identification and USB cable");
      }
      YAPI.FreeAPI();
    }
  }
}
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      YModule m;
      string errmsg = "";

      if (YAPI.RegisterHub("usb", ref errmsg) !=  YAPI.SUCCESS) {
        Console.WriteLine("RegisterHub error: " + errmsg);
        Environment.Exit(0);
      }

      Console.WriteLine("Device list");
      m = YModule.FirstModule();
      while (m != null) {
        Console.WriteLine(m.get_serialNumber() + " (" + m.get_productName() + ")");
        m = m.nextModule();
      }
      YAPI.FreeAPI();
    }
  }
}
 

24.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

25. Using the Yocto-Pressure with Universal Windows Platform

Universal Windows Platform (UWP) is not a language per say, but a software platform created by Microsoft. This platform allows you to run a new type of applications: the universal Windows applications. These applications can work on all machines running under Windows 10. This includes computers, tablets, smart phones, XBox One, and also Windows IoT Core.

The Yoctopuce UWP library allows you to use Yoctopuce modules in a universal Windows application and is written in C# in its entirety. You can add it to a Visual Studio 201771 project.

25.1. Blocking and asynchronous functions

The Universal Windows Platform does not use the Win32 API but only the Windows Runtime API which is available on all the versions of Windows 10 and for any architecture. Thanks to this library, you can use UWP on all the Windows 10 versions, including Windows 10 IoT Core.

However, using the new UWP API has some consequences: the Windows Runtime API to access the USB ports is asynchronous, and therefore the Yoctopuce library must be asynchronous as well. Concretely, the asynchronous methods do not return a result directly but a Task or Task<> object and the result can be obtained later. Fortunately, the C# language, version 6, supports the async and await keywords, which simplifies using these functions enormously. You can thus use asynchronous functions in the same way as traditional functions as long as you respect the following two rules:

Example:

async Task<int> MyFunction(int  val)
{
    // do some long computation
    ...

    return result;
}

int res = await MyFunction(1234);
Our library follows these two rules and can therefore use the await notation.

For you not to have to wonder wether a function is asynchronous or not, there is the following convention: all the public methods of the UWP library are asynchronous, that is that you must call them with the await keyword, except:

25.2. Installation

Download the Yoctopuce library for Universal Windows Platform from the Yoctopuce web site72. There is no installation software, simply copy the content of the zip file in a directory of your choice. You essentially need the content of the Sources directory. The other directories contain documentation and a few sample programs. Sample projects are Visual Studio 2017 projects. Visual Studio 2017 is available on the Microsoft web site73.

25.3. Using the Yoctopuce API in a Visual Studio project

Start by creating your project. Then, from the Solution Explorer panel right click on your project and select Add then Existing element .

A file chooser opens: select all the files in the library Sources directory.

You then have the choice between simply adding the files to your project or adding them as a link (the Add button is actually a drop-down menu). In the first case, Visual Studio copies the selected files into your project. In the second case, Visual Studio simply creates a link to the original files. We recommend to use links, as a potential library update is thus much easier.

The Package.appxmanifest file

By default a Universal Windows application doesn't have access rights to the USB ports. If you want to access USB devices, you must imperatively declare it in the Package.appxmanifest file.

Unfortunately, the edition window of this file doesn't allow this operation and you must modify the Package.appxmanifest file by hand. In the "Solution Explorer" panel, right click on the Package.appxmanifest and select "View Code".

In this XML file, we must add a DeviceCapability node in the Capabilities node. This node must have a "Name" attribute with a "humaninterfacedevice" value.

Inside this node, you must declare all the modules that can be used. Concretely, for each module, you must add a "Device" node with an "Id" attribute, which has for value a character string "vidpid:USB_VENDORID USB_DEVICE_ID". The Yoctopuce USB_VENDORID is 24e0 and you can find the USB_DEVICE_ID of each Yoctopuce device in the documentation in the "Characteristics" section. Finally, the "Device" node must contain a "Function" node with the "Type" attribute with a value of "usage:ff00 0001".

For the Yocto-Pressure, here is what you must add in the "Capabilities" node:


  <DeviceCapability Name="humaninterfacedevice">
      <!-- Yocto-Pressure -->
      <Device Id="vidpid:24e0 0075">
        <Function Type="usage:ff00 0001" />
      </Device>
    </DeviceCapability>

Unfortunately, it's not possible to write a rule authorizing all Yoctopuce modules. Therefore, you must imperatively add each module that you want to use.

25.4. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a C# code snippet to use the Temperature function.


[...]

await YAPI.RegisterHub("usb");
temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");

//To manage hot-plug, we check that the module is here
if (await temperature.isOnline()) {
        //Use temperature.get_currentValue()
     ...
}

[...]

Let us look at these lines in more details.

YAPI.RegisterHub

The YAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. The parameter is the address of the virtual hub able to see the devices. If the string "usb" is passed as parameter, the API works with modules locally connected to the machine. If the initialization does not succeed, an exception is thrown.

YTemperature.FindTemperature

The YTemperature.FindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");
temperature = YTemperature.FindTemperature("PRESSMK1-123456.MaFonction");
temperature = YTemperature.FindTemperature("MonModule.temperature");
temperature = YTemperature.FindTemperature("MonModule.MaFonction");
temperature = YTemperature.FindTemperature("MaFonction");

YTemperature.FindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by YTemperature.FindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

25.5. A real example

Launch Visual Studio and open the corresponding project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

Visual Studio projects contain numerous files, and most of them are not linked to the use of the Yoctopuce library. To simplify reading the code, we regrouped all the code that uses the library in the Demo class, located in the demo.cs file. Properties of this class correspond to the different fields displayed on the screen, and the Run() method contains the code which is run when the "Start" button is pushed.

In this example, you can recognize the functions explained above, but this time used with all the side materials needed to make it work nicely as a small demo.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {
    public string HubURL { get; set; }
    public string Target { get; set; }

    public override async Task<int> Run()
    {
      try {
        await YAPI.RegisterHub(HubURL);

        YPressure psensor;

        if (Target.ToLower() == "any") {
          psensor = YPressure.FirstPressure();

          if (psensor == null) {
            WriteLine("No module connected (check USB cable) ");
            return -1;
          }
        } else {
          psensor = YPressure.FindPressure(Target + ".pressure");
        }

        while (await psensor.isOnline()) {
          WriteLine("Pressure: " + await psensor.get_currentValue() + " mbar");
          await YAPI.Sleep(1000);
        }

        WriteLine("Module not connected (check identification and USB cable)");
      } catch (YAPI_Exception ex) {
        WriteLine("error: " + ex.Message);
      }

      YAPI.FreeAPI();
      return 0;
    }
  }
}

25.6. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {

    public string HubURL { get; set; }
    public string Target { get; set; }
    public bool Beacon { get; set; }

    public override async Task<int> Run()
    {
      YModule m;
      string errmsg = "";

      if (await YAPI.RegisterHub(HubURL) != YAPI.SUCCESS) {
        WriteLine("RegisterHub error: " + errmsg);
        return -1;
      }
      m = YModule.FindModule(Target + ".module"); // use serial or logical name
      if (await m.isOnline()) {
        if (Beacon) {
          await m.set_beacon(YModule.BEACON_ON);
        } else {
          await m.set_beacon(YModule.BEACON_OFF);
        }

        WriteLine("serial: " + await m.get_serialNumber());
        WriteLine("logical name: " + await m.get_logicalName());
        WriteLine("luminosity: " + await m.get_luminosity());
        Write("beacon: ");
        if (await m.get_beacon() == YModule.BEACON_ON)
          WriteLine("ON");
        else
          WriteLine("OFF");
        WriteLine("upTime: " + (await m.get_upTime() / 1000) + " sec");
        WriteLine("USB current: " + await m.get_usbCurrent() + " mA");
        WriteLine("Logs:\r\n" + await m.get_lastLogs());
      } else {
        WriteLine(Target + " not connected  on" + HubURL +
                  "(check identification and USB cable)");
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {

    public string HubURL { get; set; }
    public string Target { get; set; }
    public string LogicalName { get; set; }

    public override async Task<int> Run()
    {
      try {
        YModule m;

        await YAPI.RegisterHub(HubURL);

        m = YModule.FindModule(Target); // use serial or logical name
        if (await m.isOnline()) {
          if (!YAPI.CheckLogicalName(LogicalName)) {
            WriteLine("Invalid name (" + LogicalName + ")");
            return -1;
          }

          await m.set_logicalName(LogicalName);
          await m.saveToFlash(); // do not forget this
          Write("Module: serial= " + await m.get_serialNumber());
          WriteLine(" / name= " + await m.get_logicalName());
        } else {
          Write("not connected (check identification and USB cable");
        }
      } catch (YAPI_Exception ex) {
        WriteLine("RegisterHub error: " + ex.Message);
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using com.yoctopuce.YoctoAPI;

namespace Demo
{
  public class Demo : DemoBase
  {
    public string HubURL { get; set; }

    public override async Task<int> Run()
    {
      YModule m;
      try {
        await YAPI.RegisterHub(HubURL);

        WriteLine("Device list");
        m = YModule.FirstModule();
        while (m != null) {
          WriteLine(await m.get_serialNumber()
                    + " (" + await m.get_productName() + ")");
          m = m.nextModule();
        }
      } catch (YAPI_Exception ex) {
        WriteLine("Error:" + ex.Message);
      }
      YAPI.FreeAPI();
      return 0;
    }
  }
}

25.7. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software.

In the Universal Windows Platform library, error handling is implemented with exceptions. You must therefore intercept and correctly handle these exceptions if you want to have a reliable project which does not crash as soon as you disconnect a module.

Library thrown exceptions are always of the YAPI_Exception type, so you can easily separate them from other exceptions in a try{...} catch{...} block.

Example:


try {
        ....
} catch (YAPI_Exception ex) {
        Debug.WriteLine("Exception from Yoctopuce lib:" + ex.Message);
} catch (Exception ex) {
        Debug.WriteLine("Other exceptions :" + ex.Message);
}

26. Using Yocto-Pressure with Delphi

Delphi is a descendent of Turbo-Pascal. Originally, Delphi was produced by Borland, Embarcadero now edits it. The strength of this language resides in its ease of use, as anyone with some notions of the Pascal language can develop a Windows application in next to no time. Its only disadvantage is to cost something74.

Delphi libraries are provided not as VCL components, but directly as source files. These files are compatible with most Delphi versions. 75

To keep them simple, all the examples provided in this documentation are console applications. Obviously, the libraries work in a strictly identical way with VCL applications.

You will soon notice that the Delphi API defines many functions which return objects. You do not need to deallocate these objects yourself, the API does it automatically at the end of the application.

26.1. Preparation

Go to the Yoctopuce web site and download the Yoctopuce Delphi libraries76. Uncompress everything in a directory of your choice, add the subdirectory sources in the list of directories of Delphi libraries.77

By default, the Yoctopuce Delphi library uses the yapi.dll DLL, all the applications you will create with Delphi must have access to this DLL. The simplest way to ensure this is to make sure yapi.dll is located in the same directory as the executable file of your application.

26.2. Control of the Temperature function

Launch your Delphi environment, copy the yapi.dll DLL in a directory, create a new console application in the same directory, and copy-paste the piece of code below:

program helloworld;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  Windows,
  yocto_api,
  yocto_pressure;

Procedure  Usage();
  var
    exe : string;
  begin
    exe:= ExtractFileName(paramstr(0));
    WriteLn(exe+' <serial_number>');
    WriteLn(exe+' <logical_name>');
    WriteLn(exe+' any');
    halt;
  End;

var
  sensor : TYTemperature;
  errmsg : string;
  done   : boolean;

begin

  if (paramcount<1) then usage();

  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  if paramstr(1)='any' then
    begin
      // try to find  the first pressure sensor available
      sensor := yFirstPressure();
      if sensor=nil then
         begin
           writeln('No module connected (check USB cable)');
           halt;
         end
       end
   else  // or use the one specified on the commande line
    sensor:= yFindPressure(paramstr(1)+'.pressure');

  // let's poll
  done := false;
  repeat
    if (sensor.isOnline()) then
     begin
       Write('Current pressure: '+FloatToStr(sensor.get_currentValue())+' mbar');
       Writeln('   (press Ctrl-C to exit)');
       Sleep(1000);
     end
    else
     begin
       Writeln('Module not connected (check identification and USB cable)');
       done := true;
     end;
  until done;
  yFreeAPI();
end.

There are only a few really important lines in this sample example. We will look at them in details.

yocto_api and yocto_temperature

These two units provide access to the functions allowing you to manage Yoctopuce modules. yocto_api must always be used, yocto_temperature is necessary to manage modules containing a temperature sensor, such as Yocto-Pressure.

yRegisterHub

The yRegisterHub function initializes the Yoctopuce API and specifies where the modules should be looked for. When used with the parameter 'usb', it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI_SUCCESS and errmsg contains the error message.

yFindTemperature

The yFindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can also use logical names, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature := yFindTemperature("PRESSMK1-123456.temperature");
temperature := yFindTemperature("PRESSMK1-123456.MyFunction");
temperature := yFindTemperature("MyModule.temperature");
temperature := yFindTemperature("MyModule.MyFunction");
temperature := yFindTemperature("MyFunction");

yFindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by yFindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by yFindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibar.

26.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

program modulecontrol;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

const
  serial = 'PRESSMK1-123456'; // use serial number or logical name

procedure refresh(module:Tymodule) ;
  begin
    if (module.isOnline())  then
     begin
       Writeln('');
       Writeln('Serial       : ' + module.get_serialNumber());
       Writeln('Logical name : ' + module.get_logicalName());
       Writeln('Luminosity   : ' + intToStr(module.get_luminosity()));
       Write('Beacon    :');
       if  (module.get_beacon()=Y_BEACON_ON) then Writeln('on')
                                             else Writeln('off');
       Writeln('uptime       : ' + intToStr(module.get_upTime() div 1000)+'s');
       Writeln('USB current  : ' + intToStr(module.get_usbCurrent())+'mA');
       Writeln('Logs         : ');
       Writeln(module.get_lastlogs());
       Writeln('');
       Writeln('r : refresh / b:beacon ON / space : beacon off');
     end
    else Writeln('Module not connected (check identification and USB cable)');
  end;


procedure beacon(module:Tymodule;state:integer);
  begin
    module.set_beacon(state);
    refresh(module);
  end;

var
  module : TYModule;
  c      : char;
  errmsg : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  module := yFindModule(serial);
  refresh(module);

  repeat
    read(c);
    case c of
     'r': refresh(module);
     'b': beacon(module,Y_BEACON_ON);
     ' ': beacon(module,Y_BEACON_OFF);
    end;
  until  c = 'x';
  yFreeAPI();
end.

Each property xxx of the module can be read thanks to a method of type get_xxxx(), and properties which are not read-only can be modified with the help of the set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the revertFromFlash() method. The short example below allows you to modify the logical name of a module.

program savesettings;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

const
  serial = 'PRESSMK1-123456'; // use serial number or logical name

var
  module  : TYModule;
  errmsg  : string;
  newname : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  module := yFindModule(serial);
  if (not(module.isOnline)) then
   begin
     writeln('Module not connected (check identification and USB cable)');
     exit;
   end;

  Writeln('Current logical name : '+module.get_logicalName());
  Write('Enter new name : ');
  Readln(newname);
  if (not(yCheckLogicalName(newname))) then
   begin
     Writeln('invalid logical name');
     exit;
   end;
  module.set_logicalName(newname);
  module.saveToFlash();
  yFreeAPI();
  Writeln('logical name is now : '+module.get_logicalName());
end.
 

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not nil. Below a short example listing the connected modules.

program inventory;
{$APPTYPE CONSOLE}
uses
  SysUtils,
  yocto_api;

var
  module : TYModule;
  errmsg : string;

begin
  // Setup the API to use local USB devices
  if yRegisterHub('usb', errmsg)<>YAPI_SUCCESS then
  begin
    Write('RegisterHub error: '+errmsg);
    exit;
  end;

  Writeln('Device list');

  module := yFirstModule();
  while module<>nil  do
   begin
     Writeln( module.get_serialNumber()+' ('+module.get_productName()+')');
     module := module.nextModule();
   end;
  yFreeAPI();

end.

26.4. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

27. Using the Yocto-Pressure with Python

Python is an interpreted object oriented language developed by Guido van Rossum. Among its advantages is the fact that it is free, and the fact that it is available for most platforms, Windows as well as UNIX. It is an ideal language to write small scripts on a napkin. The Yoctopuce library is compatible with Python 2.6+ and 3+. It works under Windows, Mac OS X, and Linux, Intel as well as ARM. The library was tested with Python 2.6 and Python 3.2. Python interpreters are available on the Python web site78.

27.1. Source files

The Yoctopuce library classes79 for Python that you will use are provided as source files. Copy all the content of the Sources directory in the directory of your choice and add this directory to the PYTHONPATH environment variable. If you use an IDE to program in Python, refer to its documentation to configure it so that it automatically finds the API source files.

27.2. Dynamic library

A section of the low-level library is written in C, but you should not need to interact directly with it: it is provided as a DLL under Windows, as a .so files under UNIX, and as a .dylib file under Mac OS X. Everything was done to ensure the simplest possible interaction from Python: the distinct versions of the dynamic library corresponding to the distinct operating systems and architectures are stored in the cdll directory. The API automatically loads the correct file during its initialization. You should not have to worry about it.

If you ever need to recompile the dynamic library, its complete source code is located in the Yoctopuce C++ library.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

27.3. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Python code snipplet to use the Temperature function.


[...]

errmsg=YRefParam()
#Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("usb",errmsg)
temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature")

# Hot-plug is easy: just check that the device is online
if temperature.isOnline():
    #Use temperature.get_currentValue()
    ...
   
[...]    

Let's look at these lines in more details.

YAPI.RegisterHub

The yAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. When used with the parameter "usb", it will use the modules locally connected to the computer running the library. If the initialization does not succeed, this function returns a value different from YAPI.SUCCESS and errmsg contains the error message.

YTemperature.FindTemperature

The YTemperature.FindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature")
temperature = YTemperature.FindTemperature("PRESSMK1-123456.MyFunction")
temperature = YTemperature.FindTemperature("MyModule.temperature")
temperature = YTemperature.FindTemperature("MyModule.MyFunction")
temperature = YTemperature.FindTemperature("MyFunction")

YTemperature.FindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by YTemperature.FindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch Python and open the corresponding sample script provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all side materials needed to make it work nicely as a small demo.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *
from yocto_pressure import *


def usage():
    scriptname = os.path.basename(sys.argv[0])
    print("Usage:")
    print(scriptname + ' <serial_number>')
    print(scriptname + ' <logical_name>')
    print(scriptname + ' any  ')
    sys.exit()


def die(msg):
    sys.exit(msg + ' (check USB cable)')


errmsg = YRefParam()

if len(sys.argv) < 2:
    usage()

target = sys.argv[1]

# Setup the API to use local USB devices
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("init error" + errmsg.value)

if target == 'any':
    # retreive any pressure sensor
    sensor = YPressure.FirstPressure()
    if sensor is None:
        die('No module connected')
else:
    sensor = YPressure.FindPressure(target + '.pressure')

if not (sensor.isOnline()):
    die('device not connected')

while sensor.isOnline():
    print("Pressure :  " + "%2.1f" % sensor.get_currentValue() + "mbar (Ctrl-C to stop)")
    YAPI.Sleep(1000)
YAPI.FreeAPI()
 

27.4. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *


def usage():
    sys.exit("usage: demo <serial or logical name> [ON/OFF]")


errmsg = YRefParam()
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("RegisterHub error: " + str(errmsg))

if len(sys.argv) < 2:
    usage()

m = YModule.FindModule(sys.argv[1])  # # use serial or logical name

if m.isOnline():
    if len(sys.argv) > 2:
        if sys.argv[2].upper() == "ON":
            m.set_beacon(YModule.BEACON_ON)
        if sys.argv[2].upper() == "OFF":
            m.set_beacon(YModule.BEACON_OFF)

    print("serial:       " + m.get_serialNumber())
    print("logical name: " + m.get_logicalName())
    print("luminosity:   " + str(m.get_luminosity()))
    if m.get_beacon() == YModule.BEACON_ON:
        print("beacon:       ON")
    else:
        print("beacon:       OFF")
    print("upTime:       " + str(m.get_upTime() / 1000) + " sec")
    print("USB current:  " + str(m.get_usbCurrent()) + " mA")
    print("logs:\n" + m.get_lastLogs())
else:
    print(sys.argv[1] + " not connected (check identification and USB cable)")
YAPI.FreeAPI()
 

Each property xxx of the module can be read thanks to a method of type YModule.get_xxxx(), and properties which are not read-only can be modified with the help of the YModule.set_xxx() method. For more details regarding the used functions, refer to the API chapters.

Changing the module settings

When you want to modify the settings of a module, you only need to call the corresponding YModule.set_xxx() function. However, this modification is performed only in the random access memory (RAM) of the module: if the module is restarted, the modifications are lost. To memorize them persistently, it is necessary to ask the module to save its current configuration in its permanent memory. To do so, use the YModule.saveToFlash() method. Inversely, it is possible to force the module to forget its current settings by using the YModule.revertFromFlash() method. The short example below allows you to modify the logical name of a module.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys

from yocto_api import *


def usage():
    sys.exit("usage: demo <serial or logical name> <new logical name>")


if len(sys.argv) != 3:
    usage()

errmsg = YRefParam()
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("RegisterHub error: " + str(errmsg))

m = YModule.FindModule(sys.argv[1])  # use serial or logical name
if m.isOnline():
    newname = sys.argv[2]
    if not YAPI.CheckLogicalName(newname):
        sys.exit("Invalid name (" + newname + ")")
    m.set_logicalName(newname)
    m.saveToFlash()  # do not forget this
    print("Module: serial= " + m.get_serialNumber() + " / name= " + m.get_logicalName())
else:
    sys.exit("not connected (check identification and USB cable")
YAPI.FreeAPI()

Warning: the number of write cycles of the nonvolatile memory of the module is limited. When this limit is reached, nothing guaranties that the saving process is performed correctly. This limit, linked to the technology employed by the module micro-processor, is located at about 100000 cycles. In short, you can use the YModule.saveToFlash() function only 100000 times in the life of the module. Make sure you do not call this function within a loop.

Listing the modules

Obtaining the list of the connected modules is performed with the YModule.yFirstModule() function which returns the first module found. Then, you only need to call the nextModule() function of this object to find the following modules, and this as long as the returned value is not null. Below a short example listing the connected modules.

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os, sys


from yocto_api import *

errmsg = YRefParam()

# Setup the API to use local USB devices
if YAPI.RegisterHub("usb", errmsg) != YAPI.SUCCESS:
    sys.exit("init error" + str(errmsg))

print('Device list')

module = YModule.FirstModule()
while module is not None:
    print(module.get_serialNumber() + ' (' + module.get_productName() + ')')
    module = module.nextModule()
YAPI.FreeAPI()

27.5. Error handling

When you implement a program which must interact with USB modules, you cannot disregard error handling. Inevitably, there will be a time when a user will have unplugged the device, either before running the software, or even while the software is running. The Yoctopuce library is designed to help you support this kind of behavior, but your code must nevertheless be conceived to interpret in the best possible way the errors indicated by the library.

The simplest way to work around the problem is the one used in the short examples provided in this chapter: before accessing a module, check that it is online with the isOnline function, and then hope that it will stay so during the fraction of a second necessary for the following code lines to run. This method is not perfect, but it can be sufficient in some cases. You must however be aware that you cannot completely exclude an error which would occur after the call to isOnline and which could crash the software. The only way to prevent this is to implement one of the two error handling techniques described below.

The method recommended by most programming languages for unpredictable error handling is the use of exceptions. By default, it is the behavior of the Yoctopuce library. If an error happens while you try to access a module, the library throws an exception. In this case, there are three possibilities:

As this latest situation is not the most desirable, the Yoctopuce library offers another possibility for error handling, allowing you to create a robust program without needing to catch exceptions at every line of code. You simply need to call the YAPI.DisableExceptions() function to commute the library to a mode where exceptions for all the functions are systematically replaced by specific return values, which can be tested by the caller when necessary. For each function, the name of each return value in case of error is systematically documented in the library reference. The name always follows the same logic: a get_state() method returns a Y_STATE_INVALID value, a get_currentValue method returns a Y_CURRENTVALUE_INVALID value, and so on. In any case, the returned value is of the expected type and is not a null pointer which would risk crashing your program. At worst, if you display the value without testing it, it will be outside the expected bounds for the returned value. In the case of functions which do not normally return information, the return value is YAPI_SUCCESS if everything went well, and a different error code in case of failure.

When you work without exceptions, you can obtain an error code and an error message explaining the source of the error. You can request them from the object which returned the error, calling the errType() and errMessage() methods. Their returned values contain the same information as in the exceptions when they are active.

28. Using the Yocto-Pressure with Java

Java is an object oriented language created by Sun Microsystem. Beside being free, its main strength is its portability. Unfortunately, this portability has an excruciating price. In Java, hardware abstraction is so high that it is almost impossible to work directly with the hardware. Therefore, the Yoctopuce API does not support native mode in regular Java. The Java API needs a Virtual Hub to communicate with Yoctopuce devices.

28.1. Getting ready

Go to the Yoctopuce web site and download the following items:

The library is available as source files as well as a jar file. Decompress the library files in a folder of your choice, connect your modules, run the VirtualHub software, and you are ready to start your first tests. You do not need to install any driver.

In order to keep them simple, all the examples provided in this documentation are console applications. Naturally, the libraries function in a strictly identical manner if you integrate them in an application with a graphical interface.

28.2. Control of the Temperature function

A few lines of code are enough to use a Yocto-Pressure. Here is the skeleton of a Java code snippet to use the Temperature function.


[...]

// Get access to your device, connected locally on USB for instance
YAPI.RegisterHub("127.0.0.1");
temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature");

// Hot-plug is easy: just check that the device is online
if (temperature.isOnline())
{    
    // Use temperature.get_currentValue()
    [...]
}

[...]

Let us look at these lines in more details.

YAPI.RegisterHub

The yAPI.RegisterHub function initializes the Yoctopuce API and indicates where the modules should be looked for. The parameter is the address of the Virtual Hub able to see the devices. If the initialization does not succeed, an exception is thrown.

YTemperature.FindTemperature

The YTemperature.FindTemperature function allows you to find a temperature sensor from the serial number of the module on which it resides and from its function name. You can use logical names as well, as long as you have initialized them. Let us imagine a Yocto-Pressure module with serial number PRESSMK1-123456 which you have named "MyModule", and for which you have given the temperature function the name "MyFunction". The following five calls are strictly equivalent, as long as "MyFunction" is defined only once.


temperature = YTemperature.FindTemperature("PRESSMK1-123456.temperature")
temperature = YTemperature.FindTemperature("PRESSMK1-123456.MyFunction")
temperature = YTemperature.FindTemperature("MyModule.temperature")
temperature = YTemperature.FindTemperature("MyModule.MyFunction")
temperature = YTemperature.FindTemperature("MyFunction")

YTemperature.FindTemperature returns an object which you can then use at will to control the temperature sensor.

isOnline

The isOnline() method of the object returned by YTemperature.FindTemperature allows you to know if the corresponding module is present and in working order.

get_currentValue

The get_currentValue() method of the object returned by YPressure.FindPressure provides the pressure currently measured by the sensor. The value returned is a floating number, equal to the current number millibars.

A real example

Launch you Java environment and open the corresponding sample project provided in the directory Examples/Doc-GettingStarted-Yocto-Pressure of the Yoctopuce library.

In this example, you will recognize the functions explained above, but this time used with all the side materials needed to make it work nicely as a small demo.

import com.yoctopuce.YoctoAPI.*;

public class Demo {

    public static void main(String[] args)   {
        try {
            // setup the API to use local VirtualHub
            YAPI.RegisterHub("127.0.0.1");
        } catch (YAPI_Exception ex) {
            System.out.println("Cannot contact VirtualHub on 127.0.0.1 (" + ex.getLocalizedMessage() + ")");
            System.out.println("Ensure that the VirtualHub application is running");
            System.exit(1);
        }
        YPressure psensor;

        if (args.length == 0) {
            psensor = YPressure.FirstPressure();
            if (psensor == null) {
                System.out.println("No module connected (check USB cable)");
                System.exit(1);
            }
        } else {
            psensor = YPressure.FindPressure(args[0] + ".pressure");
        }

        while (true) {
            try {
                System.out.println("Current pressure: " + psensor.get_currentValue() + " mbar");
                System.out.println("  (press Ctrl-C to exit)");
                YAPI.Sleep(1000);
            } catch (YAPI_Exception ex) {
                System.out.println("Module not connected (check identification and USB cable)");
                break;
            }
        }

        YAPI.FreeAPI();
    }
}
 

28.3. Control of the module part

Each module can be controlled in a similar manner, you can find below a simple sample program displaying the main parameters of the module and enabling you to activate the localization beacon.


import com.yoctopuce.YoctoAPI.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Demo {

    public static void main(