Spacecode SDK Introduction Getting Started Device Tags Access Control Temperature Alert System Data Serialization

Introduction

This document is meant to be an overview of all the capabilities of the Spacecode SDK (Software Development Kit) and the best practices to leverage those capabilities. It is organized around the four major features the SDK delivers: The SDK is currently available for Java (local and remote devices) and Javascript (remote devices). A Python and a C++ versions will be available in a near future.

Getting Started

Requirements

Operating Systems

Others

Consider downloading and installing the following (optional) dependencies: *Most of the modern GNU/Linux distributions have the CONFIG_USB_SERIAL_FTDI_SIO module enabled by default.

Download

Device

Communication

Spacecode Devices can be operated in two ways: Some products are designed to use only one. Devices capable of using both are, in most cases, always using the same. Connecting with a local device is slightly different from connecting with a remote device.

Connection

Local Devices

A local device can be connected using its serial number and/or a serial port name. Serial port names are formatted differently according to the operating system:
Operating System Serial Port Name
Windows COM1 (COM2, COM3...)
GNU/Linux /dev/ttyUSB0 (/dev/ttyUSB1, /dev/ttyUSB2...)
Mac OS X /dev/tty.usbX ("X": serial number or location depending of the USB port)
If no serial port name is given, all serial ports available are tested. The connection can require more time.
Device localDevice;

try {
    // look on all serial ports for the device "AA7708950"
    localDevice = new Device("AA7708950");
} catch (DeviceCreationException dce) {
    // connection failed, handle exception
}
Device localDevice;

try {
    // connect any device using ttyUSB0
    localDevice = new Device(null, "/dev/ttyUSB0");
} catch (DeviceCreationException dce) {
    // connection failed, handle exception
}
Device localDevice;

try {
    // connect the device "AA7708950" using ttyUSB0
    localDevice = new Device("AA7708950", "/dev/ttyUSB0");
} catch (DeviceCreationException dce) {
    // connection failed, handle exception
}

Find Local Devices

The static method getPluggedDevices allows getting details about each local device plugged to the current computer. This method is useful when the device(s) to be used is (are) not identified.
Map<String, PluggedDevice> serialNbrToDev = Device.getPluggedDevices();

for(PluggedDevice pd : serialNbrToDev.values())
{
    System.out.println(String.format("%s on port %s", pd.getSerialNumber(), pd.getSerialPort()));
}

Remote Devices

Java Javascript
Connections to remote devices are established with their IP address. If the TCP port used by SmartServer has been changed, it must be defined as a second parameter of the TcpDevice constructor call.
Device remoteDevice;

try {
    // connect the device which IP address is "192.168.1.20"
    remoteDevice  = new TcpDevice("192.168.1.20");
} catch (DeviceCreationException dce) {
    // connection failed, handle exception
}
DeviceCreationExceptions raised by the constructors always provide the reason of the failure.
As the JavaScript API is only available for the remote devices, there is only one class Device, which is instantiated with the IP address of the device. The TCP port used for the network communication cannot be changed.
/** @type {Device} */
var device = new Device("192.168.1.20");
// [...]: Subscribe to events (see Events section below)
device.connect();
The result of the method connect is only known later, by listening to Events.

Disconnection

Java Javascript
Releasing a local device or disconnecting from a remote device is done by calling the method release.
device.release();
Disconnecting a client is done by calling the method release.
// close the connection to the remote device
device.release();

Scans

Java Javascript
As TcpDevice class extends Device, most of the features available in Device can be executed transparently with an instance of TcpDevice. Starting a scan can be done as follows:
device.requestScan();
The scan process is asynchronous: the method requestScan does not block the calling thread.
To get the inventory resulting of a scan, an event listener has to be defined.

The method stopScan allows interrupting a scan operation before it ends.
The class Device proposes a method requestScan to send a scan order to the remote device.
device.requestScan();
The result of the operation is known by subscribing to some events, described in the next section.

The method stopScan allows interrupting a scan operation before it ends.

Events

Java Javascript
There are eight types of events which can be implemented with a dedicated interface:
Interface Events
BasicEventHandler Device‘s basic events, common to all types of devices.
ScanEventHandler Scan started, completed, tag detected, ...
DoorEventHandler Door opened, closed, ...
AccessControlEventHandler Authentication successful, authentication failure, ...
AccessModuleEventHandler Badge reader connected, fingerprint reader touched, ...
LedEventHandler Tags LED lighting started, stopped
TemperatureEventHandler New temperature measurement
AlertEventHandler New alert sent by the remote device
Each interface provide as few events as possible. In most cases, an event listener implements only a couple of events, keeping the code clear and modular.
Device and TcpDevice accept event listeners as follows:
device.addListener(new DemoEventHandler());
Two of the eight interfaces implemented as an example:
public class DemoEventHandler implements BasicEventHandler, DoorEventHandler
{
    @Override
    public void deviceDisconnected()
    {
        // BasicEventHandler
        System.out.println("Device disconnected.");
    }

    @Override
    public void deviceStatusChanged(DeviceStatus status)
    {
        // BasicEventHandler
        System.out.println("Device status: "+status);
    }

    @Override
    public void doorOpened()
    {
        // DoorEventHandler
        System.out.println("Door opened.");
    }

    @Override
    public void doorClosed()
    {
        // DoorEventHandler
        System.out.println("Door closed.");
    }

    @Override
    public void doorOpenDelay()
    {
        // DoorEventHandler
        System.out.println("Door open for too long.");
    }

    @Override
    public void scanCancelledByDoor()
    {
        // DoorEventHandler
        System.out.println("Scan cancelled by door.");
    }
}
Doing time-consuming tasks in an implementation of event listeners is highly discouraged. Events are executed by an internal thread pool with a limited number of threads (for performance reasons) which should not be blocked.
In order to handle the scan result (see Scans), we can either:
// [...] other events from ScanEventHandler have been hidden

@Override
public void scanStarted()
{
    System.out.println("Scan started!");
}

@Override
public void scanCompleted()
{
    // the inventory (resulting from the scan) is ready
    System.out.println("Scan completed!");
}

@Override
public void tagAdded(String tagUid)
{
    // a tag has been detected during the scan
    System.out.println(String.format("Tag scanned: %s", tagUid));
}
AbstractEventHandler allows shortening these implementations by implementing only the desired events in an anonymous class:
device.addListener(new AbstractEventHandler()
{
    // from ScanEventHandler
    @Override
    public void scanCompleted()
    {
        // ask to light all the tags detected during the last scan
        device.startLightingTagsLed(_currentDevice.getLastInventory().getTagsAll());
    }

    // from LedEventHandler
    @Override
    public void lightingStarted(List missingTags)
    {
        System.out.println("Lighting started!");
    }
});
An event listener can be removed (and thus, disabled) by calling the method removeListener
The class Device emits some Events to which callbacks can be attached, with the method on.
device.on('connected', function ()
{
    if(device.isInitialized())
    {
        // Connection with the remote device established
        console.log('Connected to Device: '+ device.getDeviceType() + ' ('+device.getSerialNumber()+')');
    }
});

device.on('disconnected', function ()
{
    if(device.isInitialized())
    {
        // The connection to the remote device has been lost
        console.log(device.getSerialNumber() + ' - Disconnected');
        return;
    }
});

device.on('scanstarted', function ()
{
    console.log("Scan started.");
});

device.on('scancompleted', function ()
{
    // the inventory (resulting from the scan) is ready
    console.log("Scan completed.");
});

device.on('tagadded', function (tagUid)
{
    // a tag has been detected during the scan
    console.log("Tag scanned: "+ tagUid);
});

// [...]
The method isInitialized guarantees that the device data (serial number, device type...) has been initialized.
Any callback (function) attached to an event can be removed with the method off.
In the following example, we use off to make sure that our callback is executed only once.
// add the named function expression 'f' to the event 'connected' listeners.
device.on('connected', function f()
{
    // call the function 'doSomething' once the device is connected
    doSomething();

    // and remove the event listener
    device.off('connected', f);
});
The above code can be simplified using the method one. The given callback is automatically removed from the listeners once it has been executed.
device.one('connected', function()
{
    // call the function 'doSomething' once the device is connected
    doSomething();
});

Inventories

Items

Java Javascript
Once a scan is completed (see event scanCompleted), the inventory resulting from the operation can be consulted with the method getLastInventory.
// Note: with remote devices, getLastInventory can return 'null' in case of communication errors
Inventory inventory = device.getLastInventory();
System.out.println(String.format("%d tags have been scanned.", inventory.getNumberTotal());
// prints: "X tags have been scanned." (with X the result of getNumberTotal)
Once a scan is completed (see event scancompleted), the inventory resulting from the operation can be consulted with the method getLastInventory.
device.getLastInventory(function(inventory)
{
    // Note: with remote devices, getLastInventory can return 'null' in case of communication errors
    console.log(inventory.getNumberTotal() +" tags have been scanned.");
    // prints: "X tags have been scanned." (with X the result of getNumberTotal)
});
In an inventory, each tag (identified by its UID) has a state. This state can take the following values:
State Definition
Present The tag has already been scanned during the previous scan (if any previous scan exists)
Added The tag has not been scanned before: it is considered as new
Removed The tag has been scanned in the previous scan, but not this time: it has been removed
The following process describes the evolution of tags states in two scans. The first inventory results in a list of Added tags: all tags are "new" as there was no previous scan. Before the second scan, TAG0003 is removed from the device, and TAG0004 is added. In the second inventory, TAG0001 and TAG0002 are still Present. TAG0003 is Removed and TAG0004 is Added.
1st Scan
Device
TAG0001
TAG0002
TAG0003
 
Result
Inventory
TAG0001
TAG0002
TAG0003
 
2nd Scan
Device
TAG0001
TAG0002
 
TAG0004
Result
Inventory
TAG0001
TAG0002
TAG0003
TAG0004
To get the list of tags scanned or removed, the Inventory class provides the following methods:
Method Description
getTagsAll Provide the list of Added and Present tags (TAG0001, TAG0002, TAG0004)
getTagsAdded Provide the list of Added tags (TAG0004)
getTagsPresent Provide the list of Present tags (TAG0001, TAG0002)
getTagsRemoved Provide the list of Removed tags (TAG0003)

Automatic Scans

Scan operations can be started either manually (through a software), or automatically when the door(s) (if any) of the device get closed. If a user authenticated himself to open the device, the inventory resulting from the automatic scan contains additional details:
Information Description Type
Username Who opened the device and is responsible for this new inventory? String
Access Type How did the user open the device? (Badge, Fingerprint) AccessType
Door Number Which door has been closed? (0: master door, 1: slave) int
AccessType enumeration contains three values:
Value Description Scan Type Username
UNDEFINED Default value used by the Inventory class Manual (Empty)
BADGE Access with a Badge Reader Automatic Yes
FINGERPRINT Access with a Fingerprint Reader Automatic Yes
The following example demonstrates how to use these values:
Java Javascript
@Override
public void scanCompleted()
{
    // Note: with remote devices, getLastInventory can return 'null' in case of errors
    Inventory lastInventory = device.getLastInventory();

    // any other value than UNDEFINED: automatic scan (BADGE or FINGERPRINT)
    if(lastInventory.getAccessType() != AccessType.UNDEFINED)
    {
        // splitted for more readability
        String display = String.format("New Inventory available. User: %s, Access: %s.",
        lastInventory.getUsername(),
        lastInventory.getAccessType().name());

        // prints "New Inventory available. User: John, Access: BADGE."
        System.out.println(display);
    }

    // Manual scan, no username (empty)
    else
    {
        System.out.println("Manual scan completed.");
    }
}
device.on('scancompleted', function()
{
    // Note: with remote devices, getLastInventory can return 'null' in case of (communication) errors
    device.getLastInventory(function(lastInventory)
    {
        if(lastInventory.getAccessType() != AccessType.UNDEFINED)
        {
            // splitted for more readability
            var display = "New Inventory available. User: "+lastInventory.getUsername();
            display += ", Access: "+inventory.getAccessType()+".";

            // prints "New Inventory available. User: John, Access: Badge."
            console.log(display);
        }

        else
        {
            console.log("Manual scan completed.");
        }
    });
});

Inventories History

This section concerns the remote devices.
A remote device saves all the inventories it created in its dedicated database, providing the possibility to get an inventories history over a given period.
Java Javascript
The class TcpDevice provides a method getInventories (not available in Device), which accepts two Date (java.util) objects as start and end dates.
// remoteDevice is an instance of TcpDevice
// get a list of inventories, ordered by ascending creation date
List<Inventory> inventories = remoteDevice.getInventories(dateFrom, dateTo);
The class Device provides a method getInventories which accepts two Date (JavaScript) objects as start and end dates.
// results: Array of Inventories, ordered by ascending creation date
device.getInventories(function(results) { }, startDate, endDate);
For efficiency reasons, using a read-only user account to directly query these inventories from the database is recommended.

Tags

This section concerns the tags from the E2 generation and above, which provide the Lighting and the Writing features.

LED Lighting

Spacecode RFID tags from the "E2" generation can power an embedded LED on request. The SDK provides methods to start and stop the lighting operation. The time management is depending of the user‘s code.

A minimalist example of lighting operation could be:
Java Javascript
// get all the tags scanned in the last inventory
List<String> tagsList = device.getLastInventory().getTagsAll();

// send an order to light this list
if(device.startLightingTagsLed(tagsList))
{
    // at this stage, the device confirmed the order, but we assume that it started lighting
    // let the LED's blink during 4500 milliseconds
    Thread.sleep(4500);
}

else
{
    System.out.println("Could not start the lighting operation.");
}

if(!device.stopLightingTagsLed())
{
    System.out.println("Could not stop the lighting operation.");
}
// get all the tags scanned in the last inventory
var uids = lastInventory.getTagsAll();

// send an order to light this list
device.startLightingTagsLed(function(result)
{
    if(!result)
    {
        console.debug("Could not start the lighting operation.");
    }

    // let the LED's blink during 4500 milliseconds
    setTimeout(function() {
        device.stopLightingTagsLed(function(result)
        {
            if(!result)
            {
                console.debug("Could not stop the lighting operation.");
            }
        });
    }, 4500);
}, uids);
The method startLightingTagsLed returns true when the device confirmed the order. At this step, the operation can still fail starting or lighting some tags: thus, scheduling the execution of the method stopLightingTagsLed, regardless of the result of startLightingTagsLed, is highly recommended.
Java Javascript
The lighting operation is not blocking unless the code commands it (with, for instance, a sleep): LED's keep blinking until the method stopLightingTagsLed is executed.

The interface LedEventHandler comes with the event lightingStarted, which contains, as a parameter, the UID's of the tags that could not be lighted (tags missing, or functioning abnormally). If all the tags provided to startLightingTagsLed could be lighted, this list is empty.
An additional event lightingStopped allows notifying all users that the current lighting process has been stopped.
public class DemoEventHandler implements LedEventHandler
{
    @Override
    public void lightingStarted(List<String> tagsNotLighted)
    {
        // LedEventHandler
        System.out.println("Lighting started.");

        if(!tagsNotLighted.isEmpty())
        {
            System.out.println("Tags not lighted:");

            for(String uid : tagsNotLighted)
            {
                System.out.println(String.format("- %s", uid));
            }
        }

        // from here, a separate timer (or thread) could
        // wait for an event or a given delay to stop the lighting process.
    }

    @Override
    public void lightingStopped(List<String> tagsNotLighted)
    {
        // LedEventHandler
        System.out.println("Lighting stopped.");
    }
}
Doing time-consuming tasks in an implementation of event listeners is highly discouraged. Events are executed by an internal thread pool with a limited number of threads (for performance reasons) which should not be blocked.
The class Device emits an event lightingstarted when a lighting operation successfully started. The callback attached to the event is called with an array of string as parameter, containing the UID's of the tags which could not be lighted (tags missing, or functioning abnormally). This array is empty if all the tags have been lighted.
An additional event lightingstopped allows notifying all users that the current lighting process has been stopped.
device.on('lightingstarted', function(tagsNotLighted)
{
    console.log('Lighting started.');

    if(tagsNotLighted.length > 0)
    {
        console.log('Tags not lighted:');

        for(var i = 0; i < tagsNotLighted.length; ++i)
        {
            console.log('- '+ tagsNotLighted[i]);
        }
    }
});

device.on('lightingstopped', function()
{
    console.log('Lighting stopped.');
});

UID Writing

Embedded memory of the E2 tags can be written, resulting in a new UID which can be up to 17 characters long. The characters allowed are: capital letters ([A-Z]), digits ([0-9]), space, dash, slash, dot.
Valid Invalid (not allowed)
ITEM000002 Item000002 ("tem")
LOT-1234-5678 LOT+1234+5678 ("+")
TAG/REVIEW 035 TAG_REVIEW_035 ("_")
To be rewritten, the tag must be readable by the device, and from the E2 generation (or above).
Java Javascript
String currentUid   = "3006789456";
String newUid       = "ITEM000001";

// if the operation is successful, tag 3006789456 will become tag ITEM000001
RewriteUidResult result = device.rewriteUid(currentUid, newUid);

switch(result)
{
    case WRITING_CONFIRMATION_FAILED:
        System.out.println("(Tag could not be confirmed with its new UID)");
        // yet, the writing operation completed, continue to the successful case:
        case WRITING_SUCCESS:
        System.out.println("Writing operation successful!");
        break;

    default:
        System.out.println("Operation failed.");
        break;
}
UID writing (see the method rewriteUid) is a blocking operation. It waits until the device answered with a value from the enumeration RewriteUidResult.
result contains a value from the enumeration RewriteUidResult. In most cases, all results except WRITING CONFIRMATION FAILED and WRITING SUCCESS should be considered as a failure.
var currentUid   = "3006789456";
var newUid       = "ITEM000001";

device.rewriteUid(function(result)
{
    switch(result)
    {
        case RewriteUidResult.WRITING_CONFIRMATION_FAILED:
            console.log("(Tag could not be confirmed with its new UID)");
        // yet, the writing operation completed, continue to the successful case:
        case RewriteUidResult.WRITING_SUCCESS:
            console.log("Writing operation successful!");
        break;

        default:
            console.log("Operation failed.");
        break;
    }
}, currentUid, newUid);
result contains a value from the enumeration RewriteUidResult. In most cases, all results except WRITING CONFIRMATION FAILED and WRITING SUCCESS should be considered as a failure.

Access Control

Permissions

Four types of permission exist to control the access to the devices equipped with one (or two) door(s). Devices coming with two has a main door and a second door. When the device is equipped with one door, this last is considered as a main door.
Type of Permission Description
All Open all doors
Master Open only the main door (equivalent to "All" on one-door devices)
Slave Open only the second door
Undefined No permission is given (no door can be unlocked)
One-door devices only need All and Undefined.
Reminder: After a door is open and then closed, a scan operation is automatically started.

Users

A user is basically defined by a Username and a Permission (see Permissions). Additionally, a Badge Number and Fingerprints can be provided. Users are identified by their username, supposed unique.

Users are separated in two categories: Authorized and Unregistered.
Authorized users are those considered by the device when a badge or a fingerprint is scanned: they may have the permission to open the door. Unregistered users are kept in memory but are not considered: they are not allowed to open the device, regardless their permission type.
Java Javascript
// get all "active" (authorized) users, including those with a permission "Undefined"
List<User> activeUsers = device.getUsersService().getUsers();
// get the name of each unregistered user
List<String> unregisteredUsers = device.getUsersService().getUnregisteredUsers();
// get all "active" (authorized) users, including those with a permission "Undefined"
device.getUsers(function(users) { /* ... */ });
// get the name of each unregistered user
device.getUnregisteredUsers(function(users) { /* ... */ });

Register a new User

Java Javascript
The class User has three constructors. The simplest takes two parameters: a Username, and a type of Permission (see GrantType). Fingerprints and badge number can be given as parameters, or updated later.

The operations of users management are made using the UsersService instance provided by the method getUsersService.
// create the user "John" with the permission to open all doors
User userJohn = new User("John", GrantType.ALL);
// register him
device.getUsersService().addUser(userJohn);
The method addUser returns false if a user with the same name is already known (of if any error occurred during the operation).
As TcpDevice also uses a UsersService, using a local or a remote device for the management of Users is programmatically transparent.
The constructor of the class User takes up to four parameters, but only the first two are mandatory (Username and Permission). The badge number and the fingerprints can be given as parameters, or updated later.
// create the user "John" with the permission to open all doors
User userJohn = new User("John", GrantType.ALL);
// register him
device.addUser(function(result) {}, userJohn);
The value of result (passed to the callback) is false if a user with the same name is already registered (of if any error occurred during the operation).

Badge Number and Permission

A user's badge number, or permission, can be changed as follows.
Java Javascript
The class UsersService provides the methods updateBadgeNumber and updatePermission, using a username to update Badge Number and Permission.
// both methods return a boolean (true: success, false: failure)
device.getUsersService().updateBadgeNumber("John", "FOOBAR42");
device.getUsersService().updatePermission("John", GrantType.SLAVE);
The methods updateBadgeNumber and updatePermission take a username and the new value as parameters.
// "result" is a boolean (true: success, false: failure)
device.updateBadgeNumber(function(result) {}, "John", "FOOBAR42");
device.updatePermission(function(result) {}, "John", GrantType.SLAVE);

Remove a Permission, a User

Removing a permission can be achieved by two ways: In the first case, the user is still considered as active and is available in the list of authorized users. In the former case, the user account is disabled, regardless his/her type of permission, and put in the list of unregistered users. In both case, the user is not able to open the device anymore.
Java Javascript
// Remove the user's permission but keep him/her active
device.getUsersService().updatePermission("John", GrantType.UNDEFINED);
// Disable the user, who is put in the list of unregistered users
device.getUsersService().removeUser("Mike");
// Remove the user's permission but keep him/her active
device.updatePermission(function(result) { /* ... */ }, "John", GrantType.UNDEFINED);
// Disable the user account, which is transferred in the list of unregistered users
device.removeUser(function(result) { /* ... */ }, "Mike");
An unregistered user can be registered again by updating his/her permission. Thus, the user account is transferred back in the list of authorized users (even with a permission UNDEFINED).
On Local Devices, the lists of users (authorized and unregistered) are lost when the instance of Device is released. However, Remote Devices keep in memory which users are authorized and which are unregistered.

Fingerprints

Devices equipped with a Fingerprint Reader can take advantage of the biometric authentication. Fingerprints are enrolled as Templates, which are made of four Samples. The ten fingers of a user can be enrolled and each finger is differentiated with a unique index.
When using a local device equipped with fingerprint readers, the fingerprint readers have to be initialized (or "connected") before they can be exploited. Please refer to connectFingerprintReaders.
The DigitalPersona UareU driver must be installed on the system.

Enroll a Finger

Java Javascript
To start an enrollment process, the method enrollFinger takes two parameters: a username and a value from the enumeration FingerIndex.
try {
    boolean result = device.getUsersService().enrollFinger("John", FingerIndex.RIGHT_MIDDLE);
    System.out.println(result ? "Enrollment completed!" : "Operation failed.");
} catch(TimeoutException te) {
    // Delay of five minutes exceeded
}
A TimeoutException is thrown if the enrollment is not completed before five minutes.
The enrollment is a blocking process, as a fingerprint enrollment requires four samples to create a template. The progress of the operation is indicated by an event from the interface AccessModuleEventHandler: fingerprintEnrollmentSample. Once four samples have been captured, a template is created and the method enrollFinger returns a boolean result.
To start an enrollment process, the method enrollFinger takes three parameters: a callback, a username and a value from the enumeration FingerIndex.
device.enrollFinger(function(result)
{
    console.log(result ? "Enrollment completed!" : "Operation failed.");
}, "John", FingerIndex.RIGHT_MIDDLE);
After a delay of five minutes, if the operation is not completed, the callback is executed with a result false. The progress of the enrollment is reported by the event enrollmentsample.
device.on('enrollmentsample', function(sampleNumber)
{
    console.log('Enrollment progress: sample '+sampleNumber+'/4.');
});
In most cases, if the operation fails, it does as soon as it is executed (communication error, unknown user...). It can exceptionally fail if the quality of the samples acquired during the enrollment process is bad.

Set and Update Fingerprints

Setting a user's fingerprints can be done in the constructor call. This feature is particularly useful when using a local device and loading users from a database to register them.
Java Javascript
Map<FingerIndex, String> templates = new EnumMap<>(FingerIndex.class);
templates.put(FingerIndex.LEFT_RING, template1);
templates.put(FingerIndex.LEFT_INDEX, template2);

User userMark = new User("Mark", GrantType.ALL, "", templates);
device.getUsersService().addUser(userMark);
Templates are provided as Strings (base64-encoded array of bytes) by the method getFingerprintTemplate of the class User.
Remote devices automatically save the users, including their fingerprints. But it is still possible to create a user with preloaded fingerprints using the JS API.
var templates = new Map();
templates.set(FingerIndex.LEFT_RING, template1);
templates.set(FingerIndex.LEFT_INDEX, template2);

var userMark = new User("Mark", GrantType.ALL, "", templates);
device.addUser(function(result) {}, userMark);
Templates are provided as Strings (base64-encoded array of bytes) by the method getFingerprintTemplate of the class User.
Updating fingerprints is only possible by enrolling the finger again. The old template will be replaced by the new enrolled one.

Remove Fingerprints

Java Javascript
The method removeFingerprint allows removing a fingerprint, for a given Username and FingerIndex. It returns false in case of failure (unknown user, communication error...).
device.getUsersService().removeFingerprint("Sam", FingerIndex.LEFT_RING);
The method removeFingerprint allows removing a fingerprint, for a given Username and FingerIndex. It returns false in case of failure (unknown user, communication error...).
device.removeFingerprint(function(result) {}, "Sam", FingerIndex.LEFT_RING);

Authentications

This section concerns the remote devices.
Remote devices save all the authentications in an internal* database. Thus, any user is able to get the authentications history over a given period.
Java Javascript
The class TcpDevice provides a method getAuthentications (not available in Device), which accepts two Date (java.util) objects as start and end dates and returns a list of Authentications.
// remoteDevice is an instance of TcpDevice
// get a list of authentications, ordered by ascending creation date
List<Authentication> authentications = remoteDevice.getAuthentications(dateFrom, dateTo);
The class Device provides a method getAuthentications which accepts two Date (JavaScript) objects as start and end dates.
// results: Array of Authentications, ordered by ascending creation date
device.getAuthentications(function(results) { }, startDate, endDate);
results is an array of Authentications, empty in case of error, or if there is no result for the given period.
For efficiency reasons, directly querying these authentications from the database is recommended.

Temperature

This section concerns the devices equipped with a temperature probe.
Devices equipped with a temperature probe provide the current measure to allow a real-time monitoring. The two ways to obtain this measure are:
For local devices, the temperature probe must be loaded by the software, using the method addTemperatureProbe.
Remote devices automatically load it.

Current Value

Instant Measure

The first way to get the current temperature is to "manually" read it.
Java Javascript
The class Device provides a method getCurrentTemperature which returns either the current temperature or ERROR_VALUE.
double currentMeasure = device.getCurrentTemperature();
System.out.println(currentMeasure + "°C");
The class Device provides a method getCurrentTemperature which returns either the current temperature or Device.TEMPERATURE_ERROR.
device.getCurrentTemperature(function(measure)
{
    console.log(measure + "°C");
});

Events

The second way to get the current temperature is to catch the notifications sent by the device. The method addTemperatureProbe accepts two double values: a delay (time spent between two measurement) and a delta (minimum difference required between the last measure and the next to be considered).
On remote devices, default values are 60 seconds and 0.3°C. The listener can expect up to one measure per minute. However, the ambient temperature is usually not subject to such changes (0.3°C per minute).
Java Javascript
The interface TemperatureEventHandler provides an event temperatureMeasure, called with a double parameter, which is the current measure.
 // [...] other events

@Override
public void temperatureMeasure(double value)
{
    System.out.println("New temperature: "+value+"°C.");
}
The class Device provides an event temperaturemeasure, emitted with the current measure as a parameter.
device.on('temperaturemeasure', function (measure)
{
    console.log("New temperature: "+value+"°C.");
});

Measures

This section concerns the remote devices.
A remote device saves all the temperature measures in its dedicated database, providing the possibility to get a measurements history over a given period.
Java Javascript
The class TcpDevice provides a method getTemperatureMeasures (not available in Device), which accepts two Date (java.util) objects as start and end dates.
// remoteDevice is an instance of TcpDevice
// get a map of Date and Double (value), ordered by ascending creation date
Map<Date, Double> measures = remoteDevice.getTemperatureMeasures(dateFrom, dateTo);
The class Device provides a method getTemperatureMeasures which accepts two Date (JavaScript) objects as start and end dates.
// results: Map of Date and Number (value), ordered by ascending creation date
device.getTemperatureMeasures(function(results) { }, startDate, endDate);
For efficiency reasons, directly querying these measures from the database is recommended.

Alert System

Alerts

SMTP Server

Data Serialization

Serialize

Deserialize