isar 1.20.2__py3-none-any.whl → 1.34.9__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.
Files changed (124) hide show
  1. isar/apis/api.py +148 -76
  2. isar/apis/models/__init__.py +0 -1
  3. isar/apis/models/models.py +21 -11
  4. isar/apis/models/start_mission_definition.py +110 -168
  5. isar/apis/robot_control/robot_controller.py +41 -0
  6. isar/apis/schedule/scheduling_controller.py +124 -162
  7. isar/apis/security/authentication.py +5 -5
  8. isar/config/certs/ca-cert.pem +33 -31
  9. isar/config/keyvault/keyvault_service.py +1 -1
  10. isar/config/log.py +45 -40
  11. isar/config/logging.conf +16 -31
  12. isar/config/open_telemetry.py +102 -0
  13. isar/config/predefined_mission_definition/default_exr.json +0 -2
  14. isar/config/predefined_mission_definition/default_mission.json +1 -5
  15. isar/config/predefined_mission_definition/default_turtlebot.json +4 -11
  16. isar/config/predefined_missions/default.json +67 -87
  17. isar/config/predefined_missions/default_extra_capabilities.json +107 -0
  18. isar/config/settings.py +76 -111
  19. isar/eventhandlers/eventhandler.py +123 -0
  20. isar/mission_planner/local_planner.py +6 -20
  21. isar/mission_planner/mission_planner_interface.py +1 -1
  22. isar/models/events.py +184 -0
  23. isar/models/status.py +18 -0
  24. isar/modules.py +118 -199
  25. isar/robot/robot.py +377 -0
  26. isar/robot/robot_battery.py +60 -0
  27. isar/robot/robot_monitor_mission.py +357 -0
  28. isar/robot/robot_pause_mission.py +74 -0
  29. isar/robot/robot_resume_mission.py +67 -0
  30. isar/robot/robot_start_mission.py +66 -0
  31. isar/robot/robot_status.py +61 -0
  32. isar/robot/robot_stop_mission.py +68 -0
  33. isar/robot/robot_upload_inspection.py +75 -0
  34. isar/script.py +57 -40
  35. isar/services/service_connections/mqtt/mqtt_client.py +47 -11
  36. isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +5 -2
  37. isar/services/service_connections/mqtt/robot_info_publisher.py +3 -3
  38. isar/services/service_connections/persistent_memory.py +69 -0
  39. isar/services/utilities/mqtt_utilities.py +93 -0
  40. isar/services/utilities/robot_utilities.py +20 -0
  41. isar/services/utilities/scheduling_utilities.py +393 -65
  42. isar/state_machine/state_machine.py +219 -538
  43. isar/state_machine/states/__init__.py +0 -8
  44. isar/state_machine/states/await_next_mission.py +114 -0
  45. isar/state_machine/states/blocked_protective_stop.py +60 -0
  46. isar/state_machine/states/going_to_lockdown.py +95 -0
  47. isar/state_machine/states/going_to_recharging.py +92 -0
  48. isar/state_machine/states/home.py +115 -0
  49. isar/state_machine/states/intervention_needed.py +77 -0
  50. isar/state_machine/states/lockdown.py +38 -0
  51. isar/state_machine/states/maintenance.py +36 -0
  52. isar/state_machine/states/monitor.py +137 -247
  53. isar/state_machine/states/offline.py +51 -53
  54. isar/state_machine/states/paused.py +92 -23
  55. isar/state_machine/states/pausing.py +48 -0
  56. isar/state_machine/states/pausing_return_home.py +48 -0
  57. isar/state_machine/states/recharging.py +80 -0
  58. isar/state_machine/states/resuming.py +57 -0
  59. isar/state_machine/states/resuming_return_home.py +64 -0
  60. isar/state_machine/states/return_home_paused.py +109 -0
  61. isar/state_machine/states/returning_home.py +217 -0
  62. isar/state_machine/states/stopping.py +61 -0
  63. isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
  64. isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
  65. isar/state_machine/states/stopping_go_to_recharge.py +51 -0
  66. isar/state_machine/states/stopping_return_home.py +77 -0
  67. isar/state_machine/states/unknown_status.py +72 -0
  68. isar/state_machine/states_enum.py +21 -5
  69. isar/state_machine/transitions/mission.py +192 -0
  70. isar/state_machine/transitions/return_home.py +106 -0
  71. isar/state_machine/transitions/robot_status.py +80 -0
  72. isar/state_machine/utils/common_event_handlers.py +73 -0
  73. isar/storage/blob_storage.py +70 -52
  74. isar/storage/local_storage.py +25 -12
  75. isar/storage/storage_interface.py +28 -7
  76. isar/storage/uploader.py +174 -55
  77. isar/storage/utilities.py +32 -29
  78. {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/METADATA +73 -110
  79. isar-1.34.9.dist-info/RECORD +135 -0
  80. {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/WHEEL +1 -1
  81. {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/entry_points.txt +1 -0
  82. robot_interface/models/exceptions/robot_exceptions.py +91 -41
  83. robot_interface/models/initialize/__init__.py +0 -1
  84. robot_interface/models/inspection/__init__.py +0 -13
  85. robot_interface/models/inspection/inspection.py +42 -33
  86. robot_interface/models/mission/mission.py +14 -15
  87. robot_interface/models/mission/status.py +20 -26
  88. robot_interface/models/mission/task.py +154 -121
  89. robot_interface/models/robots/battery_state.py +6 -0
  90. robot_interface/models/robots/media.py +13 -0
  91. robot_interface/models/robots/robot_model.py +7 -7
  92. robot_interface/robot_interface.py +119 -84
  93. robot_interface/telemetry/mqtt_client.py +74 -12
  94. robot_interface/telemetry/payloads.py +91 -13
  95. robot_interface/utilities/json_service.py +7 -1
  96. isar/config/predefined_missions/default_turtlebot.json +0 -110
  97. isar/config/predefined_poses/__init__.py +0 -0
  98. isar/config/predefined_poses/predefined_poses.py +0 -616
  99. isar/config/settings.env +0 -25
  100. isar/mission_planner/sequential_task_selector.py +0 -23
  101. isar/mission_planner/task_selector_interface.py +0 -31
  102. isar/models/communication/__init__.py +0 -0
  103. isar/models/communication/message.py +0 -12
  104. isar/models/communication/queues/__init__.py +0 -4
  105. isar/models/communication/queues/queue_io.py +0 -12
  106. isar/models/communication/queues/queue_timeout_error.py +0 -2
  107. isar/models/communication/queues/queues.py +0 -19
  108. isar/models/communication/queues/status_queue.py +0 -20
  109. isar/models/mission_metadata/__init__.py +0 -0
  110. isar/services/readers/__init__.py +0 -0
  111. isar/services/readers/base_reader.py +0 -37
  112. isar/services/service_connections/stid/__init__.py +0 -0
  113. isar/services/utilities/queue_utilities.py +0 -39
  114. isar/state_machine/states/idle.py +0 -85
  115. isar/state_machine/states/initialize.py +0 -71
  116. isar/state_machine/states/initiate.py +0 -142
  117. isar/state_machine/states/off.py +0 -18
  118. isar/state_machine/states/stop.py +0 -95
  119. isar/storage/slimm_storage.py +0 -191
  120. isar-1.20.2.dist-info/RECORD +0 -116
  121. robot_interface/models/initialize/initialize_params.py +0 -9
  122. robot_interface/models/mission/step.py +0 -234
  123. {isar-1.20.2.dist-info → isar-1.34.9.dist-info/licenses}/LICENSE +0 -0
  124. {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/top_level.txt +0 -0
@@ -1,8 +0,0 @@
1
- from .idle import Idle
2
- from .initialize import Initialize
3
- from .initiate import Initiate
4
- from .monitor import Monitor
5
- from .off import Off
6
- from .offline import Offline
7
- from .paused import Paused
8
- from .stop import Stop
@@ -0,0 +1,114 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import LockdownResponse, MaintenanceResponse
4
+ from isar.config.settings import settings
5
+ from isar.eventhandlers.eventhandler import (
6
+ EventHandlerBase,
7
+ EventHandlerMapping,
8
+ TimeoutHandlerMapping,
9
+ )
10
+ from isar.models.events import Event
11
+ from isar.state_machine.utils.common_event_handlers import (
12
+ return_home_event_handler,
13
+ start_mission_event_handler,
14
+ stop_mission_event_handler,
15
+ )
16
+
17
+ if TYPE_CHECKING:
18
+ from isar.state_machine.state_machine import StateMachine
19
+
20
+
21
+ class AwaitNextMission(EventHandlerBase):
22
+
23
+ def __init__(self, state_machine: "StateMachine"):
24
+ events = state_machine.events
25
+ shared_state = state_machine.shared_state
26
+
27
+ def _send_to_lockdown_event_handler(
28
+ event: Event[bool],
29
+ ) -> Optional[Callable]:
30
+ should_lockdown: bool = event.consume_event()
31
+ if not should_lockdown:
32
+ return None
33
+
34
+ events.api_requests.send_to_lockdown.response.trigger_event(
35
+ LockdownResponse(lockdown_started=True)
36
+ )
37
+ state_machine.start_return_home_mission()
38
+ return state_machine.start_lockdown_mission_monitoring # type: ignore
39
+
40
+ def _robot_battery_level_updated_handler(
41
+ event: Event[float],
42
+ ) -> Optional[Callable]:
43
+ battery_level: float = event.check()
44
+ if (
45
+ battery_level is None
46
+ or battery_level >= settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
47
+ ):
48
+ return None
49
+
50
+ state_machine.start_return_home_mission()
51
+ return state_machine.start_recharging_mission_monitoring # type: ignore
52
+
53
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
54
+ should_set_maintenande_mode: bool = event.consume_event()
55
+ if should_set_maintenande_mode:
56
+ events.api_requests.set_maintenance_mode.response.trigger_event(
57
+ MaintenanceResponse(is_maintenance_mode=True)
58
+ )
59
+ return state_machine.set_maintenance_mode # type: ignore
60
+ return None
61
+
62
+ def _start_return_home():
63
+ state_machine.start_return_home_mission()
64
+ return state_machine.start_return_home_monitoring # type: ignore
65
+
66
+ event_handlers: List[EventHandlerMapping] = [
67
+ EventHandlerMapping(
68
+ name="start_mission_event",
69
+ event=events.api_requests.start_mission.request,
70
+ handler=lambda event: start_mission_event_handler(
71
+ state_machine, event, events.api_requests.start_mission.response
72
+ ),
73
+ ),
74
+ EventHandlerMapping(
75
+ name="return_home_event",
76
+ event=events.api_requests.return_home.request,
77
+ handler=lambda event: return_home_event_handler(state_machine, event),
78
+ ),
79
+ EventHandlerMapping(
80
+ name="stop_mission_event",
81
+ event=events.api_requests.return_home.request,
82
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
83
+ ),
84
+ EventHandlerMapping(
85
+ name="send_to_lockdown_event",
86
+ event=events.api_requests.send_to_lockdown.request,
87
+ handler=_send_to_lockdown_event_handler,
88
+ ),
89
+ EventHandlerMapping(
90
+ name="robot_battery_update_event",
91
+ event=shared_state.robot_battery_level,
92
+ handler=_robot_battery_level_updated_handler,
93
+ ),
94
+ EventHandlerMapping(
95
+ name="set_maintenance_mode",
96
+ event=events.api_requests.set_maintenance_mode.request,
97
+ handler=_set_maintenance_mode_event_handler,
98
+ ),
99
+ ]
100
+
101
+ timers: List[TimeoutHandlerMapping] = [
102
+ TimeoutHandlerMapping(
103
+ name="should_return_home_timer",
104
+ timeout_in_seconds=settings.RETURN_HOME_DELAY,
105
+ handler=_start_return_home,
106
+ )
107
+ ]
108
+
109
+ super().__init__(
110
+ state_name="await_next_mission",
111
+ state_machine=state_machine,
112
+ event_handler_mappings=event_handlers,
113
+ timers=timers,
114
+ )
@@ -0,0 +1,60 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import MaintenanceResponse
4
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
6
+ from robot_interface.models.mission.status import RobotStatus
7
+
8
+ if TYPE_CHECKING:
9
+ from isar.state_machine.state_machine import StateMachine
10
+
11
+
12
+ class BlockedProtectiveStop(EventHandlerBase):
13
+
14
+ def __init__(self, state_machine: "StateMachine"):
15
+ events = state_machine.events
16
+ shared_state = state_machine.shared_state
17
+
18
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
19
+ should_set_maintenande_mode: bool = event.consume_event()
20
+ if should_set_maintenande_mode:
21
+ events.api_requests.set_maintenance_mode.response.trigger_event(
22
+ MaintenanceResponse(is_maintenance_mode=True)
23
+ )
24
+ return state_machine.set_maintenance_mode # type: ignore
25
+ return None
26
+
27
+ def _robot_status_event_handler(
28
+ status_changed_event: Event[bool],
29
+ ) -> Optional[Callable]:
30
+ has_changed = status_changed_event.consume_event()
31
+ if not has_changed:
32
+ return None
33
+ robot_status: Optional[RobotStatus] = shared_state.robot_status.check()
34
+ if robot_status == RobotStatus.BlockedProtectiveStop:
35
+ return None
36
+ elif robot_status == RobotStatus.Home:
37
+ return state_machine.robot_status_home # type: ignore
38
+ elif robot_status == RobotStatus.Available:
39
+ return state_machine.robot_status_available # type: ignore
40
+ elif robot_status == RobotStatus.Offline:
41
+ return state_machine.robot_status_offline # type: ignore
42
+ return state_machine.robot_status_unknown # type: ignore
43
+
44
+ event_handlers: List[EventHandlerMapping] = [
45
+ EventHandlerMapping(
46
+ name="robot_status_event",
47
+ event=events.robot_service_events.robot_status_changed,
48
+ handler=_robot_status_event_handler,
49
+ ),
50
+ EventHandlerMapping(
51
+ name="set_maintenance_mode",
52
+ event=events.api_requests.set_maintenance_mode.request,
53
+ handler=_set_maintenance_mode_event_handler,
54
+ ),
55
+ ]
56
+ super().__init__(
57
+ state_name="blocked_protective_stop",
58
+ state_machine=state_machine,
59
+ event_handler_mappings=event_handlers,
60
+ )
@@ -0,0 +1,95 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
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 mission_started_event_handler
6
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
7
+ from robot_interface.models.mission.status import MissionStatus
8
+
9
+ if TYPE_CHECKING:
10
+ from isar.state_machine.state_machine import StateMachine
11
+
12
+
13
+ class GoingToLockdown(EventHandlerBase):
14
+
15
+ def __init__(self, state_machine: "StateMachine"):
16
+ events = state_machine.events
17
+
18
+ def _mission_failed_event_handler(
19
+ event: Event[Optional[ErrorMessage]],
20
+ ) -> Optional[Callable]:
21
+ mission_failed: Optional[ErrorMessage] = event.consume_event()
22
+ if mission_failed is None:
23
+ return None
24
+
25
+ state_machine.logger.warning(
26
+ f"Failed to go to lockdown because: "
27
+ f"{mission_failed.error_description}"
28
+ )
29
+ state_machine.publish_intervention_needed(
30
+ error_message="Lockdown mission failed."
31
+ )
32
+ return state_machine.lockdown_mission_failed # type: ignore
33
+
34
+ def _mission_failed_to_resume_event_handler(
35
+ event: Event[Optional[ErrorMessage]],
36
+ ) -> Optional[Callable]:
37
+ mission_failed_to_resume: Optional[ErrorMessage] = event.consume_event()
38
+ if mission_failed_to_resume is None:
39
+ return None
40
+
41
+ state_machine.logger.warning(
42
+ f"Failed to resume return to home mission and going to lockdown because: "
43
+ f"{mission_failed_to_resume.error_description or ''}"
44
+ )
45
+ return state_machine.lockdown_mission_failed # type: ignore
46
+
47
+ def _mission_status_event_handler(
48
+ event: Event[MissionStatus],
49
+ ) -> Optional[Callable]:
50
+ mission_status: Optional[MissionStatus] = event.consume_event()
51
+
52
+ if mission_status and mission_status not in [
53
+ MissionStatus.InProgress,
54
+ MissionStatus.NotStarted,
55
+ MissionStatus.Paused,
56
+ ]:
57
+ if mission_status != MissionStatus.Successful:
58
+ state_machine.publish_intervention_needed(
59
+ error_message="Lockdown mission failed."
60
+ )
61
+ return state_machine.lockdown_mission_failed # type: ignore
62
+
63
+ state_machine.print_transitions()
64
+ return state_machine.reached_lockdown # type: ignore
65
+ return None
66
+
67
+ event_handlers: List[EventHandlerMapping] = [
68
+ EventHandlerMapping(
69
+ name="mission_started_event",
70
+ event=events.robot_service_events.mission_started,
71
+ handler=lambda event: mission_started_event_handler(
72
+ state_machine, event
73
+ ),
74
+ ),
75
+ EventHandlerMapping(
76
+ name="mission_failed_event",
77
+ event=events.robot_service_events.mission_failed,
78
+ handler=_mission_failed_event_handler,
79
+ ),
80
+ EventHandlerMapping(
81
+ name="mission_failed_to_resume",
82
+ event=events.robot_service_events.mission_failed_to_resume,
83
+ handler=_mission_failed_to_resume_event_handler,
84
+ ),
85
+ EventHandlerMapping(
86
+ name="mission_status_event",
87
+ event=events.robot_service_events.mission_status_updated,
88
+ handler=_mission_status_event_handler,
89
+ ),
90
+ ]
91
+ super().__init__(
92
+ state_name="going_to_lockdown",
93
+ state_machine=state_machine,
94
+ event_handler_mappings=event_handlers,
95
+ )
@@ -0,0 +1,92 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import LockdownResponse
4
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
6
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
7
+ from robot_interface.models.mission.status import MissionStatus
8
+
9
+ if TYPE_CHECKING:
10
+ from isar.state_machine.state_machine import StateMachine
11
+
12
+
13
+ class GoingToRecharging(EventHandlerBase):
14
+
15
+ def __init__(self, state_machine: "StateMachine"):
16
+ events = state_machine.events
17
+
18
+ def _mission_failed_event_handler(
19
+ event: Event[Optional[ErrorMessage]],
20
+ ) -> Optional[Callable]:
21
+ mission_failed: Optional[ErrorMessage] = event.consume_event()
22
+ if mission_failed is None:
23
+ return None
24
+
25
+ state_machine.logger.warning(
26
+ f"Failed to go to recharging because: "
27
+ f"{mission_failed.error_description}"
28
+ )
29
+ state_machine.publish_intervention_needed(
30
+ error_message="Return home to recharge failed."
31
+ )
32
+ state_machine.print_transitions()
33
+ return state_machine.return_home_failed # type: ignore
34
+
35
+ def _mission_status_event_handler(
36
+ event: Event[MissionStatus],
37
+ ) -> Optional[Callable]:
38
+ mission_status: Optional[MissionStatus] = event.consume_event()
39
+
40
+ if not mission_status or mission_status in [
41
+ MissionStatus.InProgress,
42
+ MissionStatus.NotStarted,
43
+ MissionStatus.Paused,
44
+ ]:
45
+ return None
46
+
47
+ if mission_status != MissionStatus.Successful:
48
+ state_machine.logger.warning(
49
+ "Failed to return home. Mission reported as failed."
50
+ )
51
+ state_machine.publish_intervention_needed(
52
+ error_message="Return home to recharge failed."
53
+ )
54
+ state_machine.print_transitions()
55
+ return state_machine.return_home_failed # type: ignore
56
+
57
+ return state_machine.starting_recharging # type: ignore
58
+
59
+ def _send_to_lockdown_event_handler(
60
+ event: Event[bool],
61
+ ) -> Optional[Callable]:
62
+ should_lockdown: bool = event.consume_event()
63
+ if not should_lockdown:
64
+ return None
65
+
66
+ events.api_requests.send_to_lockdown.response.trigger_event(
67
+ LockdownResponse(lockdown_started=True)
68
+ )
69
+ return state_machine.go_to_lockdown # type: ignore
70
+
71
+ event_handlers: List[EventHandlerMapping] = [
72
+ EventHandlerMapping(
73
+ name="mission_failed_event",
74
+ event=events.robot_service_events.mission_failed,
75
+ handler=_mission_failed_event_handler,
76
+ ),
77
+ EventHandlerMapping(
78
+ name="mission_status_event",
79
+ event=events.robot_service_events.mission_status_updated,
80
+ handler=_mission_status_event_handler,
81
+ ),
82
+ EventHandlerMapping(
83
+ name="send_to_lockdown_event",
84
+ event=events.api_requests.send_to_lockdown.request,
85
+ handler=_send_to_lockdown_event_handler,
86
+ ),
87
+ ]
88
+ super().__init__(
89
+ state_name="going_to_recharging",
90
+ state_machine=state_machine,
91
+ event_handler_mappings=event_handlers,
92
+ )
@@ -0,0 +1,115 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import LockdownResponse, MaintenanceResponse
4
+ from isar.config.settings import settings
5
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
6
+ from isar.models.events import Event
7
+ from isar.state_machine.utils.common_event_handlers import (
8
+ return_home_event_handler,
9
+ start_mission_event_handler,
10
+ stop_mission_event_handler,
11
+ )
12
+ from robot_interface.models.mission.status import RobotStatus
13
+
14
+ if TYPE_CHECKING:
15
+ from isar.state_machine.state_machine import StateMachine
16
+
17
+
18
+ class Home(EventHandlerBase):
19
+
20
+ def __init__(self, state_machine: "StateMachine"):
21
+ events = state_machine.events
22
+ shared_state = state_machine.shared_state
23
+
24
+ def _send_to_lockdown_event_handler(event: Event[bool]):
25
+ should_send_robot_home: bool = event.consume_event()
26
+ if not should_send_robot_home:
27
+ return None
28
+
29
+ events.api_requests.send_to_lockdown.response.trigger_event(
30
+ LockdownResponse(lockdown_started=True)
31
+ )
32
+ return state_machine.reached_lockdown # type: ignore
33
+
34
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
35
+ should_set_maintenande_mode: bool = event.consume_event()
36
+ if should_set_maintenande_mode:
37
+ events.api_requests.set_maintenance_mode.response.trigger_event(
38
+ MaintenanceResponse(is_maintenance_mode=True)
39
+ )
40
+ return state_machine.set_maintenance_mode # type: ignore
41
+ return None
42
+
43
+ def _robot_status_event_handler(
44
+ status_changed_event: Event[bool],
45
+ ) -> Optional[Callable]:
46
+ has_changed = status_changed_event.consume_event()
47
+ if not has_changed:
48
+ return None
49
+ robot_status: Optional[RobotStatus] = shared_state.robot_status.check()
50
+ if robot_status == RobotStatus.Home:
51
+ return None
52
+ elif robot_status == RobotStatus.Available:
53
+ return state_machine.robot_status_available # type: ignore
54
+ elif robot_status == RobotStatus.Offline:
55
+ return state_machine.robot_status_offline # type: ignore
56
+ elif robot_status == RobotStatus.BlockedProtectiveStop:
57
+ return state_machine.robot_status_blocked_protective_stop # type: ignore
58
+ return state_machine.robot_status_unknown # type: ignore
59
+
60
+ def _robot_battery_level_updated_handler(
61
+ event: Event[float],
62
+ ) -> Optional[Callable]:
63
+ battery_level: float = event.check()
64
+ if (
65
+ battery_level is None
66
+ or battery_level >= settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
67
+ ):
68
+ return None
69
+
70
+ return state_machine.starting_recharging # type: ignore
71
+
72
+ event_handlers: List[EventHandlerMapping] = [
73
+ EventHandlerMapping(
74
+ name="start_mission_event",
75
+ event=events.api_requests.start_mission.request,
76
+ handler=lambda event: start_mission_event_handler(
77
+ state_machine, event, events.api_requests.start_mission.response
78
+ ),
79
+ ),
80
+ EventHandlerMapping(
81
+ name="return_home_event",
82
+ event=events.api_requests.return_home.request,
83
+ handler=lambda event: return_home_event_handler(state_machine, event),
84
+ ),
85
+ EventHandlerMapping(
86
+ name="stop_mission_event",
87
+ event=events.api_requests.return_home.request,
88
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
89
+ ),
90
+ EventHandlerMapping(
91
+ name="robot_status_event",
92
+ event=events.robot_service_events.robot_status_changed,
93
+ handler=_robot_status_event_handler,
94
+ ),
95
+ EventHandlerMapping(
96
+ name="send_to_lockdown_event",
97
+ event=events.api_requests.send_to_lockdown.request,
98
+ handler=_send_to_lockdown_event_handler,
99
+ ),
100
+ EventHandlerMapping(
101
+ name="robot_battery_update_event",
102
+ event=shared_state.robot_battery_level,
103
+ handler=_robot_battery_level_updated_handler,
104
+ ),
105
+ EventHandlerMapping(
106
+ name="set_maintenance_mode",
107
+ event=events.api_requests.set_maintenance_mode.request,
108
+ handler=_set_maintenance_mode_event_handler,
109
+ ),
110
+ ]
111
+ super().__init__(
112
+ state_name="home",
113
+ state_machine=state_machine,
114
+ event_handler_mappings=event_handlers,
115
+ )
@@ -0,0 +1,77 @@
1
+ from collections.abc import Callable
2
+ from typing import TYPE_CHECKING, List, Optional
3
+
4
+ from isar.apis.models.models import MaintenanceResponse
5
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
6
+ from isar.models.events import Event
7
+ from isar.state_machine.utils.common_event_handlers import return_home_event_handler
8
+ from robot_interface.models.mission.status import RobotStatus
9
+
10
+ if TYPE_CHECKING:
11
+ from isar.state_machine.state_machine import StateMachine
12
+
13
+
14
+ class InterventionNeeded(EventHandlerBase):
15
+
16
+ def __init__(self, state_machine: "StateMachine"):
17
+ events = state_machine.events
18
+ shared_state = state_machine.shared_state
19
+
20
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
21
+ should_set_maintenande_mode: bool = event.consume_event()
22
+ if should_set_maintenande_mode:
23
+ events.api_requests.set_maintenance_mode.response.trigger_event(
24
+ MaintenanceResponse(is_maintenance_mode=True)
25
+ )
26
+ return state_machine.set_maintenance_mode # type: ignore
27
+ return None
28
+
29
+ def release_intervention_needed_handler(
30
+ event: Event[bool],
31
+ ) -> Optional[Callable]:
32
+ if not event.consume_event():
33
+ return None
34
+
35
+ state_machine.events.api_requests.release_intervention_needed.response.trigger_event(
36
+ True
37
+ )
38
+ return state_machine.release_intervention_needed # type: ignore
39
+
40
+ def _robot_status_event_handler(
41
+ status_changed_event: Event[bool],
42
+ ) -> Optional[Callable]:
43
+ has_changed = status_changed_event.consume_event()
44
+ if not has_changed:
45
+ return None
46
+ robot_status: Optional[RobotStatus] = shared_state.robot_status.check()
47
+ if robot_status == RobotStatus.Home:
48
+ return state_machine.go_to_home # type: ignore
49
+ return None
50
+
51
+ event_handlers: List[EventHandlerMapping] = [
52
+ EventHandlerMapping(
53
+ name="return_home_event",
54
+ event=events.api_requests.return_home.request,
55
+ handler=lambda event: return_home_event_handler(state_machine, event),
56
+ ),
57
+ EventHandlerMapping(
58
+ name="release_intervention_needed_event",
59
+ event=events.api_requests.release_intervention_needed.request,
60
+ handler=release_intervention_needed_handler,
61
+ ),
62
+ EventHandlerMapping(
63
+ name="set_maintenance_mode",
64
+ event=events.api_requests.set_maintenance_mode.request,
65
+ handler=_set_maintenance_mode_event_handler,
66
+ ),
67
+ EventHandlerMapping(
68
+ name="robot_status_event",
69
+ event=events.robot_service_events.robot_status_changed,
70
+ handler=_robot_status_event_handler,
71
+ ),
72
+ ]
73
+ super().__init__(
74
+ state_name="intervention_needed",
75
+ state_machine=state_machine,
76
+ event_handler_mappings=event_handlers,
77
+ )
@@ -0,0 +1,38 @@
1
+ from typing import TYPE_CHECKING, List
2
+
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
5
+
6
+ if TYPE_CHECKING:
7
+ from isar.state_machine.state_machine import StateMachine
8
+
9
+
10
+ class Lockdown(EventHandlerBase):
11
+
12
+ def __init__(self, state_machine: "StateMachine"):
13
+ events = state_machine.events
14
+
15
+ def _release_from_lockdown_handler(event: Event[bool]):
16
+ should_release_from_lockdown: bool = event.consume_event()
17
+ if not should_release_from_lockdown:
18
+ return None
19
+
20
+ events.api_requests.release_from_lockdown.response.trigger_event(True)
21
+ if state_machine.battery_level_is_above_mission_start_threshold():
22
+ return state_machine.release_from_lockdown # type: ignore
23
+ else:
24
+ return state_machine.starting_recharging # type: ignore
25
+
26
+ event_handlers: List[EventHandlerMapping] = [
27
+ EventHandlerMapping(
28
+ name="release_from_lockdown",
29
+ event=events.api_requests.release_from_lockdown.request,
30
+ handler=_release_from_lockdown_handler,
31
+ ),
32
+ ]
33
+
34
+ super().__init__(
35
+ state_name="lockdown",
36
+ state_machine=state_machine,
37
+ event_handler_mappings=event_handlers,
38
+ )
@@ -0,0 +1,36 @@
1
+ from typing import TYPE_CHECKING, List
2
+
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
5
+
6
+ if TYPE_CHECKING:
7
+ from isar.state_machine.state_machine import StateMachine
8
+
9
+
10
+ class Maintenance(EventHandlerBase):
11
+
12
+ def __init__(self, state_machine: "StateMachine"):
13
+ events = state_machine.events
14
+
15
+ def _release_from_maintenance_handler(event: Event[bool]):
16
+ should_release_from_maintenance: bool = event.consume_event()
17
+ if should_release_from_maintenance:
18
+ events.api_requests.release_from_maintenance_mode.response.trigger_event(
19
+ True
20
+ )
21
+ return state_machine.release_from_maintenance # type: ignore
22
+ return None
23
+
24
+ event_handlers: List[EventHandlerMapping] = [
25
+ EventHandlerMapping(
26
+ name="release_from_maintenance",
27
+ event=events.api_requests.release_from_maintenance_mode.request,
28
+ handler=_release_from_maintenance_handler,
29
+ ),
30
+ ]
31
+
32
+ super().__init__(
33
+ state_name="maintenance",
34
+ state_machine=state_machine,
35
+ event_handler_mappings=event_handlers,
36
+ )