Copyright
©
2016
2018
W3C
®
(
MIT
,
ERCIM
,
Keio
,
Beihang
).
W3C
liability
,
trademark
and
permissive
document
use
license
rules
apply.
The
W3C
Vehicle
Signal
Server
Specification
This
specification
defines
a
WebSocket
based
API
that
enables
for
a
Vehicle
Information
Service
(VIS)
to
enable
client
applications
to
GET,
SET,
SUBSCRIBE
get,
set,
subscribe
and
UNSUBSCRIBE
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.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
This
document
was
published
by
the
Automotive
Working
Group
as
a
First
Public
Working
Draft.
Candidate
Recommendation.
This
document
is
intended
to
become
a
W3C
Recommendation.
If
you
wish
to
make
comments
Comments
regarding
this
document,
please
document
are
welcome.
Please
send
them
to
public-automotive@w3.org
(
subscribe
,
archives
).
All
comments
are
welcome.
W3C
publishes
a
Candidate
Recommendation
to
indicate
that
the
document
is
believed
to
be
stable
and
to
encourage
implementation
by
the
developer
community.
This
Candidate
Recommendation
is
expected
to
advance
to
Proposed
Recommendation
no
earlier
than
08
March
2018.
Please see the Working Group's implementation report .
Publication
as
a
First
Public
Working
Draft
Candidate
Recommendation
does
not
imply
endorsement
by
the
W3C
Membership.
This
is
a
draft
document
and
may
be
updated,
replaced
or
obsoleted
by
other
documents
at
any
time.
It
is
inappropriate
to
cite
this
document
as
other
than
work
in
progress.
This
document
was
produced
by
a
group
operating
under
the
5
February
2004
W3C
Patent
Policy
.
W3C
maintains
a
public
list
of
any
patent
disclosures
made
in
connection
with
the
deliverables
of
the
group;
that
page
also
includes
instructions
for
disclosing
a
patent.
An
individual
who
has
actual
knowledge
of
a
patent
which
the
individual
believes
contains
Essential
Claim(s)
must
disclose
the
information
in
accordance
with
section
6
of
the
W3C
Patent
Policy
.
This
document
is
governed
by
the
1
September
2015
February
2018
W3C
Process
Document
.
The
vehicle
SHALL
This
section
is
non-normative.
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.
A
future
revision
of
this
specification
may
consider
additionally
exposing
The
API
that
is
used
to
manage
access
to
vehicle
signals
via
a
RESTful
web
service
but
this
and
static
data
is
out
of
scope
for
defined
in
this
version
of
Vehicle
Information
Service
Specification
(VISS).
The
VISS
also
describes
a
discovery
mechanism
that
defines
the
specification.
set
of
signals
and
data
that
a
client
can
access
at
a
particular
point
in
time.
The
W3C
WebSocket
API
term
'signal'
is
defined
used
here
and
to
represent
an
item
of
data
that
can
vary
over
time,
for
example
vehicle
speed,
whilst
the
WebSocket
Protocol
expression
'static
data'
is
defined
in
RFC6455
.
used
to
denote
a
temporally
invariant
property
like
vehicle
width.
A
component
or
vehicle-based
software
module
running
on
may
implement
the
vehicle
is
required
to
create
interface
and
behaviours
defined
in
this
specification
by
creating
a
WebSocket
and
listen
server
instance
that
listens
for
an
inbound
connections
connection
request
from
application
clients
a
client
in
order
to
enable
secure
access
to
vehicle
signals.
In
this
specification
this
module
are
is
referred
to
as
the
‘WebSocket
Vehicle
Signal
Server’
(WVSS)
VIS
Server
or
for
simplicity
as
‘the
server’.
just
'the
server'.
This
specification
assumes
that
The
Vehicle
Information
Service
Specification
(VISS)
defines
a
single
WebSocket
is
used
number
of
methods
for
accessing
vehicle
data
which
are
strictly
agnostic
to
enable
communication
between
the
client
application
data
model.
Any
data
model
where
data
and
signals
can
be
specified
using
a
string
could
potentially
be
supported.
However
this
version
of
the
server
in
order
to
reduce
processing
overhead.
It
is
not
explicitly
prohibited
for
the
client
to
request
specification
specifies
that
the
server
opens
more
than
one
WebSocket.
However,
data
model
is
the
server
MAY
refuse
to
open
a
subsequent
WebSocket
connection
GENIVI
Vehicle
Signal
Specification
[
VSS
].
The
VSS
supports
both
extensibility
and
the
client
is
responsible
ability
to
define
private
branches
and
will
be
used
for
handling
each
of
the
examples
within
this
gracefully.
specification.
If
more
than
one
WebSocket
connection
is
established
between
a
Client
Application
and
the
server
then
each
connection
is
managed
independently.
For
example,
subscriptions
created
using
a
particular
WebSocket
connection
only
trigger
notifications
via
that
connection
and
In
addition,
the
client
must
use
'tree'
of
signals
that
WebSocket
instance
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
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
this
would
be,
where
two
the
user
(person
or
more
WebSocket
connections
are
used
to
update
a
particular
setting
at
organisation)
requesting
the
same
time.
data
and/or
the
application
or
device
(e.g.
vehicle)
where
the
request
originates.
Unless
explicitly
stated
otherwise,
To
support
this,
the
client
Service
Specification
describes
an
extensible
token
based
security
mechanism
that
can
only
assume
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
server
implements
client
application
is
running
on.
A
future
revision
of
this
specification
may
consider
additionally
exposing
vehicle
signals
via
a
simple
concurrency
model
where
lost
updates
and
dirty
reads
could
potentially
occur
if
RESTful
web
service
but
this
is
out
of
scope
for
this
version
of
the
server
has
more
than
one
WebSocket
connection
open.
specification.
The
following
example
illustrates
how
a
client
could
invoke
the
API.
This
simplified
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 = () {
vehicle.send('{"action": "authorize",
"tokens": {"authorization": "<user_token_value>"},
"requestId": 103}');
// Establish authorization
vehicle.onopen = function () {
vehicle.send('{"action": "authorize", "tokens": {"authorization": "user_token_value"}, "requestId": "103"}');
};
// request a signal
(vehicle.readyState === OPEN) {
vehicle.send();
// 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 "getMetadata":
getMetadataHandler(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;
}
};
// process messages from the server
vehicle.onmessage = function(event){
var msg = JSON.parse(event.data);
if(msg.path == && msg.value){
console.log( + msg.value);
}
};
// Auth request handler
function authHandler(msg) {
if(msg.hasOwnProperty("TTL")){
console.log("authorization successful");
requestMetadata();
} else {
console.log("authorization unsuccessful");
}
}
// close the WebSocket
vehicle.close();
// Close the WebSocket to end the WebSocket session
function closeSocket(){
vehicle.close();
}
The
following
example
shows
a
JavaScript
Once
the
WebSocket
connection
has
been
established,
the
client
subscription
request
is
able
to
retrieve
the
metadata
from
the
server
and
response.
request
signals
for
the
client's
current
level
of
authentication.
// Request the entire data model, in this example the data model is defined using GENIVI's VSS
function requestMetadata(){
vehicle.send('{"action": "getMetadata", "requestId": "103"}');
}
// Request the entire data model and if successful, request a signalfunction getMetadataHandler(msg){ if(msg.hasOwnProperty('metadata')){ console.log("Metadata Received"); console.log("Metadata: " + JSON.stringify(msg.metadata));
getSignal(msg.metadata, "Signal.Drivetrain.Transmission.Speed");
} else {
console.log("getMetadata Error");
}
}
// Request a signalfunction getSignal(metadata, path){ // A check could be made here to ensure the signal is available within the metadata
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 1var rpmSubscriptionId, rpmRequestId = "106";// Set up the subscriptionfunction subscribeToRPMNotifications(){
vehicle.send('{"action": "subscribe", "path": "Signal.Drivetrain.InternalCombustionEngine.RPM", "requestId": ' + rpmRequestId + '}');
}
// Handle the subscription responsefunction 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 notificationfunction 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.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MAY , MUST , and SHALL are to be interpreted as described in [ RFC2119 ].
This
specification
defines
conformance
criteria
that
apply
to
a
single
product:
specifically
the
'in-vehicle'
WebSocket
Vehicle
Signal
Server
Information
Service
that
implements
the
interfaces,
semantics
and
behaviour
defined
in
this
document.
For
simplicity,
this
usually
is
referred
to
as
the
'WebSocket
Server'
or
just
'the
server'
The acronym 'VISS' is used to refer to this document, the 'Vehicle Information Service Specification'.
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 ).
This section is non-normative.
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,
in
Figure
2,
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
Web
Socket
VIS
Server.
The
interface
and
communication
mechanisms
that
are
used
between
the
vehicle
System
and
the
Web
Socket
VIS
Server
are
outside
of
the
scope
of
this
specification.
The
WebSocket
As
stated
above,
the
VIS
Server
is
the
vehicle
'in-vehicle'
system
that
is
responsible
for
exposing
vehicle
signals
and
data
to
its
on-board
clients
by
implementing
the
interface
and
behaviours
defined
in
this
Vehicle
Signal
Server
Information
Service
Specification
(VSSS)
(VISS)
.
The
WebSocket
VIS
Server
exposes
signals
and
data
in
a
manner
that
is
consistent
with
the
accompanying
data
model.
The
data
model
is
not
mandated
by
this
specification,
however
the
recommended
data
model
used
within
this
specification
is
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:
Signals
Within
GENIVI's
VSS
data
model,
signals
are
named
according
to
their
path
using
the
dot
notation
e.g.
engine.rpm.
The
methods
defined
within
this
document
support
any
path
notation
which
can
be
represented
as
a
string.
The
client
MAY
may
invoke
the
WebSocket
Server
getVSS
VIS
Server's
getMetadata
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
authorised.
authorized.
This
and
other
valid
WebSocket
VIS
Server
actions
are
defined
in
more
detail
here
.
This section is non-normative.
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
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).
The
methods
defined
on
the
WebSocket
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 running in the vehicle that 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
WebSocket
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
may
directly
invoke
the
Vehicle
Signal
Server
Information
Service
interface
exposed
by
the
WebSocker
server,
but
it
is
expected
that
they
typically
access
vehicle
signals
and
data
via
VIS
Server
or
implement
a
JavaScript
Library
that
implements
the
W3C
Vehicle
Signal
Client
API
(TODO
Add
Link).
The
Client
API
defines
a
standard
approach
to
encapsulate
or
'wrap'
the
W3C
Vehicle
Server
Specification
API
to
make
it
easier
for
Web
based
clients
'wrapper'
library
to
access
simplify
accessing
vehicle
signals
and
data
in
a
controlled
way.
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
maximise
maximize
battery
life.
This
may
include
the
systems
that
enable
Wireless
or
Mobile
connectivity.
Then,
when
When
the
vehicle
is
powered
up,
various
systems
start
up,
including
potentially
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
be
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
WebSocket
Server
Specification
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 connected to the vehicle's ethernet network 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'.
The following diagram shows a number of possible states that the VIS Server could occupy:
The state diagram is for illustrative purposes only and does not assume that the VIS Server is either single or multi-threaded. The implementer of the VIS Server is free to determine it's internal design and implementation, however in normal operation, it is assumed that the server will be able to accept multiple requests in quick succession and that the VIS Server will attempt to process and respond to each request in accordance with the specified API.
The
server
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.
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. |
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
authorised
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.
The client and the server are each individually responsible for implementing security best practice. This includes but is not limited to securely obtaining and verifying tokens (as applicable) and the prevention of replays or spoofing of tokens by malicious actors or agents.
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
sequence
of
steps
are
shown
in
more
detail
is
illustrated
in
the
diagram
below:
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
server
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.
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.
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
unauthorised
unauthorized
because
the
token
has
expired,
the
server
returns
SHALL
return
an
error
response
indicating
the
fact
and
the
client
requests
SHALL
request
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.
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.
Implementations that support additional devices or multiple VIS services should provide discovery. Alternatively, the location of a particular VIS Server instance on the local vehicle network may be handled by configuration, either as part of a package manifest or by consulting a registry on application install. The 'wwwivi' hostname in this specification is used an example.
A
client
running
on
the
vehicle
is
able
to
connect
to
the
WebSocket
VIS
Server
instance
using
the
hostname
e.g.
'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
always
is
SHALL
be
'wvss'
with
a
version
number
suffix,
e.g.
wvss1.0
);
RESTful
web
services
are
out
of
scope
for
the
first
revision
of
this
specification,
but
could
wvss1.0.
The
sub-protocol
version
will
be
considered
for
addition
in
a
later
version.
To
support
‘defence
in
depth’
associated
with
exactly
one
Vehicle
Server
Specification
(VSS)
version
so
that
the
client
and
a
layered
security
approach,
connections
between
clients
server
can
correctly
validate
and
servers
are
strongly
encrypted.
This
is
to
make
it
more
difficult
for
an
attacker
that
has
succeeded
in
installing
malicious
code
on
a
vehicle
to
eavesdrop,
hijack
security
tokens
or
impersonate
valid
security
principals
in
order
to
get
parse
request
and
set
sensitive
vehicle
signals.
response
message
packets.
var vehicle = new WebSocket("wss://wwwivi", "wvss1.0");
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.
For
security
reasons,
clients
are
not
able
This
specification
assumes
that
a
single
WebSocket
is
used
to
connect
directly
enable
communication
between
a
client
application
and
the
server.
It
is
not
explicitly
prohibited
for
the
client
to
ECUs
or
request
that
the
server
opens
more
than
one
WebSocket,
however,
the
server
MAY
refuse
to
CAN,
MOST
or
LIN
networks.
All
access
open
a
subsequent
WebSocket
connection
and
the
client
is
via
WebSocket.
This
allows
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
securely
control
access
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
vehicle
signals.
update
a
particular
setting
at
the
same
time.
Unless explicitly stated otherwise, the client MAY 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.
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.
The request and response parameters contain a limited number of attributes, defined in the table below.
Attribute | Type | Description |
---|---|---|
action | Action |
The
type
of
action
|
path |
|
The path to the desired vehicle signal(s), as defined by the Vehicle Signal Specification (VSS) . |
requestId |
|
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 |
|
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 |
|
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 |
|
Returns
the
time
to
live
of
the
|
filters | object | Provides a filtering mechanism to reduce the demands of a subscription on the server. |
|
object | Metadata describing the potentially available signal tree. |
error
|
Error | Returns an error code, reason and message. |
The definitions within this section describe the datatypes referenced within the JSON Schema VISS interfaces.
{
"definitions": { "action": { "enum": [ "authorize", "getMetadata", "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 metadata schema.", "type": "string"
},
"value": { "description": "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.", "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 server is requested to provide notifications with a period equal to this field's value.", "type": "integer"
},
"range": { "description": "The server is requested to provide notifications only whilst a value is within a given range.", "type": "object", "properties":{ "below": { "description": "The server is requested to provide notifications when the value is less than or equal to this field's value.", "type": "integer"
},
"above": { "description": "The server is requested to 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"
},
"metadata":{ "description": "Metadata describing the potentially available signal 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"
}
}
}
}
}
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:
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.
The properties and schema for an authorizeRequest is:
Object Name | Attribute | Type | Required |
---|---|---|---|
|
|||
action | Action | Yes | |
tokens | object | Yes | |
requestId | string | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
authorizeSuccessResponse | |||
action | Action | Yes | |
TTL | integer | Yes | |
requestId | string | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
authorizeErrorResponse | |||
action | Action | Yes | |
error | Error | Yes | |
requestId | string | Yes |
{
"$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
|
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>" }');
} (deviceTokenOnly) {
// Pass vehicle/device token only
vehicle.send('{ "action": "authorize",
"tokens": { "www-vehicle-device": "<device_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>" }');
} (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>" }');
} 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
secure
tokens.
obtain
token(s).
Providers
of
the
server
implementation
may
choose
select
their
own
preferred
formats
token
format
and
security
methods.
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.
While
this
specification
does
not
mandate
the
token
format
and
structure
it
SHALL
at
least
contain
the
following
elements
to
provide
meaningful
authorization:
Element
Description
Path
The
signal
path
(defined
here
)
the
token
authorizes.
The
path
may
be
a
branch
name
or
contain
wildcards
to
authorize
entire
branches.
Actions
List
of
actions
that
the
token
authorizes
for
the
path.
The
list
contains
at
least
one
of
the
actions
getVSS
,
get
,
set
,
subscribe
and
unsubscribe
.
Valid
From
Timestamp
in
UTC
indicating
the
date
and
time
from
which
on
the
token
is
valid.
Valid
Until
Tmestamp
in
UTC
indicating
the
date
and
time
until
which
the
token
is
valid.
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,
ther
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.
The
client
MAY
use
the
'getVSS'
'getMetadata'
action
to
request
metadata
describing
the
potentially
available
signal
schema,
for
example
the
VSS
tree.
It
does
this
by
sending
a
'vssRequest'
'metadataRequest'
message
to
the
server.
If
the
server
is
able
to
return
the
VSS
metadata,
then
this
is
returned
using
a
'vssSuccessResponse'
'metadataSuccessResponse'
message.
If
an
error
occurs,
the
server
returns
a
'vssErrorResponse'
'metadataErrorResponse'
message
to
the
client.
The
client
is
able
to
request
VSS
metadata
from
any
point
in
the
VSS
signal
tree,
such
that
only
the
metadata
for
the
signals
within
the
given
branch
of
the
tree
schema's
hierachy
is
returned.
For
example,
only
metadata
for
the
chassis
branch
of
the
VSS
tree
is
returned
when
the
chassis
path
is
specified.
If
the
path
is
not
set,
the
response
contains
the
metadata
for
the
entire
VSS
signal
tree.
If
more
than
one
'getVSS'
'getMetadata'
call
is
made
with
the
same
'vssRequest'
'metadataRequest'
message
content
but
at
different
times,
the
metadata
in
the
'vssSuccessResponse'
'metadataSuccessResponse'
SHALL
be
the
same
provided
the
access-control
state
of
the
WebSocket
channel
has
not
changed.
The Vehicle Signal Server (VSS) specification allows branches to be defined as either public or private. The VIS server will satisfy a request for metadata in a public branch regardless of the access control permissions associated with the client making the request. This means that a user could see that a particular signal in a public branch is available but they may not be currently authorised to Get, Set, or Subscribe to that signal. If a branch is defined to be 'private', only suitably authorised clients will be able to retrieve metadata for that branch. This is to enable vehicle manufacturers to apply access controls to metadata for commercially sensitive signals and data.
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 only return metadata for the branches and nodes which are classified as "Private" branch unless the client has appropriate access permissions. Other data models may also operate similar mechanisms.
The properties and schema for a metadataRequest is:
Object Name | Attribute | Type | Required |
---|---|---|---|
|
|||
action | Action | Yes | |
path | string | Yes | |
requestId | string | Yes |
{
"$schema": "http://json-schema.org/draft-04/schema#", "title": "Metadata Request", "description": "Request metadata describing the potentially available signals", "type": "object", "required": ["action", "path", "requestId"], "properties": { "action": { "enum": [ "getMetadata" ], "description": "The identifier for the getMetadata request"
},
"path": { "$ref": "#/definitions/path"
},
"requestId": { "$ref": "#/definitions/requestId"
}
}
}
The properties and schema for a metadataSuccessResponse is:
Object Name | Attribute | Type | Required |
---|---|---|---|
metadataSuccessResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
metadata | object | Yes | |
timestamp | integer | Yes |
{
"$schema": "http://json-schema.org/draft-04/schema#", "title": "Metadata Success Response", "description": "The response sent from the server upon a successful getMetadata request", "type": "object", "required": ["action", "requestId", "metadata", "timestamp"], "properties": { "action": { "enum": [ "getMetadata" ], "description": "The identifier for the getMetadata request"
},
"requestId": { "$ref": "#/definitions/requestId"
},
"metadata": { "$ref": "#/definitions/metadata"
},
"timestamp": { "$ref": "#/definitions/timestamp"
}
}
}
The properties and schema for a metadataErrorResponse is:
Object Name | Attribute | Type | Required |
---|---|---|---|
metadataErrorResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$schema": "http://json-schema.org/draft-04/schema#", "title": "Metadata Error Response", "description": "The response sent from the server upon an unsuccessful getMetadata request", "type": "object", "required": ["action", "requestId", "error", "timestamp"], "properties": { "action": { "enum": [ "getMetadata" ], "description": "The identifier for the getMetadata request"
},
"requestId": { "$ref": "#/definitions/requestId"
},
"error": { "$ref": "#/definitions/error"
},
"timestamp": { "$ref": "#/definitions/timestamp"
}
}
}
The
following
data
flow
example
shows
a
request
for
the
signal
structure
within
the
Signal.Body
Signal.Drivetrain.InternalCombustionEngine.RPM
branch
containing
signals
related
to
the
vehicle
body.
RPM
signal,
where
the
metadata
is
defined
using
a
VSS
tree.
A
leaf
node
has
been
chosen
in
this
example
for
brevity,
however
entire
VSS
branches
and
other
schemas
can
also
be
requested
using
the
getMetadata
interface.
client -> {
,
,
"action": "getMetadata",
"path": "Signal.Drivetrain.InternalCombustionEngine.RPM",
"requestId": "3874"
}
receive <- {
,
,
: { },
"action": "getMetadata",
"requestId": "3874",
"metadata": { "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": "getMetadata", "path": "Attribute.Body", "requestId": "3875"
}
receive <- {
"action": "getMetadata", "requestId": "3875", "metadata": { "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
}
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
authorised
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:
The properties and schema for a getRequest is:
Object Name | Attribute | Type | Required |
---|---|---|---|
|
|||
action | Action | Yes | |
path | string | Yes | |
requestId | string | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
getSuccessResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
value | object | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
getErrorResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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"
}
}
}
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 <- {
,
,
,
}
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),
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
version
of
the
Vehicle
Signal
Specification.
Specification
that
is
associated
with
the
WebSocket
sub-protocol
value
specified
when
the
WebSocket
is
created.
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 <- {
,
,
,
},
}
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 <- {
,
,
},
{ },
{ },
{ } ],
}
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 <- {
,
,
},
{},
{ },
{ } ],
}
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 <- {
,
,
,
,
},
}
receive <- {
"action": "get", "requestId": "1245", "error": { "number":404, "reason": "invalid_path", "message": "The specified data path does not exist." }, "timestamp": 1489985044000
}
The
client
may
request
that
the
server
sets
the
value
of
a
signal
one
or
more
signals
e.g.
to
lock
a
door
one
or
more
doors
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
authorised
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 Name | Attribute | Type | Required |
---|---|---|---|
|
|||
action | Action | Yes | |
path | string | Yes | |
value | any | Yes | |
requestId | string | Yes |
{
"$schema": "http://json-schema.org/draft-04/schema#", "title": "Set Request", "description": "Enables the client to set one or more values 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 Name | Attribute | Type | Required |
---|---|---|---|
setSuccessResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
setErrorResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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"
}
}
}
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 <- {
,
,
},
{ },
{ },
{ } ] },
}
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 <- {
,
,
,
,
},
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 }
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.
The properties and schema for a subscribeRequest is:
Object Name | Attribute | Type | Required |
---|---|---|---|
|
|||
|
Action | Yes | |
path | string | Yes | |
filters | object | No | |
requestId | string | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
subscribeSuccessResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
subscriptionId | string | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
subscribeErrorResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
subscriptionNotification | |||
action | Action | Yes | |
subscriptionId | string | Yes | |
value | any | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
subscriptionNotificationError | |||
action | Action | Yes | |
subscriptionId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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"
}
}
}
For
example
when
a
client
need
wishes
to
subscribe
to
continuously
receive
"Signal.Drivetrain.Transmission.TripMeter"
information
from
the
server,
it
can
use
the
"subscribe"
action
with
the
target
path
property
like
below.
client -> {
,
,
}
set
as
follows:
client -> {
"action": "subscribe", "path": "Signal.Drivetrain.Transmission.TripMeter", "requestId": "1004"
}
receive <- {
,
,
,
}
receive <- {
"action": "subscribe", "requestId": "1004", "subscriptionId": "35472", "timestamp": 1489985044000
}
This example is for illustrative purposes only, it MAY or MAY NOT be the case that the version of the Vehicle Server Specification implemented by the VIS Server includes the example path 'Signal.Drivetrain.Transmission.TripMeter'.
If
the
"subscribe"
request
has
been
successed,
client
is
successful
the
server
will
receive
return
a
notificaton
with
changing
value
continuously
subscribeSuccessResponse
as
below
JSON
structure.
receive <- {
,
,
,
}
The
client
can
use
shown
in
the
'requestId'
value
to
associate
example
above,
and
the
successful
client
will
then
start
to
receive
subscription
response
with
notifications
like
the
original
request.
one
illustrated
in
the
following
JSON
structure:
receive <- {
"action": "subscription", "subscriptionId": "35472", "value": 36912, "timestamp": 1489985044000
}
The
'subscriptionId'
value
is
a
unique
value,
created
by
the
server
and
which
is
may
be
used
internally
by
the
server
to
manage
subscriptions
on
that
WebSocket
instance.
The
subscription
id
subscriptionId
value
may
also
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
subscriptionId
value
that
identifies
the
subscription
that
triggered
that
notification.
The
server
ensures
that
a
new
unique
subscription
id
subscriptionId
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
SHALL
be
sent
to
the
client.
This
allows
the
client
to
handle
the
error,
such
as
for
example
by
modifying
the
filter
condition
to
reduce
the
requested
notification
frequency.
If
the
authentication
token
expires
whilst
a
subscription
frequency
if
is
active,
the
server
will
send
a
subscriptionNotificationError
for
each
subscription
that
can
no
longer
be
fulfilled.
The
client
is
unable
then
responsible
for
communicating
with
the
relevant
Security
Authority
to
satisfy
renew
the
initial
demands
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(s) have not changed. The time window during which the client MAY re-authenticate and subscriptions continue WILL be implementation dependent. If the server has terminated any subscriptions, it is the responsibility of the client to renew them.
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 .
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.
The
client
MAY
unsubscribe
from
all
of
its
subscriptions
by
sending
an
'unsubscribeRequest'
with
the
action
property
set
to
'unsubscribeAll'.
This
does
not
require
a
subscriptionId
value.
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 to receive notifications for 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
will
remain
responsive
to
future
requests
from
the
client.
The
'unsubscribe'
message
structures
are
defined
below:
properties
and
schema
for
a
unsubscribeRequest
is:
Object Name | Attribute | Type | Required |
---|---|---|---|
|
|||
action | Action | Yes | |
subscriptionId | string | Yes | |
requestId | string | Yes |
{
"$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
single
subscription.
client -> {
,
,
}
unsubscribeSuccessResponse
is:
Object Name | Attribute | Type | Required |
---|---|---|---|
| |||
action | Action | Yes | |
subscriptionId | string | Yes | |
requestId | string | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
unsubscribeErrorResponse | |||
action | Action | Yes | |
subscriptionId | string | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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"
}
}
}
client -> {
"action": "unsubscribe", "subscriptionId": "102", "requestId": "5264"
}
receive <- {
,
,
,
}
receive <- {
"action": "unsubscribe", "subscriptionId": "102", "requestId": "5264", "timestamp": 1489985044000
}
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();
vehicle.send('{ "action": "unsubscribe", "subscriptionId": "102", "requestId": "5429" }');
// set handler
vehicle.onmesssage(function(event){
.parse(event.data);
){
+ msg.subscriptionId);
} )) {
+ msg.error.message)
}
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)
}
});
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, the VIS Server will return an 'unsubscribeSuccessResponse'.
The properties and schema for a unsubscribeAllRequest is:
Object Name | Attribute | Type | Required |
---|---|---|---|
unsubscribeAllRequest | |||
action | Action | Yes | |
requestId | string | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
unsubscribeAllSuccessResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
timestamp | integer | Yes |
{
"$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 Name | Attribute | Type | Required |
---|---|---|---|
unsubscribeAllErrorResponse | |||
action | Action | Yes | |
requestId | string | Yes | |
error | Error | Yes | |
timestamp | integer | Yes |
{
"$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"
}
}
}
client -> {
"action": "unsubscribeAll", "requestId": "3468"
}
receive <- {
"action": "unsubscribeAll", "requestId": "3468", "timestamp": 1489985044000
}
'
Filters
'
may
be
specified
to
enable
Server
side
filtering
to
be
used
in
order
to
throttle
the
demands
of
subscriptions
on
the
server.
This
may
enable
the
reduction
of
traffic
if
the
developer
has
received
a
429
'429
-
Too
Many
Requests
Requests'
error
message.
This
can
be
implementation
dependent
Server
side
filters
are
extensible,
allowing
for
additional
filtering
mechanisms
to
be
specified.
Support
is
currently
included
for
a
number
specific
range
of
potential
filtering
mechanisms,
such
as
ranges,
values,
time
intervals
and
minimum
changes.
This
can
be
implemented
using
the
"filters"
option.
option
in
the
subscribeRequest
interface.
Filters
can
only
be
applied
for
data
which
is
represented
by
a
primitive
type,
such
as
leaf
nodes
in
the
VSS
tree,
not
entire
branches.
For
example,
a
filter
cannot
be
set
on
engine.*,
Signal.Drivetrain.InternalCombustionEngine.*,
however
it
can
be
set
on
engine.rpm.
Signal.Drivetrain.InternalCombustionEngine.RPM.
The
default
behaviour
for
a
subscription
currently
defaults
is
to
sending
values
request
that
the
server
sends
a
notification
to
the
client
only
onchange,
however
'onchange'.
To
modify
this
may
cause
unnecessary
processing
demands
on
behaviour
the
vehicle
server.
A
filter
object
client
can
use
filtering
options.
The
following
filter
options
SHALL
be
included
in
the
subscription
request:
{ ,
}
Potential
tags
could
include:
supported:
If
The
client
can
use
filters
to
request
that
the
filter
server
sends
notifications
based
on
various
criteria,
but
it
is
not
set,
or
important
to
note
that
this
is
unsupported
by
the
server,
just
a
request
and
the
notification
frequency
is
will
ultimately
be
determined
by
the
server.
{
"filters": { "$ref": "#/definitions/filters"
}
}
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>" }
When
the
range
filter
is
used
a
final
message
is
sent
when
the
value
returned
is
outside
of
the
specified
range.
For
example,
if
the
range
states
{
"below":
100
},
a
final
value
may
be
received
at
101
to
indicate
that
the
value
is
now
out
of
range.
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 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
WebSocket
server
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.
The section that follows defines the error responses that shall be supported by the server.
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 Name | Attribute | Type | Required |
---|---|---|---|
Error | |||
number | integer | Yes | |
reason | string | Yes | |
message | string | Yes |
{
"error": { "$ref": "#/definitions/error"
}
}
For
some
error
codes,
for
example
'401
(Unauthorised)'
(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_metadata_definition>", "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. |
400 (Bad Request) | filter_invalid | Filter requested on non-primitive type. |
401
|
user_token_expired | User token has expired. |
401
|
user_token_invalid | User token is invalid. |
401
|
user_token_missing | User token is missing. |
401
|
device_token_expired | Device token has expired. |
401
|
device_token_invalid | Device token is invalid. |
401
|
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
|
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 .