thsq

2.7.0 • Public • Published

Description

thsq is a node.js interface for the Thingsquare REST API. Thingsquare is a software platform for IoT systems that allow connecting low-power devices over wireless networks to read or write information. The Thingsquare REST API allow developing server-side applications that operate on the data provided by the wireless devices.

The thsq module serves a dual purpose: to help develop server-side applications that work with Thingsquare device, and to help develop frontend applications that work with Thingsquare devices.

The Thingsquare native and web apps are based on the thsq module.

Installation

Server-side installation

npm install thsq

Examples

Print out the platform names of all claimed devices for a user.

var thsq = require('thsq');
var token; // User API token, acquired via web app

thsq.init({ token: token }, function (devices) {
   var id;

   for (id in devices) {
       console.log('Device with id ' + id + ' has platform ' + thsq.devicePlatform(devices[id]));
   }
});

Print out a message when a button is pushed on a device.

var thsq = require('thsq');
var token; // User API token, acquired via web app

thsq.on('device-updated', function (device, unique, update) {
    if (update.s && update.s.button) {
        console.log('Button changed, value is ' + update.s.button.value);
    }
});

thsq.init({ token: token });

Detect nearby devices and print out their name, if set, and platform.

var thsq = require('thsq');

thsq.on('device-nearby-seen', function (device) {
    var name, platform;

    name = 'unknown';
    if (device.s.name) {
        name = device.s.name.value;
    }

    platform = thsq.devicePlatform(device);

    console.log('Nearby device with name ' + name + ' and platform ' + platform + ' seen');
});

thsq.init();

Concepts

  • device: the representation of a wireless device and its variables.

  • variables: devices have a set of variables that are either of three types, d, s, and meta. d variables can be set either by the device or via the API, and are pushed to the device. s variables can be set either by the device or via the API, but are not pushed to the device. meta variables can not be set by neither the device nor the via the API, and contain meta information about the device. Each variable has a value and a timestamp. The values and timestamps of variables are directly accessible via the device object. For example, the value of the s variable called name is accessed via device.s.name.value and its timestamp as device.s.name.time. Variables are set with the thsq.setVariable() method.

  • unique: each device is identified by a unique identity, contained in the meta.unique device variable. The thsq module uses this unique number when referring to a device.

  • update: when the thsq module sees that a device has been updated, it will post the new variables in an update object, which contains all the new values of the variables.

  • user: a user account and its associated data. A user account has a login name, a set of devices, and a data structure that can be used to store user-specific application data.

  • token: an API token. API tokens give access for a specific user and can be used as an alternative to login/password pairs for running server-side applications.

  • Nearby device: Thingsquare devices with BLE transmitters send out a short-ranged BLE beacon that is picked up by nearby smartphones and laptops. This beacon is encrypted and changes over time. When a beacon is picked up by a smartphone or laptop, the Thingsquare system knows that the device and the smartphone or laptop are in close proximity of each other. This is typically used during installation phases, when devices are deployed.

  • Network device: when a Thingsquare device and a smartphone or laptop are on the same physical network (WiFi, Ethernet), the smartphone or laptop sends out an encrypted message over the network that the devices pick up. The Thingsquare system can then determine that the device and the smartphone or laptop are on the same network. This is used to prove proximity in a similar way as with BLE beacons, but can also be used for devices that does not have BLE beacon capabilities.

Theory of operation

The thsq module sets up and maintains a connection with its backend server. This lets applications receive notifications in the form of events when devices are updated, which relieves them from the need to poll the backend for updates.

The thsq module requires a user session. The application receives updates for devices that are claimed by the user account. A user account can be either identified with a login/password pair, which is typical for frontend applications, or an API token, which is typical for server-side applications. Starting the thsq module without a user account results in an anonymous user session to be created.

When running inside native app frontend, the thsq module is able to detect and interact with nearby devices. Nearby devices are detected via Bluetooth Low Energy (BLE) beacons.

API

Events

Server events

  • server-connected - Emitted when thsq is connected with its backend server.

  • server-disconnected - Emitted is thsq becomes disconnected from its backend server. This can be used to indicate to a user that the system is currently offline.

  • server-loading (url, method) - Emitted when thsq is currently loading data via the REST API. Can be used to indicate to a user that the system is currently doing work. The url argument contains the URL that is currently being processed and method contains the REST verb that is being used.

  • server-loading-done (url, method) - Emitted when thsq has completed a REST API transaction. The url and method arguments are the same as for the server-loading event.

  • server-time-received (time, diff) - Emitted when we receive time information from the server. The time argument contains the server's time in milliseconds since January 1, 1970 and diff is the difference in milliseconds from the local time.

User events

  • logged-in - Emitted when a user account has logged in. This can be used to indicate to a user that the user is now logged in.
  • logged-out - Emitted when a user account has logged out. This can be used to indicate to a user that the user is now logged out.

Bluetooth events

  • ble-enabled - Emitted when Bluetooth Low Energy (BLE) ability has been enabled. This can be used to indicate to a user that BLE is turned on and that nearby devices now can be detected.
  • ble-disabled (ble, location) - Emitted when BLE ability has been disabled. This can be used to indicate to a user that BLE is turned off or disabled, which will make it impossible to detect nearby devices. The ble argument is true if BLE is turned on and the location argument is true if location access is available. On most platforms, both BLE and location access is needed to be able to detect nearby devices. This can be used to display a user-friendly message telling the user to enable either BLE or location services, or both.

Device events

  • device-claimed (device, unique) - Emitted when a device has been claimed by the logged in user. The device argument contains the device data and the unique argument is the device's unique identifier.

  • device-removed (unique) - Emitted when a device has been removed from the logged in user. The user no longer has access to the device and the device's data. The unique argument is the unique identifier for the device.

  • device-updated (device, unique, update) - Emitted when a device has been updated. The device object contains all the current device variables, the unique argument is the unique identifier for the device, and update holds the variable values that were updated. An update may contain multiple variables being updated.

Nearby devices events

  • device-nearby-first-seen (device, unique, state) - Emitted when a new nearby device has been detected. The device argument contains the device information that the user has access to, the unique argument is the unique identifier for the device, and the state argument is the device's current state. The state can be fed into the thsq.deviceStateName() method to translate the number into a human-readable string.

  • device-nearby-seen (device, unique, state) - Emitted when a nearby device is seen again. This is emitted periodically when a device is nearby, after the device-nearby-first-seen event has been posted. The arguments are the same as for the device-nearby-first-seen event.

  • device-nearby-gone (device, unique) - Emitted when a nearby device has not been seen for a while and therefore is determined to be gone. The device argument contains the last known information about the device and the unique argument is the device's unique identifier.

  • device-unknown-nearby-seen (key, platform, state) - Emitted when a nearby device that has not yet registered with the backend system is seen. The key is an opaque string that the device has generated that later can be used to identify this device with a device object, once the device has registered itself with the backend system. The platform argument is the name of the device's platform and the state argument is the device's current state. The state can be fed into the thsq.deviceStateName() method to translate the number into a human-readable string.

Methods

Initialization and exit

  • thsq.init([ options, ] callback) - initialize the thsq module. This must be done after registering event handlers. The options argument is optional and can be a combination of the options below. The callback will be called once everything is initialized and will receive the list of claimed devices by the user.

    The available options are:

    • token: the user API token (default: none)
    • server: the address of the backend server to use for REST API calls (default: developer.thingsquare.com)
    • frontend: the frontend ID to use for REST API calls (default: 0ac48bf3-9fab-4bad-8455-e394808eda6b)
    • exit: batch mode operation: set to true to cause the thsq module exit after performing the thsq.init() method
    • devicedatafilter: a regular expression that will cause only the filtered data to be transmitted across the connection, thus reducing the overall data load. This can be used in scripts that will operate only on specific variables. Example: thsq.init({ devicedatafilter: 'devicedatafilter: 's\.(lat|lng)$' })
    • cachefile: a filename that the system will use as a cache for device data, to avoid having to load all devices anew on each invocation (only available when running on node.js)
    • noupdates: set to true to indicate that the script is not interested in ongoing data updates via a connected websocket to the backend
  • thsq.exit(callback) - wait for any ongoing transfers to complete, then exit at the first possible time. callback is called when everything is exited.

  • thsq.pause() - disconnect from the backend until thsq.unpause() is called. No new device data will be received while the connection is paused.

  • thsq.unpause() - reconnect with the backend to start receiving device data updates again.

User methods

  • thsq.login(username, password, callback) - login with the username provided by the username argument and the password provided by the password argument. The callback will be called with a string that indicates the result:

    • login-ok: the user was successfully logged in.
    • login-fail: the user could not be logged in.
  • thsq.logout(callback) - log out the currently logged in user. The callback function callback will be called when the user has been logged out.

  • thsq.userSignup(username, password, callback) - sign up a new user with the username username and password password. The callback function callback is called with a string that indicates the result of the operation:

    • signup-ok: a new user account was successfully created.
    • signup-fail-already-exists: a user account with the same name already exists.
    • signup-fail-no-email: the username was not an email address.
  • thsq.userResendConfirmationEmail(callback) - request a new user account confirmation email to be sent. The calback function callback will be called with a string that indicates the result of the operation:

    • resend-ok: a user confirmation email was successfully sent.
    • resend-fail: the user confirmation email could not be sent.
  • thsq.userSendPasswordRecoveryEmail(username, callback) - request a password recover email to be send to the user with the user name username. The password recover email will contain a password token that later can be used as a parameter to the recoverNewPassword() function. The callback function callback will be called with a string that indicates the result of the operation:

    • recover-ok: a password reset email was successfully sent
    • recover-fail: a password reset email could not be sent.
  • thsq.recoverNewPassword(username, passwordtoken, newpassword, callback) - set a new password for the user account. The username is the username of the user, and must match the username that previously requested the password reset, the passwordtoken is a password token that was previously generated as a result of a call to userSendPasswordRecoveryEmail(), newpassword is the new password, and callback is a callback function that gets called with a string that indicates the result of the operation:

    • recover-ok: the new password was successfully set.
    • recover-fail: the new password was not set.
  • thsq.getUser(callback) - get the user data and application data associated with the user account. The callback function callback will be called with an object that represents the user information. The user object has the following fields:

    • login: the user login name.
    • data: the application user data that was previously stored with storeUserData().
  • thsq.storeUserData(data, callback) - store new user data for the user account. The argument data is an object that holds the data to be stored and the callback function callback will be called once the data has been stored, with a string that indicates the result of the operation:

    • user-data-ok: user data was successfully stored.
    • user-data-fail: user data could not be stored.
    • user-fail: no user account was logged in.
  • thsq.createAccessToken(callback) - create a new user API access token for the logged in user. The function callback will be called with a string that contains the new access token, or an error message that indicates the result of the operation:

    • user-token-fail: user token could not be created.
  • thsq.deleteAccessToken(token, callback) - delete a user API access token. The token argument should be a token that was previously created with createAccessToken(). The callback function callback will be called with a string that indicates the result of the operation:

    • user-token-deleted: the user API access token was successfully deleted.
    • user-token-fail: the user API access token could not be deleted.

Device methods

  • thsq.claimDevice(unique, callback) - claim a device for the logged in user account. This makes the device available for this user only. Any updated for the device will be received as device-updated events. The unique argument is the unique device identifier and callback is a callback function that is called to indicate the result of the operation:

    • device ID: the device was successfully claimed
    • claim-fail: the device could not be claimed
    • claim-fail-no-auth: bad user account
  • thsq.removeDevice(unique, callback) - remove the device from the user account. The user will no longer have access to its data. The unique argument is the device's unique identifier and callback is a callback function that gets called with a string that indicates the result of the operation:

    • delete-ok: the device was successfully removed
    • delete-fail: the device could not be removed
  • thsq.shareDevice(unique, username, callback) - share the device with another user. This makes the device also be available for the other user. The uniqueargument is the device's unique identifier, the username argument is the username of the user with which the device should be shared, and callback is a callback function that is called with a string that indicates the result of the operation:

    • add-user-ok: the new user was successfully added
    • claim-fail: the new user could not be added
  • thsq.getVariable(unique, type, variable, callback) - get the current value of a specified variable. The unique argument is the unique identifier for the device, the type can be either d, s, or meta, and variable is the name of the variable. The callback function will be called with an object that contains the value and time for the variable, or undefined if the variable does not exist.

  • thsq.getVariableValue(unique, type, variable, fallback, callback) - get the current value of a specified variable, and with a fallback if the value is not defined. The unique argument is the unique identifier for the device, the type can be either d, s, or meta, and variable is the name of the variable. The callback function will be called with two arguments: the first is the value of the variable, or fallback if the value is not defined, and the second is an object that contains the value and time for the variable, or undefined if the variable does not exist.

  • thsq.getVariableStringValue(unique, type, variable, fallback, callback) - like thsq.getVariableValue(), except the value will be provided as a string.

  • thsq.getVariableNumberValue(unique, type, variable, fallback, callback) - like thsq.getVariableValue(), except the value will be provided as a number. If the value was NaN, the fallback value is provided instead.

  • thsq.getVariableBufferValue(unique, type, variable, fallback, callback) - like thsq.getVariableValue(), except the value will be provided as a Buffer object. (Node.js version only.)

  • thsq.setVariable(unique, type, variable, value, [options,] callback) - set a device variable. The unique argument is the unique identifier for the device, the type can be either d or s, variable is the name of the variable, and value is the value of the variable. The optional options argument can take one { timestamp: timestamp } value, which sets a specific timestamp, in seconds since the Unix epoch, for the variable. The callback function will be called with an object that indicates the result of the operation:

    • device-ok: the variable could be set
    • device-fail: the variable could not be set
  • thsq.deleteVariable(unique, type, variable, callback) - delete a device variable. The unique argument is the unique identifier for the device, the type can be either d or s, and variable is the name of the variable. The callback function will be called with an object that indicates the result of the operation:

    • delete-ok: the variable could be deleted
    • delete-fail: the variable could not be deleted
  • thsq.getVariableHistory(unique, type, variable, [options,] callback) - get the variable history for a specific variable. The unique argument is the unique identifier for the device, the type can be either d, s, or meta, and variable is the name of the variable. The optional options argument is used to delimit the number of history items to be returned, per below. The callback function will be called with an array of items from the data history, with each item as per below.

    The options argument determines what history elements are returned. They are either returned starting from a given timestamp, or starting from a given logical history element id. If no timestamp or element id is provided, the most recent history is returned.

    • startid: request history elements from given id
    • starttime: request history elements from given timestamp
    • num: the number of elements to request in total (default: 1000)
    • chunksize: the maximum number of elements to retrieve per request (default: 1000)
    • progress(num): a callback function that gets called on each request, with the num argument being the number of history elements read so far (default: none).

    The callback will receive an array with objects with the following properties:

    • value: the value of the data object. For binary data, this is a Javascript object with the field type set to the string Buffer. In this case, the data field will be an array of integers that represent the binary data value.
    • time: the timestamp of the value
  • thsq.addHistoryListener(unique, type, name, options, listener) - adds a history listener for the given device and variable. This function returns a unique history listener id that can later be used to remove the history listener via thsq.clearHistoryListener().

    The options parameter is the same as for thsq.getVariableHistory().

    The listener will receive the following parameters:

    • device: the device object
    • unique: the device unique
    • type: the variable type e.g. s
    • variable: the variable name e.g. button
    • data: the variable value object containing time and variable value
  • thsq.clearHistoryListener(id) - clears a previously registered history listener.

  • thsq.clearAllHistoryListeners() - clears all previously registered history listeners.

  • thsq.sendCommand(unique, command, [options,] callback) - send a command to the device identified by unique. The command is a string that will be sent to the device. Commands are sent in a best-effort fashion and there is no guarantee that it will be received by the device. The callback function callback will be called with a string that indicates the result of the API call, but does not indicate anything regarding the command propagation itself.

    Possible results for the callback function are:

    • device-ok: command was sent towards the device
    • device-fail: the command could not be sent

    The possible options are:

    • sendcallback: a function that gets called when the command has been sent towards the device
    • sendtimeout: the number of milliseconds to wait before giving up on the send callback (default 60000 ms)
    • sendtimeoutcallback: a function that gets called when the sendtimeout occurs
    • ackedcallback: a function that gets called when the command has been acked by the device
    • ackedtimeout: the number of milliseconds to wait after the command has been sent before giving up on the acked callback (default 10000 ms)
    • ackedtimeoutcallback: a function that gets called when the ackedtimeout occurs
    • priority: the priority of the command (0: default urgency, 1: urgent, 2: most urgent)
    • lifetime: the time, in milliseconds, that the command should be on the command queue before being removed
  • thsq.getDevice(unique, callback) - get the device object for the unique identifier unique. The callback function callback will be called with the device object, or undefined if the device does not exist.

  • thsq.getDevicelist(callback) - get all devices claimed by the user. The callback function callback will receive a Javascript object that is indexed by defice ID and where each item represents a device.

  • thsq.deviceStateName(state) - returns a human-readable string representation of a nearby device's state, as given by the state argument that has previously been received received via the device-nearby-seen, device-nearby-first-seen, and device-unknown-nearby-seen events.

  • thsq.deviceEUI(device) - returns the EUI for the device in the device argument.

  • thsq.deviceId(unique, callback) - receives the device ID for the device with unique provided in the unique argument as a callback to the callback(deviceiq) function.

  • thsq.devicePlatform(device) - returns the platform for the device in the device argument.

Firmware update methods

  • thsq.getFirmwarelist(callback) - retreive the list of firmware updates that the user has access to. The callback function callback will be called with an array that contains items with the following structure:

    • name: the filename of the firmware file, which later can be used with the updateFirmware() method.
    • version: the version of the firmware file.
    • platform: the platform that the firmware file was compiled for.
    • info: a free-form information object contained in the firmware update's corresponding .json file. This information object typically includes:
      • fromversion: a string with information about what firmware versions that can load this firmware update
      • platforms: an object that contains:
        • from: an array of strings of platform names that can load this firmware update
        • to: an object that describes what this firmware update contains:
          • platform: the platform name that the device will have after the update.
          • name: a human-readable representation of the platform name
          • power: the power configuration (high or low) of this firmware update
      • warning: a string with a warning message to be displayed to a user, if any
      • experimental: a boolean value that indicates if this is an experimental version or not
  • thsq.startFirmwareUpdate(unique, firmwarename, callback) - start a firmware update on the device identified by the unique argument and with the firmware update file name firmwarename, which was previously retrieved from the list of available firmware updates in getFirmwarelist(). The callback function callback will receive a string that indicates the status of the operation:

    • device-ok: the firmware update was successfully started
    • firmware-fail: the firmware update could not be started
  • thsq.stopFirmwareUpdate(unique, callback) - stop an ongoing firmware update for the device identified by unique. The callback function callback will receive a string that indicates the status of the operation:

    • delete-ok: the firmware update was successfully stopped
    • delete-fail: the firmware update could not be stopped

Nearby and network device methods

  • thsq.getNetworkDevices(callback) - get a list of devices that are in the same network as the user. The callback function callback will receive a Javascript object which is indexed by device IDs and where each item is a device object.

  • thsq.scanBLE(milliseconds) - tell the underlying OS to listen for BLE devices for milliseconds milliseconds. This must be called repeatedly to receive notifications of nearby devices (device-nearby-first-seen, device-nearby-seen, device-unknown-nearby-seen events).

Status methods

  • thsq.sendPing() - send a ping to the backend to check that the backend connection is alive.

Convenience functions

  • thsq.deviceunique(device) - get the device unique of a device.

  • thsq.isacked(variable) - returns true if a variable is acked by the device.

  • thsq.valuestring(value) - convert a variable value to string value.

  • thsq.valuebuffer(val) - convert a variable value to a Buffer value.

  • thsq.valuecbor(val) - parse a CBOR Buffer value to a Javascript object.

  • thsq.devicename(device) - get the device name of a device.

  • thsq.deviceidstring(devicedata, str) - get the substring str from the s.id variable of a device.

  • thsq.devicefwver(devicedata) - get the device firmware timestamp version of a device.

  • thsq.devicefwid(devicedata) - get the device SDK version ID of a device.

  • thsq.devicefreq(devicedata) - get the device frequency mode (fcc or etsi) of a device.

  • thsq.devicepower(devicedata) - get the device power mode (low or high) of a device.

  • thsq.variablevalue(device, type, name, fallback) - get the variable value for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.variablevaluestring(device, type, name, fallback): - get the variable value as a string for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.variablevaluebuffer(device, type, name, fallback): - get the variable value as a Buffer for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.variablevaluecbor(device, type, name, fallback): - get the variable value as a Javascript object decoded from the CBOR (https://datatracker.ietf.org/doc/html/rfc8949) value in the device variable with type type and name name. If the variable is undefined, return fallback instead.

  • thsq.variablevaluejson(device, type, name, fallback): - get the variable value as a Javascript object decoded from the JSON value in the device variable with type type and name name. If the variable is undefined, or if the variable contains unparseable JSON, return fallback instead.

  • thsq.variableage(device, type, name, fallback) - get the variable age for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.variabletime(device, type, name, fallback) - get the variable time for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.ackedvariablevalue(device, type, name, fallback) - get the acknowledged variable (most recently known value) value for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.ackedvariablevaluebuffer(device, type, name, fallback): - get the acknowledged variable (most recently known value) value as a Buffer for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.ackedvariablevaluestring(device, type, name, fallback): - get the acknowledged variable (most recently known value) value as a string for a device variable with type type and name name. If the variable does not exist, return fallback.

  • thsq.variablevaluestringnum(device, type, name, num, fallback): - get the numth value of a comma separated variable, as a string.

  • thsq.variablevaluenumbernum(device, type, name, num, fallback) - get the numth value of a comma separated variable, as a Number.

  • thsq.currentmode(device): - get the current device mode (master, feather, or deadleaf) for a device. Returns an array with [0] being the mode and [1] being the wake-up rate, if the mode is deadleaf.

  • thsq.reachable(device) - get the number of milliseconds until the device will be reachable, in case of a deadleaf device.

Position functions

Each device may have a position. A position is a { lat: lat, lng: lng } object that is set with the thsq.setdeviceposition() method. The position is retreieved with the thsq.deviceposition() method. If the device has no position, the method returns undefined.

Positions may be locked in place with the thsq.lockdeviceposition() method and unlocked with the thsq.unlockdeviceposition() method. When a device's position is locked, thsq.setdeviceposition() will refuse to update its position. The thsq.devicepositionlocked() method checks if a device's position is locked.

The position is stored as a JSON string in the device's s.position variable.

Example code:

thsq.getDevice(unique, function (device) {
  if (thsq.deviceposition(device)) {
    let position = thsq.deviceposition(device);
    console.log('The device ' + thsq.devicename(device) + ' has position latitude ' + position.lat + ' and longitude ' + position.lng);
  } else {
    console.log('The device ' + thsq.devicename(device) + ' has no position);
  }

  if (thsq.devicepositionlocked(device)) {
    console.log('The position of the device ' + thsq.devicename(device) + ' is locked in place');

    // This will not have any effect on the device's position here, because it is locked:
    thsq.setdeviceposition(device, { lat: 59.3293, lng: 18.0686 });
  }

});

  • thsq.deviceposition(device) - get the position of the device device, if it has one. The position is returned as a { lat: lat, lng: lng } object.

  • thsq.setdeviceposition(device, position, callback) - set the position of the device device, where position is a { lat: lat, lng: lng } object. The callback is called when the position is set.

  • thsq.lockdeviceposition(device, callback) - lock the position of the device device. The callback is called when the position is locked.

  • thsq.unlockdeviceposition(device, callback) - unlock the position of the device device. The callback is called when the position is unlocked.

  • thsq.devicepositionlocked(device) - returns true if the position of the device device is locked. Returns false if the position is unlocked, or if the device has no position.

Time methods

  • thsq.getServerTimeOffset() - returns the current estimate of the time difference between us and the server, in milliseconds. Useful for notifying the user if there is a significant difference, which can indicate an erroneous time setting either on the local machine or on the server.
  • thsq.getServerTime() - gets the current time that the server has. This is computed by adding the most recent time offset from the server to our local time. This is useful for computing time deltas from data that is timestamped by the server.

Dependents (6)

Package Sidebar

Install

npm i thsq

Weekly Downloads

8

Version

2.7.0

License

MIT

Unpacked Size

368 kB

Total Files

3

Last publish

Collaborators

  • adamdunkels
  • fredrik-thingsquare