isar 1.30.5__py3-none-any.whl → 1.31.1__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.
Potentially problematic release.
This version of isar might be problematic. Click here for more details.
- isar/apis/api.py +7 -51
- isar/apis/models/models.py +1 -0
- isar/apis/models/start_mission_definition.py +4 -0
- isar/apis/robot_control/robot_controller.py +0 -2
- isar/apis/schedule/scheduling_controller.py +12 -4
- isar/config/log.py +8 -29
- isar/config/open_telemetry.py +62 -0
- isar/config/settings.py +12 -0
- isar/eventhandlers/eventhandler.py +93 -0
- isar/mission_planner/local_planner.py +0 -3
- isar/models/events.py +118 -0
- isar/modules.py +1 -1
- isar/robot/robot.py +16 -21
- isar/robot/robot_start_mission.py +8 -14
- isar/robot/robot_status.py +2 -3
- isar/robot/robot_stop_mission.py +3 -9
- isar/robot/robot_task_status.py +3 -7
- isar/script.py +4 -1
- isar/services/utilities/robot_utilities.py +0 -3
- isar/services/utilities/scheduling_utilities.py +45 -35
- isar/state_machine/state_machine.py +79 -11
- isar/state_machine/states/await_next_mission.py +46 -11
- isar/state_machine/states/blocked_protective_stop.py +24 -15
- isar/state_machine/states/home.py +40 -9
- isar/state_machine/states/monitor.py +83 -14
- isar/state_machine/states/offline.py +25 -13
- isar/state_machine/states/paused.py +24 -38
- isar/state_machine/states/returning_home.py +75 -14
- isar/state_machine/states/robot_standing_still.py +41 -11
- isar/state_machine/states/stopping.py +52 -67
- isar/state_machine/states/unknown_status.py +37 -64
- isar/state_machine/transitions/functions/pause.py +39 -10
- isar/state_machine/transitions/functions/resume.py +44 -15
- isar/state_machine/transitions/functions/robot_status.py +4 -5
- isar/state_machine/transitions/functions/stop.py +3 -12
- isar/state_machine/transitions/mission.py +12 -2
- isar/state_machine/transitions/return_home.py +1 -1
- isar/state_machine/utils/common_event_handlers.py +166 -0
- isar/storage/blob_storage.py +0 -2
- isar/storage/uploader.py +1 -4
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/METADATA +7 -4
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/RECORD +48 -58
- robot_interface/models/mission/task.py +0 -3
- robot_interface/robot_interface.py +1 -4
- isar/models/communication/__init__.py +0 -0
- isar/models/communication/message.py +0 -8
- isar/models/communication/queues/__init__.py +0 -0
- isar/models/communication/queues/events.py +0 -58
- isar/models/communication/queues/queue_io.py +0 -12
- isar/models/communication/queues/queue_timeout_error.py +0 -2
- isar/models/communication/queues/queue_utils.py +0 -38
- isar/models/communication/queues/status_queue.py +0 -22
- isar/models/mission_metadata/__init__.py +0 -0
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/state_machine/generic_states/idle.py +0 -133
- isar/state_machine/generic_states/ongoing_mission.py +0 -294
- isar/state_machine/generic_states/robot_unavailable.py +0 -61
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/WHEEL +0 -0
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/entry_points.txt +0 -0
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/licenses/LICENSE +0 -0
- {isar-1.30.5.dist-info → isar-1.31.1.dist-info}/top_level.txt +0 -0
|
@@ -1,74 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
import time
|
|
3
|
-
from queue import Queue
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
5
2
|
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
from isar.
|
|
9
|
-
check_for_event,
|
|
10
|
-
check_shared_state,
|
|
11
|
-
)
|
|
12
|
-
from isar.models.communication.queues.status_queue import StatusQueue
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from isar.state_machine.utils.common_event_handlers import stop_mission_event_handler
|
|
13
6
|
from robot_interface.models.mission.status import RobotStatus
|
|
14
7
|
|
|
15
8
|
if TYPE_CHECKING:
|
|
16
9
|
from isar.state_machine.state_machine import StateMachine
|
|
17
10
|
|
|
18
11
|
|
|
19
|
-
class UnknownStatus(
|
|
20
|
-
def __init__(self, state_machine: "StateMachine") -> None:
|
|
21
|
-
super().__init__(name="unknown_status", on_enter=self.start, on_exit=self.stop)
|
|
22
|
-
self.state_machine: "StateMachine" = state_machine
|
|
23
|
-
self.logger = logging.getLogger("state_machine")
|
|
24
|
-
self.events = self.state_machine.events
|
|
25
|
-
self.shared_state = self.state_machine.shared_state
|
|
26
|
-
self.signal_state_machine_to_stop = state_machine.signal_state_machine_to_stop
|
|
27
|
-
|
|
28
|
-
def start(self) -> None:
|
|
29
|
-
self.state_machine.update_state()
|
|
30
|
-
self._run()
|
|
31
|
-
|
|
32
|
-
def stop(self) -> None:
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
def _check_and_handle_stop_mission_event(self, event: Queue) -> bool:
|
|
36
|
-
if check_for_event(event):
|
|
37
|
-
self.state_machine.stop() # type: ignore
|
|
38
|
-
return True
|
|
39
|
-
return False
|
|
40
|
-
|
|
41
|
-
def _check_and_handle_robot_status_event(
|
|
42
|
-
self, event: StatusQueue[RobotStatus]
|
|
43
|
-
) -> bool:
|
|
44
|
-
robot_status: RobotStatus = check_shared_state(event)
|
|
45
|
-
if (
|
|
46
|
-
robot_status == RobotStatus.Home
|
|
47
|
-
or robot_status == RobotStatus.Offline
|
|
48
|
-
or robot_status == RobotStatus.BlockedProtectiveStop
|
|
49
|
-
or robot_status == RobotStatus.Available
|
|
50
|
-
):
|
|
51
|
-
self.state_machine.robot_status_changed() # type: ignore
|
|
52
|
-
return True
|
|
12
|
+
class UnknownStatus(EventHandlerBase):
|
|
53
13
|
|
|
54
|
-
|
|
14
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
15
|
+
events = state_machine.events
|
|
16
|
+
shared_state = state_machine.shared_state
|
|
55
17
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
self.events.api_requests.stop_mission.input
|
|
66
|
-
):
|
|
67
|
-
break
|
|
68
|
-
|
|
69
|
-
if self._check_and_handle_robot_status_event(
|
|
70
|
-
self.shared_state.robot_status
|
|
18
|
+
def _robot_status_event_handler(
|
|
19
|
+
event: Event[RobotStatus],
|
|
20
|
+
) -> Optional[Callable]:
|
|
21
|
+
robot_status: RobotStatus = event.check()
|
|
22
|
+
if (
|
|
23
|
+
robot_status == RobotStatus.Home
|
|
24
|
+
or robot_status == RobotStatus.Offline
|
|
25
|
+
or robot_status == RobotStatus.BlockedProtectiveStop
|
|
26
|
+
or robot_status == RobotStatus.Available
|
|
71
27
|
):
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
28
|
+
return state_machine.robot_status_changed # type: ignore
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
32
|
+
EventHandlerMapping(
|
|
33
|
+
name="stop_mission_event",
|
|
34
|
+
event=events.api_requests.stop_mission.input,
|
|
35
|
+
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
36
|
+
),
|
|
37
|
+
EventHandlerMapping(
|
|
38
|
+
name="robot_status_event",
|
|
39
|
+
event=shared_state.robot_status,
|
|
40
|
+
handler=_robot_status_event_handler,
|
|
41
|
+
),
|
|
42
|
+
]
|
|
43
|
+
super().__init__(
|
|
44
|
+
state_name="unknown_status",
|
|
45
|
+
state_machine=state_machine,
|
|
46
|
+
event_handler_mappings=event_handlers,
|
|
47
|
+
)
|
|
@@ -3,22 +3,51 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
if TYPE_CHECKING:
|
|
4
4
|
from isar.state_machine.state_machine import StateMachine
|
|
5
5
|
|
|
6
|
+
import time
|
|
7
|
+
|
|
6
8
|
from isar.apis.models.models import ControlMissionResponse
|
|
9
|
+
from isar.config.settings import settings
|
|
10
|
+
from robot_interface.models.exceptions.robot_exceptions import (
|
|
11
|
+
RobotActionException,
|
|
12
|
+
RobotException,
|
|
13
|
+
)
|
|
7
14
|
from robot_interface.models.mission.status import MissionStatus, TaskStatus
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def pause_mission(state_machine: "StateMachine") -> bool:
|
|
11
18
|
state_machine.logger.info("Pausing mission: %s", state_machine.current_mission.id)
|
|
12
|
-
state_machine.current_mission.status = MissionStatus.Paused
|
|
13
|
-
state_machine.current_task.status = TaskStatus.Paused
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
max_retries = settings.STATE_TRANSITION_NUM_RETIRES
|
|
21
|
+
retry_interval = settings.STATE_TRANSITION_RETRY_INTERVAL_SEC
|
|
22
|
+
|
|
23
|
+
for attempt in range(max_retries):
|
|
24
|
+
try:
|
|
25
|
+
state_machine.robot.pause()
|
|
26
|
+
state_machine.current_mission.status = MissionStatus.Paused
|
|
27
|
+
state_machine.current_task.status = TaskStatus.Paused
|
|
28
|
+
|
|
29
|
+
paused_mission_response: ControlMissionResponse = (
|
|
30
|
+
state_machine._make_control_mission_response()
|
|
31
|
+
)
|
|
32
|
+
state_machine.events.api_requests.pause_mission.output.put(
|
|
33
|
+
paused_mission_response
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
state_machine.publish_mission_status()
|
|
37
|
+
state_machine.publish_task_status(task=state_machine.current_task)
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
|
|
39
|
+
state_machine.logger.info("Mission paused successfully.")
|
|
40
|
+
return True
|
|
41
|
+
except RobotActionException as e:
|
|
42
|
+
state_machine.logger.warning(
|
|
43
|
+
f"Attempt {attempt + 1} to pause mission failed: {e.error_description}"
|
|
44
|
+
)
|
|
45
|
+
time.sleep(retry_interval)
|
|
46
|
+
except RobotException as e:
|
|
47
|
+
state_machine.logger.warning(
|
|
48
|
+
f"Attempt {attempt + 1} to pause mission raised a RobotException: {e.error_description}"
|
|
49
|
+
)
|
|
50
|
+
time.sleep(retry_interval)
|
|
22
51
|
|
|
23
|
-
state_machine.
|
|
24
|
-
return
|
|
52
|
+
state_machine.logger.error("Failed to pause mission after multiple attempts.")
|
|
53
|
+
return False
|
|
@@ -3,25 +3,54 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
if TYPE_CHECKING:
|
|
4
4
|
from isar.state_machine.state_machine import StateMachine
|
|
5
5
|
|
|
6
|
+
import time
|
|
7
|
+
|
|
6
8
|
from isar.apis.models.models import ControlMissionResponse
|
|
9
|
+
from isar.config.settings import settings
|
|
10
|
+
from robot_interface.models.exceptions.robot_exceptions import (
|
|
11
|
+
RobotActionException,
|
|
12
|
+
RobotException,
|
|
13
|
+
)
|
|
7
14
|
from robot_interface.models.mission.status import MissionStatus, TaskStatus
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def resume_mission(state_machine: "StateMachine") -> bool:
|
|
11
18
|
state_machine.logger.info("Resuming mission: %s", state_machine.current_mission.id)
|
|
12
|
-
state_machine.current_mission.status = MissionStatus.InProgress
|
|
13
|
-
state_machine.current_mission.error_message = None
|
|
14
|
-
state_machine.current_task.status = TaskStatus.InProgress
|
|
15
|
-
|
|
16
|
-
state_machine.mission_ongoing = True
|
|
17
|
-
|
|
18
|
-
state_machine.publish_mission_status()
|
|
19
|
-
state_machine.publish_task_status(task=state_machine.current_task)
|
|
20
|
-
|
|
21
|
-
resume_mission_response: ControlMissionResponse = (
|
|
22
|
-
state_machine._make_control_mission_response()
|
|
23
|
-
)
|
|
24
|
-
state_machine.events.api_requests.resume_mission.output.put(resume_mission_response)
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
max_retries = settings.STATE_TRANSITION_NUM_RETIRES
|
|
21
|
+
retry_interval = settings.STATE_TRANSITION_RETRY_INTERVAL_SEC
|
|
22
|
+
|
|
23
|
+
for attempt in range(max_retries):
|
|
24
|
+
try:
|
|
25
|
+
state_machine.robot.resume()
|
|
26
|
+
state_machine.current_mission.status = MissionStatus.InProgress
|
|
27
|
+
state_machine.current_mission.error_message = None
|
|
28
|
+
state_machine.current_task.status = TaskStatus.InProgress
|
|
29
|
+
|
|
30
|
+
state_machine.mission_ongoing = True
|
|
31
|
+
|
|
32
|
+
state_machine.publish_mission_status()
|
|
33
|
+
state_machine.publish_task_status(task=state_machine.current_task)
|
|
34
|
+
|
|
35
|
+
resume_mission_response: ControlMissionResponse = (
|
|
36
|
+
state_machine._make_control_mission_response()
|
|
37
|
+
)
|
|
38
|
+
state_machine.events.api_requests.resume_mission.output.put(
|
|
39
|
+
resume_mission_response
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
state_machine.logger.info("Mission resumed successfully.")
|
|
43
|
+
return True
|
|
44
|
+
except RobotActionException as e:
|
|
45
|
+
state_machine.logger.warning(
|
|
46
|
+
f"Attempt {attempt + 1} to resume mission failed: {e.error_description}"
|
|
47
|
+
)
|
|
48
|
+
time.sleep(retry_interval)
|
|
49
|
+
except RobotException as e:
|
|
50
|
+
state_machine.logger.warning(
|
|
51
|
+
f"Attempt {attempt + 1} to resume mission raised a RobotException: {e.error_description}"
|
|
52
|
+
)
|
|
53
|
+
time.sleep(retry_interval)
|
|
54
|
+
|
|
55
|
+
state_machine.logger.error("Failed to resume mission after multiple attempts.")
|
|
56
|
+
return False
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
|
-
from isar.models.communication.queues.queue_utils import check_shared_state
|
|
4
3
|
from robot_interface.models.mission.status import RobotStatus
|
|
5
4
|
|
|
6
5
|
if TYPE_CHECKING:
|
|
@@ -8,20 +7,20 @@ if TYPE_CHECKING:
|
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
def is_offline(state_machine: "StateMachine") -> bool:
|
|
11
|
-
robot_status =
|
|
10
|
+
robot_status = state_machine.shared_state.robot_status.check()
|
|
12
11
|
return robot_status == RobotStatus.Offline
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def is_available(state_machine: "StateMachine") -> bool:
|
|
16
|
-
robot_status =
|
|
15
|
+
robot_status = state_machine.shared_state.robot_status.check()
|
|
17
16
|
return robot_status == RobotStatus.Available
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
def is_home(state_machine: "StateMachine") -> bool:
|
|
21
|
-
robot_status =
|
|
20
|
+
robot_status = state_machine.shared_state.robot_status.check()
|
|
22
21
|
return robot_status == RobotStatus.Home
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
def is_blocked_protective_stop(state_machine: "StateMachine") -> bool:
|
|
26
|
-
robot_status =
|
|
25
|
+
robot_status = state_machine.shared_state.robot_status.check()
|
|
27
26
|
return robot_status == RobotStatus.BlockedProtectiveStop
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
from typing import TYPE_CHECKING
|
|
2
2
|
|
|
3
|
-
from isar.models.communication.queues.queue_utils import (
|
|
4
|
-
check_for_event_without_consumption,
|
|
5
|
-
trigger_event_without_data,
|
|
6
|
-
)
|
|
7
|
-
|
|
8
3
|
if TYPE_CHECKING:
|
|
9
4
|
from isar.state_machine.state_machine import StateMachine
|
|
10
5
|
|
|
@@ -13,7 +8,7 @@ from robot_interface.models.mission.status import MissionStatus, TaskStatus
|
|
|
13
8
|
|
|
14
9
|
|
|
15
10
|
def trigger_stop_mission_event(state_machine: "StateMachine") -> bool:
|
|
16
|
-
|
|
11
|
+
state_machine.events.state_machine_events.stop_mission.trigger_event(True)
|
|
17
12
|
return True
|
|
18
13
|
|
|
19
14
|
|
|
@@ -56,9 +51,7 @@ def stop_return_home_mission_cleanup(state_machine: "StateMachine") -> bool:
|
|
|
56
51
|
state_machine.reset_state_machine()
|
|
57
52
|
return True
|
|
58
53
|
|
|
59
|
-
if not
|
|
60
|
-
state_machine.events.api_requests.start_mission.input
|
|
61
|
-
):
|
|
54
|
+
if not state_machine.events.api_requests.start_mission.input.has_event():
|
|
62
55
|
state_machine.current_mission.status = MissionStatus.Cancelled
|
|
63
56
|
|
|
64
57
|
for task in state_machine.current_mission.tasks:
|
|
@@ -81,9 +74,7 @@ def stop_return_home_mission_cleanup(state_machine: "StateMachine") -> bool:
|
|
|
81
74
|
|
|
82
75
|
|
|
83
76
|
def stop_return_home_mission_failed(state_machine: "StateMachine") -> bool:
|
|
84
|
-
if
|
|
85
|
-
state_machine.events.api_requests.start_mission.input
|
|
86
|
-
):
|
|
77
|
+
if state_machine.events.api_requests.start_mission.input.has_event():
|
|
87
78
|
return True
|
|
88
79
|
stopped_mission_response: ControlMissionResponse = (
|
|
89
80
|
state_machine._make_control_mission_response()
|
|
@@ -32,13 +32,23 @@ def get_mission_transitions(state_machine: "StateMachine") -> List[dict]:
|
|
|
32
32
|
"trigger": "pause",
|
|
33
33
|
"source": state_machine.monitor_state,
|
|
34
34
|
"dest": state_machine.paused_state,
|
|
35
|
-
"
|
|
35
|
+
"conditions": def_transition(state_machine, pause_mission),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"trigger": "pause",
|
|
39
|
+
"source": state_machine.monitor_state,
|
|
40
|
+
"dest": state_machine.monitor_state,
|
|
36
41
|
},
|
|
37
42
|
{
|
|
38
43
|
"trigger": "resume",
|
|
39
44
|
"source": state_machine.paused_state,
|
|
40
45
|
"dest": state_machine.monitor_state,
|
|
41
|
-
"
|
|
46
|
+
"conditions": def_transition(state_machine, resume_mission),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"trigger": "resume",
|
|
50
|
+
"source": state_machine.paused_state,
|
|
51
|
+
"dest": state_machine.paused_state,
|
|
42
52
|
},
|
|
43
53
|
{
|
|
44
54
|
"trigger": "stop",
|
|
@@ -63,7 +63,7 @@ def get_return_home_transitions(state_machine: "StateMachine") -> List[dict]:
|
|
|
63
63
|
"trigger": "return_home_failed",
|
|
64
64
|
"source": state_machine.returning_home_state,
|
|
65
65
|
"dest": state_machine.robot_standing_still_state,
|
|
66
|
-
"before": def_transition(state_machine,
|
|
66
|
+
"before": def_transition(state_machine, report_failed_mission_and_finalize),
|
|
67
67
|
},
|
|
68
68
|
]
|
|
69
69
|
return return_home_transitions
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, Optional
|
|
2
|
+
|
|
3
|
+
from isar.apis.models.models import ControlMissionResponse
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
6
|
+
from robot_interface.models.mission.mission import Mission
|
|
7
|
+
from robot_interface.models.mission.status import RobotStatus, TaskStatus
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from isar.state_machine.state_machine import StateMachine
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def start_mission_event_handler(
|
|
14
|
+
state_machine: "StateMachine", event: Event[Mission]
|
|
15
|
+
) -> Optional[Callable]:
|
|
16
|
+
mission: Optional[Mission] = event.consume_event()
|
|
17
|
+
if mission:
|
|
18
|
+
state_machine.start_mission(mission=mission)
|
|
19
|
+
return state_machine.request_mission_start # type: ignore
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def return_home_event_handler(
|
|
24
|
+
state_machine: "StateMachine", event: Event[bool]
|
|
25
|
+
) -> Optional[Callable]:
|
|
26
|
+
if event.consume_event():
|
|
27
|
+
state_machine.events.api_requests.return_home.output.put(True)
|
|
28
|
+
return state_machine.request_return_home # type: ignore
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def robot_status_event_handler(
|
|
33
|
+
state_machine: "StateMachine",
|
|
34
|
+
expected_status: RobotStatus,
|
|
35
|
+
event: Event[RobotStatus],
|
|
36
|
+
) -> Optional[Callable]:
|
|
37
|
+
robot_status: RobotStatus = event.check()
|
|
38
|
+
if robot_status != expected_status:
|
|
39
|
+
return state_machine.robot_status_changed # type: ignore
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def stop_mission_event_handler(
|
|
44
|
+
state_machine: "StateMachine", event: Event[str]
|
|
45
|
+
) -> Optional[Callable]:
|
|
46
|
+
mission_id: str = event.consume_event()
|
|
47
|
+
if mission_id is not None:
|
|
48
|
+
if state_machine.current_mission.id == mission_id or mission_id == "":
|
|
49
|
+
return state_machine.stop # type: ignore
|
|
50
|
+
else:
|
|
51
|
+
state_machine.events.api_requests.stop_mission.output.put(
|
|
52
|
+
ControlMissionResponse(
|
|
53
|
+
mission_id=mission_id,
|
|
54
|
+
mission_status=state_machine.current_mission.status,
|
|
55
|
+
mission_not_found=True,
|
|
56
|
+
task_id=state_machine.current_task.id,
|
|
57
|
+
task_status=state_machine.current_task.status,
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def mission_started_event_handler(
|
|
64
|
+
state_machine: "StateMachine",
|
|
65
|
+
event: Event[bool],
|
|
66
|
+
) -> Optional[Callable]:
|
|
67
|
+
if event.consume_event():
|
|
68
|
+
state_machine.mission_ongoing = True
|
|
69
|
+
return None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def mission_failed_event_handler(
|
|
73
|
+
state_machine: "StateMachine",
|
|
74
|
+
event: Event[Optional[ErrorMessage]],
|
|
75
|
+
) -> Optional[Callable]:
|
|
76
|
+
mission_failed: Optional[ErrorMessage] = event.consume_event()
|
|
77
|
+
if mission_failed is not None:
|
|
78
|
+
state_machine.logger.warning(
|
|
79
|
+
f"Failed to initiate mission "
|
|
80
|
+
f"{str(state_machine.current_mission.id)[:8]} because: "
|
|
81
|
+
f"{mission_failed.error_description}"
|
|
82
|
+
)
|
|
83
|
+
state_machine.current_mission.error_message = ErrorMessage(
|
|
84
|
+
error_reason=mission_failed.error_reason,
|
|
85
|
+
error_description=mission_failed.error_description,
|
|
86
|
+
)
|
|
87
|
+
return state_machine.mission_failed_to_start # type: ignore
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def task_status_failed_event_handler(
|
|
92
|
+
state_machine: "StateMachine",
|
|
93
|
+
handle_task_completed: Callable[[TaskStatus], Callable],
|
|
94
|
+
event: Event[Optional[ErrorMessage]],
|
|
95
|
+
) -> Optional[Callable]:
|
|
96
|
+
if not state_machine.mission_ongoing:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
task_failure: Optional[ErrorMessage] = event.consume_event()
|
|
100
|
+
if task_failure is not None:
|
|
101
|
+
if state_machine.current_task is None:
|
|
102
|
+
state_machine.logger.warning(
|
|
103
|
+
"Received task status failed event when no task was running"
|
|
104
|
+
)
|
|
105
|
+
return None
|
|
106
|
+
state_machine.awaiting_task_status = False
|
|
107
|
+
state_machine.current_task.error_message = task_failure
|
|
108
|
+
state_machine.logger.error(
|
|
109
|
+
f"Monitoring task {state_machine.current_task.id[:8]} failed "
|
|
110
|
+
f"because: {task_failure.error_description}"
|
|
111
|
+
)
|
|
112
|
+
return _handle_new_task_status(
|
|
113
|
+
state_machine, handle_task_completed, TaskStatus.Failed
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
elif (
|
|
117
|
+
not state_machine.awaiting_task_status
|
|
118
|
+
and state_machine.current_task is not None
|
|
119
|
+
):
|
|
120
|
+
state_machine.events.state_machine_events.task_status_request.trigger_event(
|
|
121
|
+
state_machine.current_task.id,
|
|
122
|
+
)
|
|
123
|
+
state_machine.awaiting_task_status = True
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def task_status_event_handler(
|
|
128
|
+
state_machine: "StateMachine",
|
|
129
|
+
handle_task_completed: Callable[[TaskStatus], Callable],
|
|
130
|
+
event: Event[Optional[TaskStatus]],
|
|
131
|
+
) -> Optional[Callable]:
|
|
132
|
+
if not state_machine.mission_ongoing:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
status: Optional[TaskStatus] = event.consume_event()
|
|
136
|
+
if status is not None:
|
|
137
|
+
state_machine.awaiting_task_status = False
|
|
138
|
+
return _handle_new_task_status(state_machine, handle_task_completed, status)
|
|
139
|
+
|
|
140
|
+
elif (
|
|
141
|
+
not state_machine.awaiting_task_status
|
|
142
|
+
and state_machine.current_task is not None
|
|
143
|
+
):
|
|
144
|
+
state_machine.events.state_machine_events.task_status_request.trigger_event(
|
|
145
|
+
state_machine.current_task.id,
|
|
146
|
+
)
|
|
147
|
+
state_machine.awaiting_task_status = True
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _handle_new_task_status(
|
|
152
|
+
state_machine: "StateMachine",
|
|
153
|
+
handle_task_completed: Callable[[TaskStatus], Callable],
|
|
154
|
+
status: TaskStatus,
|
|
155
|
+
) -> Optional[Callable]:
|
|
156
|
+
if state_machine.current_task is None:
|
|
157
|
+
state_machine.iterate_current_task()
|
|
158
|
+
|
|
159
|
+
state_machine.current_task.status = status
|
|
160
|
+
|
|
161
|
+
if state_machine.current_task.is_finished():
|
|
162
|
+
state_machine.report_task_status(state_machine.current_task)
|
|
163
|
+
state_machine.publish_task_status(task=state_machine.current_task)
|
|
164
|
+
|
|
165
|
+
return handle_task_completed(status)
|
|
166
|
+
return None
|
isar/storage/blob_storage.py
CHANGED
|
@@ -4,7 +4,6 @@ from typing import Union
|
|
|
4
4
|
|
|
5
5
|
from azure.core.exceptions import ResourceExistsError
|
|
6
6
|
from azure.storage.blob import BlobClient, BlobServiceClient, ContainerClient
|
|
7
|
-
from dependency_injector.wiring import inject
|
|
8
7
|
|
|
9
8
|
from isar.config.keyvault.keyvault_service import Keyvault
|
|
10
9
|
from isar.config.settings import settings
|
|
@@ -15,7 +14,6 @@ from robot_interface.models.mission.mission import Mission
|
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class BlobStorage(StorageInterface):
|
|
18
|
-
@inject
|
|
19
17
|
def __init__(
|
|
20
18
|
self, keyvault: Keyvault, container_name: str = settings.BLOB_CONTAINER
|
|
21
19
|
) -> None:
|
isar/storage/uploader.py
CHANGED
|
@@ -6,10 +6,8 @@ from queue import Empty, Queue
|
|
|
6
6
|
from threading import Event
|
|
7
7
|
from typing import List, Union
|
|
8
8
|
|
|
9
|
-
from dependency_injector.wiring import inject
|
|
10
|
-
|
|
11
9
|
from isar.config.settings import settings
|
|
12
|
-
from isar.models.
|
|
10
|
+
from isar.models.events import Events
|
|
13
11
|
from isar.storage.storage_interface import StorageException, StorageInterface
|
|
14
12
|
from robot_interface.models.inspection.inspection import (
|
|
15
13
|
Inspection,
|
|
@@ -63,7 +61,6 @@ class BlobItem(UploaderQueueItem):
|
|
|
63
61
|
|
|
64
62
|
|
|
65
63
|
class Uploader:
|
|
66
|
-
@inject
|
|
67
64
|
def __init__(
|
|
68
65
|
self,
|
|
69
66
|
events: Events,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: isar
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.31.1
|
|
4
4
|
Summary: Integration and Supervisory control of Autonomous Robots
|
|
5
5
|
Author-email: Equinor ASA <fg_robots_dev@equinor.com>
|
|
6
6
|
License: Eclipse Public License version 2.0
|
|
@@ -113,9 +113,6 @@ Requires-Dist: fastapi-azure-auth
|
|
|
113
113
|
Requires-Dist: fastapi
|
|
114
114
|
Requires-Dist: dependency-injector
|
|
115
115
|
Requires-Dist: numpy
|
|
116
|
-
Requires-Dist: opencensus-ext-azure
|
|
117
|
-
Requires-Dist: opencensus-ext-logging
|
|
118
|
-
Requires-Dist: opencensus-ext-requests
|
|
119
116
|
Requires-Dist: paho-mqtt
|
|
120
117
|
Requires-Dist: pydantic_settings
|
|
121
118
|
Requires-Dist: pydantic
|
|
@@ -126,6 +123,12 @@ Requires-Dist: requests-toolbelt
|
|
|
126
123
|
Requires-Dist: requests
|
|
127
124
|
Requires-Dist: transitions
|
|
128
125
|
Requires-Dist: uvicorn
|
|
126
|
+
Requires-Dist: opentelemetry-api
|
|
127
|
+
Requires-Dist: opentelemetry-sdk
|
|
128
|
+
Requires-Dist: opentelemetry-exporter-otlp
|
|
129
|
+
Requires-Dist: opentelemetry-instrumentation-fastapi
|
|
130
|
+
Requires-Dist: azure-monitor-opentelemetry
|
|
131
|
+
Requires-Dist: azure-monitor-opentelemetry-exporter>=1.0.0b38
|
|
129
132
|
Provides-Extra: dev
|
|
130
133
|
Requires-Dist: black; extra == "dev"
|
|
131
134
|
Requires-Dist: isort; extra == "dev"
|