... | ... | @@ -53,27 +53,29 @@ Return to the main menu and go to the flight menu (Icon labeled with the number |
|
|
And you are ready to go.
|
|
|
|
|
|
# Developer Telemetry Connection
|
|
|
### Obtain token
|
|
|
To obtain the token necessary for sending telemetry, you need to make a GET request to this URL dev-dsdp-acquisition.airus-suite.com/api/token?username=USERNAME&password=PASSWORD .
|
|
|
For more information on the authentication process and how to obtein the token in general, you can consult here: [Get token in airus](get_token_in_airus)
|
|
|
### Send Surveillance Data
|
|
|
|
|
|
### Sending Telemetry
|
|
|
To send Target Reports to this server you must connect via WS to the following endpoint: `wss://dev-dsdp-acquisition.airus-suite.com/ws/dsdp/$station-id/$token`.
|
|
|
The token and station-id parameters included in the URL are explained below.
|
|
|
To send Target Reports to AIRUS server you must connect via WS to the following endpoint: `wss://dev-dsdp-acquisition.airus-suite.com/ws/dsdp/$station-id/$token`.
|
|
|
Note that the AIRUS environment to which the websocket is going to be send is included in the endpoint (in this case dev, could be changed to pre).
|
|
|
To open this websocket connection two parameters are needed:
|
|
|
|
|
|
* `$token` : This token needs to be obtained by sending an API-REST GET request to the following endpoint: `https://dev-fcm.airus-suite.com/api/token?username=external-user&password=airus23`
|
|
|
* `$station-id`: This is the surveillance station identifier, use unique serial numbers. For instance: pildo.
|
|
|
|
|
|
* Only one connection per station is accepted at the same time
|
|
|
* The connection will close if the client sends target report for the same drone too fast
|
|
|
* The connection will close if the Target Report is malformed X times
|
|
|
* If the TargetReport is malformed. The ws will send a message notifying what's wrong
|
|
|
Take into account:
|
|
|
|
|
|
#### Custom close codes
|
|
|
- **Multiple connections**
|
|
|
Only one connection per station-id is accepted at the same time, the websocket will send a close with the code **3001** if the client's stations is already in use by other connection
|
|
|
|
|
|
* **3001 - DUPLICATED_STATION**: The websocket will send a close with the code 3001 if the client's stations is already in use by other connection
|
|
|
* **3002 - NO_VIGILANT_ID**: The ws will send a close with the code 3002 if no vigilant could not be retrieved from the DSDP API.
|
|
|
- **Refresh frequency**
|
|
|
The connection will close if the client sends target report for the same drone at more than 1Hz
|
|
|
|
|
|
### Target Report
|
|
|
An example of target report would be:
|
|
|
- **Target report wrong format**
|
|
|
The connection will close if the Target Report is sent malformed X times
|
|
|
|
|
|
Tip: If the TargetReport is malformed. The websocket will send a message notifying what's wrong
|
|
|
|
|
|
Each time there's an update in the aircraft position a new target report will be sent using the already opened websocket, an example would be:
|
|
|
|
|
|
```json
|
|
|
{
|
... | ... | @@ -165,26 +167,297 @@ An example of target report would be: |
|
|
}
|
|
|
},
|
|
|
"association":{
|
|
|
|
|
|
|
|
|
},
|
|
|
"post_to_simulator":false,
|
|
|
"timestamp":1675954177
|
|
|
}
|
|
|
```
|
|
|
**timestamp** and **toa** must contain the unix time in the moment of sending the targert report, **drone_serial** must have a value. The **sending frequency** shouldn't be higher than **1 Hz**.
|
|
|
|
|
|
### Example Code
|
|
|
Here you can find a python snippet showing how to send one target report using websocket to Airus:
|
|
|
`timestamp` and `toa` must contain the unix time in the moment of sending the target report, `drone_serial` must have a value. The **sending frequency** shouldn't be higher than **1 Hz**.
|
|
|
Note that here, the field `alarm` contains the possible alarms that the drone can be having: LoL (Loss of Link), LoE (Loss of Engine), LoS (Loss of Separation). Moreover, the different aircraft types that are supported are the following: 'MANNED_HELICOPTER', 'MANNED_FIXEDWING', 'MULTIROTOR', 'AEROPLANE', 'HELICOPTER', 'HYBRID', 'LIGHTER_THAN_AIR', 'DEFAULT'.
|
|
|
|
|
|
### Contingency Trajectory
|
|
|
When wanting to send a contingency trajectory this needs to be added inside the `data_items` field in the target report. Moreover, in order to activate this contingency trajectory, an alarm needs to be sent at the same time.
|
|
|
```json
|
|
|
{
|
|
|
"surveillance_station":{
|
|
|
"period":1,
|
|
|
"identification":{
|
|
|
"uuid":"GCS_DEFAULT"
|
|
|
},
|
|
|
"type":"TELEMETRY"
|
|
|
},
|
|
|
"data_items":{
|
|
|
"identification":{
|
|
|
"reported_identification_data":{
|
|
|
"reported_uuids":{
|
|
|
"drone_serial":"M600SCR"
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"supplemental":{
|
|
|
"aircraft":{
|
|
|
"aircraft_type":{
|
|
|
"type":"MULTIROTOR"
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"alarm":[
|
|
|
"LoL",
|
|
|
"LoE"
|
|
|
],
|
|
|
"take_off_location":{
|
|
|
"latitude":43.7053348814,
|
|
|
"longitude":-7.4636306758
|
|
|
},
|
|
|
"kinematic":{
|
|
|
"position":{
|
|
|
"geodetic":{
|
|
|
"measured":true,
|
|
|
"toa":1675954177,
|
|
|
"position":{
|
|
|
"latitude":43.72263488140057,
|
|
|
"longitude":-7.4636306758
|
|
|
},
|
|
|
"relayed":true
|
|
|
},
|
|
|
"altitude_atp":10,
|
|
|
"enu":{
|
|
|
"measured":false,
|
|
|
"toa":0,
|
|
|
"position":{
|
|
|
"east":0,
|
|
|
"north":0,
|
|
|
"up":0
|
|
|
},
|
|
|
"error":{
|
|
|
"horizontal":{
|
|
|
"mean":{
|
|
|
"east":0,
|
|
|
"north":0
|
|
|
},
|
|
|
"covariance":{
|
|
|
"e_n":0,
|
|
|
"e_e":1,
|
|
|
"n_n":1
|
|
|
},
|
|
|
"outliers":{
|
|
|
"probability":0,
|
|
|
"scale":10
|
|
|
}
|
|
|
},
|
|
|
"vertical":{
|
|
|
"mean":{
|
|
|
"up":0
|
|
|
},
|
|
|
"covariance":{
|
|
|
"u_u":1
|
|
|
},
|
|
|
"outliers":{
|
|
|
"probability":0,
|
|
|
"scale":10
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"relayed":false
|
|
|
}
|
|
|
},
|
|
|
"attitude":{
|
|
|
"yaw":0
|
|
|
}
|
|
|
},
|
|
|
"contingency_trajectory": {
|
|
|
"type": "FeatureCollection",
|
|
|
"features": [
|
|
|
{
|
|
|
"type": "Feature",
|
|
|
"geometry": {
|
|
|
"coordinates": [
|
|
|
[
|
|
|
-7.4368004867396,
|
|
|
43.71497492967933,
|
|
|
5
|
|
|
],
|
|
|
[
|
|
|
-7.386107200188093,
|
|
|
43.70183475081768,
|
|
|
10
|
|
|
],
|
|
|
[
|
|
|
-7.366521157656962,
|
|
|
43.70081672942018,
|
|
|
10
|
|
|
]
|
|
|
],
|
|
|
"type": "LineString"
|
|
|
},
|
|
|
"properties": {
|
|
|
"upper_limit": 20,
|
|
|
"lower_limit": 0,
|
|
|
"reference": "AGL",
|
|
|
"effective_datetime": {
|
|
|
"start_datetime": "2023-11-08T16:20:05.601Z",
|
|
|
"end_datetime": "2023-11-08T16:30:05.601Z"
|
|
|
},
|
|
|
"offset": {
|
|
|
"start_offset": "00:00:00",
|
|
|
"end_offset": "00:10:00",
|
|
|
"segmented_offset": null
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
},
|
|
|
"association":{
|
|
|
|
|
|
},
|
|
|
"post_to_simulator":false,
|
|
|
"timestamp":1675954177,
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Python example
|
|
|
Here you can find a python snippet showing how to send one target report using websocket to AIRUS:
|
|
|
```python
|
|
|
from websocket import create_connection, _exceptions
|
|
|
import websocket
|
|
|
import json
|
|
|
import time
|
|
|
import threading
|
|
|
import requests
|
|
|
|
|
|
def on_close(ws, close_status_code, close_msg):
|
|
|
if close_status_code == websocket.WebSocketConnectionClosedException.code:
|
|
|
print(f"Connection closed unexpectedly: {close_msg}")
|
|
|
else:
|
|
|
print("Closed connection")
|
|
|
|
|
|
token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ0dzlVNjhzLWxiVk1xRmtoUnUtblp4UzY2bExhYU1pczR3NDRTWF9tYVUwIn0.eyJleHAiOjE2NDUwMjIzMDksImlhdCI6MTY0NTAyMTEwOSwianRpIjoiM2I4N2M1NGEtYjQzZC00NzQ1LTlhMzAtMzlmZTYyMTUzMmZlIiwiaXNzIjoiaHR0cHM6Ly9kZXYtYXV0aC5haXJ1cy1zdWl0ZS5jb20vYXV0aC9yZWFsbXMvYWlydXMiLCJhdWQiOlsiYWlydXMtY2JtcyIsInJlYWxtLW1hbmFnZW1lbnQiLCJhaXJ1cy11c2ltIiwidGVzdC1hcHAiLCJhaXJ1cy11cmVnIiwiYWNjb3VudCIsImFpcnVzLWZwbSJdLCJzdWIiOiJhNmM3NTA0NS0wZWJjLTRiZDAtYWNhMC04NTM4MjhlOGNhMWEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhaXJ1cy1kc2RwIiwic2Vzc2lvbl9zdGF0ZSI6Ijc3ZWU1ODk3LWVkYjctNDBkZS05MTU3LTg4YTVhMDdmMzRmYyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJhZG1pbiIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWlydXMtY2JtcyI6eyJyb2xlcyI6WyJhZG1pbmlzdHJhdG9yIl19LCJyZWFsbS1tYW5hZ2VtZW50Ijp7InJvbGVzIjpbInZpZXctZXZlbnRzIiwiY3JlYXRlLWNsaWVudCIsIm1hbmFnZS11c2VycyIsInF1ZXJ5LXJlYWxtcyIsInZpZXctdXNlcnMiLCJ2aWV3LWNsaWVudHMiLCJtYW5hZ2UtYXV0aG9yaXphdGlvbiIsInZpZXctYXV0aG9yaXphdGlvbiIsInF1ZXJ5LWNsaWVudHMiLCJtYW5hZ2UtY2xpZW50cyIsInF1ZXJ5LWdyb3VwcyIsInF1ZXJ5LXVzZXJzIl19LCJhaXJ1cy11c2ltIjp7InJvbGVzIjpbInRlY2huaWNpYW4iXX0sInRlc3QtYXBwIjp7InJvbGVzIjpbImRpcmVjdG9yIl19LCJhaXJ1cy11cmVnIjp7InJvbGVzIjpbIm9wZXJhdG9yX3VyZWciLCJyZWFkX3VyZWciLCJwaWxvdF91cmVnIl19LCJhaXJ1cy1kc2RwIjp7InJvbGVzIjpbImFkbWluX2RzZHAiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfSwiYWlydXMtZnBtIjp7InJvbGVzIjpbImFkbWluX2ZwbSIsInVzZXJfZnBtIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiSnVhbiDDgWx2YXJleiIsInByZWZlcnJlZF91c2VybmFtZSI6ImphbHZhcmZlIiwiZ2l2ZW5fbmFtZSI6Ikp1YW4iLCJmYW1pbHlfbmFtZSI6IsOBbHZhcmV6In0.j_QAcvX-2ArwX5EgREfsKqCbGUTzKU1vQ8zkZVF2UKwRhe19z73CP5IWw7c2_HazK9v_iRXQnuL6XEtdNHyZNRFi239oWdQ5fniwj-jodGu_yVK7M6PDCtPf6nqPmUrDm2h3rXr-qwHQmaqx237E3xRJ8RLvcMVv6c5D9CYheZpDtXe8AEMhrSGZMieByj5aUq7xo1JV8uRRxVJ1sGlXqBdhKeiiUhvD43QKWobaGFgGRLsYIXUR1da1zg3N413lcweJbM1z_ahDL9-kkbGDXMwzb-0NcRrAFf7hhtgjZ5qvPPmV1UdfakiGaG4ousfqKH6tAi3v0XJW5vhG33m8CA"
|
|
|
user = enaire
|
|
|
host = "dev-dsdp.airus-suite.com"
|
|
|
def on_error(ws, error):
|
|
|
print(f"Error: {error}")
|
|
|
|
|
|
def on_message(ws, message):
|
|
|
print(f"Received message: {message}")
|
|
|
|
|
|
token = requests.get('https://dev-fcm.airus-suite.com/api/token?username=external-user&password=airus23', timeout=3.05)
|
|
|
host = "dev-dsdp-acquisition.airus-suite.com"
|
|
|
surveillance_id = "08f73584-bbe7-48e8-88ee-56519ff040c7"
|
|
|
url = f"wss://{host}/ws/dsdp/{surveillance_id}/{token}"
|
|
|
ws = create_connection(url)
|
|
|
target_report = json.dumps({'surveillance_station': {'identification': {'uuid': '08f73584-bbe7-48e8-88ee-56519ff040c7'}, 'type': 'MS_RADAR', 'period': 3.3}, 'timestamp': 30, 'association': {'track_uuid': '8f0002a9-d256-47f4-92ed-56e0ac149ae0'}, 'data_items': {'identification': {'reported_identification_data': {'reported_uuids': {'drone_serial': 'EA61723123Sergio', 'utm_transponder': '4526d17d-3d36-4d3e-a048-3371b7e256c4', 'telemetry': '926f3090-156d-4218-81e6-e5b1fa3c7fa5', 'pilot_uuid': 'abcde_sim', 'operator_uuid': 'abcde_sim'}}}, 'supplemental': {'aircraft': {'aircraft_type': {'type': 'MULTIROTOR'}}}, 'take_off_location': {'longitude': -4.010009765624999, 'latitude': 41.15797827873605, 'altitude': 2.317273050917592}, 'kinematic': {'position': {'geodetic': {'toa': 30, 'measured': True, 'relayed': True, 'position': {'longitude': -4.010009765624999, 'latitude': 41.15797827873605, 'altitude': -5.797273617990068}}, 'altitude_amsl': 1, 'altitude_agl': 1, 'enu': {'toa': 1, 'measured': False, 'relayed': False, 'position': {'east': 0, 'north': 0, 'up': 0}, 'error': {'horizontal': {'mean': {'east': 0, 'north': 0}, 'covariance': {'e_e': 1, 'n_n': 1, 'e_n': 0}, 'outliers': {}}, 'vertical': {'mean': {'up': 0}, 'covariance': {'u_u': 1}, 'outliers': {}}}}}, 'velocity': {'ned': {'vel_n': 1, 'vel_e': 2, 'vel_d': 3}}, 'attitude': {'yaw': 4}}}, 'vigilant_id': '8b0855b9-196c-4bc4-b949-8668742efb07'})
|
|
|
ws.send(target_report)
|
|
|
|
|
|
websocket.enableTrace(True) # Active debug traces
|
|
|
|
|
|
ws = websocket.WebSocketApp(url,
|
|
|
on_message=on_message,
|
|
|
on_error=on_error,
|
|
|
on_close=on_close)
|
|
|
|
|
|
# Start execution in a thread
|
|
|
thread = threading.Thread(target=ws.run_forever)
|
|
|
thread.start()
|
|
|
|
|
|
tr = {
|
|
|
"surveillance_station":{
|
|
|
"period":1,
|
|
|
"identification":{
|
|
|
"uuid":"GCS_DEFAULT"
|
|
|
},
|
|
|
"type":"TELEMETRY"
|
|
|
},
|
|
|
"data_items":{
|
|
|
"identification":{
|
|
|
"reported_identification_data":{
|
|
|
"reported_uuids":{
|
|
|
"drone_serial":"M600SCR"
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"supplemental":{
|
|
|
"aircraft":{
|
|
|
"aircraft_type":{
|
|
|
"type":"MULTIROTOR"
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"alarm":[
|
|
|
"LoL",
|
|
|
"LoE"
|
|
|
],
|
|
|
"take_off_location":{
|
|
|
"latitude":43.7053348814,
|
|
|
"longitude":-7.4636306758
|
|
|
},
|
|
|
"kinematic":{
|
|
|
"position":{
|
|
|
"geodetic":{
|
|
|
"measured":True,
|
|
|
"toa":1675954177,
|
|
|
"position":{
|
|
|
"latitude":43.72263488140057,
|
|
|
"longitude":-7.4636306758
|
|
|
},
|
|
|
"relayed":True
|
|
|
},
|
|
|
"altitude_atp":10,
|
|
|
"enu":{
|
|
|
"measured":False,
|
|
|
"toa":0,
|
|
|
"position":{
|
|
|
"east":0,
|
|
|
"north":0,
|
|
|
"up":0
|
|
|
},
|
|
|
"error":{
|
|
|
"horizontal":{
|
|
|
"mean":{
|
|
|
"east":0,
|
|
|
"north":0
|
|
|
},
|
|
|
"covariance":{
|
|
|
"e_n":0,
|
|
|
"e_e":1,
|
|
|
"n_n":1
|
|
|
},
|
|
|
"outliers":{
|
|
|
"probability":0,
|
|
|
"scale":10
|
|
|
}
|
|
|
},
|
|
|
"vertical":{
|
|
|
"mean":{
|
|
|
"up":0
|
|
|
},
|
|
|
"covariance":{
|
|
|
"u_u":1
|
|
|
},
|
|
|
"outliers":{
|
|
|
"probability":0,
|
|
|
"scale":10
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"relayed":False
|
|
|
}
|
|
|
},
|
|
|
"attitude":{
|
|
|
"yaw":0
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
"association":{
|
|
|
|
|
|
},
|
|
|
"post_to_simulator":False,
|
|
|
"timestamp":1675954177
|
|
|
}
|
|
|
|
|
|
# Loop to send JSON target report every second
|
|
|
while True:
|
|
|
tr.update({"timestamp":{"position":{"geodetic":{"toa":{int(time.time())}}}}})
|
|
|
tr.update({"timestamp":int(time.time())})
|
|
|
if ws.sock is not None and ws.sock.connected:
|
|
|
print("envio")
|
|
|
target_report = json.dumps(tr)
|
|
|
ws.send(target_report)
|
|
|
time.sleep(1)
|
|
|
|
|
|
``` |