Network Tables Protocol Specification, Version 4.0
A pub/sub WebSockets API for accessing NetworkTables.
Motivation
Currently in NetworkTables there is no way to synchronize user value updates and NT update sweeps, and if user value updates occur more frequently than NT update sweeps, the intermediate values are lost. This prevents NetworkTables from being a viable transport layer for data logging at rates higher than the NetworkTables update rate (e.g. for capturing high frequency PID changes). While custom code can work around the second issue, it is more difficult to work around the first issue (unless full timestamps are also sent).
Adding built-in support for capturing and communicating all timestamped data value changes with minimal additional user code changes will make it much easier for inexperienced teams to get high resolution, accurate data to dashboard displays with the minimal possible bandwidth and airtime usage. Assuming the dashboard performs record and playback of NT updates, this also meets the desire to provide teams a robust data capture and playback mechanism.
Migration to a pub/sub style protocol layer where the client can request only its desired topics and the frequency in which it wants to receive value changes provides some mitigation for increased network utilization due to the data logging changes.
Using WebSockets (RFC 6455) as the transport layer along with JSON and MessagePack data encoding enables browser-based dashboards and other web technologies to easily access the protocol and minimizes the amount of custom wire protocol implementation required. Support for this protocol can easily be added in parallel to the existing NetworkTables protocol stack in order to maintain compatibility with older clients/servers and facilitate a gradual transition.
References
-
RFC 6455, The WebSocket Protocol, https://tools.ietf.org/html/rfc6455
-
RFC 7159, The JavaScript Object Notation (JSON) Data Interchange Format, https://tools.ietf.org/html/rfc7159
-
MessagePack, MessagePack Specification, https://github.com/msgpack/msgpack/blob/master/spec.md
-
Cristian’s algorithm, https://en.wikipedia.org/wiki/Cristian%27s_algorithm
Design
Both text and binary WebSocket frames are used for transport. Text frames are JSON, and binary frames are MessagePack. JSON is used for control messages for human readability and ease of debugging. MessagePack is used only for time and space efficient encoding of values, and the MessagePack subset used in this protocol is small enough that a custom encoder/decoder can be easily implemented for languages that lack good MessagePack libraries.
Consistent with pub/sub nomenclature, this spec uses the term "topic" for what was called an "entry" or "key" in the NT 3.0 spec.
MessagePack messages use numeric IDs for topics to reduce data size; these IDs have a 1:1 mapping to a full topic name (a string). This mapping is communicated via the JSON Topic Announcement Message (announce).
Topic Names
Topic have UTF-8 string names. Names starting with $ are reserved for use by the server (see Server-Published Meta Topics). Otherwise names are unrestricted, but convention is for them to start with / and be /-separated (without consecutive //) to make a Unix-path-like structure.
Timestamps
All MessagePack messages are timestamped. Timestamps are specified in unsigned integer microseconds—for robot programs, microseconds are preferred as the FPGA provides time in microseconds, and integers result in a more compact wire encoding (in typical robot use, integer microseconds timestamps will be half the size of double timestamps until about T=70 minutes, and in the worst case will be no larger).
Timestamps in messages always use the server time base. The server time base is synchronized across the network by the means described in this section (an implementation of Cristian’s algorithm).
Implementations should expose the actual timestamps for messages as well as provide methods to convert from server time base to local time to facilitate applications that prefer the server time base (e.g. a dashboard showing robot events might prefer to use server time instead of wall clock time).
The topic ID of -1 is reserved for timestamp communication. Clients shall periodically (e.g. every few seconds) send, in a manner that minimizes transmission delays, a MessagePack message with ID of -1, a timestamp of 0, and an implementation-selected type and data value (typically int or float 64) containing its (the client’s) current local time.
When the server receives an -1 ID message from a client, it shall respond to the client, in a manner that minimizes transmission delays, with a MessagePack message with ID=-1, a timestamp of its (the server’s) current local time (in microseconds), and the client-provided data value.
When the client receives an -1 ID message from the server, it shall compute the round trip time (RTT) from the delta between the message’s data value and the current local time. If the RTT is less than that from previous measurements, the client shall use the timestamp in the message plus ½ the RTT as the server time equivalent to the current local time, and use this equivalence to compute server time base timestamps from local time for future messages.
Due to the fact there can be multiple publishers for a single topic and unpredictable network delays / clock drift, there is no global total order for timestamps either globally or on a per-topic basis. While single publishers for real-time data will be the norm, and in that case the timestamps will usually be in order, applications that use timestamps need to be able to handle out-of-order timestamps.
Caching and Reconnection Handling
Servers shall keep a retained value for each topic for the purposes of both Get Values Message (getvalues) and Subscribe Message (subscribe) requests; the retained value shall be the value in the largest timestamp (greater-than or equal-to) message received for that topic. This retained value is deleted if the topic is deleted (e.g. there are no more publishers).
Clients may similarly keep a retained value for each topic for ease of use by user code. If this is done, this retained value shall be updated by both locally published values and received messages for that topic with greater-than/equal-to timestamps, and the retained value shall be deleted when a Topic Removed Message (unannounce) is received.
Clients should support a "set default" operation for a topic. This is a "weak" value update that publishes a value with a timestamp of 0 (thereby not causing the retained value of the server or other clients to be updated if they have a current value update with a timestamp > 0). Typically the "set default" operation should also result in the retained property being set on the topic.
Clients may accept application commands to publish and subscribe while disconnected. If a client does so, in addition to maintaining a retained value as described above, it must keep track for each application-published topic whether any of the locally published values were "strong" (via a "set" operation), or all of them were "weak" (via a "set default" operation). While disconnected, there is no reference clock; "strong" timestamps shall be set to 1 and "weak" timestamps shall be set to 0.
When the client disconnects, the client shall delete any topics that are not published by the application and do not have the retained or persistent properties set. The client shall also reset the application-published retained value timestamps to 0 and 1 as per the previous paragraph.
When the connection to the server is established (either reconnect or initial connection), the client shall publish and send only the retained values to the server that are in application-published topics (those with timestamps of 0 and 1, per above). Only the values with timestamp 0 may be sent immediately upon reconnection. The values with timestamp 1 must wait until the client clock is synchronized with the server clock; the timestamps for these values when sent to the server must be either the current server time or, if possible, an estimation of server time when the values were actually written.
Note: the previous paragraphs enable offline, multi-publisher operation under network/server reboot conditions without creating zombie topics, assuming clients use "set default" and the retained property appropriately. This is achieved mainly via the use of timestamps 0 and 1 to enable tie breaks such that normally-set values (timestamp X) are used in preference to retained values (timestamp 1), and retained values are used in preference to weakly set values (timestamp 0). An example use case is as follows:
-
Server starts
-
Dashboard client connects
-
Coprocessor client connects
-
Coprocessor client publishes configuration topic, sends an initial value using "set default", and subscribes to the topic (to detect configuration changes)
-
Dashboard client sees configuration topic published and subscribes to it
-
Dashboard user changes configuration value—dashboard client publishes to the topic and sends the user value
-
Coprocessor receives the user value and updates its retained value
-
Server reboots (this also disconnects the dashboard and coprocessor clients)
-
If the dashboard reconnects first:
-
The user value was published and cached (retained value) on the dashboard client, so the dashboard client re-publishes and sends the cached data with timestamp 1.
-
The coprocessor client reconnects later. It also published and cached, but it only ever called "set default" and sends the cached data (which is also the user value) with timestamp 0. It receives the retained value from the server with timestamp 1, and updates locally.
-
The server propagates the timestamp 0 message, but since it has a retained value with timestamp 1, as do other clients, the retained value is not updated and the user value remains active.
-
-
If the coprocessor reconnects first:
-
The coprocessor client only ever called "set default", so it sends the cached data (the user-set value) with timestamp 0.
-
If the dashboard never reconnects, no new values are published, so the user-set value is active
-
If the dashboard reconnects, it sends a message with timestamp 1 ("strong" set). This propagates but does not change the value (it’s the same user-set as before).
-
-
If the dashboard updates the value while offline, it’s still a "strong set" and wins the tie
A second use case:
-
Server starts
-
Dashboard client connects
-
Dashboard client publishes configuration value with the retained property set, and publishes an initial value
-
Dashboard client disconnects. The topic is not deleted on the server because the retained property is set.
-
Coprocessor client connects
-
Server sends announce message for topic and sends retained value (with timestamp 1)
-
Coprocessor client publishes, uses "set default", and subscribes to the topic. Since "set default" uses a timestamp of 0, it loses to the retained value with timestamp 1, and the coprocessor subscriber will see the value previously set by the dashboard.
-
Dashboard client reconnects
Server Behavior
Topic IDs may be common across all client connections or be connection-specific. If they are common, the server needs to be careful regarding topic ID reuse due to deleted topics, as the protocol provides no way to change a client topic ID. Requests (e.g. subscribe or publish) are always specific to a single client connection.
When a client initially connects, the server shall send it announce messages for each existing topic.
The server shall keep a publisher count for each topic. Persistent and retained topics have an additional implicit publisher. When the publisher count reaches zero (which only happens for non-persistent and non-retained topics), the server shall delete the topic (including its retained value). When a client connection is lost, the server shall handle that as an implicit unpublish for all topics currently published by that client.
The server may operate in-process to an application (e.g. a robot program). In this case, the application operationally behaves like a client (e.g. it sends publish requests and receives topic announcements), but of course does not need to estimate delta time, create JSON/MessagePack messages, etc, as all of the necessary operations can be performed programmatically within the same process.
Client Behavior
Clients are responsible for keeping server connections established (e.g. via retries when a connection is lost). Topic IDs must be treated as connection-specific; if the connection to the server is lost, the client is responsible for sending new publish and subscribe messages as required for the application when a new connection is established, and not using old topic IDs, but rather waiting for new announce messages to be received.
Except for offline-published values with timestamps of 0, the client shall not send any other published values to the server until its clock is synchronized with the server per the Timestamps section.
Server-Published Meta Topics
The server shall publish a standard set of topics with information about server state. Clients may subscribe to these topics for diagnostics purposes. These topics are hidden—they are only announced to clients that have subscribed to them.
| Topic Name | Data Type | Description |
|---|---|---|
|
Connected clients |
|
|
Client |
|
|
Server subscriptions |
|
|
Subscriptions to |
|
|
Client |
|
|
Server publishers |
|
|
Publishers to |
Connected Clients ($clients)
The server shall update this topic when a client connects or disconnects.
The MessagePack contents shall be an array of maps. Each map in the array shall have the following contents:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Client name |
|
|
String |
Connection info |
Connection information about the client; typically host:port |
Client Subscriptions ($clientsub$<client>)
The server shall update this topic when the corresponding client subscribes or unsubscribes to any topic.
The MessagePack contents shall be an array of maps. Each map in the array shall have the following contents:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Integer |
Subscription UID |
A client-generated unique identifier for this subscription. |
|
Array of String |
Array of topic prefixes |
One or more topic prefixes to start receiving messages for. |
|
Object |
Options |
Subscription options, see |
Server Subscriptions ($serversub)
Same as $clientsub, except it’s updated when the server subscribes or unsubscribes to any topic.
Subscriptions ($sub$<topic>)
The server shall update this topic when a client subscribes or unsubscribes to <topic>.
The MessagePack contents shall be an array of maps. Each map in the array shall have the following contents:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Client name |
Empty string for server subscriptions. |
|
Integer |
Subscription UID |
A client-generated unique identifier for this subscription. |
Client Publishers ($clientpub$<client>)
The server shall update this topic when the corresponding client publishes or unpublishes any topic.
The MessagePack contents shall be an array of maps. Each map in the array shall have the following contents:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Integer |
Publisher UID |
A client-generated unique identifier for this publisher. |
|
String |
Topic name |
Server Publishers ($serverpub)
Same as $clientpub, except it’s updated when the server publishes or unpublishes any topic.
Publishers ($pub$<topic>)
The server shall update this topic when a client publishes or unpublishes to <topic>.
The MessagePack contents shall be an array of maps. Each map in the array shall have the following contents:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Client name |
Empty string for server publishers. |
|
Integer |
Publisher UID |
A client-generated unique identifier for this publisher. |
WebSockets Protocol Configuration
Both clients and servers shall support unsecure connections (ws:) and may support secure connections (wss:). In a trusted network environment (e.g. a robot network), clients that support secure connections should fall back to an unsecure connection if a secure connection is not available.
Servers shall support a resource name of /nt/<name>, where <name> is an arbitrary string representing the client name. The client name must be unique (for a particular server). Servers shall reject duplicate connections to the same resource name by responding with HTTP Error Code 409 (Conflict). Clients should provide a way to specify the resource name (in particular, the client name portion) and should provide a mechanism to make the name unique (e.g. by suffixing the name with a unique identifier).
Both clients and servers shall support/use subprotocol networktables.first.wpi.edu for this protocol. Clients and servers shall terminate the connection in accordance with the WebSocket protocol unless both sides support this subprotocol.
The unsecure standard server port number shall be 5810, the secure standard port number shall be 5811.
Supported Data Types
The following data types are supported. Note: implementations may map integer and float to double internally. Any data type string not in the table below shall be handled in the binary protocol as data type 5 (binary); some specific binary examples are included in the table below.
| Data type | MessagePack format family | NT 3 data type | Data Type string | Notes |
|---|---|---|---|---|
0 |
bool |
Boolean |
|
|
1 |
float 64 |
Number (double) |
|
|
2 |
int |
Number (double) |
|
Current NetworkTables protocol and user APIs only support double-precision float numeric values; implementations may choose to upgrade APIs to support integer and/or single-precision float values. |
3 |
float 32 |
Number (double) |
|
|
4 |
str |
String |
|
|
|
JSON data (e.g. structured data) |
|||
5 |
bin |
Raw |
|
Raw data, no specified format |
|
For backwards compatibility with NT 3.0 |
|||
|
Nested MessagePack data (e.g. structured data) |
|||
|
Google Protocol Buffers data (structured). Uses property |
|||
16 |
array of all bool |
Boolean Array |
|
All elements of the array must be boolean |
17 |
array of all float 64 |
Number Array |
|
All elements of the array must be double-precision floats |
18 |
array of all int |
Number Array |
|
All elements of the array must be integers. See note on Number |
19 |
array of all float 32 |
Number Array |
|
All elements of the array must be single-precision floats. See note on Number |
20 |
array of all str |
String Array |
|
All elements of the array must be text strings |
Properties
Each published topic may also have properties associated to it. Properties are represented in the protocol as JSON and thus property values may be any JSON type. Property keys must be strings. The following properties have a defined meaning in this spec. Servers shall support arbitrary properties being set outside of this set. Clients shall ignore properties they do not recognize. Properties are initially set on publish and may be changed (by any client) using Set Properties Message (setproperties).
| Property | Type | Description | Notes |
|---|---|---|---|
|
boolean |
Persistent Flag |
If true, the last set value will be periodically saved to persistent storage on the server and be restored during server startup. Topics with this property set to true will not be deleted by the server when the last publisher stops publishing. |
|
boolean |
Retained Flag |
Topics with this property set to true will not be deleted by the server when the last publisher stops publishing. |
|
boolean |
Hidden Flag |
If true, the topic will not be announced to a client until the client subscribes to it. Note the topic will still be visible via the |
Text Data Frames
Each WebSockets text data frame shall consist of a list of JSON objects ("JSON messages").
Each JSON message shall be a JSON object with two keys: a method key containing a lowercase string value describing the type of message as per the following table, and a params key containing the message parameters as a JSON object. The contents of the params object depends on the method; see the sections for each message for details.
Clients and servers shall ignore JSON messages that:
-
are not objects
-
have no
methodkey orparamskey -
have a
methodvalue that is not a string -
have a
paramsvalue that is not an object -
have a
methodvalue that is not listed in the below table
| Method | Description | Direction | Response |
|---|---|---|---|
Publish Messages (Client to Server) |
|||
Publish Request |
Client to Server |
|
|
Publish Release |
Client to Server |
|
|
Set Properties |
Client to Server |
|
|
Value/Subscription Messages (Client to Server) |
|||
Get Values |
Client to Server |
||
Subscribe |
Client to Server |
MessagePack messages (once topic is announced) |
|
Unsubscribe |
Client to Server |
--- |
|
Announcement Messages (Server to Client) |
|||
Topic Announcement |
Server to Client |
--- |
|
Topic Removed |
Server to Client |
--- |
|
Publish Messages (Client to Server)
Publish Request Message (publish)
Sent from a client to the server to indicate the client wants to start publishing values at the given topic. The server shall respond with a Topic Announcement Message (announce), even if the topic was previously announced. The client can start publishing data values via MessagePack messages immediately after sending this message, but the messages will be ignored by the server if the publisher data type does not match the topic data type.
The publish JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Publish name |
The topic name being published |
|
Integer |
Publisher UID |
A client-generated unique identifier for this publisher. Use the same UID later to unpublish. This is also the identifier that the client will use in MessagePack messages for this topic. |
|
String |
Type of data |
The requested data type (as a string). If the topic is newly created (e.g. there are no other publishers) this sets the value type. If the topic was previously published, this is ignored. The Implementations should indicate an error if the user tries to publish an incompatible type to that already set for the topic. |
|
Object |
Properties |
Initial topic properties. If the topic is newly created (e.g. there are no other publishers) this sets the topic properties. If the topic was previously published, this is ignored. The |
Publish Release Message (unpublish)
Sent from a client to the server to indicate the client wants to stop publishing values for the given topic and publisher. The client should stop publishing data value updates via binary MessagePack messages for this publisher prior to sending this message.
When there are no remaining publishers for a non-persistent topic, the server shall delete the topic and send a Topic Removed Message (unannounce).
The unpublish JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Integer |
Publisher UID |
The same unique identifier passed to the |
Set Properties Message (setproperties)
Sent from a client to the server to change properties (see Properties) for a given topic. The server will respond with an updated Topic Announcement Message (announce) (if the topic is published). This message shall be ignored by the server if the topic is not published.
The setproperties JSON message shall contain the following parameters:
| Key | Value type | Description |
|---|---|---|
|
String |
Topic name |
|
Object |
Properties to update |
If a property is not included in the update object, its value is not changed. If a property is provided in the update object with a value of null, the property is deleted.
Value/Subscription Messages (Client to Server)
Get Values Message (getvalues)
Sent from a client to the server to indicate the client wants to get the current values for the specified topics / groups of topics. The server shall treat this identically to a subscribe message, except only send the values once. The server shall send announcement messages (for virtual topics) and MessagePack messages containing the current values immediately upon receipt. While this message could theoretically be used to poll for value updates, it is much better to use a Subscribe Message (subscribe) to request push updates.
The getvalues JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Array of String |
Array of topic prefixes |
One or more topic prefixes |
Subscribe Message (subscribe)
Sent from a client to the server to indicate the client wants to subscribe to value changes for the specified topics / groups of topics. The server shall send MessagePack messages containing the current values for any existing topics upon receipt, and continue sending MessagePack messages for future value changes. If a topic does not yet exist, no message is sent until it is created (via a publish), at which point a Topic Announcement Message (announce) will be sent and MessagePack messages will automatically follow as they are published.
Subscriptions may overlap; only one MessagePack message is sent per value change regardless of the number of subscriptions. Sending a subscribe message with the same subscription UID as a previous subscribe message results in updating the subscription (replacing the array of identifiers and updating any specified options).
The subscribe JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Array of String |
Array of topic prefixes |
One or more topic prefixes to start receiving messages for. |
|
Integer |
Subscription UID |
A client-generated unique identifier for this subscription. Use the same UID later to unsubscribe. |
|
Object |
Options |
Subscription options, see below |
If present, the options object shall contain zero or more of the following keys/values:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Boolean |
Immediate Flag |
If true, value updates seen by the server should be immediately sent to this client, rather than waiting for a periodic "sweep" of changed values. Note this will increase network bandwidth utilization—use with caution! If not specified, defaults to false. |
|
Number |
Periodic sweep time (in seconds) |
How frequently the server should send changes (if not immediate). The server may send more frequently than this (e.g. use a combined minimum period for all values) or apply a restricted range to this value. The default if unspecified (and the |
|
Boolean |
Logging Flag |
If true, the server should send all value changes over the wire regardless of the |
Unsubscribe Message (unsubscribe)
Sent from a client to the server to indicate the client wants to stop subscribing to messages for the given subscription.
The unsubscribe JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
Integer |
Subscription UID |
The same unique identifier passed to the |
Announcement Messages (Server to Client)
Topic Announcement Message (announce)
The server shall send this message for each existing topic to a client when it initially connects. It shall also send this message to all clients when a topic is created, or when any topic properties are changed. Additionally the server shall send this message to a client in response to an publish message.
The announce JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Topic name |
|
|
Integer |
Topic ID |
The identifier that the server will use in MessagePack messages for this topic |
|
String |
Data type |
The data type for the topic (as a string) |
|
Integer |
Publisher UID |
If this message was sent in response to a |
|
Object |
Properties |
Topic properties (see |
Topic Removed Message (unannounce)
The server shall send this message when a previously announced (via a Topic Announcement Message (announce)) topic is deleted.
The unannounce JSON message shall contain the following parameters:
| Key | Value type | Description | Notes |
|---|---|---|---|
|
String |
Topic name |
|
|
Integer |
Topic ID |
The identifier that the server was using for value updates |
Binary Data Frames
Each WebSockets binary data frame shall consist of a MessagePack data stream with one or more complete MessagePack arrays ("MessagePack messages"). MessagePack messages shall not span across WebSockets data frames. It is up to implementations to decide how many MessagePack messages to put into each transmitted WebSockets data frame (as there is an efficiency/latency tradeoff).
Each MessagePack message shall be a MessagePack array with 4 elements. Implementations can either ignore other types of messages (e.g. non-arrays, other numbers of elements) or terminate the connection (allowing this enables use of simplified decoder implementations).
Messages shall consist of (in this order):
-
Topic/Publisher ID: unsigned integer, or -1 (RTT measurement)
-
Timestamp: integer microseconds
-
Data type: unsigned integer
-
Data value (see below)
Topic IDs are used for server to client messages. Topic IDs shall be assigned via JSON announce messages. Client implementations shall ignore messages with topic IDs they do not recognize. Server implementations shall not send messages with topic IDs that were not assigned previously with a JSON message.
Publisher IDs are used for client to server messages. Publisher IDs shall be assigned by the client and be communicated to the server via JSON publish messages. Server implementations shall ignore messages with publisher IDs they do not recognize. Client implementations shall not send messages with publisher IDs that were not assigned previously with a JSON message.
Implementations must ignore messages with data values they cannot decode (either by ignoring the message or by terminating the connection), and shall send messages with data values consistent with the above table.
An example double value update would be 17 bytes:
94 (array with 4 elements)
32 (topic/publisher ID=50)
D2 07 27 0E 00 (timestamp of exactly 2 minutes in integer microseconds)
01 (data type: double-precision float)
CB 3F BF 97 24 74 53 8E F3 (double value of 0.1234)
For comparison, a double value update in NT 3.0 is 14 bytes (and does not contain a timestamp).
Drawbacks
API Changes
While the server (robot) APIs can have minimal to no changes, the current NetworkTables API doesn’t directly map to a pub/sub approach, except for the listener API. A new API will be required to take full advantage of the features of this protocol. One big advantage of the current APIs is that the client and server APIs are the same, so if we update the client API it should work on the server as well.
TCP Only
Everything is sent via the WebSockets pipe, which can result in latency spikes due to TCP retransmissions, even for "immediate" subscriptions and timestamp updates. Should there be a send-via-UDP option? Web technologies generally can’t use UDP but this feature could be useful for other use cases. However, adding this would add significant complexity and might be better left to MQTT or other full-stack alternatives.
No peer-to-peer client connections
This protocol continues the previous NT approach of having all traffic go through the central NT server, rather than supporting direct peer to peer connections. This adds latency but simplifies the overall protocol design and makes it possible to have clients that can’t set up servers (e.g. web browsers).
Alternatives
Do nothing
The major features in this proposal (accessibility to web technologies and timestamping and data logging) would not be made available to users. Users would continue to need to deal with these issues manually or by using third-party workarounds.
Update the raw NetworkTables protocol (without using WebSockets)
This does not provide one of the major benefits to moving to a WebSockets protocol, which is easy to use by browsers. While current workarounds like pynetworktables2js exist, a protocol revision which does not address this need feels shortsighted.
Encapsulate the current NT 3.0 protocol in WebSockets
While this makes the current protocol more easily accessible to web technologies, the current protocol does not have integrated support for timestamping or data logging. It also requires substantially more custom decoder implementation work than MessagePack, and does not offer human-readable control messages.
Use MQTT or another existing protocol
MQTT requires running a separate server from the robot program, and the robot program to be a client to it (unlike NT, it has no means of doing value updates within the server itself). MQTT natively does not use WebSockets (it’s a custom wire protocol like the current NetworkTables), although there is a WebSockets variant. MQTT is a significantly more complicated protocol with support for things like full QOS.
Trades
JSON option for value updates (rejected)
This was considered, but rejected for two reasons: encoding overhead and spec/implementation effort. In benchmarking on desktop systems, JSON was 25% the speed of MessagePack when encoding doubles (due to text conversion), and in typical robot use, this overhead would largely land on the robot controller, which also has the fewest resources. In addition, requiring implementation of both JSON and MessagePack encoding nearly doubles the amount of encode/decode implementation effort, particularly as JSON does not have good binary data support and would require Base64 or something similar to encode binary data as a string.
Timestamp format
The spec uses integer microseconds. This seems to be a reasonable enough resolution for FRC use and is common with the FPGA clock resolution.