CommandFusion iViewer
Scripting Documentation

Table of contents

Sensors API

The sensors API, added in iViewer 4.0.216, allows applications to access low-level hardware sensors on the device and receive sensor updates. Using the sensor API, you can implement advanced code that detects movements and rotations in three dimensions, know the device's attitude (roll, pitch, yaw), heading relative to true north (compass) and get location information. You determine the rate at which you want to receive sample updates, which can be independent of the rate at which those samples are being collected. This way, you can collect a lot of samples and only process them in chunks.

Since some of sampled data can lead to very high callback rates (depending on the update rate you chose), you may want to use thresholds when configuring the sensors monitor, so that your callback function starts being triggered only when certain threshold values are being reached. This way, you can detect the beginning and end of an acceleration movement (you are guaranteed to be called once more after the acceleration or rotation diminishes below the threshold) and react appropriately.

The sensors may or may not be present on your hardware platform (in particular, on the variety of Android platforms). You can determine whether the device has any of the supported sensors by querying the CF.device.hasSensor object at runtime. For example, if you want to determine whether the device supports a hardware accelerometer, you can use the code below:

if (CF.device.hasSensor[CF.AttitudeSensor]) {
	// Yes, this device has an attitude sensor onboard
}

To start monitoring a sensor, you can use the CF.startMonitoring() function. You can monitor the same sensor multiple times with different parameters, although make sure to not do this permanently with high callback rates, of you could slow down the application to the point where it becomes unusable.

To stop monitoring a sensor, use the CF.stopMonitoring() function, using the monitor ID that was returned to you when you started monitoring the sensor.

Accelerometer

An accelerometer is a hardware sensor that samples acceleration on three axis. Acceleration is expressed in G, the G (gravity force) constant being 9.81 m/s^2.

The accelerometer is identified by CF.AccelerometerSensor.

The options object you pass when starting monitoring the accelerometer sensor can contain the following properties (note that all properties are optional):

If you do specify any of X, Y or Z threshold, your callback function will start being called only when all the aforementioned values are above threshold. When the acceleration slows down to below threshold, your callback function will be called once more to allow you to detect the end of the monitored acceleration, allowing you to take any action necessary.

If you do not specify a historySize, you will receive an array with only one element (the current acceleration). Otherwise, you receive an array with most recent acceleration values first, further elements going back in time up to historySize elements.

The structure of each data capture point is the following:

Since the hardware may not support fast data sample rate, we highly recommend that you use reasonable values for capture and particularly report intervals. For example, a report every 200ms (5 times a second) with a 20ms capture interval (50 times a second) and historySize of 10 means that you get 10 data sample points 5 times per second, which is fast enough to react to acceleration changes and slow enough to aboid bogging down the device CPU.

In addition, make sure you set threshold values to guarantee that your callback won't be called all the time but only when you need to detect specific device movements.

Gyroscope

A gyroscope is a hardware sensor that samples rotation rate on three axis. Rotation rate is indicated in radians per second. The rotation rate allows you to directly quantify the device's movements, but is very low level. It is not easy to calculate the actual attitude of the device. You may also want to look at the Attitude sensor for more synthetic information.

The gyroscope is identified by CF.GyroscopeSensor.

The gyroscope rotation sign follows the right hand rule, as explained by the diagram below: if the right hand is wrapped around the axis such that the tip of the thumb points toward positive values, a positive rotation is one toward the tips of the other four fingers.

Gyroscope rotation sign

The options object you pass when starting monitoring the gyroscope sensor can contain the following properties (note that all properties are optional):

If you do specify any of X, Y or Z threshold, your callback function will start being called only when all the values for which a threshold was defined are above threshold. When the rotation rate slows down to below threshold, your callback function will be called once more to allow you to detect the end of the monitored acceleration, allowing you to take any action necessary.

If you do not specify an historySize, you will receive an array with only one element (the current rotation rate). Otherwise, you receive an array with most recent rotation rates first, further elements going back in time up to historySize elements.

The structure of each data capture point is the following:

Since the hardware may not support fast data sample rate, we highly recommend that you use reasonable values for capture and particularly report intervals. For example, a report every 200ms (5 times a second) with a 20ms capture interval (50 times a second) and historySize of 10 means that you get 10 data sample points 5 times per second, which is fast enough to react to acceleration changes and slow enough to avoid bogging down the device CPU.

In addition, make sure you set threshold values to guarantee that your callback won't be called all the time but only when you need to detect specific device movements.

Attitude

The device attitude is a composite sensor assembled from hardware sensors information, to give you the devices' roll, pitch and yaw angles (in radians). As with other sensors, you can set thresholds to limit the frequency of reports (only report when the change is over X degrees).

The attitude sensor is identified by CF.AttitudeSensor.

Roll, pitch and yaw are defined as follows:

The options object you pass when starting monitoring the attitude sensor can contain the following properties (note that all properties are optional):

If you do specify any of roll, pitch or yaw threshold, your callback function will be called only when all the values for which a threshold was defined are above threshold.

If you do not specify an historySize, you will receive an array with only one element (the current attitude). Otherwise, you receive an array with most recent rotation rates first, further elements going back in time up to historySize elements.

The structure of each data capture point is the following:

Since the hardware may not support fast data sample rate, we highly recommend that you use reasonable values for capture and particularly report intervals. For example, a report every 200ms (5 times a second) with a 20ms capture interval (50 times a second) and historySize of 10 means that you get 10 data sample points 5 times per second, which is fast enough to react to acceleration changes and slow enough to avoid bogging down the device CPU.

In addition, make sure you set threshold values to guarantee that your callback won't be called all the time but only when you need to detect specific device movements.

Heading

The heading sensor is a synthetic version of the magnetometer hardware sensor. It delivers true north heading information, so you can obtain the current heading (relative to the current device orientation, so the heading always indicates where the top of the current page is pointing at). You can specify a threshold to receive heading updates only when a significant change occurred.

The heading sensor is identified by CF.HeadingSensor.

Heading is defined as the heading angle (in degrees) relative to the geographic North Pole. This means that to get a proper heading reading, the device must have its Location feature enabled so it can determine where it is on the globe to provide an accurate reading. A value of 0 points to North, 90 points to East, 180 points to South and 270 points to West. A negative value indicates that the heading could not be determined.

The options object you pass when starting monitoring the heading sensor can contain the following properties (note that all properties are optional):

If you do not specify an historySize, you will receive an array with only one element (the current heading). Otherwise, you receive an array with most recent rotation rates first, further elements going back in time up to historySize elements.

The structure of each data capture point is the following:

We highly recommend that you pass a reasonable threshold for the kind of application you are developing, so as to minimize the number of times your code is being called.

Location

The location sensor reports the current location of your device (in GPS coordinates). For this, location must be enabled for iViewer at the device level. On iOS devices, the first time your code uses the Location sensor, the user will be presented a dialog asking whether she authorizes the application to access the location data. If she denies it, the location sensor is disabled and you will never receive an update.

The location sensor is identified by CF.LocationSensor.

The options object you pass when starting monitoring the location sensor can contain the following properties (note that all properties are optional):

The structure of each data capture point is the following:

Contrary to other sensors, there is no threshold for location data. The OS reports new location when it receives updates from the GPS chip, so your code just has to wait for new incoming data.

Example code:

// Monitor the current location and update on-screen text values
// in joins s100 to s106
var locationMonitor = -1;

function startMonitoringLocation() {
	if (locationMonitor !== -1) {
		return;
	}
	locationMonitor = CF.startMonitoring(CF.LocationSensor, {
		historySize: 1 // this is optional, if you don't specify it it defaults to 1
	}, function(sensor, data) {
		CF.setJoins([
			{ join: "s100", value: data[0].lon },
			{ join: "s101", value: data[0].lat },
			{ join: "s102", value: data[0].alt + "m" },
			{ join: "s103", value: data[0].speed + " m/s" },
			{ join: "s104", value: data[0].course + "°" },
			{ join: "s105", value: data[0].err },
			{ join: "s106", value: data.length }
		]);
	});
}

function stopMonitoringLocation() {
	if (locationMonitor !== -1) {
		CF.stopMonitoring(locationMonitor);
		locationMonitor = -1;
	}
}

iBeacons

In iViewer, you can detect iBeacons using beacon detection events. iBeacons all carry a UUID (unique identifier) string, as well as major and minor numbers. The major number is typically used as a group identifier, and the minor number as a beacon identifier in the group. iViewer only needs you to provide a unique identifier string to start detecting beacons, although you can restrict detection to one or more specifics groups, or even to individual beacons if need be.

Detection event are emitted through the use of the CF.watch API with the CF.BeaconDetectionEvent event. Every time visible beacons change, your callback is invoked with the array of currently visible beacons (the array may be empty if no beacon is in sight).

To start watching beacons, use CF.watch:

// start watching all beacons carrying the UUID we configured them with:
var ourUUID = "28E30DDC-2261-4DF3-AC0B-0B5B78F333B8"
CF.watch(CF.BeaconDetectionEvent, ourUUID, onBeaconDetectionEvent);

// alternately, start watching beacons of group 5 only (major = 5)
CF.watch(CF.BeaconDetectionEvent, ourUUID, 5, onBeaconDetectionEvent);

// alternately, watch for a single beacon (UUID + major = 5 + minor = 1)
CF.watch(CF.BeaconDetectionEvent, ourUUID, 5, 1, onBeaconDetectionEvent);

Your beacon callback receives an array of beacon objects. Each object has the following structure (examplified with values):

var beacon = {
	uuid: "28E30DDC-2261-4DF3-AC0B-0B5B78F333B8",
	major: 5,
	minor: 1,
	proximity: CF.BeaconProximityNear,
	distance: 0.834,
	accuracy: 0,
	rssi: 0
}

Each beacon object indicates the approximate distance in terms of "proximity" (due to numerous factors, it's difficult to obtain a fine-grained distance with bluetooth devices). Possible values for proximity are:

CF.BeaconProximityImmediate
CF.BeaconProximityNear
CF.BeaconProximityFar
CF.BeaconProximityUnknown

If possible, avoid relying on this proximity indication. Apple mentions that it's really approximate and can vary widely if there is interference in the line of sight (i.e. a person or furniture between your device and the beacon).

The distance property may or may not exist. This indicates the approximate distance the receiving device is from the beacon in meters, rounded to 3 decimal places.

The accuracy property may or may not exist. This will be a number above 0 rounded to 3 decimal places, which defines the accuracy in meters. So a value of 0.400 would be "approximately accurate to within 0.4 meters". This value can help determine how accurate the proximity value is. A large accuracy value means the proximity is not accurate, whilst a low accuracy value means the proximity is somewhat accurate. A negative value means the accuracy is unknown.

The rssi property is the "Received Signal Strength Indicator". It is the strength of the beacon's signal as seen on the receiving device, e.g. your phone.

Your beacon detection callback should take a single parameter, an array of beacon objects:

function onBeaconDetectionEvent(beacons) {
	CF.log("Beacon detection event, we're seeing "+beacons.length+" beacon(s)");
	var i;
	for (i=0; i < beacons.length; i++) {
		var beacon = beacons[i];
		var whereString = ""
		switch (beacon.proximity) {
		case CF.BeaconProximityUnknown:
			whereString = "unknown";
			break;
		case CF.BeaconProximityImmediate:
			whereString = "immediate";
			break;
		case CF.BeaconProximityNear:
			whereString = "near";
			break;
		case CF.BeaconProximityFar:
			whereString = "far";
			break;
		default:
			whereString = "???"; // will not happen
			break;
		}
		// Accuracy values below zero are considered as "unknown"
		// Otherwise it represents the approximate accuracy in meters
		var accuracy = "unknown";
		if (beacon.accuracy && beacon.accuracy >= 0) {
			accuracy = beacon.accuracy + "m";
		}
		var distance = "unknown";
		if (beacon.distance && beacon.distance >= 0) {
			distance = beacon.distance + "m";
		}
		CF.log("Beacon "+beacon.major+"."+beacon.minor+" ("+beacon.uuid+"): proximity="+whereString+" ("+beacon.proximity+") [Distance "+distance+", Accuracy "+accuracy+", RSSI: "+beacon.rssi+"]");
	}
}

Note that you can simultaneously watch for beacons with different criteria. Just invoke CF.watch multiple times with different parameters.

Finally, to stop watching for beacons use CF.unwatch with the same filter criteria you used when starting detection. Note that this only cancels detection for the related CF.watch call that was made with the exact same parameters:

CF.unwatch(CF.BeaconDetectionEvent, ourUUID);
CF.unwatch(CF.BeaconDetectionEvent, ourUUID, 5);
CF.unwatch(CF.BeaconDetectionEvent, ourUUID, 5, 1);

Constants

Functions

CF.startMonitoring(sensor,options,callback)

Start monitoring a sensor (for example, CF.Accelerometer). You can pass an object with options, depending on the type of sensor you want to monitor:

The function returns a monitor ID that you can use later to stop monitoring the sensor.

Your callback function will be of the type:

function mySensorCallback(sensorType, data) {
	// sensorType is for example CF.Accelerometer
	// data is an object with properties defined by the type of sensor you are monitoring
}

Example of use:

// Monitor the gyroscope sensor. Gather data points every 20ms (50 times per second)
// but only callback into JavaScript every 200ms (5 times per second) which is enough
// to react to detected movements in many cases
var gyroMonitor = CF.startMonitoring(CF.Gyroscope, {
	historySize: 50,
	captureInterval: 20,
	reportInterval: 200
}, function(sensorType, data) {
	// each entry in the data array is an object with x,y and z rotation rates
	// captured at one point in time, plus a t member that gives the capture time
	// most recent entries come first
	var i, len = data.len;
	for (i = 0; i < len; i++) {
		var dataPoint = data[i];
		// ... process your data here ...
	}
});

CF.stopMonitoring(monitorID)

Stop monitoring a particular sensor that was started using CF.startMonitoring(). Typically, you will monitor a particular sensor while in a specific page or situation, and you will stop monitoring it once you don't need it anymore (for example, when the user changes page).

Example:

// Stop monitoring the gyroscope sensor (see the CF.startMonitoring code example)
CF.stopMonitoring(gyroMonitor);