Accessing LiveTraffic's Aircraft Data

Ways for plugin developers to access information of LiveTraffic's aircraft

There are a few ways to access LiveTraffic's aircraft data programmatically:

Read Traffic Data

LTAPI

LiveTraffic offers a C++ API to read (nearly) all information of all aircraft that LiveTraffic operates. With a single call, you are provided with a vector of LTAircraft objects. You can subclass the LTAircraft class to add your own management functionality. Technically, data is packed and transferred very efficiently in the background and transferred by means of binary dataRefs. Available from X-Plane.org and from GitHub. Includes a sample plugin implementation demonstrating most features.

I am aware of one plugin, which makes already active use of it, which is ABC.

TCAS Targets

As of X-Plane 11.50, X-Plane offers a new approach called TCAS Override to report planes to TCAS systems and to other plugins interested in multiplayer aircraft informaton. New plugins shall definitely follow this new approach. Find implementaton details in Laminar's blog entry.

While LiveTraffic has TCAS control, and only then, LiveTraffic reports the closest up to 63 aircraft as TCAS targets with the following values:

.../tcas/targets/

LiveTraffic's Value

modeS_id

24 bit Mode S transponder code

modeC_code

Squawk Code

flight_id

Flight number or, if unavailable, tail number (registration)

icao_type

ICAO aircraft type designator

All dataRefs under sim/cockpit2/tcas/targets/position are filled as expected and documented except for the following, which are not populated:

  • weight_on_wheels

  • wing_sweep

  • yolk_pitch/roll/yaw [sic!]

Standard Multiplayer DataRefs

The classic 19 sets of multiplayer dataRefs (sim/multiplayer/position/plane*) are mirrored automatically while providing TCAS target information. So the closest 19 aircraft are also available via this channel while LiveTraffic has TCAS control.

With TCAS Override, XPLMCountAircraft returns the actual number of reported aircraft independend of how many AI Aircraft the user has configured. So you can rely on this number and don't necessarily need to always monitor all these 19 slots. Still, for backward compatibility, LiveTraffic fills unused slots' _x/y/z values with > 9999999. (They are deliberately not set to 0 in this case, because 0/0/0 is a totally valid geographic location.)

Starting with 11.50 Beta 8, X-Plane can return values larger than 20 in XPLMCountAircraft! If you are dealing with the 19 multiplayer slots only you need to make sure to handle larger values correctly, e.g. by capping at 20.

Shared DataRefs for Textual Information

As a supplement to the standard multiplay dataRefs, textual aircraft and flight information is provided via shared dataRefs of type xplmType_Data as suggested by FSTramp (LiveTraffic issue #144) with # being a plane number between 1 and 63:

  • sim/multiplayer/position/plane#_tailnum - Tail number, registration

  • sim/multiplayer/position/plane#_ICAO - ICAO Aircraft type

  • sim/multiplayer/position/plane#_manufacturer - Aircraft manufacturer, human readable

  • sim/multiplayer/position/plane#_model - Aircraft model, human readable

  • sim/multiplayer/position/plane#_ICAOairline - ICAO airline/operator code

  • sim/multiplayer/position/plane#_airline - Airline/operator

  • sim/multiplayer/position/plane#_flightnum - Flight number

  • sim/multiplayer/position/plane#_apt_from - Origin airport

  • sim/multiplayer/position/plane#_apt_to - Destination airport

  • sim/multiplayer/position/plane#_cslModel - CSL model used to render the plane (folder name plus model id)

A plugin wanting to use this data must call XPLMShareData, can optionally thereby register a notification callback, then calls XPLMFindDataRef and XPLMGetDatab as usual. Provide at least a 40 character buffer per dataRef to be on the safe side.

Take Over Camera View of an Aircraft

A LiveTraffic user can activate a camera view on any aircraft. LiveTraffic publishes which aircraft the camera shows and even provides a setting that disables LiveTraffic's internal camera implementation so that a 3rd party camera tool can instead provide the view.

  • LiveTraffic operates two integer shared dataRefs with global names, ie. not LiveTraffic-specific. In fact, they pick up the naming scheme as used by the shared dataRefs for textual aircraft information. Shared dataRefs have the advantage that a reading plugin can register a notification callback and several plugins can write to them and this way inform both the camera plugin as well as LiveTraffic. See SDK documentation on XPLMShareData.

    • sim/multiplayer/camera/tcas_idx is set to the TCAS index (1..63) of the aircraft being viewed, or to -1 if that aircraft has no TCAS index, or to 0 if camera view is turned off.

    • sim/multiplayer/camera/modeS_id is set to the aircraft key, usually the 24bit ICAO transponder code (like 0xAB1234=11211316) of the aircraft being viewed, or to 0 if camera view is turned off.

  • A camera plugin

    • should register a notification on sim/multiplayer/camera/tcas_idx because this dataRef is set last. By the time your notification callback triggers both modeS_id and tcas_idx will be updated.

    • should, in the notification callback, read one or both values and do your camera magic if values are not 0.

    • can - optionally but welcome - write the dataRef values, too, ie. if your user switches off the camera view then update modeS_id and tcas_idx (in this order) to 0 to indicate that no camera view is on an aircraft; or even update them with aircraft info if your user selects another aircraft inside your plugin. (Note that your callbacks get called even if you set the values...weird twist of the SDK implementation.)

  • Alternatively, a camera plugin can just use LTAPI, which handles all that internally:

    • Override LTAPIAircraft::toggleCamera(), which is called whenever the shared dataRef values change on the current aircraft and even provides you with a pointer to the previous aircraft if any. The LTAPIExample plugin includes an example implementation.

    • LTAPIAircraft::setCameraAc() and LTAPIConnect::clearCameraInfo() are available for write operations.

UDP Broadcast in ForeFlight Data Format

You can make use of the data broadcasted on the ForeFlight channel for other purposes than just ForeFlight. The ForeFlight data format is described here and LiveTraffic sticks to it. Example broadcasts (around OMDB) look like this:

Example ForeFlight broadcast datagrams
XGPSLiveTraffic,55.367,25.256,240.6,119.235,52.2
XATTLiveTraffic,119.3,1.8,-0.5
XTRAFFICLiveTraffic,4921470,25.269,55.200,5023.0,0.0,1,289.6,208.9,SWR243
XTRAFFICLiveTraffic,7701531,25.252,55.359,9.9,0.0,0,123.0,14.9,CEB015
XTRAFFICLiveTraffic,8994918,25.157,55.366,6707.5,2711.5,1,273.7,266.6,GFA513
XTRAFFICLiveTraffic,9003216,25.245,55.366,36.9,0.0,0,253.2,11.2,UAE529

User plane's position is broadcasted with 1Hz, its attitude with 5Hz. The repeat interval of traffic data is not defined by ForeFlight and configurable in LiveTraffic.

Output port is 49002 as defined by ForeFlight. There is no GUI setting for it so that nobody can accidently change it. But you'll find it in LiveTraffic's configuration file.

Here's a simplistic Python script, with which I test receiving any broadcasts. It does not interpret the data, but only displays it together with a timestamp. It works for Python 2 and 3 (only the output format slightly differs) and takes just one parameter, the port number:

udp_listen.py
#!/usr/bin/python
import sys
import socket
import time
#---socket creation
connexion = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
connexion.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if sys.platform != "win32":
connexion.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
#---Bind
try:
connexion.bind(('', int(sys.argv[1])))
except socket.error:
print ("connexion failed")
connexion.close()
sys.exit()
#---wait for and print data
while 1:
data, addr = connexion.recvfrom(1024)
print (time.time(), ":", data)

Called like ./udp_listen.py 49002, it would output received UDP datagrams continuously like this:

Example Output of udp_listen.py
(1554490061.876467, ':', 'XTRAFFICLiveTraffic,3958292,50.021,8.430,1569.0,-1146.4,1,69.6,186.4,DLH805')
(1554490061.876575, ':', 'XTRAFFICLiveTraffic,3958350,50.035,8.545,324.9,0.0,0,58.1,2.3,DLH2VH')
(1554490061.876621, ':', 'XTRAFFICLiveTraffic,3958370,50.043,8.522,350.3,0.0,0,70.4,59.8,DLH8A')
(1554490061.878866, ':', 'XTRAFFICLiveTraffic,3958394,50.048,8.570,366.6,0.0,0,0.0,0.0,DLH5MR')
(1554490061.889803, ':', 'XGPSLiveTraffic,8.583,50.032,106.5,180.000,0.0')
(1554490061.891284, ':', 'XTRAFFICLiveTraffic,3957833,50.042,8.582,358.0,0.0,0,27.2,12.4,DLH21U')
(1554490061.900316, ':', 'XTRAFFICLiveTraffic,3958441,50.044,8.536,341.7,0.0,0,81.9,30.8,DLH1449')
(1554490061.923233, ':', 'XTRAFFICLiveTraffic,3958443,50.045,8.569,360.9,0.0,0,270.0,0.0,DLH57F')
(1554490061.944078, ':', 'XTRAFFICLiveTraffic,3958499,50.043,8.561,351.1,0.0,0,162.2,11.5,DLH044')
(1554490061.95145, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490061.964778, ':', 'XTRAFFICLiveTraffic,3958610,50.072,8.526,23984.0,135.9,1,335.5,332.7,EWG1910')
(1554490061.987202, ':', 'XTRAFFICLiveTraffic,3958617,50.040,8.575,347.0,0.0,0,60.1,24.4,DLH9KL')
(1554490061.992343, ':', 'XTRAFFICLiveTraffic,3958157,50.043,8.547,342.5,0.0,0,145.1,22.6,DLH087')
(1554490062.009156, ':', 'XTRAFFICLiveTraffic,3960929,50.041,8.562,345.9,0.0,0,248.7,9.7,GEC8343')
(1554490062.029472, ':', 'XTRAFFICLiveTraffic,4458944,50.039,8.555,339.9,0.0,0,247.5,20.5,EJU25DA')
(1554490062.05433, ':', 'XTRAFFICLiveTraffic,4566062,50.049,8.589,359.1,0.0,0,342.2,4.1,SAS1636')
(1554490062.076019, ':', 'XTRAFFICLiveTraffic,4920849,50.029,8.542,452.8,-1150.5,1,69.9,125.7,SWR1076')
(1554490062.094481, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490062.098079, ':', 'XTRAFFICLiveTraffic,4921315,50.041,8.559,343.6,0.0,0,0.0,0.0,SWR106U')
(1554490062.121316, ':', 'XTRAFFICLiveTraffic,5270561,50.032,8.526,324.9,0.0,0,190.1,20.1,ADR125')
(1554490062.145733, ':', 'XTRAFFICLiveTraffic,7786223,49.952,8.592,8000.0,0.0,1,249.1,280.6,SIA326')
(1554490062.152416, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490062.167006, ':', 'XTRAFFICLiveTraffic,7867067,50.060,8.653,2733.6,682.0,1,71.9,228.2,CPA282')
(1554490062.197146, ':', 'XTRAFFICLiveTraffic,3958217,50.049,8.570,368.4,0.0,0,0.0,0.0,DLH892')
(1554490062.299546, ':', 'XTRAFFICLiveTraffic,3958350,50.035,8.545,324.9,0.0,0,58.1,2.3,DLH2VH')
(1554490062.354267, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490062.403429, ':', 'XTRAFFICLiveTraffic,3958441,50.044,8.536,341.7,0.0,0,81.9,30.8,DLH1449')
(1554490062.504334, ':', 'XTRAFFICLiveTraffic,3958443,50.045,8.569,360.9,0.0,0,270.0,0.0,DLH57F')
(1554490062.55615, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490062.608154, ':', 'XTRAFFICLiveTraffic,3958610,50.072,8.526,23984.0,135.9,1,335.5,332.7,EWG1910')
(1554490062.693573, ':', 'XGPSLiveTraffic,8.583,50.032,106.5,180.000,0.0')
(1554490062.710873, ':', 'XTRAFFICLiveTraffic,3960929,50.041,8.562,345.9,0.0,0,248.7,9.7,GEC8343')
(1554490062.757548, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490062.915558, ':', 'XTRAFFICLiveTraffic,4921315,50.041,8.559,343.6,0.0,0,0.0,0.0,SWR106U')
(1554490062.96226, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490063.018004, ':', 'XTRAFFICLiveTraffic,7786223,49.952,8.592,8000.0,0.0,1,249.1,280.6,SIA326')
(1554490063.120083, ':', 'XTRAFFICLiveTraffic,7867067,50.060,8.653,2733.6,682.0,1,71.9,228.2,CPA282')
(1554490063.162793, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490063.220842, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490063.364389, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')
(1554490063.564868, ':', 'XATTLiveTraffic,114.3,-1.3,0.2')

Send Traffic Data to LiveTraffic

The RealTraffic channel receives data from a local app, the RealTraffic app, which sends it out via UDP. Any other program can send the same kind of UDP data and LiveTraffic would just use it as well.

This paragraph might need more details...but a well working proof of concept that I use when testing LiveTraffic's handling of aircraft is discussed in this forum thread.

  • SendTraffic.py is a Python 3 script, which takes a well-formatted CSV as input and sends each line to LiveTraffic using the RealTraffic port. In LiveTraffic, the RealTraffic channel must be enabled. Run SendTraffic.py -h to see all options.

  • Here are some sample files I also use for testing LiveTraffic in reproducible scenarios, the file names give away the airport you need to be at to see something happening:

    • edkb_10s.csv: single C172 doing one take-off, traffic pattern, landing, can run in a loop with -l

    • KLAX_20200624_2220Z.csv: Recorded session with lots of live traffic in the region at that time.