How to access ADS-B data from OpenSky live API?
Warning
OpenSky data are subject to particular terms of use. In particular, if you plan to use data for commercial purposes, you should contact them.
Anonymous access to the OpenSky live API is possible, but functionalities may be limited. The first thing to do once you have an account is to put your credentials in you configuration file. Add the following lines to the [opensky] section of your configuration file.
[opensky]
username =
password =
You can check the path to your configuration file here. The path is different according to OS versions so do not assume anything and check the contents of the variable.
>>> import traffic
>>> traffic.config_file
PosixPath('/home/xo/.config/traffic/traffic.conf')
State vectors
The most basic usage for the OpenSky REST API is to get the instant position for all aircraft. This part actually does not require authentication.
import matplotlib.pyplot as plt
import pandas as pd
from cartes.crs import EuroPP
from cartes.utils.features import countries
from traffic.data import opensky
sv = opensky.api_states()
with plt.style.context('traffic'):
fig, ax = plt.subplots(subplot_kw=dict(projection=EuroPP()))
ax.add_feature(countries())
ax.gridlines()
ax.set_extent((-7, 15, 40, 55))
ax.spines['geo'].set_visible(False)
sv.plot(ax, s=10, color="#4c78a8")
now = pd.Timestamp("now", tz="utc")
ax.set_title(
f"Snapshot generated at {now:%Y-%m-%d %H:%MZ}",
fontsize=14
)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[1], line 9
5 from cartes.utils.features import countries
7 from traffic.data import opensky
----> 9 sv = opensky.api_states()
11 with plt.style.context('traffic'):
12 fig, ax = plt.subplots(subplot_kw=dict(projection=EuroPP()))
File ~/work/traffic/traffic/src/traffic/data/adsb/opensky.py:190, in OpenSky.api_states(self, own, bounds)
181 @copy_documentation(rest.REST.states)
182 def api_states(
183 self,
(...)
188 | tuple[float, float, float, float] = None,
189 ) -> StateVectors:
--> 190 df = self.rest_client.states(own, bounds).pipe(format_history)
191 return StateVectors(df)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:193, in REST.states(self, own, bounds, retry)
189 west, south, east, north = bounds
191 what += f"?lamin={south}&lamax={north}&lomin={west}&lomax={east}"
--> 193 json = self.get(f"https://opensky-network.org/api/states/{what}")
194 columns: list[str] = list(self._json_columns)
196 # For some reason, OpenSky may return 18 fields instead of 17
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:61, in REST.get(self, query, retry)
60 def get(self, query: str, retry: int = 5) -> Any:
---> 61 c = self.client.get(query, auth=self.auth)
62 try:
63 if limit := c.headers.get("X-Rate-Limit-Remaining", None):
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1036 def get(
1037 self,
1038 url: URL | str,
(...)
1046 extensions: RequestExtensions | None = None,
1047 ) -> Response:
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
810 warnings.warn(message, DeprecationWarning, stacklevel=2)
812 request = self.build_request(
813 method=method,
814 url=url,
(...)
823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:912, in Client.send(self, request, stream, auth, follow_redirects)
904 follow_redirects = (
905 self.follow_redirects
906 if isinstance(follow_redirects, UseClientDefault)
907 else follow_redirects
908 )
910 self._set_timeout(request)
--> 912 auth = self._build_request_auth(request, auth)
914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:463, in BaseClient._build_request_auth(self, request, auth)
457 def _build_request_auth(
458 self,
459 request: Request,
460 auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
461 ) -> Auth:
462 auth = (
--> 463 self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)
464 )
466 if auth is not None:
467 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:449, in BaseClient._build_auth(self, auth)
447 return None
448 elif isinstance(auth, tuple):
--> 449 return BasicAuth(username=auth[0], password=auth[1])
450 elif isinstance(auth, Auth):
451 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:133, in BasicAuth.__init__(self, username, password)
132 def __init__(self, username: str | bytes, password: str | bytes) -> None:
--> 133 self._auth_header = self._build_auth_header(username, password)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:140, in BasicAuth._build_auth_header(self, username, password)
139 def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
--> 140 userpass = b":".join((to_bytes(username), to_bytes(password)))
141 token = b64encode(userpass).decode()
142 return f"Basic {token}"
TypeError: sequence item 0: expected a bytes-like object, NoneType found
Flight tables
Flight tables are accessible by airport (use the ICAO code) given temporal bounds:
# Have you seen Santa Claus coming to Toulouse?
opensky.api_arrival("LFBO", "2021-12-24 20:00", "2021-12-25 06:00")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[2], line 2
1 # Have you seen Santa Claus coming to Toulouse?
----> 2 opensky.api_arrival("LFBO", "2021-12-24 20:00", "2021-12-25 06:00")
File ~/work/traffic/traffic/src/traffic/data/adsb/opensky.py:234, in OpenSky.api_arrival(self, airport, begin, end)
227 @copy_documentation(rest.REST.arrival)
228 def api_arrival(
229 self,
(...)
232 end: None | timelike = None,
233 ) -> pd.DataFrame:
--> 234 return self.rest_client.arrival(
235 airport if isinstance(airport, str) else airport.icao, begin, end
236 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:410, in REST.arrival(self, airport, begin, end)
407 else:
408 end_ts = to_datetime(end)
--> 410 json = self.get(
411 f"https://opensky-network.org/api/flights/arrival"
412 f"?begin={begin_ts.timestamp():.0f}&airport={airport}&"
413 f"end={end_ts.timestamp():.0f}"
414 )
416 return (
417 pd.DataFrame.from_records(json)
418 .convert_dtypes(dtype_backend="pyarrow")[
(...)
438 .sort_values("lastSeen")
439 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:61, in REST.get(self, query, retry)
60 def get(self, query: str, retry: int = 5) -> Any:
---> 61 c = self.client.get(query, auth=self.auth)
62 try:
63 if limit := c.headers.get("X-Rate-Limit-Remaining", None):
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1036 def get(
1037 self,
1038 url: URL | str,
(...)
1046 extensions: RequestExtensions | None = None,
1047 ) -> Response:
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
810 warnings.warn(message, DeprecationWarning, stacklevel=2)
812 request = self.build_request(
813 method=method,
814 url=url,
(...)
823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:912, in Client.send(self, request, stream, auth, follow_redirects)
904 follow_redirects = (
905 self.follow_redirects
906 if isinstance(follow_redirects, UseClientDefault)
907 else follow_redirects
908 )
910 self._set_timeout(request)
--> 912 auth = self._build_request_auth(request, auth)
914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:463, in BaseClient._build_request_auth(self, request, auth)
457 def _build_request_auth(
458 self,
459 request: Request,
460 auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
461 ) -> Auth:
462 auth = (
--> 463 self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)
464 )
466 if auth is not None:
467 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:449, in BaseClient._build_auth(self, auth)
447 return None
448 elif isinstance(auth, tuple):
--> 449 return BasicAuth(username=auth[0], password=auth[1])
450 elif isinstance(auth, Auth):
451 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:133, in BasicAuth.__init__(self, username, password)
132 def __init__(self, username: str | bytes, password: str | bytes) -> None:
--> 133 self._auth_header = self._build_auth_header(username, password)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:140, in BasicAuth._build_auth_header(self, username, password)
139 def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
--> 140 userpass = b":".join((to_bytes(username), to_bytes(password)))
141 token = b64encode(userpass).decode()
142 return f"Basic {token}"
TypeError: sequence item 0: expected a bytes-like object, NoneType found
# Or maybe leaving?
opensky.api_departure("LFBO", "2021-12-24 20:00", "2021-12-25 06:00")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[3], line 2
1 # Or maybe leaving?
----> 2 opensky.api_departure("LFBO", "2021-12-24 20:00", "2021-12-25 06:00")
File ~/work/traffic/traffic/src/traffic/data/adsb/opensky.py:245, in OpenSky.api_departure(self, airport, begin, end)
238 @copy_documentation(rest.REST.departure)
239 def api_departure(
240 self,
(...)
243 end: None | timelike = None,
244 ) -> pd.DataFrame:
--> 245 return self.rest_client.departure(
246 airport if isinstance(airport, str) else airport.icao, begin, end
247 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:470, in REST.departure(self, airport, begin, end)
467 else:
468 end_ts = to_datetime(end)
--> 470 json = self.get(
471 f"https://opensky-network.org/api/flights/departure"
472 f"?begin={begin_ts.timestamp():.0f}&airport={airport}&"
473 f"end={end_ts.timestamp():.0f}"
474 )
476 return (
477 pd.DataFrame.from_records(json)
478 .convert_dtypes(dtype_backend="pyarrow")[
(...)
498 .sort_values("firstSeen")
499 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:61, in REST.get(self, query, retry)
60 def get(self, query: str, retry: int = 5) -> Any:
---> 61 c = self.client.get(query, auth=self.auth)
62 try:
63 if limit := c.headers.get("X-Rate-Limit-Remaining", None):
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1036 def get(
1037 self,
1038 url: URL | str,
(...)
1046 extensions: RequestExtensions | None = None,
1047 ) -> Response:
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
810 warnings.warn(message, DeprecationWarning, stacklevel=2)
812 request = self.build_request(
813 method=method,
814 url=url,
(...)
823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:912, in Client.send(self, request, stream, auth, follow_redirects)
904 follow_redirects = (
905 self.follow_redirects
906 if isinstance(follow_redirects, UseClientDefault)
907 else follow_redirects
908 )
910 self._set_timeout(request)
--> 912 auth = self._build_request_auth(request, auth)
914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:463, in BaseClient._build_request_auth(self, request, auth)
457 def _build_request_auth(
458 self,
459 request: Request,
460 auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
461 ) -> Auth:
462 auth = (
--> 463 self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)
464 )
466 if auth is not None:
467 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:449, in BaseClient._build_auth(self, auth)
447 return None
448 elif isinstance(auth, tuple):
--> 449 return BasicAuth(username=auth[0], password=auth[1])
450 elif isinstance(auth, Auth):
451 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:133, in BasicAuth.__init__(self, username, password)
132 def __init__(self, username: str | bytes, password: str | bytes) -> None:
--> 133 self._auth_header = self._build_auth_header(username, password)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:140, in BasicAuth._build_auth_header(self, username, password)
139 def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
--> 140 userpass = b":".join((to_bytes(username), to_bytes(password)))
141 token = b64encode(userpass).decode()
142 return f"Basic {token}"
TypeError: sequence item 0: expected a bytes-like object, NoneType found
A basic route database is also accessible through the REST API:
opensky.api_routes("AFR292")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 1
----> 1 opensky.api_routes("AFR292")
File ~/work/traffic/traffic/src/traffic/data/adsb/opensky.py:200, in OpenSky.api_routes(self, callsign)
198 @copy_documentation(rest.REST.routes)
199 def api_routes(self, callsign: str) -> tuple[str, str]:
--> 200 return self.rest_client.routes(callsign)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:280, in REST.routes(self, callsign)
278 def routes(self, callsign: str) -> tuple[str, str]:
279 """Returns the route associated to a callsign."""
--> 280 json = self.get(
281 f"https://opensky-network.org/api/routes?callsign={callsign}"
282 )
284 return tuple(json["route"])
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/pyopensky/rest.py:61, in REST.get(self, query, retry)
60 def get(self, query: str, retry: int = 5) -> Any:
---> 61 c = self.client.get(query, auth=self.auth)
62 try:
63 if limit := c.headers.get("X-Rate-Limit-Remaining", None):
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1036 def get(
1037 self,
1038 url: URL | str,
(...)
1046 extensions: RequestExtensions | None = None,
1047 ) -> Response:
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
810 warnings.warn(message, DeprecationWarning, stacklevel=2)
812 request = self.build_request(
813 method=method,
814 url=url,
(...)
823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:912, in Client.send(self, request, stream, auth, follow_redirects)
904 follow_redirects = (
905 self.follow_redirects
906 if isinstance(follow_redirects, UseClientDefault)
907 else follow_redirects
908 )
910 self._set_timeout(request)
--> 912 auth = self._build_request_auth(request, auth)
914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:463, in BaseClient._build_request_auth(self, request, auth)
457 def _build_request_auth(
458 self,
459 request: Request,
460 auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT,
461 ) -> Auth:
462 auth = (
--> 463 self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth)
464 )
466 if auth is not None:
467 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_client.py:449, in BaseClient._build_auth(self, auth)
447 return None
448 elif isinstance(auth, tuple):
--> 449 return BasicAuth(username=auth[0], password=auth[1])
450 elif isinstance(auth, Auth):
451 return auth
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:133, in BasicAuth.__init__(self, username, password)
132 def __init__(self, username: str | bytes, password: str | bytes) -> None:
--> 133 self._auth_header = self._build_auth_header(username, password)
File ~/work/traffic/traffic/.venv/lib/python3.11/site-packages/httpx/_auth.py:140, in BasicAuth._build_auth_header(self, username, password)
139 def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str:
--> 140 userpass = b":".join((to_bytes(username), to_bytes(password)))
141 token = b64encode(userpass).decode()
142 return f"Basic {token}"
TypeError: sequence item 0: expected a bytes-like object, NoneType found