CARVIEW |
Generic Sensor API
Editor’s Draft,
- This version:
- https://w3c.github.io/sensors/
- Latest version:
- https://www.w3.org/TR/generic-sensor/
- Version History:
- https://github.com/w3c/sensors/commits/gh-pages/index.bs
- Feedback:
- public-device-apis@w3.org with subject line “[generic-sensor] … message topic …” (archives)
- Issue Tracking:
- GitHub
- Level 1 Issues
- Editors:
- Tobie Langel (Intel Corporation)
- Rick Waldron (jQuery Foundation)
- Bug Reports:
- via the w3c/sensors repository on GitHub
Copyright © 2016 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and document use rules apply.
Abstract
This specification defines a framework for exposing sensor data to the Open Web Platform in a consistent way. It does so by defining a blueprint for writing specifications of concrete sensors along with an abstract Sensor interface that can be extended to accommodate different sensor types.
Status of this document
This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.
If you wish to make comments regarding this document, please send them to public-device-apis@w3.org (subscribe, archives). When sending e-mail, please put the text “generic-sensor” in the subject, preferably like this: “[generic-sensor] …summary of comment…”. All comments are welcome.
This document was produced by the Device APIs Working Group.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 September 2015 W3C Process Document.
1. Introduction
Increasingly, sensor data is used in application development to enable new use cases such as geolocation, counting steps or head-tracking. This is especially true on mobile devices where new sensors are added regularly.
Exposing sensor data to the Web has so far been both slow-paced and ad-hoc. Few sensors are already exposed to the Web. When they are, it is often in ways that limit their possible use cases (for example by exposing abstractions that are too high-level and which don’t perform well enough). APIs also vary greatly from one sensor to the next which increases the cognitive burden of Web application developers and slows development.
The goal of the Generic Sensor API is to promote consistency across sensor APIs, enable advanced use cases thanks to performant low-level APIs, and increase the pace at which new sensors can be exposed to the Web by simplifying the specification and implementation processes.
2. Scope
The scope of this specification is currently limited to specifying primitives which enable expose data from local sensors.
Exposing remote sensors or sensors found on personal area networks is out of scope. As work in these areas mature, it is possible that common, lower-level primitives be found, in which case this specification will be updated accordingly. This should have little to no effects on implementations, however.
This specification also does not currently expose a sensor discovery API. This is because the limited number of sensors currently available to User Agents does not warrant such an API. Using feature detection, such as described in §4 A note on Feature Detection of Hardware Features, is good enough for now. A subsequent version of this specification might specify such an API, and the current API has been designed with this in mind.
3. Terminology
A sensor measures different physical quantities and provide corresponding raw sensor readings which are a source of information about the user and their environment.
Known, predictable discrepancies between raw sensor readings and the corresponding physical quantities being measured are corrected through calibration.
Known but unpredictable discrepancies need to be addressed dynamically through a process called sensor fusion.
Calibrated raw sensor readings are referred to as sensor readings, whether or not they have undergone sensor fusion.
Different sensor types measure different physical quantities such as temperature, air pressure, heart-rate, or luminosity.
For the purpose of this specification we distinguish between high-level and low-level sensor types.
Sensor types which are characterized by their implementation are referred to as low-level sensors. For example a Gyroscope is a low-level sensor types.
Sensors named after their readings,
regardless of the implementation,
are said to be high-level sensors.
For instance, geolocation sensors provide information about the user’s location,
but the precise means by which this data is obtained
is purposefully left opaque
(it could come from a GPS chip, network cell triangulation,
wifi networks, etc. or any combination of the above)
and depends on various, implementation-specific heuristics. High-level sensors are generally the fruits of
applying algorithms to low-level sensors—
That said, the distinction between high-level and low-level sensor types is somewhat arbitrary and the line between the two is often blurred.
For instance, a barometer, which measures air pressure,
would be considered low-level for most common purposes,
even though it is the product of the sensor fusion of
resistive piezo-electric pressure and temperature sensors.
Exposing the sensors that compose it would serve no practical purpose;
Who cares about the temperature of a piezo-electric sensor?
A pressure-altimeter would probably fall in the same category,
while a nondescript altimeter—
Because the distinction is somewhat blurry, extensions to this specification (see §9 Extensibility) are encouraged to provide domain-specific definitions of high-level and low-level sensors for the given sensor types they are targeting.
Sensor readings from different sensor types can be combined together through a process called sensor fusion. This process provides higher-level or more accurate data (often at the cost of increased latency). For example, the readings of a three-axis magnetometer needs to be combined with the readings of an accelerometer to provide a correct bearing.
Smart sensors and sensor hubs have built-in conpute resources which allow them to carry out calibration and sensor fusion at the hardware level, freeing up CPU resources and lowering battery consumption in the process.
But sensor fusion can also be carried out in software. This is particularly useful when performance requirements can only be met by relying on application-specific data. For example, head tracking for virtual or augmented reality applications, requires extremely low latency to avoid causing motion sickness. That low-latency is best provided by using the raw output of a gyroscope, and waiting for quick rotational movements of the head to compensate for drift.
Note: sensors created through sensor fusion are sometimes
called virtual or synthetic sensors.
However, the specification doesn’t make any practical differences between them,
preferring instead to differentiate sensors as to whether they describe
the kind of readings produced--these are high-level sensors—
Sensors have two different reporting modes. When sensor readings are reported at regular intervals, at an ajustable frequency, the reporting mode is said to be periodic. When it is only reported upon measurable change, the reporting mode is said to be episodic.
Episodic reporting modes can give the user agent more latitude to carry out power- or CPU-saving strategies and should generally be favored. Periodic reporting mode, on the other hand, allows a much more fine-grained approach and is essential for use cases with, for example, low latency requirements.
Note: reporting mode is distinct from, but related to, sensor readings acquisition. If sensors are polled at regular interval, as is generally the case, reporting mode can be either periodic or episodic. However, when the underlying implementation itself only provides sensor readings when it measures change, perhaps because is is relying on smart sensors or a sensor hubs, the reporting mode cannot be periodic, as that would require data inference.
4. A note on Feature Detection of Hardware Features
This section is non-normative.
Feature detection is an established Web development best practice. Resources on the topic are plentiful on and offline and the purpose of this section is not to discuss it further, but rather to put it in the context of detecting hardware-dependent features.
Consider the below feature detection examples:
if (typeof Gyroscope === "function") { // run in circles... } if ("ProximitySensor" in window) { // watch out! } if (window.AmbientLightSensor) { // go dark... } // etc.
All of these tell you something about the presence and possible characteristics of an API. They do not tell you anything, however, about whether that API is actually connected to a real hardware sensor, whether that sensor works, if its still connected, or even whether the user is going to allow you to access it. Note you can check the latter using the Permissions API [permissions].
In an ideal world, information about the underlying status would be available upfront. The problem with this is twofold. First, getting this information out of the hardware is costly, in both performance and battery time, and would sit in the critical path. Secondly, the status of the underlying hardware can evolve over time. The user can revoke permission, the connection to the sensor be severed, the operating system may decide to limit sensor usage below a certain battery threshold, etc.
Therefore, an effective strategy is to combine feature detection, which checks whether an API for the sought-after sensor actually exists, and defensive programming which includes:
-
checking for error thrown when instantiating a Sensor object,
-
listening to errors emitted by it,
-
setting an appropriate timeout for your particular use case,
-
handling all of the above graciously so that the user’s experienced is enhanced by the possible usage of a sensor, not degraded by its absence.
try { // No need to feature detect thanks to try..catch block. let sensor = new GeolocationSensor({ timeout: 3 * 1000 // 3 seconds }); sensor.onerror = error => gracefullyDegrade(error); sensor.onchange = data => updatePosition(data.coords); } catch(error) { gracefullyDegrade(error); }
5. Model
This section is non-normative.
The Generic Sensor API is designed to make the most common use cases straightforward while still enabling more complex use cases.
Most devices deployed today do not carry more than one sensor of each type. This shouldn’t come as a surprise since use cases for more than a sensor of a given type are rare and generally limited to specific sensor types such as proximity sensors.
The API therefore makes it easy to interact with the device’s default (and often unique) sensor for each type simply by instantiating the corresponding Sensor subclass.
Indeed, without specific information identifying a particular sensor of a given type, the default sensor is chosen.
let sensor = new GeolocationSensor({ accuracy: "high" }); sensor.onchange = function(event) { var coords = [event.reading.latitude, event.reading.longitude]; updateMap(null, coords, reading.data.accuracy); }; sensor.onerror = function(error) { updateMap(error); };
Note: extension to this specification may choose not to define a default sensor when doing so wouldn’t make sense. For example, it might be difficult to agree on an obvious default sensor for proximity sensors.
In cases where multiple sensors of the same type may coexist on the same device, specification extension will have to define ways to uniquely identify each one.
let sensor = new DirectTirePressureSensor({ position: "rear", side: "left" }); sensor.onchange = event => console.log(event.reading.pressure);) {
6. API
6.1. The Sensor Interface
A Sensor object has an associated sensor.
A Sensor object observes the changes in its associated sensor at regular intervals and reports those values by firing DOM events.
Frequency is measured in hertz (Hz).
TODO: define the following concepts
-
interface Sensor : EventTarget { attribute double timeout; readonly attribute SensorReading? reading; attribute EventHandler onerror; attribute EventHandler ondata; attribute EventHandler onchange; attribute EventHandler oncalibration; }; [Constructor(DOMString type, SensorReadingEventInit eventInitDict)] interface SensorReadingEvent : Event { readonly attribute SensorReading reading; }; dictionary SensorReadingEventInit : EventInit { SensorReading reading; }; dictionary SensorOptions { double? frequency; double? timeout; };
6.1.1. Sensor.timeout
6.1.2. Sensor.reading
The reading attribute of must always point to the latest SensorReading whatever the frequency so that the reading attribute of two instances of the same Sensor interface associated with the same sensor hold the same SensorReading during a single event loop turn.
6.1.3. Sensor.onerror
6.1.4. Sensor.ondata
6.1.5. Sensor.onchange
6.1.6. Sensor.oncalibration
6.1.7. Event handlers
The following are the event handlers (and their corresponding event handler event types) that MUST be supported as attributes by the objects implementing the Sensor interface:
event handler | event handler event type |
---|---|
ondata
| data
|
onchange
| change
|
onerror
| error
|
oncalibration
| calibration
|
6.2. The SensorReading Interface
A SensorReading represents the state of a sensor at a given point in time.
[Constructor()] interface SensorReading { readonly attribute DOMHighResTimeStamp timeStamp; };
6.2.1. SensorReading.timeStamp
Returns a timestamp of the time at which the read steps was carried out expressed in milliseconds that passed since the time origin.
7. Abstract Operations
7.1. Sensor Object Construction
-
input
-
options, a SensorOptions object.
-
output
-
sensor, an instance of a subclass of Sensor.
-
If the incumbent settings object is not a secure context, then:
-
throw a SecurityError.
-
-
If the browsing context is not a top-level browsing context, then:
-
throw a SecurityError.
-
-
Otherwise, if identifying parameters in options are set, then:
-
If these identifying parameters allow a unique sensor to be identified, then:
-
Otherwise, throw a TypeError.
-
-
Otherwise, if a default sensor exists for this sensor type:
-
Otherwise, throw a TypeError.
-
Set sensor’s reading attribute to
null
. -
return sensor.
-
Run these sub-steps in parallel:
-
If permission is not granted, queue a task to fire a simple event named error on sensor, and terminate these sub-steps.
-
If cached SensorReadings are available,
-
let latest_reading be the most recent of those SensorReadings.
-
set the value of sensor’s reading attribute to latest_reading.
-
-
run the read steps for sensor.
-
8. Security and privacy considerations
Privacy risks can arise when sensors are used with each other, in combination with other functionality, or when used over time, specifically with the risk of correlation of data and user identification through fingerprinting. Web application developers using these JavaScript APIs should consider how this information might be correlated with other information and the privacy risks that might be created. The potential risks of collection of such data over a longer period of time should also be considered.
Variations in sensor readings as well as event firing rates offer the possibility of fingerprinting to identify users. Browser implementations may reduce the risk by limiting event rates available to web application developers.
Note: do we really want this mitigation strategy?
If the same JavaScript code using the API can be used simultaneously in different window contexts on the same device it may be possible for that code to correlate the user across those two contexts, creating unanticipated tracking mechanisms.
Browser implementations should consider providing the user an indication of when the sensor is used and allowing the user to disable it.
Web application developers that use sensors should perform a privacy assessment of their application taking all aspects of their application into consideration.
8.1. Browsing Context
Sensor readings must only be available in the top-level browsing context to avoid the privacy risk of sharing the information defined in this specification (and specifications extending it) with contexts unfamiliar to the user. For example, a mobile device will only fire the event on the active tab, and not on the background tabs or within iframes.
8.2. Secure Context
Sensor readings are explicitly flagged by the Secure Contexts specification [powerful-features] as a high-value target for network attackers. As such, sensor readings must only be available within a secure context.
8.3. Obtaining Explicit User Permission
Make sure the API is compatible with sensors which need to ask the user's permission before being used.
Proposed resolutions:
- The Generic Sensor API must be compatible with an async permissioning model.
Actions:
- Identify the best solution to communicate that the permission to access the sensor has been denied by the user agent.
9. Extensibility
This section is non-normative.
Its purpose is to describe how this specification can be extended to specify APIs for different sensor types.
Extension specifications are encouraged to focus on a single sensor type, exposing both high and low level as appropriate.
9.1. Naming
Sensor interfaces for low-level sensors should be
named after their associated sensor.
So for example, the interface associated with a gyroscope
should be simply named Gyroscope
. Sensor interfaces for high-level sensors should be
named by combining the physical quantity the sensor measures
with the "Sensor" suffix.
For example, a sensor measuring
the distance at which an object is from it
may see its associated interface called ProximitySensor
.
Attributes of the SensorReading subclass that
hold sensor readings values
should be named after the full name of these values.
For example, the TemperatureSensorReading
interface should hold
the sensor reading’s value in
a temperature
attribute (and not a value
or temp
attribute).
A good starting point for naming are the
Quantities, Units, Dimensions and Data Types Ontologies [QUDT].
9.2. Unit
Extension specification must specify the unit of sensor readings.
As per the Technical Architecure Group’s (TAG) API Design Principles [API-DESIGN-PRINCIPLES], all time measurement should be in milliseconds. All other units should be specified using, in order of preference, and with the exception of temperature (for which Celsius should be favored over Kelvin), the International System of Units (SI), SI derived units, and Non-SI units accepted for use with the SI, as described in the SI Brochure [SI].
9.3. Exposing High-Level vs. Low-Level Sensors
So far, specifications exposing sensors to the Web platform have focused on high-level sensors APIs. [geolocation-API] [orientation-event]
This was a reasonable approach for a number of reasons. Indeed, high-level sensors:
-
convey developer intent clearly,
-
do not require intimate knowledge of how the underlying hardware sensors functions,
-
are easy to use,
-
may enable the User Agent to make significant performance and battery life improvements,
-
help avoid certain privacy and security issues by decreasing the amount and type of information exposed.
However, an increasing number of use cases such as virtual and augmented reality require low-level access to sensors, most notably for performance reasons.
Providing low-level access enables Web application developers to leverage domain-specific constraints and design more performant systems.
Following the precepts of the Extensible Web Manifesto [EXTENNNNSIBLE], extension specifications should focus primarily on exposing low-level sensor APIs, but should also expose high-level APIs when they are clear benefits in doing so.
9.4. When is Enabling Multiple Sensors of the Same Type Not the Right Choice?
TODO: provide guidance on when to:
-
allow multiple sensors of the same type to be instantiated,
-
create different interfaces that inherit from Sensor,
-
add constructor parameters to tweak sensors settings (e.g. setting required accuracy).
9.5. Defining a default
Extension specifications should define a default sensor for each sensor type they define. Generally, devices are equipped with a single sensor of each type, so defining a default sensor should be easy. For sensor types where multiple sensors are common, extension specifications may choose not to define a default sensor.
9.6. Extending the Permission API
Provide guidance on how to extend the Permission API [permissions] for each sensor types.
Accessing sensor data has multiple privacy implications and is therefore subject to permissioning. The Permission API allows developers to check whether the permission to access a given API was already granted (or denied) by the user on a per origin basis.
Currently, exposing that status through the Permissions API requires a modification of the Permission API spec itself. Ideally, we'd want sped editors authoring concrete sensor specs to be able to extend the Permission API within the same document.
This needs concertation with the editors of the Permissions API.
Actions:
- Liaise with @mounirlamouri and @marcoscaceres
- Investigate relationship to Permissions API.
- Try to find a solution that doesn't imply a Permissions API update for every concrete Sensor spec.
-
Email @public-script-coord about
partial enum
proposal - Wait for @public-script-coord feedback
- Document current issue as a note in the Extensibility section of the spec.
9.7. Immutability requirements
Attributes of the SensorReading subclass that hold sensor readings values must be readonly.
9.8. Example WebIDL
Here’s example WebIDL for a possible extension of this specification for proximity sensors.
[Constructor(optional ProximitySensorOptions proximitySensorOptions)] interface ProximitySensor : Sensor { readonly attribute ProximitySensorReading? reading; }; interface ProximitySensorReading : SensorReading { readonly attribute unrestricted double distance; }; dictionary ProximitySensorOptions : SensorOptions { double? min = -Infinity; double? max = Infinity; ProximitySensorPosition? position; ProximitySensorDirection? direction; }; enum ProximitySensorPosition { "top-left", "top", "top-right", "middle-left", "middle", "middle-right", "bottom-left", "bottom", "bottom-right" }; enum ProximitySensorDirection { "front", "rear", "left", "right", "top", "bottom" };
10. Acknowledgements
The following people have greatly contributed to this specification through extensive discussions on GitHub: Anssi Kostiainen, Boris Smus, chaals, Claes Nilsson, Dave Raggett, David Mark Clements, Domenic Denicola, Dominique Hazael-Massieux (via the HTML5Apps project), Francesco Iovine, Frederick Hirsch, gmandyam, Jafar Husain, Johannes Hund, Kris Kowal, Marcos Caceres, Marijn Kruisselbrink, Mark Foltz, Mats Wichmann, Matthew Podwysocki, pablochacin, Remy Sharp, Rich Tibbett, Rick Waldron, Rijubrata Bhaumik, robman, Sean T. McBeth, smaug----, Tab Atkins Jr., Virginie Galindo, zenparsing, and Zoltan Kis.
We’d also like to thank Anssi Kostiainen, Dominique Hazael-Massieux, Erik Wilde, and Michael[tm] Smith for their editorial input.
Conformance
Document conventions
Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.
All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]
Examples in this specification are introduced with the words "for example"
or are set apart from the normative text with class="example"
,
like this:
Because this document doesn’t itself define APIs for specific sensor types—
Informative notes begin with the word "Note" and are set apart from the
normative text with class="note"
, like this:
Note, this is an informative note.
Conformant Algorithms
Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.
Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.
Conformance Classes
A conformant user agent must implement all the requirements listed in this specification that are applicable to user agents.
Index
Terms defined by this specification
- calibration, in §3
- conformant user agent, in §Unnumbered section
- episodic, in §3
-
frequency
- definition of, in §3
- dict-member for SensorOptions, in §6.1
- high-level, in §3
- identifying parameters, in §6.1
- low-level, in §3
- oncalibration, in §6.1
- onchange, in §6.1
- ondata, in §6.1
- onerror, in §6.1
- periodic, in §3
- permission, in §6.1
- raw sensor readings, in §3
-
reading
- attribute for Sensor, in §6.1
- attribute for SensorReadingEvent, in §6.1
- dict-member for SensorReadingEventInit, in §6.1
- read steps, in §6.1
- reporting modes, in §3
- Sensor, in §6.1
- sensor, in §3
- sensor fusion, in §3
- sensor hubs, in §3
- SensorOptions, in §6.1
-
SensorReading
- definition of, in §6.2
- (interface), in §6.2
- SensorReading(), in §6.2
- SensorReadingEvent, in §6.1
- SensorReadingEventInit, in §6.1
- SensorReadingEvent(type, eventInitDict), in §6.1
- sensor readings, in §3
- sensor types, in §3
- Smart sensors, in §3
-
timeout
- attribute for Sensor, in §6.1
- dict-member for SensorOptions, in §6.1
- timeStamp, in §6.2
Terms defined by reference
- [dom] defines the following terms:
- [HTML] defines the following terms:
- [WebIDL] defines the following terms:
- [dom] defines the following terms:
- [hr-time-2] defines the following terms:
- [powerful-features] defines the following terms:
References
Normative References
- [HTML]
- Ian Hickson. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
- [WebIDL]
- Cameron McCormack; Boris Zbarsky. WebIDL Level 1. 4 August 2015. WD. URL: https://www.w3.org/TR/WebIDL-1/
- [DOM]
- Anne van Kesteren; et al. W3C DOM4. 19 November 2015. REC. URL: https://www.w3.org/TR/dom/
- [HR-TIME-2]
- Ilya Grigorik; James Simonsen; Jatinder Mann. High Resolution Time Level 2. 25 February 2016. WD. URL: https://www.w3.org/TR/hr-time-2/
- [POWERFUL-FEATURES]
- Mike West; Yan Zhu. Privileged Contexts. 24 April 2015. WD. URL: https://www.w3.org/TR/powerful-features/
- [RFC2119]
- S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
Informative References
- [API-DESIGN-PRINCIPLES]
- Domenic Denicola. API Design Principles. 29 December 2015. URL: https://w3ctag.github.io/design-principles/
- [EXTENNNNSIBLE]
- The Extensible Web Manifesto. 10 June 2013. URL: https://extensiblewebmanifesto.org/
- [QUDT]
- Ralph Hodgson; et al. QUDT - Quantities, Units, Dimensions and Data Types Ontologies. 18 March 2014. URL: https://www.qudt.org/
- [SI]
- SI Brochure: The International System of Units (SI), 8th edition. 2014. URL: https://www.bipm.org/en/publications/si-brochure/
- [geolocation-API]
- Andrei Popescu. Geolocation API Specification. 28 May 2015. PER. URL: https://www.w3.org/TR/geolocation-API/
- [ORIENTATION-EVENT]
- Stephen Block; Andrei Popescu. DeviceOrientation Event Specification. 1 December 2011. LCWD. URL: https://www.w3.org/TR/orientation-event/
- [PERMISSIONS]
- Mounir Lamouri; Marcos Caceres. The Permissions API. 7 April 2015. WD. URL: https://www.w3.org/TR/permissions/
IDL Index
interface Sensor : EventTarget { attribute double timeout; readonly attribute SensorReading? reading; attribute EventHandler onerror; attribute EventHandler ondata; attribute EventHandler onchange; attribute EventHandler oncalibration; }; [Constructor(DOMString type, SensorReadingEventInit eventInitDict)] interface SensorReadingEvent : Event { readonly attribute SensorReading reading; }; dictionary SensorReadingEventInit : EventInit { SensorReading reading; }; dictionary SensorOptions { double? frequency; double? timeout; }; [Constructor()] interface SensorReading { readonly attribute DOMHighResTimeStamp timeStamp; };