This specification defines a WebSocket based API for a vehicle information service that provides the functionality for client applications to get, set, subscribe and unsubscribe to vehicle signals and data attributes.

The purpose of the specification is to promote a Server API that enables application development in a consistent manner across participating automotive manufacturers.

Introduction

This specification describes how a vehicle can expose vehicle signals and static data via a WebSocket. This enables a client to GET or SET vehicle signals and data; to SUBSCRIBE to receive notifications and to UNSUBSCRIBE from receiving notifications.

The API that is used to manage access to vehicle signals and static data is defined in this Vehicle Information Service Specification (VISS). The VISS also describes a discovery mechanism that defines the set of signals and data that a client can access at a particular point in time.

The term 'signal' is used here to represent an item of data that can vary over time, for example vehicle speed, whilst the expression 'static data' is used to denote a temporally invariant property like vehicle width.

The GENIVI Vehicle Signal Specification (VSS) defines the set of vehicle signals and data that are exposed via this Vehicle Information Service Specification (VISS). The Vehicle Signal Specification (VSS) supports both extensibility and the ability to define private branches.

In addition, the 'tree' of signals that is accessible at any point in time may also vary depending on standard access control principles. That is, it can vary based on the identity of the user (person or organisation) requesting the data and/or the application or device (e.g. vehicle) where the request originates.

To support this, the Service Specification describes an extensible token based security mechanism that can optionally be used to pass tokens to the VIS Server, for example to represent the user of an application and/or the device that the client application is running on.

A vehicle-based software module may implement the interface and behaviours defined in this specification by creating a WebSocket instance that listens for an inbound connection request from a client in order to enable secure access to vehicle signals. In this specification this module is referred to as the VIS Server or just 'the server'.

A future revision of this specification may consider additionally exposing vehicle signals via a RESTful web service but this is out of scope for this version of the specification.

It is recommended that this Vehicle Information Service Specification (VISS) is read in conjunction with the W3C Vehicle Information API Specification (VIAS). The VIAS defines a client API that wraps the data access and security primitives defined in this Service Specification. It has been defined to support the development of 'standards-compliant' JavaScript libraries that can be used by web based clients.

Use of the VIAS is optional as any client that can instantiate a WebSocket may connect to the VIS Server directly. The following example is for illustrative purposes only, it does not show error handling and is not intended to be commercial code.

// Open the WebSocket
var vehicle  = new WebSocket("wss://wwwivi", "wvss1.0");

// Establish authorization
vehicle.onopen = function () {
  vehicle.send('{"action": "authorize", "tokens": {"authorization": "user_token_value"}, "requestId": "103"}');
};

// Message response handler for all possible actions
vehicle.onmessage = function(event){
  var msg = JSON.parse(event.data);
  switch(msg.action){
    case "authorize":
      authHandler(msg);
      break;
    case "getVSS":
      getVSSHandler(msg);
      break;
    case "get":
      getReqHandler(msg);
      break;
    case "set":
      setReqHandler(msg);
      break;
    case "subscribe":
      subscriptionSetupHandler(msg);
      break;
    case "subscription":
      subscriptionHandler(msg);
      break;
    case "unsubscribe":
      unsubscribeHandler(msg, false);
      break;
    case "unsubscribeAll":
      unsubscribeHandler(msg, true);
      break;
  }
};

// Auth request handler
function authHandler(msg) {
  if(msg.hasOwnProperty("TTL")){
    console.log("authorization successful");
    requestVSS();
  } else {
    console.log("authorization unsuccessful");
  }
}

// Close the WebSocket to end the WebSocket session
function closeSocket(){
  vehicle.close();
}
  

Once the WebSocket connection has been established, the client is able to retrieve the VSS from the server and request signals for the client's current level of authentication.

// Request the entire VSS tree
function requestVSS(){
  vehicle.send('{"action": "getVSS", "requestId": "103"}');
}

// Request the entire VSS tree and if successful, request a signal
function getVSSHandler(msg){
  if(msg.hasOwnProperty('vss')){
    console.log("VSS Received");
    console.log("VSS: " + JSON.stringify(msg.vss));
    getSignal(vss, "Signal.Drivetrain.Transmission.Speed");
  } else {
    console.log("getVSS Error");
  }
}

// Request a signal
function getSignal(vss, path){
  // A check could be made here to ensure the signal is available in the VSS
  vehicle.send('{"action": "get", "path": ' + path + ', "requestId": "105"}');
}
  

The client is also able to subscribe to signals if the client's authentication permits access.

// Set a subscription, assuming the same authorization and set up from Example 1
var rpmSubscriptionId, rpmRequestId = "106";

// Set up the subscription
function subscribeToRPMNotifications(){
  vehicle.send('{"action": "subscribe", "path": "Signal.Drivetrain.InternalCombustionEngine.RPM",  "requestId": ' + rpmRequestId + '}');
}

// Handle the subscription response
function subscriptionSetupHandler(msg){
    if(msg.hasOwnProperty("requestId") && msg.requestId == rpmRequestId){
      console.log("Subscription set with a subscription ID of " + msg.subscriptionId);
      rpmSubscriptionId = msg.subscriptionId;
    }
}

// Handle the subscription notification
function subscriptionHandler(msg){
    if(msg.hasOwnProperty("subscriptionId") && msg.subscriptionId == rpmSubscriptionId){
      console.log("The current engine rpm is " + msg.value);
    }
}

  

The target platform supported by the specification is exclusively passenger vehicles. Use of this specification for non-passenger applications (for example heavy machinery, marine and airline infotainment) is not prohibited, but is not covered in the design or content of the API.

An example use case could be the implementation of a 'Home Mechanic' application that provides warnings if any the following need attention: tire pressure, engine oil level, washer fluid level and battery charge level.

Exposing vehicle signals in a standardized manner facilitates the integration of vehicles within the Web of Things (WoT) and supports future use case innovations in a variety of fields including transportation, safety, navigation, energy management, smart transportation and consumer infotainment.

The data format used for client/server communication within this specification is JSON encoded strings, however other data formats may be supported in future versions of the specification.

This specification defines conformance criteria that apply to a single product: specifically the 'in-vehicle' WebSocket Vehicle Information Service that implements the interfaces, semantics and behaviour defined in this document. For simplicity, this usually is referred to as the 'VIS Server' or just 'the server'

Terminology

The acronym 'VISS' is used to refer to this document, the 'Vehicle Information Service Specification'. The term 'VIS Server' is used to refer to a server which conforms to the 'VISS' specification.

The acronym 'VIAS' is used to refer to the 'Vehicle Information API Specification' (see here) which has been developed alongside the VISS to expose a client API which can implement the VISS.

The acronym 'VSS' is used to refer to the 'Vehicle Signal Specification' (see here) which is defined by the GENIVI Alliance.

The term 'WebSocket' when used in this document, is as defined in the W3C WebSocket API (see here) and the WebSocket Protocol (see RFC6455).

Architecture

Overview

In a typical vehicle design, signals and data are transmitted between Electronic Control Units (ECUs) connected via internal vehicle networks. These include Controller Area Networks (CAN), Media Oriented Systems Transport (MOST) and Local Interconnect Networks (LIN). ECUs on these networks broadcast messages on network buses, and other ECUs on the bus respond to the messages.

In the component diagram included below, the internal vehicle CAN, MOST and LIN networks and the ECUs that communicate via these networks are abstracted and for simplicity, represented by the System component.

For safety, security and commercial reasons not all clients should be able to GET, SET or SUBSCRIBE to particular vehicle signals and data attributes. As a consequence, access-control must be managed so clients cannot simply connect directly to ECUs or to CAN, MOST or LIN network buses.

In this specification, the term 'signal' refers to a value that can change over time, for example, vehicle speed, whilst 'static data' or simply 'data' is used for a value that does not change e.g. vehicle length.

The vehicle signals and static data that are available within the vehicle System are exposed in a controlled manner to the VIS Server. The interface and communication mechanisms that are used between the vehicle System and the VIS Server are outside of the scope of this specification.

VIS Server

The VIS Server is the vehicle system that is responsible for exposing vehicle signals and data to its clients by implementing the interface and behaviours defined in this Vehicle Information Service Specification (VISS).

The VIS Server exposes signals and data in a manner that is consistent with the Vehicle Signal Specification (VSS). This defines a 'tree-like' logical taxonomy of the vehicle, (formally a Directed Acyclic Graph), where major vehicle structures (e.g. body, engine) are near the top of the tree and the logical assemblies and components that comprise them, are defined as their child nodes. Each of the child nodes in the tree is further decomposed into its logical constituents, and the process is repeated until leaf nodes are reached. A 'leaf node' is a node at the end of a branch that cannot be decomposed because it represents a single signal or data attribute value. An example VSS tree is shown below, its contents are illustrative:

Diagram showing an example Vehicle Signal tree
Diagram showing an example Vehicle Signal Tree

Signals are named according to their path using the dot notation e.g. engine.rpm.

The client MAY invoke the VIS Server's getVSS method to request that the server returns metadata that describes which signals and data attributes could potentially be accessed provided that the user and/or device is suitably authorized. This and other valid VIS Server actions are defined in more detail here.

In-Vehicle Clients

In-vehicle clients include both those clients that are running on an ECU in the vehicle itself, e.g. an ECU that implements an In Vehicle Infotainment (IVI) system, but also includes clients running on a user's device, e.g. a laptop, phone or tablet, that is connected via the vehicle's WiFi client (if one exists).

Component diagram showing W3C Vehicle Information APIs
Diagram showing Components that implement the W3C Vehicle Information APIs and their clients

The methods defined on the VIS Server interface may be invoked by different types of on-board and off-board clients. On-board clients, running on the vehicle fall into one of two major categories:

Applications can access vehicle signals and data and have a User Interface that the driver or passengers in the vehicle can interact with.

Agents typically have no user interface. They can also invoke methods exposed on the VIS Server but their purpose is to connect to one or more off-board e.g. Vehicle to Everything (V2X) internet Servers in order to send data off-board.

Both applications and agents can be subdivided into those that are web-based and which run in a 'Web Runtime' and are implemented using Web Standards like HTML, CSS and JavaScript; those that run in their own native process written using e.g. C, C++ or Objective-C; and those that run in a Managed Runtime process written using languages like C# or Java.

Web applications and web agents MAY directly invoke the Vehicle Information Service interface exposed by the VIS Server, but it is expected that they typically access vehicle signals and data via a JavaScript Library that implements the W3C Vehicle Information API Specification (VIAS) (see here). The VIAS is a client API that defines a standard approach to encapsulate or 'wrap' the API defined in this specification to make it easier for Web based clients to access vehicle signals and data in a controlled way.

Sending Signals and Data off-board

In addition to local, in-vehicle applications and agents, a variety of internet-based clients and servers may be interested in accessing vehicle signals and data. However, when a vehicle is not being used, most electrical systems are shut down in order to maximize battery life. This may include the systems that enable Wireless or Mobile connectivity. Then, when the vehicle is powered up, various systems start up, including those that provide off-board connectivity and the vehicle typically connects either to a local WiFi network or to a Mobile Network Operator (MNO) and is dynamically assigned an IP address.

At this point, internet based clients and servers do not know the dynamic IP address that was assigned to a specific vehicle. So normally, a vehicle has to connect to a well known endpoint, generally using a URL to connect to a V2X Server. The vehicle and the internet server typically mutually authenticate and the vehicle 'registers' with the V2X server over an encrypted channel passing it a unique identifier e.g. its Vehicle Identification Number (VIN). From that point on, the V2X server has the IP address that is currently assigned to a vehicle with a particular VIN, and can share this information with other internet based clients and servers, which are then able to send messages to the vehicle.

However, if the vehicle loses connectivity and is dynamically assigned a new IP address, it needs to re-register its new IP address and the new address needs to be communicated to any interested parties. For simplicity, this is not shown in the component diagram, primarily because this connectivity only becomes possible after the vehicle has registered with at least one off-board server (which is shown) but also because these scenarios do not affect the interface and behaviours defined in this Vehicle Information Service Specification.

The component diagram shows four different types of internet based clients. A user may use a Web Page or a Web Application running on a phone or tablet to request access to vehicle signals on a particular vehicle. Alternatively these signals could be accessed using a Native or Managed Runtime Application or via another automated Client System or service e.g. the Traffic Management System in a 'Smart City'.

This specification assumes that a single WebSocket is used to enable communication between a client application and the server. It is not explicitly prohibited for the client to request that the server opens more than one WebSocket, however, the server may refuse to open a subsequent WebSocket connection and the client is responsible for handling this gracefully.

If more than one WebSocket connection is established between a client application and the server then each connection MUST be managed independently. For example, subscriptions created using a particular WebSocket connection SHALL only trigger notifications via that connection and the client MUST use that WebSocket connection to unsubscribe.

If more than one WebSocket connection has been established between one or more clients and a particular server instance, there is a risk that race conditions and concurrency issues could occur. An example of this would be where two or more WebSocket connections are used to update a particular setting at the same time.

Unless explicitly stated otherwise, the client can only assume that the server implements a simple concurrency model where lost updates and dirty reads could potentially occur if the server has more than one WebSocket connection open.

Security and Privacy Considerations

Introduction

The VIS Server implementation MAY optionally restrict access to one or more vehicle signals so that they can only be accessed in response to a request from an authorized user and/or device. This could be for a variety of reasons, including safety, privacy or commercial considerations.

Hence, a request to GET, SET, SUBSCRIBE or UNSUBSCRIBE to data may require the client to demonstrate to the server that the request is from one or more suitably authorized Security Principals.

The different types of Security Principal, the approach taken to control access to signals and the importance of data privacy are described in the sections that follow.

Security Principals

The types of security principal include:

Type Description
User A person, system or organisation responsible for making the request e.g. driver, Emergency Services, Smart City Traffic Management System.
Device Vehicle or device where the request originates. Could for example be a user's Consumer Electronics (CE) device connected to the vehicle's WiFi hotspot or another vehicle in a convoy; an Electronic Control Unit (ECU) on the same vehicle or any internet connected system e.g. a Web of Things (WoT) device.

Access Control and Authorization

When a client makes a request to access signal data it is performing the request on behalf of one or more Security Principals, that is, for a particular user and/or vehicle/device.

Access to signals is managed and controlled by the server. The server MAY elect not to enforce access controls on a particular signal or set of signals and to enforce different access controls on other signals.

For each security principal that must be authorized by the server, the client SHALL obtain and pass a security token e.g. an OAuth 2.0 token (see RFC6749) to the server using a message containing an 'authorize' action as defined here.

A server implementation MAY require that a request for a particular signal includes a security token for both the user (e.g. driver of the vehicle) and for the device (e.g. the vehicle) that is hosting the client. A request for a different set of vehicle signals MAY require that only the user is authorized or that only the device is authorized to access particular signals.

WebSocket Channel Authorization

The client MAY send a message with an 'authorize' action to modify the access-control state of the WebSocket channel. The message structure is defined in detail here.

The following diagram illustrates a scenario where the client requests vehicle speed. In this example scenario, this signal is not under access control and so the server returns a message containing the requested data. The client then requests that the server sets the vehicle trunk status to open and the server demands that the client passes access-control credentials before satisfying the request. The steps are shown in more detail in the diagram below:

WebSocket Security token flow
Diagram showing conceptual WebSocket Security Token flow (data structures are illustrative only)

TODO: Update diagram to reflect auth token structure and review including other diagrams from Wiki

After receiving a message with an 'authorize' action the server attempts to verify the tokens e.g. by checking with the issuing Security Authority. If all of the tokens that are passed to the server are valid, it returns a success response and all subsequent requests received by the WebSocket instance have elevated access control privileges. Specifically, each of the GET, SET, SUBSCRIBE and UNSUBSCRIBE actions have the access control rights that the server deems to be appropriate for the security principals represented by the token(s).

If the client sends a subsequent 'authorize' message to the server with different token value(s). If one or more of these are invalid, then the server returns an error response and the WebSocket access control status remain unchanged. However, if the new token values are valid, then the server returns a success response and the access control privileges associated with the new token(s) only, applies for all requests from that point.

If the client or the server close the WebSocket connection and a new WebSocket instance is opened, then it is opened without elevated access control privileges.

This service specification defines a standardized, token based approach for access control that includes specific error responses for common user and device access control scenarios. It is important however, that the security model is extensible. Hence, the server MAY implement any type of token that is consistent with this standardized approach and MAY optionally define additional token(s) for other Security Principal type(s). If this is the case, it is expected that the precise type of security tokens that are supported by a particular server implementation, the format of those tokens and all additional error codes and reasons (e.g. to indicate that an additional token type has expired and needs to be renewed) is defined in the Server's documentation.

Use of Encryption

To support a layered security model and to help establish a 'defence in depth', all vehicle signal and data communications between the client and server MUST be strongly encrypted. This is to make it more difficult for an attacker to eavesdrop or tamper with the security tokens; the request data or the response payload.

One way in which this may be implemented is for the client and the server to use a Public Key Infrastructure (PKI) approach, where the client verifies the server's identity by checking the server's X.509 certificate and the client and the server negotiate to establish a secure Transport Layer Security (TLS) 'tunnel'.

The WebSocket protocol mandates that if a client requests that the server opens a WebSocket connection and the request is received over HTTPS, then the WebSocket is established over TLS, that is, a secure 'wss' connection is created.

Token Renewal

Each security token SHALL have a specified lifetime during which it is valid. If on receiving a request for signals that are subject to access-control, the server determines that the request is unauthorized because the token has expired, the server returns an error response indicating the fact and the client requests a new token from the Security Authority and repeat the request.

If the server returns an error response indicating that the request is forbidden, renewing the security token does not make the request valid. In this case, the client should not repeat the request unless some other change has been made that may mean the request is now valid.

Initialisation of the WebSocket

If the client application is an HTML Application running in a web runtime or is a web page running in a browser, the WebSocket instance may either be instantiated natively or be created using a 'standards compliant' WebSocket JavaScript library.

A WebSocket can also be initiated from a native (e.g. C++) Application or from an Application written using a 'Managed Runtime' language like Java or C#. It is assumed that native and managed clients use a suitable standards compliant WebSocket library to request that a WebSocket connection is opened on the server.

A client running on the vehicle is able to connect to the VIS Server instance using the hostname 'wwwivi' and uses the default port 443. The hostname 'wwwivi' may locally be mapped to the localhost IP address 127.0.0.1 e.g. by adding an entry to the /etc/hosts file.

The sub-protocol name SHALL be 'wvss' with a version number suffix, e.g. wvss1.0

	  var vehicle  = new WebSocket("wss://wwwivi", "wvss1.0");
	

Discuss merits of using 'wwwivi' as a standardized hostname. Do we want a more generic hostname, not just for IVI but also encompassing WoT standards?

The client SHALL connect to the server over HTTPS and request that the server opens a WebSocket. All WebSocket communications between the client and server MUST be over ‘wss’. Non encrypted communication is not supported, hence the server MUST refuse ‘ws’ connection requests.

Message Structure

The client MUST use the WebSocket send method, defined here, to pass request messages to the server. The message signature SHALL be:

		WebSocket.send(request)
	

The request message MUST be comprised of one the request objects defined in this section. The client SHALL receive responses from the server using the WebSocket onmessage method, as follows:

		WebSocket.onmessage = function(obj){
			// process data
		}
	

The message returned by the server MUST be one of the response objects defined in the table below.

Request Objects Response Objects
authorizeRequest authorizeSuccessResponse
authorizeErrorResponse
vssRequest vssSuccessResponse
vssErrorResponse
getRequest getSuccessResponse
getErrorResponse
setRequest setSuccessResponse
setErrorResponse
subscribeRequest subscribeSuccessResponse
subscribeErrorResponse
subscriptionNotification
subscriptionNotificationError
unsubscribeRequest unsubscribeSuccessResponse
unsubscribeErrorResponse
unsubscribeAllRequest unsubscribeAllSuccessResponse
unsubscribeAllErrorResponse

The request and response parameters contain a limited number of attributes, defined in the table below.

Term Definitions

Attribute Type Description
action Action The type of action requested by the client or delivered by the server.
path String The path to the desired vehicle signal(s), as defined by the Vehicle Signal Specification (VSS).
requestId String Unique id value specified by the client. Returned by the server in the response and used by client to link the request and response messages. The value MAY be an integer or a Universally Unique Identifier (UUID).
subscriptionId String Value returned by the server to uniquely identify each subscription. The value MAY be an integer or a Universally Unique Identifier (UUID).
tokens object Structure containing one or more security token (e.g OAuth2) name/value pairs.
timestamp integer The Coordinated Universal Time (UTC) time that the server returned the response (expressed as number of milliseconds).
value any The data value returned by the server. This could either be a basic type, or a complex type comprised of nested name/value pairs in JSON format.
TTL integer Returns the time to live of the authorization token in seconds.
filters object Provides a filtering mechanism to reduce the demands of a subscription on the server.
vss object Metadata describing the potentially available VSS tree.
error Error Returns an error code, reason and message.

JSON Schema Definitions

The definitions within this section describe the datatypes referenced within the JSON Schema VISS interfaces.

{
    "definitions": {
        "action": {
            "enum": [ "authorize", "getVSS", "get", "set", "subscribe", "subscription", "unsubscribe", "unsubscribeAll"],
            "description": "The type of action requested by the client or delivered by the server",
        },
        "requestId": {
            "description": "Returned by the server in the response and used by the client to 
              link the request and response messages.",
            "type": "string"
        },
        "path": {
            "description": "The path to the desired vehicle signal(s), as defined by the Vehicle 
              Signal Specification (VSS).",
            "type": "string"
        },
        "value": {
            "description": "The path to the desired vehicle signal(s), as defined by the Vehicle 
              Signal Specification (VSS).",
            "type": "string"
        },
        "timestamp": {
            "description": "The Coordinated Universal Time (UTC) time that the server returned 
              the response (expressed as number of milliseconds).",
            "type": "integer"
        },
        "filters": {
            "description": "May be specified in order to throttle the demands of subscriptions 
              on the server.",
            "type": ["object", "null"],
            "properties": {
                "interval": {
                    "description": "The subscription will provide notifications with a period 
                      equal to this field's value.",
                    "type": "integer"                   
                },
                "range": {
                    "description": "The subscription will provide notifications only when within 
                      a given range.",
                    "type": "object",
                    "properties":{
                      "below": {
                        "description": "The subscription will provide notifications when the value 
                          is less or equal to this field's value.",
                        "type": "integer"  
                      },
                      "above": {
                        "description": "The subscription will provide notifications when the value 
                          is greater than or equal to this field's value.",
                        "type": "integer"  
                      },
                    }                   
                },
                "minChange": {
                    "description": "The subscription will provide notifications when a value has 
                      changed by the amount specified in this field.",
                    "type": "integer"                   
                }
            }
        },
        "subscriptionId":{
            "description": "Integer handle value which is used to uniquely identify the 
              subscription.",
            "type": "string"
        },
        "vss":{
            "description": "Metadata describing the potentially available VSS tree.",
            "type": "object"
        },
        "error": {
            "description": "Server response for error cases",
            "type": "object",
            "properties": {
                "number": {
                    "description": "HTTP Status Code Number",
                    "type": "integer"                   
                },
                "reason": {
                    "description": "Pre-defined string value that can be used to distinguish 
                      between errors that have the same code",
                    "type": "string"                    
                },
                "message": {
                    "description": "Message text describing the cause in more detail",
                    "type": "string"                    
                },
            }   
        }
    }
}

Action

The Action enumeration is used to define the type of action requested by the client. All client messages MUST contain a JSON structure that has an 'action' name/value pair and the value of the 'action' property MUST be one of the values specified in the enumeration:

authorize
Enables client to pass security tokens for Security Principals to the server to support access-control.
getVSS
Allows the client to request metadata describing signals and data attributes that are potentially accessible.
get
Enables the client to get a value once.
set
Enables the client to set a value once.
subscribe
Enables the client to request notifications containing a JSON data structure with values for one or more vehicle signals and/or data attributes. The client requests that it is notified when the signal changes on the server.
subscription
Enables the server to send notifications to the client containing a JSON data structure with values for one or more vehicle signals and/or data attributes.
unsubscribe
Allows the client to notify the server that it should no longer receive notifications based on that subscription.
unsubscribeAll
Allows the client to notify the server that it should no longer receive notifications for any active subscription.

Authorize

To enable access to signals and data attributes that are under access control, the client MAY optionally pass a message with an 'authorize' action to the server. The structure of the message and the associated success and error responses are defined below.

Authorize Request Properties

The properties and schema for an authorizeRequest is:

Object NameAttributeTypeRequired
authorizeRequest
actionActionYes
tokensobjectYes
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Authorize Request",
    "description": "Enables the user to set access controls for the vehicle signals",
    "type": "object",
    "required": ["action", "tokens", "requestId"],
    "properties": {
        "action": {
            "enum": [ "authorize" ],
            "description": "The identifier for the authorize request",
        },
        "tokens": {
            "description": "Extensible key-value pair token mechanism used for access control",
            "type": "object",
            "properties": {
                "authorization": {
                    "description": "The user token, for the user that the client is making 
                      requests on behalf of",
                    "type": "string"
                },
                "www-vehicle-device": {
                    "description": "The device token for the originating device that is making 
                      the request to the server",
                    "type": "string"
                }
            }
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for an authorizeSuccessResponse is:

Object NameAttributeTypeRequired
authorizeSuccessResponse
actionActionYes
TTLintegerYes
requestIdstringYes
    
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Authorize Success Response",
    "description": "The response sent from the server upon a successful authorization request",
    "type": "object",
    "required": ["action", "TTL", "requestId"],
    "properties": {
        "action": {
            "enum": [ "authorize" ],
            "description": "The identifier for the authorize request",
        },
        "TTL": {
            "description": "The time to live of the authorization token",
            "type": "integer"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for an authorizeErrorResponse is:

Object NameAttributeTypeRequired
authorizeErrorResponse
actionActionYes
errorErrorYes
requestIdstringYes
  
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Authorize Error Response",
    "description": "The response sent from the server upon an unsuccessful authorization request",
    "type": "object",
    "required": ["action", "error", "requestId"],
    "properties": {
        "action": {
            "enum": [ "authorize" ],
            "description": "The identifier for the authorize request",
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The server SHALL provide support the following security token types and names:

Security Principal Token Name Description
User authorization The user that the client is making requests on behalf of. This MAY be a person e.g. driver or passenger, it MAY be an organisation e.g. Emergency Services or MAY be any other legal entity.
Device www-vehicle-device The originating device that is making the request to the server. This MAY be an ECU in the vehicle that is hosting the VIS Server or MAY be a device that is connected to the vehicle via a WiFi hotspot or MAY be any other device.

The 'tokens' JSON fragment MAY contain an 'authorization' structure that contains just a single name/value pair, for example, to pass only the user token. Or it may contain only the 'www-vehicle-device' name/value pair to pass the just the vehicle token; alternatively it MAY include name/value pairs for both the 'authorization' and 'www-vehicle-device' tokens. These alternatives are illustrated in the following example:

		if(userTokenOnly){
			// Pass user token only
			vehicle.send('{ "action": "authorize",
				"tokens": { "authorization": "<user_token_value>" },
				"requestId": "<some_unique_value>" }');

		} else if (deviceTokenOnly) {
			// Pass vehicle/device token only
			vehicle.send('{ "action": "authorize",
				"tokens": { "www-vehicle-device": "<device_token_value>" },
				"requestId": "<some_unique_value>" }');

		} else if (userAndDeviceToken) {
			// Pass tokens for user and device
			vehicle.send('{ "action": "authorize",
				"tokens": { "authorization": "<user_token_value>",
					"www-vehicle-device": "<device_token_value>" },
				"requestId": "<some_unique_value>" }');
		}
	

This specification purposely does not define the token structure and the methods to obtain token(s). Providers of the server implementation may select their own preferred token format and method for verifying the authenticity of token(s) passed to the server. The server may also treat tokens as opaque structures and pass them on to underlying software layers for evaluation.

It is expected that client and server use the same token format. If a client presents a token using a format that is not understood by the server, the server rejects the token.

In order to make dictionary attacks more difficult, authentication will be denied after a number of failed authentication requests. A 401 (Unauthorized) too_many_requests error will be sent by the server in response to any subsequent authentication requests. The number of failed requests and the period of time during which attempts will be denied is to be determined by the implementation.

VSS Request

The client MAY use the 'getVSS' action to request metadata describing the potentially available VSS tree. It does this by sending a 'vssRequest' message to the server. If the server is able to return the VSS metadata, then this is returned using a 'vssSuccessResponse' message. If an error occurs, the server returns a 'vssErrorResponse' message to the client.

The client is able to request VSS metadata from any point in the VSS tree, such that only the metadata for the signals within the given branch of the tree is returned. For example, only metadata for the chassis branch of the tree is returned when the chassis path is specified. If the path is not set, the response contains the metadata for the entire VSS tree.

If more than one 'getVSS' call is made with the same 'vssRequest' message content but at different times, the metadata in the 'vssSuccessResponse' SHALL be the same provided the access-control state of the WebSocket channel has not changed.

The server shall return VSS metadata for all branches and nodes in the VSS tree, with the exception of the "Private" branch, regardless of whether the client can access them under the current access controls. If a signal is requested to which the client has no access then the server will reject the request as detailed by the Get, Set, and Subscribe sections of this specification. The server shall not return the metadata for the branches and nodes within the "Private" branch unless the client has appropriate access permissions.

VSS Request Properties

The properties and schema for a vssRequest is:

Object NameAttributeTypeRequired
vssRequest
actionActionYes
pathstringYes
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "VSS Request",
    "description": "Request metadata describing the potentially available VSS tree",
    "type": "object",
    "required": ["action", "path", "requestId"],
    "properties": {
        "action": {
            "enum": [ "getVSS" ],
            "description": "The identifier for the getVSS request"
        },
        "path": {
            "$ref": "#/definitions/path"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for a vssSuccessResponse is:

Object NameAttributeTypeRequired
vssSuccessResponse
actionActionYes
requestIdstringYes
vssobjectYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "VSS Success Response",
    "description": "The response sent from the server upon a successful getVSS request",
    "type": "object",
    "required": ["action", "requestId", "vss", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "getVSS" ],
            "description": "The identifier for the getVSS request"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "vss": {
            "$ref": "#/definitions/vss"
        },
	"timestamp": {
	    "$ref": "#/definitions/timestamp"
    	}
    }
}

The properties and schema for a vssErrorResponse is:

Object NameAttributeTypeRequired
vssErrorResponse
actionActionYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "VSS Error Response",
    "description": "The response sent from the server upon an unsuccessful getVSS request",
    "type": "object",
    "required": ["action", "requestId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "getVSS" ],
            "description": "The identifier for the getVSS request"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
	"timestamp": {
	    "$ref": "#/definitions/timestamp"
    	}
    }
}

Examples

The following data flow example shows a request for the signal structure within the Signal.Drivetrain.InternalCombustionEngine.RPM branch containing the vehicle RPM signal. A leaf node has been chosen in this example for brevity, however entire VSS branches can also be requested using the getVSS interface.

  client -> {
    "action": "getVSS",
    "path": "Signal.Drivetrain.InternalCombustionEngine.RPM",
    "requestId": "3874"
  }
  receive <- {
    "action": "getVSS",
    "requestId": "3874",
    "vss": { "Signal": {
        "description": "All signals that can dynamically be updated by the vehicle",
        "type": "branch",
        "children": {
          "Drivetrain": {
            "description": "Drivetrain data for internal combustion engines, transmissions, electric motors, etc.",
            "type": "branch",
            "children": {
              "InternalCombustionEngine": {
                "description": "Engine-specific data, stopping at the bell housing.",
                "type": "branch",
                "children": {
                  "RPM": {
                    "description": "Engine speed measured as rotations per minute.",
                    "min": 0,
                    "max": 20000,
                    "type": "UInt16",
                    "id": 54,
                    "unit": "rpm"
                  }
                }
              }
            }
          }
        }
      }
    },
    "timestamp": 1496087968995
  }
  

The following data flow example shows a request for the VSS structure within the Attribute.Body branch of the VSS. The example assumes the VSS contains two leaf nodes within the Attribute.Body branch.

  client -> {
    "action": "getVSS",
    "path": "Attribute.Body",
    "requestId": "3875"
  }
  receive <- {
    "action": "getVSS",
    "requestId": "3875",
    "vss": { "Attribute": {
        "description": "Attribute signals that do not change during the power cycle of a vehicle.",
        "type": "branch",
        "children": {
          "Body": {
            "description": "All body components",
            "type": "branch",
            "children": {
              "BodyType": {
                "description": "Body type code as defined by ISO 3779",
                "type": "string"
              },
              "RefuelPosition": {
                "description": "Location of the fuel cap or charge port",
                "type": "string",
                "enum": ["front_left", "front_right", "middle_left", "middle_right", "rear_left", "rear_right"]
              }
            }
          }
        }
      }
    },
    "timestamp": 1489985044000
  }
  

Get

The client MAY send a 'getRequest' message to the server to get the value of one or more vehicle signals and data attributes. If the server is able to satisfy the request it SHALL return a 'getSuccessResponse' message. If the server is unable to fulfil the request, e.g. because the client is not authorized to retrieve one or more of the signals, then the server SHALL return a 'getErrorResponse'. The structure of these message objects is defined below:

Get Request Properties

The properties and schema for a getRequest is:

Object NameAttributeTypeRequired
getRequest
actionActionYes
pathstringYes
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Get Request",
    "description": "Get the value of one or more vehicle signals and data attributes",
    "type": "object",
    "required": ["action", "path", "requestId"],
    "properties": {
        "action": {
            "enum": [ "get" ],
            "description": "The identifier for the get request",
        },
        "path": {
            "$ref": "#/definitions/path"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for a getSuccessResponse is:

Object NameAttributeTypeRequired
getSuccessResponse
actionActionYes
requestIdstringYes
valueobjectYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Get Success Response",
    "description": "The response sent from the server upon a successful get request",
    "type": "object",
    "required": ["action", "requestId", "value", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "get" ],
            "description": "The identifier for the get request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "value": {
            "$ref": "#/definitions/value"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a getErrorResponse is:

Object NameAttributeTypeRequired
getErrorResponse
actionActionYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Get Error Response",
    "description": "The response sent from the server upon an unsuccessful get request",
    "type": "object",
    "required": ["action", "requestId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "get" ],
            "description": "The identifier for the get request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

Examples

It is important to note that all examples involving paths are illustrative. Valid path values and the signals and data attributes that correspond to a particular path are defined in the Vehicle Signal Specification.

The example below shows the JSON structure for a 'getRequest' message sent by the client to obtain the engine RPM value and a 'getSuccessResponse' returned by the server.

	client -> {
		"action": "get",
		"path": "Signal.Drivetrain.InternalCombustionEngine.RPM",
		"requestId": "8756"
	}

	receive <- {
		"action": "get",
		"requestId": "8756",
		"value": 2372,
		"timestamp": 1489985044000
	}
	

In the case where the server returns a value that is a complex type, i.e. a value that is not a single basic JavaScript type (e.g. string, number, boolean), the value SHALL be returned as a set of name/value pairs in a JSON object structure. The format MUST be as defined by the Vehicle Signal Specification.

The following shows an example of a 'getRequest' that results in the server returning a 'getSuccessResponse' with a value that is a complex type:

	client -> {
		"action": "get",
		"path": "Signal.Body.Trunk",
		"requestId": "9078"
	}

	receive <- {
		"action": "get",
		"requestId": "9078",
		"value": { "Signal.Body.Trunk.IsLocked": false,
			"Signal.Body.Trunk.IsOpen": true },
		"timestamp": 1489985044000
	}
	

One or more wildcards (denoted by asterisk '*') MAY be included at any level in the path to specify that all nodes at that level are to be included.

In the example below, the path in the 'getRequest' includes a wildcard at the levels above the leaf (signal) node, in order to request just the 'IsLocked' state for all doors.

	client -> {
		"action": "get",
		"path": "Signal.Cabin.Door.*.IsLocked",
		"requestId": "4523"
	}

	receive <- {
		"action": "get",
		"requestId": "4523",
		"value": [ {"Signal.Cabin.Door.Row1.Right.IsLocked" : true },
		           {"Signal.Cabin.Door.Row1.Left.IsLocked" : true },
			       {"Signal.Cabin.Door.Row2.Right.IsLocked" : false },
			       {"Signal.Cabin.Door.Row2.Left.IsLocked" : true } ],
		"timestamp": 1489985044000
	}
	

In this example, a complex type with a nested array is returned in response to the Path: "Signal.Cabin.Door.*" which denotes: 'Return all signals and data attributes for all doors'. For simplicity, the example assumes that the VSS definition for each door only has two attributes 'IsLocked' and 'Window.Position'.

	client -> {
		"action": "get",
		"path": "Signal.Cabin.Door.*",
		"requestId": "6745"
	}

	receive <- {
		"action": "get",
		"requestId": "6745",
		"value": [ {"Signal.Cabin.Door.Row1.Right.IsLocked" : true, "Signal.Cabin.Door.Row1.Right.Window.Position": 50},
		           {"Signal.Cabin.Door.Row1.Left.IsLocked" : true, "Signal.Cabin.Door.Row1.Left.Window.Position": 23},
		           {"Signal.Cabin.Door.Row2.Right.IsLocked" : false, "Signal.Cabin.Door.Row2.Right.Window.Position": 100 },
		           {"Signal.Cabin.Door.Row2.Left.IsLocked": true, "Signal.Cabin.Door.Row2.Left.Window.Position": 0 } ],
		"timestamp": 1489985044000
	}
	

The following shows a request for non-existent data

	client -> {
		"action": "get",
		"path": "Body.Flux.Capacitor",
		"requestId": "1245"
	}

	receive <- {
		"action": "get",
		"requestId": "1245",
		"error": { "number":404,
			"reason": "invalid_path",
			"message": "The specified data path does not exist." },
		"timestamp": 1489985044000
	}
	

Set

The client may request that the server sets the value of a signal e.g. to lock a door or open a window by sending a 'setRequest' message to the server. If the server is able to satisfy the request it SHALL return a 'setSuccessResponse' message. If an error occurs e.g. because the client is not authorized to set the requested value, or the value is read-only, the server SHALL return a 'setErrorResponse' message.

The properties and schema for a setRequest is:

Object NameAttributeTypeRequired
setRequest
actionActionYes
pathstringYes
valueanyYes
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Set Request",
    "description": "Enables the client to set a value once.",
    "type": "object",
    "required": ["action", "path", "value", "requestId"],
    "properties": {
        "action": {
            "enum": [ "set" ],
            "description": "The identifier for the set request",
        },
        "path": {
            "$ref": "#/definitions/path"
        },
        "value": {
            "$ref": "#/definitions/value"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for a setSuccessResponse is:

Object NameAttributeTypeRequired
setSuccessResponse
actionActionYes
requestIdstringYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Set Success Response",
    "description": "The response sent from the server upon a successful set request",
    "type": "object",
    "required": ["action", "requestId", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "set" ],
            "description": "The identifier for the set request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a setErrorResponse is:

Object NameAttributeTypeRequired
setErrorResponse
actionActionYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Set Error Response",
    "description": "The response sent from the server upon an unsuccessful set request",
    "type": "object",
    "required": ["action", "requestId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "set" ],
            "description": "The identifier for the set request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

Examples

Successfully set a signal.

    client -> {
      "action": "set",
      "path": "Signal.Cabin.Door.*.IsLocked",
      "value": [ {"Row1.Right.IsLocked": true },
                 {"Row1.Left.IsLocked": true },
                 {"Row2.Right.IsLocked": true },
                 {"Row2.Left.IsLocked": true } ],
      "requestId": "5689"
    }

    receive <- {
        "action": "set",
        "requestId": "5689",
        "timestamp": 1489985044000
    }
	

Unsuccessful set. The value cannot be set.

    client -> {
        "action": "set",
        "path": "Signal.Drivetrain.InternalCombustionEngine.RPM",
        "value": 2000,
        "requestId": "8912"
    }

    receive <- {
        "action": "set",
        "requestId": "8912",
        "error": { "number": 401,
        "reason": "read_only",
        "message": "The desired signal cannot be set since it is a read only signal"},
        "timestamp": 1489985044000
    }
	

Unsuccessful set. The value does not exist in the specified path.

    client -> {
    "action": "set",
    "path": "Signal.Drivetrain.InternalCombustionEngine.RPM",
    "value": { "locked" : true }
    "requestId": "2311"
    }

    receive <- {
        "action": "set",
        "requestId": "2311",
        "error": { "number": 400,
        "reason": "bad_request" ,
        "message": "The server is unable to fulfil the client
                    request because the request is malformed."},
        "timestamp": 1489985044000
     }
	

Subscribe

Vehicle data subscriptions provide data to the client whenever the signal changes on the server, unless otherwise specified using Server Side Filtering. The server MAY reduce the number of notifications sent to the client in order to reduce processing demands, particularly when the client has subscribed to continuously varying signals.

When the client makes a request to the server to create a new subscription, a JSON data object is returned. This object contains the attributes that were passed to the server to make the subscription and a 'subscriptionId' integer handle value which is used to uniquely identify the subscription.

Subscribe Request Properties

The properties and schema for a subscribeRequest is:

Object NameAttributeTypeRequired
subscribeRequest
actionActionYes
pathstringYes
filtersobjectNo
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Subscribe Request",
    "description": "Allows the client to subscribe to time-varying signal notifications on the 
      server.",
    "type": "object",
    "required": ["action", "path", "requestId"],
    "properties": {
        "action": {
            "enum": [ "subscribe" ],
            "description": "The identifier for the subscription request"
        },
        "path": {
            "$ref": "#/definitions/path"
        },
        "filters": {
            "$ref": "#/definitions/filters"
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for a subscribeSuccessResponse is:

Object NameAttributeTypeRequired
subscribeSuccessResponse
actionActionYes
requestIdstringYes
subscriptionIdstringYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Subscribe Success Response",
    "description": "The response sent from the server upon a successful subscription request",
    "type": "object",
    "required": ["action", "requestId", "subscriptionId", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "subscribe" ],
            "description": "The identifier for the subscription request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        },                
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a subscribeErrorResponse is:

Object NameAttributeTypeRequired
subscribeErrorResponse
actionActionYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Subscribe Error Response",
    "description": "The response sent from the server upon an unsuccessful subscribe request",
    "type": "object",
    "required": ["action", "requestId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "subscribe" ],
            "description": "The identifier for the subscription request",
        },
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a subscriptionNotification is:

Object NameAttributeTypeRequired
subscriptionNotification
actionActionYes
subscriptionIdstringYes
valueanyYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Subscription Notification",
    "description": "Notification sent from the server to provide the requested data to the client",
    "type": "object",
    "required": ["action", "subscriptionId", "value", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "subscription" ],
            "description": "The identifier for the subscription notification",
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        },
        "value": {
            "$ref": "#/definitions/value"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a subscriptionNotificationError is:

Object NameAttributeTypeRequired
subscriptionNotificationError
actionActionYes
subscriptionIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Subscription Notification Error",
    "description": "Error message sent by the server when there is an error with an existing 
      subscription",
    "type": "object",
    "required": ["action", "subscriptionId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "subscription" ],
            "description": "The identifier for the subscription notification",
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

Examples

For example when client need to continuously receive "Signal.Drivetrain.Transmission.TripMeter" information from the server, it can use "subscribe" action with the target property like below.

	client -> {
		"action": "subscribe",
		"path": "Signal.Drivetrain.Transmission.TripMeter",
		"requestId": "1004"
	}

	receive <- {
            "action": "subscribe",
            "requestId": "1004",
            "subscriptionId": "35472",
            "timestamp": 1489985044000
	}
  
When this "subscribe" request has been successed, client will receive a notificaton with changing value continuously as below JSON structure.
      receive <- {
          "action": "subscription",
          "subscriptionId": "35472",
          "value": 36912,
          "timestamp": 1489985044000
      }
  

The client can use the 'requestId' value to associate the successful subscription response with the original request.

The 'subscriptionId' value is a unique value, created by the server and which is used internally by the server to manage subscriptions on that WebSocket instance.

The subscription id value may be used by the client to unsubscribe from receiving future notifications, by passing the handle value to the server with the unsubscribe action.

To differentiate subscription response from responses for ‘GET’ requests, subscription responses shall additionally include the subscription id value that identifies the subscription that triggered that notification.

The server ensures that a new unique subscription id value is returned for each successful subscription request on a particular WebSocket connection. However the server does not guarantee that subscription handle values are unique between different WebSocket instances.

Once the subscription is successfully registered with the server, the client receives subscription notifications containing the requested data, at a rate defined either by the server or by the server side filter. If there is an error with an existing subscription a subscriptionNotificationError is received by the client. This allows the client to handle the error, such as to reduce the subscription frequency if the server is unable to satisfy the initial demands of the client.

If the authentication token expires whilst a subscription is active, the server will send a subscriptionNotificationError for each subscription that can no longer be fulfilled. The client is then responsible for requesting a renewed authentication token.

After the client authentication token has expired, the server MAY continue to send notifications for data that is not subject to access control restrictions. The client will NOT receive notifications for subscriptions that require a valid authentication token until the client sends a renewed authentication token to the server.

If a new authentication token is presented by the client to the server in a timely manner, all existing subscriptions will continue to cause notifications to be sent from the server, provided the security principal has not changed. The time window during which the client MAY re-authenticate and subscriptions continue WILL be implementation dependent.

At any time the server MUST only send subscription notifications for data that the client is authorized to access.

The server MAY close the WebSocket connection at any time and in so doing, terminate all subscriptions for the client. The client is then responsible for renewing subscriptions. The client MUST close the WebSocket connection if the server data is no longer required.

An example of a subscription can be found here.

Unsubscribe

To unsubscribe from a subscription, the client SHALL send an 'unsubscribeRequest' message to the server. This is comprised of a JSON structure which contains an action property set to 'unsubscribe' and a string containing the 'subscriptionId'. If the server is able to satisfy the request it returns an 'unsubscribeSuccessResponse'. If an error occurs, for example because an invalid subscriptionId is passed to the server, an 'unsubscribeErrorResponse' is returned.

If the client has created more than one WebSocket instance, it MUST always unsubscribe using the same WebSocket instance that was originally used to create the subscription.

It is not possible to unsubscribe from a subset of signals within a subscription. The client must unsubscribe and set up a new subscription with the desired signals. For example, if there is an active subscription for all lights, using the path Signal.Body.Lights.*, and the client requires information for only Signal.Body.Lights.IsLowBeamOn, the client will have to unsubscribe from the Signal.Body.Lights.* subscription and re-subscribe to Signal.Body.Lights.IsLowBeamOn.

The client should always unsubscribe from receiving notifications when it is no longer using the data. Over a long vehicle journey, this significantly reduces the processing load on the server and allow the server to free memory. It therefore makes it more likely that the server remains responsive to future requests from the client.

Unsubscribe Request Properties

The properties and schema for a unsubscribeRequest is:

Object NameAttributeTypeRequired
unsubscribeRequest
actionActionYes
subscriptionIdstringYes
requestIdstringYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Unsubscribe Request",
    "description": "Allows the client to unsubscribe to time-varying signal notifications on 
      the server.",
    "type": "object",
    "required": ["action", "subscriptionId", "requestId"],
    "properties": {
        "action": {
            "enum": [ "unsubscribe" ],
            "description": "The identifier for the unsubscribe request"
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        }, 
        "requestId": {
            "$ref": "#/definitions/requestId"
        }
    }
}

The properties and schema for a unsubscribeSuccessResponse is:

Object NameAttributeTypeRequired
unsubscribeSuccessResponse
actionActionYes
subscriptionIdstringYes
requestIdstringYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Unsubscribe Success Response",
    "description": "The response sent from the server upon a successful unsubscribe request",
    "type": "object",
    "required": ["action", "subscriptionId", "requestId", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "unsubscribe" ],
            "description": "The identifier for the unsubscribe request"
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        }, 
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

The properties and schema for a unsubscribeErrorResponse is:

Object NameAttributeTypeRequired
unsubscribeErrorResponse
actionActionYes
subscriptionIdstringYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "Unsubscribe Error Response",
    "description": "The response sent from the server upon an unsuccessful unsubscribe request",
    "type": "object",
    "required": ["action", "subscriptionId", "requestId", "error", "timestamp"],
    "properties": {
        "action": {
            "enum": [ "unsubscribe" ],
            "description": "The identifier for the subscription request"
        },
        "subscriptionId": {
            "$ref": "#/definitions/subscriptionId"
        }, 
        "requestId": {
            "$ref": "#/definitions/requestId"
        },
        "error": {
            "$ref": "#/definitions/error"
        },
        "timestamp": {
            "$ref": "#/definitions/timestamp"
        }
    }
}

Examples

The example below shows the JSON message structure for a 'unsubscribeRequest' and 'unsubscribeSuccessResponse' to unsubscribe from a single subscription.
	client -> {
		"action": "unsubscribe",
		"subscriptionId": "102",
		"requestId": "5264"
	}

	receive <- {
		"action": "unsubscribe",
		"subscriptionId": "102",
		"requestId": "5264",
		"timestamp": 1489985044000
	}
	
The following shows an example of error case with invalid susbscriptionId.
	client -> {
		"action": "unsubscribe",
		"subscriptionId": "3542",
		"requestId": "7846"
	}
	receive <- {
		"action": "unsubscribe",
		"subscriptionId": "3542",
		"requestId": "7846",
		"error": { "number":404,
			"reason": "invalid_subscriptionId",
			"message": "The specified subscription was not found." },
		"timestamp": 1489985044000
	}
	
		// send unsubscribe message
		vehicle.send('{ "action": "unsubscribe", "subscriptionId": "102", "requestId": "5429" }');

		// set handler
		vehicle.onmesssage(function(event){
			var msg = JSON.parse(event.data);
			// success case
			if(msg.hasOwnProperty("requestId") && msg.requestId == "5429"){
				console.log("Successfully unsubscribed for id " + msg.subscriptionId);
			// error case
			} else if (msg.hasOwnProperty("error")) {
				console.log("Unsuccessful unsubscribe. " + msg.error.message)
			}
		});
	

Unsubscribe All

To unsubscribe from all subscriptions, the client SHALL send an 'unsubscribeAllRequest' message to the server. This is comprised of a JSON structure which contains an action property set to 'unsubscribeAll'. This does not require a subscriptionId value. If the request is successful, or there are no active subscriptions to unsubscribe from, this will return an 'unsubscribeSuccessResponse'.

Unsubscribe All Request Properties

The properties and schema for a unsubscribeAllRequest is:

Object NameAttributeTypeRequired
unsubscribeAllRequest
actionActionYes
requestIdstringYes
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "unsubscribeAll Request",
  "description": "Allows the client to unsubscribe from all notifications on the server.",
  "type": "object",
  "required": ["action", "requestId"],
  "properties": {
    "action": {
      "enum": [ "unsubscribeAll" ],
      "description": "The identifier for the unsubscribeAll request"
    },
    "requestId": {
      "$ref": "#/definitions/requestId"
    }
  }
}

The properties and schema for a unsubscribeAllSuccessResponse is:

Object NameAttributeTypeRequired
unsubscribeAllSuccessResponse
actionActionYes
requestIdstringYes
timestampintegerYes
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "unsubscribeAll Success Response",
  "description": "The response sent from the server upon a successful unsubscribeAll request",
  "type": "object",
  "required": ["action", "requestId", "timestamp"],
  "properties": {
    "action": {
      "enum": [ "unsubscribeAll" ],
      "description": "The identifier for the unsubscribeAll request"
    },
    "requestId": {
      "$ref": "#/definitions/requestId"
    },
    "timestamp": {
      "$ref": "#/definitions/timestamp"
    }
  }
}

The properties and schema for a unsubscribeAllErrorResponse is:

Object NameAttributeTypeRequired
unsubscribeAllErrorResponse
actionActionYes
requestIdstringYes
errorErrorYes
timestampintegerYes
{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "UnsubscribeAll Error Response",
  "description": "The response sent from the server upon an unsuccessful unsubscribeAll request",
  "type": "object",
  "required": ["action", "requestId", "error", "timestamp"],
  "properties": {
    "action": {
    "enum": [ "unsubscribeAll" ],
    "description": "The identifier for the unsubscribeAll request"
    },
    "requestId": {
      "$ref": "#/definitions/requestId"
    },
    "error": {
      "$ref": "#/definitions/error"
    },
    "timestamp": {
      "$ref": "#/definitions/timestamp"
    }
  }
}

Examples

The example below shows an example of a 'unsubscribeAllRequest' and 'unsubscribeAllSuccessResponse' for unsubscribeAll action, in order to unsubscribe from all subscriptions.
client -> {
    "action": "unsubscribeAll",
    "requestId": "3468"
}

receive <- {
    "action": "unsubscribeAll",
    "requestId": "3468",
    "timestamp": 1489985044000
}

Server Side Filtering

'Filters' may be specified to enable Server side filtering to be used to throttle the demands of subscriptions on the server. This may enable the reduction of traffic if the developer has received a 429 - Too Many Requests error message. Server side filters are extensible, allowing for further filtering mechanisms. Support is currently provisioned for a specific range of values, time intervals and minimum changes. This can be implemented using the "filters" option in the subscribeRequest interface.

Filters can only be applied for nodes in the VSS tree, not entire branches. For example, a filter cannot be set on Signal.Drivetrain.InternalCombustionEngine.*, however it can be set on Signal.Drivetrain.InternalCombustionEngine.RPM.

The default behaviour for a subscription is to send values to the client only onchange. To modify this behaviour the client can use filtering options. The following filter options SHALL be supported.

If the filter is not set, or the server is unable to satisfy the request, the notification frequency is determined by the server.

JSON Schema

{
  "filters": {
      "$ref": "#/definitions/filters"
  }
}

Examples

The following structures are examples of subscribeRequest objects which are requesting server side filters

	//client receives data every 100ms
	{ "action": "subscribe", "path": "<any_path>",
        	"filters": { "interval": 100 },
        	"requestId": "<some_unique_value>" }

	//client receives data when the value is between 100 and 200 (inclusive)
	{ "action": "subscribe", "path": "<any_path>",
        	"filters": { "range": { "above": 100, "below": 200 } },
        	"requestId": "<some_unique_value>" }

	//client receives data when the value is below 100 (inclusive)
	{ "action": "subscribe", "path": "<any_path>",
        	"filters": { "range": { "below": 100 } },
        	"requestId": "<some_unique_value>" }

	//client receives data when the value changes by 100 units
	{ "action": "subscribe", "path": "<any_path>",
        	"filters": { "minChange": 100 },
        	"requestId": "<some_unique_value>" }

	//client receives data when the value is above 200 (inclusive)
	//and the value changes by 20 units
	{ "action": "subscribe", "path": "<any_path>",
        	"filters": { "range": { "below": 200 }, "minChange": 20},
        	"requestId": "<some_unique_value>" }
      

The client should not specify a minimum change amount that is smaller than it needs - in order to prevent adding unnecessary load on the server. The server shall return a '429 - Too Many Request' error response if it is unable to fulfil the request made by the client.

The section that follows defines the error responses that shall be supported by the server.

WebSocket Closure

The WebSocket may be closed by either the client or the server by invoking the ‘close()’ method on the WebSocket instance.

The following example shows the lifetime of a WebSocket on the client:

// Open the WebSocket
var vehicle  = new WebSocket("wss://localhost:4343", "wvss1.0");

// WebSocket is used to GET, SET, SUBSCRIBE and UNSUBSCRIBE
…

// Close the WebSocket
vehicle.close();
	

The VIS Server may terminate the WebSocket connection if it has not received a request for a period determined by the server. It is the client’s responsibility to handle this gracefully and to recover and request new subscriptions, where required.

Errors

If there is an error with any of the client’s requests, the server responds with an error number, reason and message.

The properties and schema for an Error object is:

Object NameAttributeTypeRequired
Error
numberintegerYes
reasonstringYes
messagestringYes
{
  "error": {
      "$ref": "#/definitions/error"
  }
}

Examples

For some error codes, for example '401 (Unauthorized)' there can be more than one cause. The error number that is returned is the HTTP Status Code Number e.g. 401. An error reason is also returned, this contains a pre-defined string value that can be used to distinguish between errors that have the same code (e.g. '401 Unauthorized)' but a difference cause. The error message is used to provide message text describing the cause in more detail.

      client -> { 
        "action": "subscribe",
      	"filters": { "<filter_expression>" },
      	"path": "<any_vss_path>",
      	"requestId": "<some_unique_value>" 
      }
      receive on error <- {
          "action": "subscribe",
          "requestId": "<some_unique_value>",
          "error":{ 
            "number": "<error_num>",
            "reason": "<error_reason>",
            "message": "<error_message>" 
          },
          "timestamp": "1489985044000" 
        }
	

The server implementation supports at least the error numbers and reasons listed in the table below.

Error Number (Code) Error Reason Error Message
304 (Not Modified) not_modified No changes have been made by the server.
400 (Bad Request) bad_request The server is unable to fulfil the client request because the request is malformed.
401 (Unauthorized) user_token_expired User token has expired.
401 (Unauthorized) user_token_invalid User token is invalid.
401 (Unauthorized) user_token_missing User token is missing.
401 (Unauthorized) device_token_expired Device token has expired.
401 (Unauthorized) device_token_invalid Device token is invalid.
401 (Unauthorized) device_token_missing Device token is missing.
401 (Unauthorized) too_many_attempts The client has failed to authenticate too many times.
401 (Unauthorized) read_only The desired signal cannot be set since it is a read only signal.
403 (Forbidden) user_forbidden The user is not permitted to access the requested resource. Retrying does not help.
403 (Forbidden) user_unknown The user is unknown. Retrying does not help.
403 (Forbidden) device_forbidden The device is not permitted to access the requested resource. Retrying does not help.
403 (Forbidden) device_unknown The device is unknown. Retrying does not help.
404 (Not Found) invalid_path The specified data path does not exist.
404 (Not Found) private_path The specified data path is private and the request is not authorized to access signals on this path.
404 (Not Found) invalid_subscriptionId The specified subscription was not found.
406 (Not Acceptable) not_acceptable The server is unable to generate content that is acceptable to the client
429 (Too Many Requests) too_many_requests The client has sent the server too many requests in a given amount of time.
502 (Bad Gateway) bad_gateway The server was acting as a gateway or proxy and received an invalid response from an upstream server.
503 (Service Unavailable) service_unavailable The server is currently unable to handle the request due to a temporary overload or scheduled maintenance (which may be alleviated after some delay).
504 (Gateway Timeout) gateway_timeout The server did not receive a timely response from an upstream server it needed to access in order to complete the request.

The server may optionally return additional error codes. It is expected that if this is the case, they are defined in the Server Documentation. Wherever possible the Server returns a standard HTTP error code where one has been defined for the error condition. See for example RFC7231, RFC7235, and RFC6585.