Review of Sensor API Specification

Hi,   
Quick review…  


On Wednesday, March 14, 2012 at 3:56 PM, Marcos Caceres wrote:

> W3C Editor's Draft 09 March 2012
>  
> Abstract
>  
> This specification defines a generic API for getting access to information provided by sensors available from a hosting device.
s/from/on ?   
>  
>  
> This section is non-normative
>  
> This specification defines an API that allows application code to obtain information given by the various sensors available on a hosting device. The information provided through this API is raw sensor data. The specification is aimed at covering well-known sensors that are commonly found in devices.  

Citation needed. Or at least some evidence that the scope is targeted at mobile devices (and not too narrow, given that specs take about 5 years to standardize).  
  
> The API is extensible, allowing integration of vendor or external specific sensors.


What does this mean? In what sense is it "extensible"?   
>  
> The following code snippet illustrates how to monitor sensor data, for instance the ambient temperature:
>  
> var sensorCnx = new SensorConnection('Temperature');
Please make it case insensitive if you haven't already.   
> sensorCnx.addEventListener('sensordata', function(e) {
> if(e.data > 20.0) {
> window.console.log('Temperature is too high!!!!');
> }
> } );

"sensordata" is redundant. You are already getting *data* for a sensor, just say ("data", function(){...}).  

> var watchOptions = { interval: (15 * 60 * 1000) };
> sensorCnx.startWatch(watchOptions);
> The following code snippet illustrates how to discover all sensors of type 'Temperature' that are available from the device:
>  
> var sensorReq = navigator.findSensors('Temperature');
I think the above is a typo (SensorManager missing)? Also what is the sensors are not available or become available over time?  

How about making scanning for sensors a static thing?  

window.sensors.addEventListener("found", function(e){var sensor = e.sensor;})
window.navigator.sensors.find();  

> sensorReq.onsuccess = function() {
> for(var count = 0; count < this.result.length; count++) {
> window.console.log("Discovered: " + this.result[count].name);
> }
> }
>  
> sensorReq.onerror = function() {
> window.console.error(this.error.code);
> }


This is a round about way of getting to the sensor (means you need to know all your sensors up front?). The request and the connection should be the same thing.  

var mySensor = new Sensor('temperature');  

mySensor.onerror = function (){}
mySensor.onwateva = function (){}  
  

> 2. Conformance
>  
> A conforming implementation is required to implement all fields defined in this specification.
>  
> 3. Security and Privacy Considerations
>  
> A conforming implementation of this specification must provide a mechanism that protects the user's privacy and this mechanism should ensure that no sensitive information is made available through this API without the user's express permission.
This statement is useless and untestable. If you want privacy, then bake it explicitly into the API.
  
> User agents must acquire permission through a user interface, unless they have prearranged trust relationships with users.

The above statement is also useless. Bake it into the API.   
>  
> 4. Sensor Discovery
>  
> Navigator implements SensorManager;
> All instances of the Navigator type are defined to also implement the SensorManager interface.

The above statement is redundant (the WebIDL already says it)…. It also doesn't really say_how_ to implement the sensor manager (is it a method or an attribute? is it read only?):


[NoInterfaceObject]
interface NavigatorSensorManager {
   readonly attribute SensorManager SensorManager;
};
Navigator implements SensorManager;



> 4.1 SensorManager
>  
> This is an asynchronous API that returns without blocking the calling thread.
This is redundant to state here. The proof is in the pudding (i.e., in the getter algorithms). Please remove.    
> This interface allows applications to discover what sensors are available from the device.  

  
> The sensor information is acquired by calling platform native sensor interfaces, creating a list of Sensor objects, and populating that object with appropriate data accordingly.

Please remove this sentence from here. It will just cause duplicate text in findSensors(), which is confusing and will lead to errors.   
>  
> [NoInterfaceObject]
> interface SensorManager {
> SensorRequest findSensors (DOMString type);
> };

Why is this a NoInterfaceObject?   
> 4.1.1 Methods
>  
> findSensors
> When invoked the user agent must immediately return a SensorRequest instance with the readyState set to processing,  

What's the use case for the ready state?  

> which does not initially contain any information about the result of the operation. If the user permissions are ok
What user permissions?   
> then the UA must queue a new listSensors process

What is a "new ListSensor process"?   
> that will call platform native sensor interfaces to fill a list of Sensor objects that will contain metadata about the sensors hosted by the device. The argument type must be set to the type of sensor to be searched for.

Why? How many times would you need to do this for the life of the application? How often do you need to run "finSensors()" that would justify the creation of multiple SensorRequest objects. Also, seems ridiculous to have to wait for the whole list to be populated before I get anything back… This could be made as a progress event that is tied to one object, as a demonstrated before:   

//send them to me as you find them…  
navigator.onfound = function(e){var sensor = e.sensor};  

//search for all the sensors on the device… take your time…. I don't mind.  
navigator.sensors.search();  
   
> If user permissions are not ok the process must finish and an error event on the request must be fired.

When where the permissions asked?   
>  
> Once the listSensors process finishes without error, the onSuccess event is fired on the request and the information becomes available through the properties of the SensorRequest instance.
So wait… I get an onSuccess event, but the event does not contain the list? I need to go to another object to get it?  
  
> If an error occurs while performing the operation, the onError event

lowercase onerror.
  
> is fired and the error is set to the error code.

Which error code?   
> If no matching sensors are found, this is NOT reported as an error but just an empty list of sensors. In either case the the readyState is set to done to indicate the discovery process has completed

The whole thing above needs to be written as an algorithm.   
>  
> This interface provides means
"a means"
  
> to access results of asynchronous sensor discovery requests.
> [NoInterfaceObject]

Why is this a NoInterfaceObject?   
> interface SensorRequest {
> readonly attribute DOMError error;

DOMError?   
> attribute Function onerror;

In addition to DOMError??? This seems confused… it's like you are mixing callbacks and events.  
> attribute Function onsuccess;
> readonly attribute DOMString readyState;
> readonly attribute Sensor[] result;

is this list being updated dynamically? I think this is supposed to be a sequence<Sensor>.  

So that:  
var list = navigator.findSensors('Temperature').results;
list.push("woopsy!");  

> };
  
> 4.2.1 Attributes
>  
> error of type DOMError, readonly
> When the readyState is done and an error exception has been raised, must return the error of the request. This is null when no error occurred. When the readyState is processing, must throw a DOMException of type InvalidStateError.

I can't parse the above.  
  
> onerror of type Function
> The event handler for the error event
> onsuccess of type Function
> The event handler for the success event
> readyState of type DOMString, readonly
> Represents the status of the request. It must be set to one of the following:
> processing. If the discovery process is still pending.
> done. If the discovery process is completed.
> result of type array of Sensor, readonly
> When the readyState is done, must return list of sensors discovered. This is undefined when the request resulted in an error. When the readyState is processing, must throw a InvalidStateError.

  
> 5. Sensor Metadata

Please don't use the word Metadata  
>  
> 5.1 Sensor
>  
> The Sensor object contains different attributes that provide sensor metadata.
> [NoInterfaceObject]
> interface Sensor {
> readonly attribute short? minDelay;
> readonly attribute DOMString name;
> readonly attribute short? minRange;
> readonly attribute short? maxRange;
> readonly attribute float? resolution;
> readonly attribute DOMString type;
> };

Make this object represent the sensor, not "metadata". Move all the connection stuff to this object.  
  
> 5.1.1 Attributes
>  
> maxRange of type short, readonly, nullable
> It must return the maximum range of the sensor in the sensor's unit or null if it is not known.
> minDelay of type short, readonly, nullable
> It must return the minimum delay allowed between two sensor data events in microseconds or zero if only sensor data events are dispatched when there is a change in the measured magnitude. null must be returned if this parameter is not known to the implementation.
> minRange of type short, readonly, nullable
> It must return the minimum range of the sensor in the sensor's unit or null if it is not known.
> name of type DOMString, readonly
> It must return an unique identifier for the sensor.
> resolution of type float, readonly, nullable
> It must return the sensor's resolution of the sensor in unit of measurement or null if this parameter is not known to the implementation.
> type of type DOMString, readonly
> It must return the sensor type. See table below for a list sensor types defined by this specification
> 6. Sensor Data
>  
> 6.1 SensorConnection Interface
Fold this into Sensor.   
>  
> The SensorConnection object is an event target that must be used to request a connection to a sensor of a specified type on the hosting device. The sensor connection is acquired by calling platform native sensor interfaces.
> [Constructor(DOMString type),Constructor(SensorOptions options)]
> interface SensorConnection : EventTarget {
> readonly attribute Sensor sensor;
> readonly attribute DOMString status;
> readonly attribute DOMError error;
> attribute Function? onerror;
> attribute Function? onsensordata;

saying "onsensordata" on a sensor is redundant. Say "ondata"
> attribute Function? onstatuschange;

The ready states are not really defined, and this seems like a pointless rip off of XHR without a clear use case.   
> attribute Function? oncalibneed;

how does one calibrate the sensor?  
> void read ();
> void startWatch (SensorWatchOptions watchOptions);
> void endWatch ();
> };
> 6.1.1 Attributes
>  
> error of type DOMError, readonly
> Represents the current error of the event target. This is null when no error occurred.
> oncalibneed of type Function, nullable
> Allows to set an event handler that will be invoked when the sensor needs calibration
> onerror of type Function, nullable
> Allows to set an event handler that will be invoked when the sensor connection is in error
> onsensordata of type Function, nullable

ondata  
> Allows to set an event handler that will be invoked when new sensor data is available
> onstatuschange of type Function, nullable
> Allows to set an event handler that will be invoked when connection status change
> sensor of type Sensor, readonly
> Represents the metadata of the sensor that is currently connected to this event target.
> status of type DOMString, readonly
> Represents the current status of the event target. The status must be set to one of the following:
> new. The object has been instantiated but a connection to the sensor has not been established yet.
> open. All the infrastructure to get sensor data is ready.
> watching. The sensor is under monitoring.
> disconnected. The connection with the sensor has been lost.
> error. An error has occured
> 6.1.2 Methods
>  
> endWatch
> When this method is called the user agent must run the following steps:
> If status is other than watching an ILLEGAL_STATE exception must be thrown.
> If status is watching then the following substeps must be done:
> Invoke platform native interfaces to notify the end of the monitoring.
> If the invocation succeeds, the status attribute must be set to the open value and the control must be returned to the caller. Finally, Queue a task to fire a simple event named statuschange at the SensorConnection.
> If the invocation fails Queue a task to fire a simple event named error at the SensorConnection.
> No parameters.
> Return type: void
> read
> When invoked the user agent must run the following steps:
> If the status is other than open or watching an ILLEGAL_STATE exception must be thrown.
> Otherwise the user agent must queue a task TRead to perform a reading from the sensor and then return immediately.
> Once TRead has finished successfully, the implementation must queue a task to fire a SensorDataEvent with:
> data field equal to the values read from the sensor.
> isWatchPoint field equal to 'false'
> If TRead fails Queue a task to fire a simple event named error at the SensorConnection.
> No parameters.
> Return type: void
> startWatch
> When called the user agent must run the following steps:
>  
> If status is other than open an ILLEGAL_STATE exception must be thrown
> If status is open then run the following sub-steps:
> Queue a task TWatch in charge of invoking the platform native interfaces to start monitoring sensor values in accordance with the parameters specified as part of SensorWatchOptions argument. Then, return immediately to the caller.
> If TWatch succeeds, the status attribute must be set to the watching value. Queue a task to fire a simple event named statuschange at the SensorConnection
> If TWatch fails then Queue a task to fire a simple event named error at the SensorConnection.
> Everytime the platform monitoring mechanism notifies of a new sensor value the user agent must queue a task to fire a SensorDataEvent with:
>  
> data field equal to the values read from the sensor
> isWatchPoint field equal to 'true'
> Parameter Type Nullable Optional Description
> watchOptions SensorWatchOptions ✘ ✘  
> Return type: void
> [Constructor(SensorOptions options)]
> Constructs a new SensorConnection. when invoked the user agent must run the following steps:
> Let _sensor be the target sensor to be connected to. If none of the dictionary members are defined then raise an instantiation exception.
> If the dictionary member name is not defined then _sensor must correspond to the default sensor type specified by the type member. Otherwise _sensor must be assigned to a sensor of the specified type and whose identifier is equal to the name member.
> Check if the sensor identified by _sensor is available and ready to be connected
> If the sensor exists, is available and user permissions are ok, then instantiate a SensorConnection object and set its status to 'open'.
> If user permissions are needed then instantiate the SensorConnection object, set its status to 'new' and prompt the user in a user-agent-specific manner for permission.
> Once the user gives permission set status to 'open'. If the user does not give permission set status to 'error' and fire an error event.
>  
> If the sensor is not available or does not exist raise an instantiation exception (tbd).
> Implementations may support other connection options as part of the SensorOptions interface
> [Constructor(DOMString type)]
> Constructs a new SensorConnection by passing a sensor type. This is a convenient function for the more general function described above.
> These constructors must be visible when the script's global object is either a Window object or an object implementing the WorkerUtils interface.
>  
> 6.2 SensorWatchOptions Interface
>  
> dictionary SensorWatchOptions {
> attribute double threshold;
> attribute double interval;
> };


Dictionary don't have "attribute"s  
> 6.2.1 Dictionary SensorWatchOptions Members
>  
> interval of type attribute double
> The interval attribute represents the monitorization interval at which data should be obtained from the underlying sensor hardware and must be expressed in milliseconds. The caller should be aware that setting a value too small can adversely affect the battery life. If the interval is set to zero, then the implementation must return sensor data only when there is a change since the last acquisition.
> threshold of type attribute double
> This attribute only applies to sensors that provide single value readings. It indicates that a data event must only be raised when the sensor value crosses the specified threshold (in either direction).
> This attribute is likely to be revisited to support these use cases:
> - Low and high thresholds
> - Ranges [10,20] (10,20] ....  
> - Thresholds that apply to the different data components of a sensor, for instance x,y,z in the case of accelerometer.
> 6.3 SensorOptions Interface
>  
> dictionary SensorOptions {
> attribute DOMString type;
> attribute DOMString name;
> };


Dictionary don't have "attribute"s
  
> 6.3.1 Dictionary SensorOptions Members
>  
> name of type attribute DOMString
> Sensor name for which a connection is requested
> type of type attribute DOMString
> Sensor type for which a connection is requested
> 6.4 SensorDataEvent Interface
>  
> This section will be changed to comply with the DOM4 Event interfaces
> interface SensorDataEvent : Event {
> readonly attribute any data;
> readonly attribute DOMString accuracy;
> readonly attribute double timestamp;
> readonly attribute boolean isWatchPoint;
> void initSensorDataEvent (DOMString type, boolean bubbles, boolean cancelable, boolean isWatchPoint, double timestamp, DOMString accuracy, any data);


I think init*Event constructors are discouraged.  
  
> };
> 6.4.1 Attributes
>  
> accuracy of type DOMString, readonly
> This attribute must return an enumerated value that gives an indication of the accuracy of the sensor data. The allowed values are:
> high - This sensor is reporting data with maximum accuracy
> medium - This sensor is reporting data with average accuracy, calibration with the environment may improve readings
> low This sensor is reporting data with low level of accuracy, calibration with the environment is needed
> unreliable - This sensor is reporting data that can't be trusted, calibration is needed.
> data of type any, readonly
> This attribute represents the raw data provided by the sensor. The specific type depends on the type of the sensor. See for implementation requirements for this attribute depending on the type of sensor.
> isWatchPoint of type boolean, readonly
> It is a boolean that denotes if this is a watch point. The only admissible values for this attribute are:
> false. The event was raised due to onetime read operation
> true. The event was raised due to a recurring watch operation
> timestamp of type double, readonly
> The time in nanosecond at which the sensor data was read.
> 6.4.2 Methods
>  
> initSensorDataEvent
> Initializes a SensorDataEvent created through the DocumentEvent interface.
> Parameter Type Nullable Optional Description
> type DOMString ✘ ✘  
> bubbles boolean ✘ ✘  
> cancelable boolean ✘ ✘  
> isWatchPoint boolean ✘ ✘  
> timestamp double ✘ ✘  
> accuracy DOMString ✘ ✘  
> data any ✘ ✘  
> Return type: void
> A section describing all the events defined by the API might be added for next draft.
> 7. Sensor Type Definitions
>  
> This section specifies some base sensor types and related data formats.
> 7.1 Sensor Types and Related Data Formats
>  
> This section specifies a base set of sensor types and related data formats. If the UA supports these sensor types, they must use this data format definition. Any UA can also extend its support to other sensors that are defined elsewhere outside of this specification. It is implementation dependent how to register and support new sensor types.
>  
> For the sensor types defined here, an implementation must set the specific type of the SensorDataEvent.data and SensorDataEvent.type attributes in accordance with the following table:
I think the spec is overstepping it's bounds here. These should be seperate specs.  
>  
> Sensor Type Description Data Type Units
> Temperature A ambient temperature sensor double degree Celsius (ºC)
> AtmPressure A pressure sensor double kiloPascal (kP)
> RelHumidity A releative humidity sensor double percentage
> AmbientLight A light sensor double Lux
> AmbientNoise A ambient noise sensor double dbA
> MagneticField A magnetic field sensor MagneticFieldData micro-Tesla (uTesla)
> Proximity A proximity sensor double centimetres (cm)

Please use all lowercase.   
> 7.2 The MagneticFieldData interface
>  
> interface MagneticFieldData {
> readonly attribute double x;
> readonly attribute double y;
> readonly attribute double z;
> };
> 7.2.1 Attributes
>  
> x of type double, readonly
> ambient magnetic field in X
> y of type double, readonly
> ambient magnetic field in Y
> z of type double, readonly
> ambient magnetic field in Z

Received on Wednesday, 14 March 2012 16:57:38 UTC