isar 1.20.2__py3-none-any.whl → 1.34.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- isar/apis/api.py +135 -86
- isar/apis/models/__init__.py +0 -1
- isar/apis/models/models.py +21 -11
- isar/apis/models/start_mission_definition.py +115 -170
- isar/apis/robot_control/robot_controller.py +41 -0
- isar/apis/schedule/scheduling_controller.py +123 -187
- isar/apis/security/authentication.py +5 -5
- isar/config/certs/ca-cert.pem +33 -31
- isar/config/keyvault/keyvault_service.py +4 -2
- isar/config/log.py +45 -40
- isar/config/logging.conf +16 -31
- isar/config/open_telemetry.py +102 -0
- isar/config/settings.py +74 -117
- isar/eventhandlers/eventhandler.py +123 -0
- isar/models/events.py +184 -0
- isar/models/status.py +22 -0
- isar/modules.py +117 -200
- isar/robot/robot.py +383 -0
- isar/robot/robot_battery.py +60 -0
- isar/robot/robot_monitor_mission.py +357 -0
- isar/robot/robot_pause_mission.py +74 -0
- isar/robot/robot_resume_mission.py +67 -0
- isar/robot/robot_start_mission.py +66 -0
- isar/robot/robot_status.py +61 -0
- isar/robot/robot_stop_mission.py +68 -0
- isar/robot/robot_upload_inspection.py +75 -0
- isar/script.py +58 -41
- isar/services/service_connections/mqtt/mqtt_client.py +47 -11
- isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +5 -2
- isar/services/service_connections/mqtt/robot_info_publisher.py +3 -3
- isar/services/service_connections/persistent_memory.py +69 -0
- isar/services/utilities/mqtt_utilities.py +93 -0
- isar/services/utilities/robot_utilities.py +20 -0
- isar/services/utilities/scheduling_utilities.py +386 -100
- isar/state_machine/state_machine.py +242 -539
- isar/state_machine/states/__init__.py +0 -8
- isar/state_machine/states/await_next_mission.py +114 -0
- isar/state_machine/states/blocked_protective_stop.py +60 -0
- isar/state_machine/states/going_to_lockdown.py +95 -0
- isar/state_machine/states/going_to_recharging.py +92 -0
- isar/state_machine/states/home.py +115 -0
- isar/state_machine/states/intervention_needed.py +77 -0
- isar/state_machine/states/lockdown.py +38 -0
- isar/state_machine/states/maintenance.py +43 -0
- isar/state_machine/states/monitor.py +137 -247
- isar/state_machine/states/offline.py +51 -53
- isar/state_machine/states/paused.py +92 -23
- isar/state_machine/states/pausing.py +48 -0
- isar/state_machine/states/pausing_return_home.py +48 -0
- isar/state_machine/states/recharging.py +80 -0
- isar/state_machine/states/resuming.py +57 -0
- isar/state_machine/states/resuming_return_home.py +64 -0
- isar/state_machine/states/return_home_paused.py +109 -0
- isar/state_machine/states/returning_home.py +217 -0
- isar/state_machine/states/stopping.py +69 -0
- isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
- isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
- isar/state_machine/states/stopping_go_to_recharge.py +51 -0
- isar/state_machine/states/stopping_paused_mission.py +36 -0
- isar/state_machine/states/stopping_paused_return_home.py +59 -0
- isar/state_machine/states/stopping_return_home.py +59 -0
- isar/state_machine/states/unknown_status.py +74 -0
- isar/state_machine/states_enum.py +23 -5
- isar/state_machine/transitions/mission.py +225 -0
- isar/state_machine/transitions/return_home.py +108 -0
- isar/state_machine/transitions/robot_status.py +87 -0
- isar/state_machine/utils/common_event_handlers.py +138 -0
- isar/storage/blob_storage.py +70 -52
- isar/storage/local_storage.py +25 -12
- isar/storage/storage_interface.py +28 -7
- isar/storage/uploader.py +174 -55
- isar/storage/utilities.py +32 -29
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/METADATA +119 -123
- isar-1.34.13.dist-info/RECORD +120 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/WHEEL +1 -1
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/entry_points.txt +1 -0
- robot_interface/models/exceptions/robot_exceptions.py +91 -41
- robot_interface/models/inspection/__init__.py +0 -13
- robot_interface/models/inspection/inspection.py +42 -33
- robot_interface/models/mission/mission.py +14 -15
- robot_interface/models/mission/status.py +20 -26
- robot_interface/models/mission/task.py +154 -121
- robot_interface/models/robots/battery_state.py +6 -0
- robot_interface/models/robots/media.py +13 -0
- robot_interface/models/robots/robot_model.py +7 -7
- robot_interface/robot_interface.py +119 -84
- robot_interface/telemetry/mqtt_client.py +74 -12
- robot_interface/telemetry/payloads.py +91 -13
- robot_interface/utilities/json_service.py +7 -1
- isar/config/configuration_error.py +0 -2
- isar/config/keyvault/keyvault_error.py +0 -2
- isar/config/predefined_mission_definition/__init__.py +0 -0
- isar/config/predefined_mission_definition/default_exr.json +0 -51
- isar/config/predefined_mission_definition/default_mission.json +0 -91
- isar/config/predefined_mission_definition/default_turtlebot.json +0 -124
- isar/config/predefined_missions/__init__.py +0 -0
- isar/config/predefined_missions/default.json +0 -92
- isar/config/predefined_missions/default_turtlebot.json +0 -110
- isar/config/predefined_poses/__init__.py +0 -0
- isar/config/predefined_poses/predefined_poses.py +0 -616
- isar/config/settings.env +0 -25
- isar/mission_planner/__init__.py +0 -0
- isar/mission_planner/local_planner.py +0 -82
- isar/mission_planner/mission_planner_interface.py +0 -26
- isar/mission_planner/sequential_task_selector.py +0 -23
- isar/mission_planner/task_selector_interface.py +0 -31
- isar/models/communication/__init__.py +0 -0
- isar/models/communication/message.py +0 -12
- isar/models/communication/queues/__init__.py +0 -4
- isar/models/communication/queues/queue_io.py +0 -12
- isar/models/communication/queues/queue_timeout_error.py +0 -2
- isar/models/communication/queues/queues.py +0 -19
- isar/models/communication/queues/status_queue.py +0 -20
- isar/models/mission_metadata/__init__.py +0 -0
- isar/services/auth/__init__.py +0 -0
- isar/services/auth/azure_credentials.py +0 -14
- isar/services/readers/__init__.py +0 -0
- isar/services/readers/base_reader.py +0 -37
- isar/services/service_connections/request_handler.py +0 -153
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/services/utilities/threaded_request.py +0 -68
- isar/state_machine/states/idle.py +0 -85
- isar/state_machine/states/initialize.py +0 -71
- isar/state_machine/states/initiate.py +0 -142
- isar/state_machine/states/off.py +0 -18
- isar/state_machine/states/stop.py +0 -95
- isar/storage/slimm_storage.py +0 -191
- isar-1.20.2.dist-info/RECORD +0 -116
- robot_interface/models/initialize/__init__.py +0 -1
- robot_interface/models/initialize/initialize_params.py +0 -9
- robot_interface/models/mission/step.py +0 -234
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info/licenses}/LICENSE +0 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/top_level.txt +0 -0
isar/apis/api.py
CHANGED
|
@@ -1,65 +1,70 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
3
|
+
import time
|
|
4
|
+
from datetime import datetime, timezone
|
|
2
5
|
from http import HTTPStatus
|
|
3
6
|
from logging import Logger
|
|
4
7
|
from typing import List, Union
|
|
5
8
|
|
|
6
9
|
import click
|
|
7
10
|
import uvicorn
|
|
8
|
-
from fastapi import FastAPI,
|
|
11
|
+
from fastapi import FastAPI, Security
|
|
9
12
|
from fastapi.middleware.cors import CORSMiddleware
|
|
10
13
|
from fastapi.routing import APIRouter
|
|
11
|
-
from injector import inject
|
|
12
|
-
from opencensus.ext.azure.trace_exporter import AzureExporter
|
|
13
|
-
from opencensus.trace.attributes_helper import COMMON_ATTRIBUTES
|
|
14
|
-
from opencensus.trace.samplers import ProbabilitySampler
|
|
15
|
-
from opencensus.trace.span import SpanKind
|
|
16
|
-
from opencensus.trace.tracer import Tracer
|
|
17
14
|
from pydantic import AnyHttpUrl
|
|
18
15
|
|
|
19
16
|
from isar.apis.models.models import ControlMissionResponse, StartMissionResponse
|
|
17
|
+
from isar.apis.robot_control.robot_controller import RobotController
|
|
20
18
|
from isar.apis.schedule.scheduling_controller import SchedulingController
|
|
21
19
|
from isar.apis.security.authentication import Authenticator
|
|
22
|
-
from isar.config.configuration_error import ConfigurationError
|
|
23
|
-
from isar.config.keyvault.keyvault_error import KeyvaultError
|
|
24
20
|
from isar.config.keyvault.keyvault_service import Keyvault
|
|
25
21
|
from isar.config.settings import settings
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
from robot_interface.telemetry.mqtt_client import MqttClientInterface
|
|
23
|
+
from robot_interface.telemetry.payloads import StartUpMessagePayload
|
|
24
|
+
from robot_interface.utilities.json_service import EnhancedJSONEncoder
|
|
29
25
|
|
|
30
26
|
|
|
31
27
|
class API:
|
|
32
|
-
@inject
|
|
33
28
|
def __init__(
|
|
34
29
|
self,
|
|
35
30
|
authenticator: Authenticator,
|
|
36
31
|
scheduling_controller: SchedulingController,
|
|
37
|
-
|
|
32
|
+
robot_controller: RobotController,
|
|
33
|
+
keyvault: Keyvault,
|
|
34
|
+
mqtt_publisher: MqttClientInterface,
|
|
38
35
|
port: int = settings.API_PORT,
|
|
39
|
-
azure_ai_logging_enabled: bool = settings.LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED,
|
|
40
36
|
) -> None:
|
|
41
37
|
self.authenticator: Authenticator = authenticator
|
|
42
38
|
self.scheduling_controller: SchedulingController = scheduling_controller
|
|
43
|
-
self.
|
|
39
|
+
self.robot_controller: RobotController = robot_controller
|
|
40
|
+
self.keyvault: Keyvault = keyvault
|
|
44
41
|
self.host: str = "0.0.0.0" # Locking uvicorn to use 0.0.0.0
|
|
45
42
|
self.port: int = port
|
|
46
|
-
self.
|
|
43
|
+
self.mqtt_publisher: MqttClientInterface = mqtt_publisher
|
|
47
44
|
|
|
48
45
|
self.logger: Logger = logging.getLogger("api")
|
|
49
46
|
|
|
50
47
|
self.app: FastAPI = self._create_app()
|
|
48
|
+
self.server = self._setup_server()
|
|
51
49
|
|
|
52
50
|
def get_app(self) -> FastAPI:
|
|
53
51
|
return self.app
|
|
54
52
|
|
|
55
|
-
def
|
|
56
|
-
uvicorn.
|
|
53
|
+
def _setup_server(self) -> uvicorn.Server:
|
|
54
|
+
config = uvicorn.Config(
|
|
57
55
|
self.app,
|
|
58
56
|
port=self.port,
|
|
59
57
|
host=self.host,
|
|
60
58
|
reload=False,
|
|
61
59
|
log_config=None,
|
|
62
60
|
)
|
|
61
|
+
return uvicorn.Server(config)
|
|
62
|
+
|
|
63
|
+
def wait_for_api_server_ready(self) -> None:
|
|
64
|
+
while not self.server.started:
|
|
65
|
+
time.sleep(0.01)
|
|
66
|
+
self.logger.info("Uvicorn server has been started")
|
|
67
|
+
self._publish_startup_message()
|
|
63
68
|
|
|
64
69
|
def _create_app(self) -> FastAPI:
|
|
65
70
|
tags_metadata = [
|
|
@@ -70,7 +75,10 @@ class API:
|
|
|
70
75
|
]
|
|
71
76
|
app = FastAPI(
|
|
72
77
|
openapi_tags=tags_metadata,
|
|
73
|
-
on_startup=[
|
|
78
|
+
on_startup=[
|
|
79
|
+
self.authenticator.load_config,
|
|
80
|
+
self._log_startup_message,
|
|
81
|
+
],
|
|
74
82
|
swagger_ui_oauth2_redirect_url="/oauth2-redirect",
|
|
75
83
|
swagger_ui_init_oauth={
|
|
76
84
|
"usePkceWithAuthorizationCodeGrant": True,
|
|
@@ -91,13 +99,12 @@ class API:
|
|
|
91
99
|
allow_headers=["*"],
|
|
92
100
|
)
|
|
93
101
|
|
|
94
|
-
if self.azure_ai_logging_enabled:
|
|
95
|
-
self._add_request_logging_middleware(app)
|
|
96
|
-
|
|
97
102
|
app.include_router(router=self._create_scheduler_router())
|
|
98
103
|
|
|
99
104
|
app.include_router(router=self._create_info_router())
|
|
100
105
|
|
|
106
|
+
app.include_router(router=self._create_media_control_router())
|
|
107
|
+
|
|
101
108
|
return app
|
|
102
109
|
|
|
103
110
|
def _create_scheduler_router(self) -> APIRouter:
|
|
@@ -106,37 +113,39 @@ class API:
|
|
|
106
113
|
authentication_dependency: Security = Security(self.authenticator.get_scheme())
|
|
107
114
|
|
|
108
115
|
router.add_api_route(
|
|
109
|
-
path="/schedule/start-mission
|
|
110
|
-
endpoint=self.scheduling_controller.
|
|
116
|
+
path="/schedule/start-mission",
|
|
117
|
+
endpoint=self.scheduling_controller.start_mission,
|
|
111
118
|
methods=["POST"],
|
|
112
|
-
deprecated=True,
|
|
113
119
|
dependencies=[authentication_dependency],
|
|
114
|
-
summary="Start
|
|
120
|
+
summary="Start the mission provided in JSON format",
|
|
115
121
|
responses={
|
|
116
122
|
HTTPStatus.OK.value: {
|
|
117
123
|
"description": "Mission succesfully started",
|
|
118
124
|
"model": StartMissionResponse,
|
|
119
125
|
},
|
|
120
|
-
HTTPStatus.
|
|
121
|
-
"description": "
|
|
126
|
+
HTTPStatus.UNPROCESSABLE_ENTITY.value: {
|
|
127
|
+
"description": "Invalid body - The JSON is incorrect",
|
|
122
128
|
},
|
|
123
129
|
HTTPStatus.CONFLICT.value: {
|
|
124
130
|
"description": "Conflict - Invalid command in the current state",
|
|
125
131
|
},
|
|
132
|
+
HTTPStatus.BAD_REQUEST.value: {
|
|
133
|
+
"description": "Bad request - Robot does not have the capabilities to perform the mission",
|
|
134
|
+
},
|
|
126
135
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
127
136
|
"description": "Internal Server Error - Current state of state machine unknown",
|
|
128
137
|
},
|
|
129
138
|
},
|
|
130
139
|
)
|
|
131
140
|
router.add_api_route(
|
|
132
|
-
path="/schedule/
|
|
133
|
-
endpoint=self.scheduling_controller.
|
|
141
|
+
path="/schedule/return-home",
|
|
142
|
+
endpoint=self.scheduling_controller.return_home,
|
|
134
143
|
methods=["POST"],
|
|
135
144
|
dependencies=[authentication_dependency],
|
|
136
|
-
summary="Start
|
|
145
|
+
summary="Start return home mission",
|
|
137
146
|
responses={
|
|
138
147
|
HTTPStatus.OK.value: {
|
|
139
|
-
"description": "
|
|
148
|
+
"description": "Return home mission succesfully started",
|
|
140
149
|
"model": StartMissionResponse,
|
|
141
150
|
},
|
|
142
151
|
HTTPStatus.UNPROCESSABLE_ENTITY.value: {
|
|
@@ -161,9 +170,15 @@ class API:
|
|
|
161
170
|
"description": "Mission succesfully stopped",
|
|
162
171
|
"model": ControlMissionResponse,
|
|
163
172
|
},
|
|
173
|
+
HTTPStatus.UNPROCESSABLE_ENTITY.value: {
|
|
174
|
+
"description": "Invalid body - The JSON is incorrect",
|
|
175
|
+
},
|
|
164
176
|
HTTPStatus.CONFLICT.value: {
|
|
165
177
|
"description": "Conflict - Invalid command in the current state",
|
|
166
178
|
},
|
|
179
|
+
HTTPStatus.BAD_REQUEST.value: {
|
|
180
|
+
"description": "Bad request - Robot does not have the capabilities to perform the mission",
|
|
181
|
+
},
|
|
167
182
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
168
183
|
"description": "Internal Server Error - Current state of state machine unknown",
|
|
169
184
|
},
|
|
@@ -208,60 +223,86 @@ class API:
|
|
|
208
223
|
},
|
|
209
224
|
)
|
|
210
225
|
router.add_api_route(
|
|
211
|
-
path="/schedule/
|
|
212
|
-
endpoint=self.scheduling_controller.
|
|
226
|
+
path="/schedule/lockdown",
|
|
227
|
+
endpoint=self.scheduling_controller.lockdown,
|
|
213
228
|
methods=["POST"],
|
|
214
229
|
dependencies=[authentication_dependency],
|
|
215
|
-
summary="
|
|
230
|
+
summary="Send the robot to dock and ensure that it stays there",
|
|
216
231
|
responses={
|
|
217
|
-
HTTPStatus.OK.value: {
|
|
218
|
-
"description": "Drive to succesfully started",
|
|
219
|
-
},
|
|
232
|
+
HTTPStatus.OK.value: {"description": "Robot going to dock"},
|
|
220
233
|
HTTPStatus.CONFLICT.value: {
|
|
221
|
-
"description": "Conflict - Invalid command in the current state"
|
|
234
|
+
"description": "Conflict - Invalid command in the current state"
|
|
222
235
|
},
|
|
223
236
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
224
|
-
"description": "Internal Server Error - Current state of state machine unknown"
|
|
237
|
+
"description": "Internal Server Error - Current state of state machine unknown"
|
|
225
238
|
},
|
|
226
239
|
},
|
|
227
240
|
)
|
|
228
241
|
router.add_api_route(
|
|
229
|
-
path="/schedule/
|
|
230
|
-
endpoint=self.scheduling_controller.
|
|
242
|
+
path="/schedule/release-lockdown",
|
|
243
|
+
endpoint=self.scheduling_controller.release_lockdown,
|
|
231
244
|
methods=["POST"],
|
|
232
245
|
dependencies=[authentication_dependency],
|
|
233
|
-
summary="
|
|
246
|
+
summary="Allow the robot to start missions again",
|
|
234
247
|
responses={
|
|
235
248
|
HTTPStatus.OK.value: {
|
|
236
|
-
"description": "
|
|
249
|
+
"description": "Robot is able to receive missions again"
|
|
237
250
|
},
|
|
238
251
|
HTTPStatus.CONFLICT.value: {
|
|
239
|
-
"description": "Conflict - Invalid command in the current state"
|
|
252
|
+
"description": "Conflict - Invalid command in the current state"
|
|
240
253
|
},
|
|
241
254
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
242
|
-
"description": "Internal Server Error - Current state of state machine unknown"
|
|
255
|
+
"description": "Internal Server Error - Current state of state machine unknown"
|
|
243
256
|
},
|
|
244
257
|
},
|
|
245
258
|
)
|
|
246
259
|
router.add_api_route(
|
|
247
|
-
path="/schedule/
|
|
248
|
-
endpoint=self.scheduling_controller.
|
|
260
|
+
path="/schedule/maintenance-mode",
|
|
261
|
+
endpoint=self.scheduling_controller.set_maintenance_mode,
|
|
249
262
|
methods=["POST"],
|
|
250
263
|
dependencies=[authentication_dependency],
|
|
251
|
-
summary="
|
|
264
|
+
summary="Place the robot in maintenance mode, where it will not run missions before begin released from maintenance mode",
|
|
252
265
|
responses={
|
|
253
266
|
HTTPStatus.OK.value: {
|
|
254
|
-
"description": "
|
|
267
|
+
"description": "Robot is in maintenance mode and cannot receive missions"
|
|
255
268
|
},
|
|
256
|
-
HTTPStatus.
|
|
257
|
-
|
|
258
|
-
"
|
|
269
|
+
HTTPStatus.CONFLICT.value: {"description": "Conflict"},
|
|
270
|
+
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
271
|
+
"description": "Internal Server Error"
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
)
|
|
275
|
+
router.add_api_route(
|
|
276
|
+
path="/schedule/release-maintenance-mode",
|
|
277
|
+
endpoint=self.scheduling_controller.release_maintenance_mode,
|
|
278
|
+
methods=["POST"],
|
|
279
|
+
dependencies=[authentication_dependency],
|
|
280
|
+
summary="Allow the robot to start missions again",
|
|
281
|
+
responses={
|
|
282
|
+
HTTPStatus.OK.value: {
|
|
283
|
+
"description": "Robot is able to receive missions again"
|
|
284
|
+
},
|
|
285
|
+
HTTPStatus.CONFLICT.value: {"description": "Conflict"},
|
|
286
|
+
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
287
|
+
"description": "Internal Server Error"
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
)
|
|
291
|
+
router.add_api_route(
|
|
292
|
+
path="/schedule/release-intervention-needed",
|
|
293
|
+
endpoint=self.scheduling_controller.release_intervention_needed,
|
|
294
|
+
methods=["POST"],
|
|
295
|
+
dependencies=[authentication_dependency],
|
|
296
|
+
summary="Release the intervention needed state",
|
|
297
|
+
responses={
|
|
298
|
+
HTTPStatus.OK.value: {
|
|
299
|
+
"description": "Robot released from intervention needed state"
|
|
259
300
|
},
|
|
260
301
|
HTTPStatus.CONFLICT.value: {
|
|
261
|
-
"description": "Conflict - Invalid command in the current state"
|
|
302
|
+
"description": "Conflict - Invalid command in the current state"
|
|
262
303
|
},
|
|
263
304
|
HTTPStatus.INTERNAL_SERVER_ERROR.value: {
|
|
264
|
-
"description": "Internal Server Error - Current state of state machine unknown"
|
|
305
|
+
"description": "Internal Server Error - Current state of state machine unknown"
|
|
265
306
|
},
|
|
266
307
|
},
|
|
267
308
|
)
|
|
@@ -275,7 +316,7 @@ class API:
|
|
|
275
316
|
|
|
276
317
|
router.add_api_route(
|
|
277
318
|
path="/info/robot-settings",
|
|
278
|
-
endpoint=self.
|
|
319
|
+
endpoint=self.robot_controller.get_info,
|
|
279
320
|
methods=["GET"],
|
|
280
321
|
dependencies=[authentication_dependency],
|
|
281
322
|
summary="Information about the robot-settings",
|
|
@@ -283,6 +324,29 @@ class API:
|
|
|
283
324
|
|
|
284
325
|
return router
|
|
285
326
|
|
|
327
|
+
def _create_media_control_router(self) -> APIRouter:
|
|
328
|
+
router: APIRouter = APIRouter(tags=["Media"])
|
|
329
|
+
|
|
330
|
+
authentication_dependency: Security = Security(self.authenticator.get_scheme())
|
|
331
|
+
|
|
332
|
+
router.add_api_route(
|
|
333
|
+
path="/media/media-stream-config",
|
|
334
|
+
endpoint=self.robot_controller.generate_media_config,
|
|
335
|
+
methods=["GET"],
|
|
336
|
+
dependencies=[authentication_dependency],
|
|
337
|
+
summary="Generates a media stream connection config",
|
|
338
|
+
responses={
|
|
339
|
+
HTTPStatus.OK.value: {
|
|
340
|
+
"description": "Media stream was successfully generated",
|
|
341
|
+
},
|
|
342
|
+
HTTPStatus.NO_CONTENT.value: {
|
|
343
|
+
"description": "Robot has no media config",
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
return router
|
|
349
|
+
|
|
286
350
|
def _log_startup_message(self) -> None:
|
|
287
351
|
address_format = "%s://%s:%d/docs"
|
|
288
352
|
message = f"Uvicorn running on {address_format} (Press CTRL+C to quit)"
|
|
@@ -300,35 +364,20 @@ class API:
|
|
|
300
364
|
extra={"color_message": color_message},
|
|
301
365
|
)
|
|
302
366
|
|
|
303
|
-
def
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
connection_string = self.keyvault_client.get_secret(
|
|
307
|
-
"application-insights-connection-string"
|
|
308
|
-
).value
|
|
309
|
-
except KeyvaultError:
|
|
310
|
-
message: str = (
|
|
311
|
-
"Missing connection string for Application Insights in key vault. "
|
|
312
|
-
)
|
|
313
|
-
self.logger.critical(message)
|
|
314
|
-
raise ConfigurationError(message)
|
|
315
|
-
|
|
316
|
-
@app.middleware("http")
|
|
317
|
-
async def middlewareOpencensus(request: Request, call_next):
|
|
318
|
-
tracer = Tracer(
|
|
319
|
-
exporter=AzureExporter(connection_string=connection_string),
|
|
320
|
-
sampler=ProbabilitySampler(1.0),
|
|
321
|
-
)
|
|
322
|
-
with tracer.span("main") as span:
|
|
323
|
-
span.span_kind = SpanKind.SERVER
|
|
367
|
+
def _publish_startup_message(self) -> None:
|
|
368
|
+
if not self.mqtt_publisher:
|
|
369
|
+
return
|
|
324
370
|
|
|
325
|
-
|
|
371
|
+
payload: StartUpMessagePayload = StartUpMessagePayload(
|
|
372
|
+
isar_id=settings.ISAR_ID,
|
|
373
|
+
timestamp=datetime.now(timezone.utc),
|
|
374
|
+
)
|
|
326
375
|
|
|
327
|
-
|
|
328
|
-
attribute_key=HTTP_STATUS_CODE, attribute_value=response.status_code
|
|
329
|
-
)
|
|
330
|
-
tracer.add_attribute_to_current_span(
|
|
331
|
-
attribute_key=HTTP_URL, attribute_value=str(request.url)
|
|
332
|
-
)
|
|
376
|
+
self.logger.info("Publishing startup message to MQTT broker")
|
|
333
377
|
|
|
334
|
-
|
|
378
|
+
self.mqtt_publisher.publish(
|
|
379
|
+
topic=settings.TOPIC_ISAR_STARTUP,
|
|
380
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
381
|
+
qos=1,
|
|
382
|
+
retain=True,
|
|
383
|
+
)
|
isar/apis/models/__init__.py
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .models import InputPose, StartMissionResponse
|
isar/apis/models/models.py
CHANGED
|
@@ -3,16 +3,14 @@ from typing import List, Optional
|
|
|
3
3
|
from alitra import Frame, Orientation, Pose, Position
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
class StepResponse(BaseModel):
|
|
8
|
-
id: str
|
|
9
|
-
type: str
|
|
6
|
+
from robot_interface.models.mission.task import TaskTypes
|
|
10
7
|
|
|
11
8
|
|
|
12
9
|
class TaskResponse(BaseModel):
|
|
13
10
|
id: str
|
|
14
11
|
tag_id: Optional[str] = None
|
|
15
|
-
|
|
12
|
+
inspection_id: Optional[str] = None
|
|
13
|
+
type: TaskTypes
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
class StartMissionResponse(BaseModel):
|
|
@@ -21,12 +19,24 @@ class StartMissionResponse(BaseModel):
|
|
|
21
19
|
|
|
22
20
|
|
|
23
21
|
class ControlMissionResponse(BaseModel):
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
success: bool
|
|
23
|
+
failure_reason: Optional[str] = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class MissionStartResponse(BaseModel):
|
|
27
|
+
mission_id: Optional[str] = None
|
|
28
|
+
mission_started: bool
|
|
29
|
+
mission_not_started_reason: Optional[str] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class LockdownResponse(BaseModel):
|
|
33
|
+
lockdown_started: bool
|
|
34
|
+
failure_reason: Optional[str] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class MaintenanceResponse(BaseModel):
|
|
38
|
+
is_maintenance_mode: bool
|
|
39
|
+
failure_reason: Optional[str] = None
|
|
30
40
|
|
|
31
41
|
|
|
32
42
|
class RobotInfoResponse(BaseModel):
|