API Overview

Positions are represented by GPS data that is generated locally onboard each train-set. The current position is transmitted as a message every second to Oxyfi’s real-time server on shore.

Beside storing the message for future use, the server customizes messages on the fly by tagging it with additional information and passes them on to subscribers. One such subscriber is the websocket API service.

The Trainpos API is one such subscriber. It subscribes on messages that contains the NMEA version 2.2 specification of the $GPRMC sentence tagged with vehicleId and train number (tågnummer), both public and internal train numbers.

VehicleId is a unique number assigned to every train-set or carriage in Sweden, this number is typically written on the vehicle and is never changed. The train number on the other hand identifies a specific route, the train number is typically found on tickets, billboards and timetables. A train can serve 0 or more train identities at any one time, see further information under

.PlainText | safeHTML

The Trainpos API will redistribute the real-time positions to all Trainpos subscribers. A Trainpos API subscriber is typically some form of server that in turn is responsible to distribute positions to all of its clients. In other words, the clients should not try to subscribe directly from the Trainspos API. In fact, the API key is only valid for one subscriber, if a new subscribe request arrives at the API, it will close any open websocket with the same API key.

The total delay from position generation onboard until it is sent out from the real-time server is typically less than 100 ms. The vast majority of this delay is occurring in the mobile network that connects the vehicle to the internet.

Each train-set or carriage reports its position every second, so you should get a message per second for each vehicle that currently has both power and radio coverage.

Message Details

– API version 1.0

A message sent from the real-time server to a subscriber is encoded as an ASCII-string and sent over the subscribers websocket.

The message format is based on the NMEA specification version 2.2 and contains the GPRMC sentence followed by a number of additional fields as explained in Table 1. Each message begins with $GP and fields are separated by comma. Time zone will always be UTC.

This is a sample message:

$GPRMC,142937,A,5948.7028,N,01307.9771,E,49.53,349.7,101212,1.8,E* 3A,,1421.trains.se,,8955.public.trains.se@2012-12-10;8957.public.trains.se@2012-12-10,oxyfi

Table 1 message Specification

NoField exampleExplanation
1RMCRecommended Minimum sentence C
2142937Fix taken at 14:29:37 UTC
3AStatus A=active or V=Void
45948.7028Latitude 59 deg 48.7028'
5NLatitude hemisphere N for northern and S for southern
601307.9771Longitude 13 deg 07.9771'
7ELongitude direction, E for east of the meridian 0° and W for west
849.53Speed over ground in knots
9349.7Track angle in degrees True
10101212Date – 10th of December 2012
111.8Magnetic Variation
12EMagnetic deviation direction, E for east of the meridian 0° and W for west
13*3AThe checksum data, always begins with *
14n/aNot used
151421.trains.seIdentifies the vehicle, 1421 in this case (Värmlandstrafik)
16n/aNot used
178955.public.trains.se@2012-12-10;
8957.public.trains.se@2012-12-10Train numbers concatenated with semicolon if more than one is present. See more details about how this string is built
up in section “A Note on Train Numbers”.
18oxyfiData origin

A Note on Train Numbers

A train-set or carriage may carry more than one train number at a time, each being either announced (public) or technical (internal). The string in the message field that carries train number is therefore built up like domain-names concatenated together with semicolon. For instance, train number 8955 is the announced train number and thus “tagged” with public resulting in 8955.public.trains.se. If there had been a corresponding technical only train number too, say 8845, that would have resulted in the following string 8955.public.trains.se;8845.internal.trains.se.

In addition to the above, if a train-set or carriage is running late so that the current train number becomes overlapping with the next planned number, both those numbers will be presented in the field. As the message sample shows, at the time when the message was intercepted that particular train served both 8955 and 8957, thus the train number field is 8955.public.trains.se@2012-12-10;8957.public.trains.se@2012-12-10.

To give subscribers a head start, the train number is applied 5 minutes before the actual train starts to serve it.

How to Subscribe

Subscribe to stream

wss://api.oxyfi.com/trainpos/listen?v=1&key=YOUR-KEY-HERE

Code example

Python:

1# Uses https://github.com/websocket-client/websocket-client
2import websocket
3def on_message(ws, message):
4print(message)
5ws = websocket.WebSocketApp("wss://api.oxyfi.com/trainpos/listen?v=1&key=YOUR-KEY-HERE",on_message = on_message)
6ws.run_forever()

Node.js:

// Uses https://github.com/websockets/ws
const WebSocket = require('ws');
const ws = new WebSocket('wss://api.oxyfi.com/trainpos/listen?v=1&key=YOUR-KEY-HERE');
ws.on('message', function incoming(data) {console.log(data); })

Usage

A Trainpos API subscriber is typically some form of server that in turn is responsible to distribute positions to all of its clients. In other words, the clients should not try to subscribe directly from the Trainspos API. In fact, the API key is only valid for one subscriber at the time, if a new websocket request is made, the Trainpos API will close any open websocket with the same API key.

Here are some suggestion of libraries that can be used to parse NMEA formatted data to objects or data structures:

VehicleIds

To get the current list of trains that delivers data through the Trainpos API, see

The current list of trains is not available over HTTPS.

http://api.oxyfi.com/trainpos/trainIdentites.htm push-API

On the 2021-09-24 the current list of trains is:

Värmlandstrafik

14141415141614201421
90489049905090669067
908190829083

Norrtåg

14293112316731899032
90339034904290519062
6200162002620036200462005
6200662007620086200962010
6201162012

Tåg i Bergslagen

31903223323132343235
90059006900790089009
90119012901390149015
90189019902090219022
90239024902590379039
905690579068

Blekingetrafiken

310831093111

Kalmars länstrafik

31063134313531363137
31683169

What is next

Oxyfi continuously works on adding more vehicles to this real-time position API. It may also be possible to add filters in the websocket request so only positions for the specified trains are forwarded over the websocket.

We are very happy to receive feedback and feature requests, please drop an email to [email protected].

Known Issues

It is the train operator who plans the traffic that decides which vehicle will serve what train number. On occasion the train operator has reported one vehicle to serve a specific train number but in reality it is served by another train. At present the vehicle to train number mapping, as reported by the train operator, is not verified to conform to reality in any way, it is just forwarded as is. Any such checks have to be carried out by the subscriber.