środa, 1 grudnia 2021

Python - JSON where is iss-now

W tym poście chciałbym opisać szybki projekt pobrania danych dotyczących lokalizacji sateli na mapie.


[Źródło: https://applover.pl/technology/python]

API Open Notify.


Z tego portalu można pobrać dwa rodzaje danych. Jeden z aktualnym położeniem satelity ISS na orbicie (http://api.open-notify.org/iss-now.json):

  1. {
  2.     "iss_position":
  3.     {
  4.         "longitude": "-145.2106",
  5.         "latitude": "20.8397"
  6.     },
  7.     "timestamp": 1637799853,
  8.     "message": "success"
  9. }

Powyższe dane zawierają długość i szerokość geograficzną z aktualnym położeniem międzynarodowej stacji kosmicznej. 

Drugie z wykazem osób aktualnie umieszczonych w kosmosie (http://api.open-notify.org/astros.json):

  1. {
  2.     "message": "success",
  3.     "people": [
  4.         {   "name": "Mark Vande Hei",
  5.             "craft": "ISS" },
  6.         {   "name": "Pyotr Dubrov",
  7.             "craft": "ISS" },
  8.         {   "name": "Anton Shkaplerov",
  9.             "craft": "ISS" },
  10.         {   "name": "Zhai Zhigang",
  11.             "craft": "Shenzhou 13" },
  12.         {   "name": "Wang Yaping",
  13.             "craft": "Shenzhou 13" },
  14.         {   "name": "Ye Guangfu",
  15.             "craft": "Shenzhou 13" },
  16.         {   "name": "Raja Chari",
  17.             "craft": "ISS" },
  18.         {   "name": "Tom Marshburn",
  19.             "craft": "ISS" },
  20.         {   "name": "Kayla Barron",
  21.             "craft": "ISS" },
  22.         {   "name": "Matthias Maurer",
  23.             "craft": "ISS" }
  24.         ],
  25.         "number": 10
  26. }

Powyższe dane zawierają informację z danymi osób w kosmosie, oraz gdzie one są umieszczone.

Poniżej przedstawię prosty program w Python, który pobiera dane umieszczone powyżej.

  1. import pandas as pd
  2.  
  3. URL_ISS_POS = "http://api.open-notify.org/iss-now.json"
  4. URL_PEOPLE_SPACE = "http://api.open-notify.org/astros.json"
  5.  
  6. iss_pos = pd.read_json(URL_ISS_POS)
  7. people_space = pd.read_json(URL_PEOPLE_SPACE)
  8.  
  9. print(iss_pos)
  10. print(people_space)

Wykonanie powyższego skryptu spowoduje wyświetlenie w terminalu pobranych danych z serwisu:

  1.            message  iss_position           timestamp
  2. latitude   success      -22.3959 2021-11-29 23:24:40
  3. longitude  success      163.6874 2021-11-29 23:24:40
  4.    message                                            people  number
  5. 0  success        {'name': 'Mark Vande Hei', 'craft': 'ISS'}      10
  6. 1  success          {'name': 'Pyotr Dubrov', 'craft': 'ISS'}      10
  7. 2  success      {'name': 'Anton Shkaplerov', 'craft': 'ISS'}      10
  8. 3  success  {'name': 'Zhai Zhigang', 'craft': 'Shenzhou 13'}      10
  9. 4  success   {'name': 'Wang Yaping', 'craft': 'Shenzhou 13'}      10
  10. 5  success    {'name': 'Ye Guangfu', 'craft': 'Shenzhou 13'}      10
  11. 6  success            {'name': 'Raja Chari', 'craft': 'ISS'}      10
  12. 7  success         {'name': 'Tom Marshburn', 'craft': 'ISS'}      10
  13. 8  success          {'name': 'Kayla Barron', 'craft': 'ISS'}      10
  14. 9  success       {'name': 'Matthias Maurer', 'craft': 'ISS'}      10

Poniżej program wykonujący wyświetlenie pozycji satelity na mapie:

  1. import pandas as pd
  2. import plotly.express as px
  3.  
  4. URL_ISS_POS = "http://api.open-notify.org/iss-now.json"
  5.  
  6. iss_pos = pd.read_json(URL_ISS_POS)
  7.  
  8. print(iss_pos)
  9.  
  10. iss_pos['latitude'] = iss_pos.loc['latitude','iss_position']
  11. iss_pos['longitude'] = iss_pos.loc['longitude','iss_position']
  12. iss_pos.reset_index(inplace=True)
  13.  
  14. print(iss_pos)
  15.  
  16. iss_pos = iss_pos.drop(['index','message'],axis=1)
  17.  
  18. fig = px.scatter_geo(iss_pos, lat = 'latitude', lon = 'longitude')
  19. fig.show()

Powyższy skrypt pobiera dane z pozycją satelity, następnie w przeglądarce wyświetla mapę z aktualną pozycją satelity:


N2YO:


Drugi portal wymaga logowania utworzenia konta. Po tych operacjach do konta zostanie przyporządkowany tzw. apiKey. Dzięki niemu będzie można pobierać dane z serwisu. 

Pozwala on na pobranie znacznie większej ilości informacji o różnych satelitach. Dane można pobierać w kilku formach. Dokładny opis sposobu pobierania danych i informacji zawartych w pakietach można znaleźć na tej stronie https://www.n2yo.com/api/.

TLE



Aby wygenerować ten format należy pobrać dane w następujący sposób:

  1. https://api.n2yo.com/rest/v1/satellite/tle/<NORAD_ID>&apiKey=<API_KEY>

Podmieniając NORAD_ID z informacją o numerze wyszukiwanego satelity oraz wpisując api key wygenerowany podczas rejestracji otrzymamy następujące informacje: 

  1. {
  2.     "info": {
  3.         "satid":40069,
  4.         "satname":"METEOR M2",
  5.         "transactionscount":0 },
  6.         "tle":"1 40069U 14037A   21331.82919958 -.00000030  00000-0  54218-5 0  9994\r\n
  7.                2 40069  98.4475 353.6844 0005598 176.3639 183.7568 14.20692081383233"
  8. }

Dokładny opis powyższych danych można znaleźć na Wikipedii w linku powyżej.

Poniższy skrypt pobierze dane z informacjami TLE:

  1. import pandas as pd
  2.  
  3. URL_SAT_POS = "https://api.n2yo.com/rest/v1/satellite/tle/25544&apiKey=DB5DJT-UYAT8J-TV7H47-4T5O"
  4.  
  5. sat_pos = pd.read_json(URL_SAT_POS)
  6.  
  7. print(sat_pos)

Wynik operacji jest następujący:

  1. satid                      25544  1 25544U 98067A   21333.49546977  .00004890  0...
  2. satname            SPACE STATION  1 25544U 98067A   21333.49546977  .00004890  0...
  3. transactionscount              1  1 25544U 98067A   21333.49546977  .00004890  0...

Pozycja satelity:


Można pobrać dane z pozycją satelity w ciągu następnych x sekund. Wymagane jest tutaj podanie bardziej szczegółowych informacji niż w przypadku wcześniejszym.

  1. https://api.n2yo.com/rest/v1/satellite/positions/25544/52.22977/21.01178/0/5/&apiKey=<api_key>

Powyżej sposób pobrania pozycji satelity ISS w ciągu najbliższych 5 sekund. Dane z pozycją obserwatora ustawione na Warszawę. Pobrane dane wyglądają następująco:

  1. {"info":{"satname":"SPACE STATION","satid":25544,"transactionscount":3},
  2. "positions":
  3. [{
  4. "satlatitude":51.73568431,
  5. "satlongitude":-98.80227514,
  6. "sataltitude":429.44,
  7. "azimuth":323.43,
  8. "elevation":-29.25,
  9. "ra":299.81417259,
  10. "dec":2.40118541,
  11. "timestamp":1638230086,
  12. "eclipsed":false
  13. },{"satlatitude":51.73907025,"satlongitude":-98.70270951,"sataltitude":429.44,"azimuth":323.38,"elevation":-29.22,"ra":299.86938512,"dec":2.4044969,"timestamp":1638230087,"eclipsed":false},{"satlatitude":51.74236474,"satlongitude":-98.60312859,"sataltitude":429.44,"azimuth":323.32,"elevation":-29.2,"ra":299.92463653,"dec":2.40775649,"timestamp":1638230088,"eclipsed":false},{"satlatitude":51.74556775,"satlongitude":-98.50353279,"sataltitude":429.44,"azimuth":323.27,"elevation":-29.18,"ra":299.97992683,"dec":2.41096408,"timestamp":1638230089,"eclipsed":false},{"satlatitude":51.74867926,"satlongitude":-98.40392254,"sataltitude":429.44,"azimuth":323.22,"elevation":-29.16,"ra":300.03525602,"dec":2.41411958,"timestamp":1638230090,"eclipsed":false}]}

W tym przypadku pobranie danych będzie nieco trudniejsze. Wykorzystanie scryptu z przykładu dla danych TLE spowoduje wygenerowanie błędu:

  1. ValueError: Mixing dicts with non-Series may lead to ambiguous ordering.

Najprostszym sposobem na pobranie tych danych jest skorzystanie z biblioteki requests:

  1. import requests
  2.  
  3. response = requests.get('https://api.n2yo.com/rest/v1/satellite/positions/25544/52.22977/21.01178/0/1/&apiKey=<api_key>')
  4. print('Response text:\n', response.text[: 500])
  5. data = response.json()
  6. print(data)

Pobrane dane z serwera wyglądają następująco:

  1. {'info': {'satname': 'SPACE STATION', 'satid': 25544, 'transactionscount': 7}, 'positions': [{'satlatitude': -18.10606349, 'satlongitude': 149.64040855, 'sataltitude': 424.47, 'azimuth': 69.14, 'elevation': -62.75, 'ra': 241.49872209, 'dec': -37.05163099, 'timestamp': 1638317573, 'eclipsed': False}]}

Wyświetlenie pozycji satelity na mapie może wyglądać w następujący sposób:

  1. import requests
  2. import json
  3. import plotly.express as px
  4. import pandas as pd
  5.  
  6. response = requests.get('https://api.n2yo.com/rest/v1/satellite/positions/25544/52.22977/21.01178/0/1/&apiKey=<api_key>')
  7. print('Response text:\n', response.text[: 500])
  8. data = response.json()
  9. print(data)
  10.  
  11. resp_dist = json.loads(response.text[: 500])
  12.  
  13. print("--------------------------------")
  14. satlat = resp_dist['positions'][0]['satlatitude']
  15. satlong = resp_dist['positions'][0]['satlongitude']
  16. print(satlat)
  17. print(satlong)
  18. print("--------------------------------")
  19.  
  20. df = pd.DataFrame(dict(lat=[satlat], lon=[satlong]))
  21. fig = px.scatter_geo(df, lat="lat", lon="lon", height=600)
  22. fig.update_traces(marker=dict(size=30))
  23. fig.show()

Wynik operacji wygląda następująco:


W podobny sposób można pobrać znacznie więcej danych np. 100, czyli położenie przez najbliższe 100 sekund, co pozwoli  na wyświetlenie pozycji satelity w przyszłości.

Portal NY2O pozwala na pobranie danych z znacznie większej ilości satelit niż tylko ISS, jak w przypadku wcześniejszego serwisu. Niektóre z nich można znaleźć pod tym linkiem, gdzie znajdują się najczęściej podglądane satelity. Po wejściu w dane dla konkretnego obiektu, pobieranie danych odbywa się przez podanie do serwisu danych NORAD ID.


Dodatkowo można pobrać informację z danymi Visual Passes oraz Radio Passes. Pierwszy z nich wysyłana pozycję satelity  kiedy będzie ona widoczna z całej lub części ziemi podczas. Drugi z nich wyświetla pozycję satelity, tak aby była widoczna z miejsca w którym znajduje się obserwator. Głównie dla uzyskania komunikacji radiowej.