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
isar/models/events.py ADDED
@@ -0,0 +1,184 @@
1
+ from collections import deque
2
+ from queue import Empty, Queue
3
+ from typing import Generic, Optional, Tuple, TypeVar
4
+
5
+ from transitions import State
6
+
7
+ from isar.apis.models.models import (
8
+ ControlMissionResponse,
9
+ LockdownResponse,
10
+ MaintenanceResponse,
11
+ MissionStartResponse,
12
+ )
13
+ from isar.config.settings import settings
14
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
15
+ from robot_interface.models.mission.mission import Mission
16
+ from robot_interface.models.mission.status import MissionStatus, RobotStatus
17
+ from robot_interface.models.mission.task import TASKS
18
+
19
+ T = TypeVar("T")
20
+ T1 = TypeVar("T1")
21
+ T2 = TypeVar("T2")
22
+
23
+
24
+ class Event(Queue[T]):
25
+ def __init__(self, name: str) -> None:
26
+ super().__init__(maxsize=1)
27
+ self.name = name
28
+
29
+ def trigger_event(self, data: T, timeout: int = None) -> None:
30
+ try:
31
+ # We always want a timeout when blocking for results, so that
32
+ # the thread will never get stuck waiting for a result
33
+ self.put(data, block=timeout is not None, timeout=timeout)
34
+ except Exception:
35
+ if timeout is not None:
36
+ raise EventTimeoutError
37
+ return None
38
+
39
+ def consume_event(self, timeout: int = None) -> Optional[T]:
40
+ try:
41
+ return self.get(block=timeout is not None, timeout=timeout)
42
+ except Empty:
43
+ if timeout is not None:
44
+ raise EventTimeoutError
45
+ return None
46
+ except ValueError:
47
+ raise EventConflictError
48
+
49
+ def clear_event(self) -> None:
50
+ while True:
51
+ try:
52
+ self.get(block=False)
53
+ except Empty:
54
+ break
55
+ except ValueError:
56
+ break
57
+
58
+ def has_event(self) -> bool:
59
+ return (
60
+ self.qsize() != 0
61
+ ) # Queue size is not reliable, but should be sufficient for this case
62
+
63
+ def check(self) -> Optional[T]:
64
+ if not self._qsize():
65
+ return None
66
+ with self.mutex:
67
+ queueList = list(self.queue)
68
+ return queueList.pop()
69
+
70
+ def update(self, item: T):
71
+ with self.mutex:
72
+ self.queue: deque[T] = deque()
73
+ self.queue.append(item)
74
+
75
+
76
+ class Events:
77
+ def __init__(self) -> None:
78
+ self.api_requests: APIRequests = APIRequests()
79
+ self.state_machine_events: StateMachineEvents = StateMachineEvents()
80
+ self.robot_service_events: RobotServiceEvents = RobotServiceEvents()
81
+
82
+ self.upload_queue: Queue = Queue(maxsize=10)
83
+
84
+ if settings.MQTT_ENABLED:
85
+ self.mqtt_queue: Queue = Queue()
86
+
87
+
88
+ class APIEvent(Generic[T1, T2]):
89
+ """
90
+ Creates request and response event. The events are defined such that the request is from
91
+ api to state machine while the response is from state machine to api.
92
+ """
93
+
94
+ def __init__(self, name: str):
95
+ self.request: Event[T1] = Event("api-" + name + "-request")
96
+ self.response: Event[T2] = Event("api-" + name + "-request")
97
+
98
+
99
+ class APIRequests:
100
+ def __init__(self) -> None:
101
+ self.start_mission: APIEvent[Mission, MissionStartResponse] = APIEvent(
102
+ "start_mission"
103
+ )
104
+ self.stop_mission: APIEvent[str, ControlMissionResponse] = APIEvent(
105
+ "stop_mission"
106
+ )
107
+ self.pause_mission: APIEvent[bool, ControlMissionResponse] = APIEvent(
108
+ "pause_mission"
109
+ )
110
+ self.resume_mission: APIEvent[bool, ControlMissionResponse] = APIEvent(
111
+ "resume_mission"
112
+ )
113
+ self.return_home: APIEvent[bool, bool] = APIEvent("return_home")
114
+ self.release_intervention_needed: APIEvent[bool, bool] = APIEvent(
115
+ "release_intervention_needed"
116
+ )
117
+ self.send_to_lockdown: APIEvent[bool, LockdownResponse] = APIEvent(
118
+ "send_to_lockdown"
119
+ )
120
+ self.release_from_lockdown: APIEvent[bool, bool] = APIEvent(
121
+ "release_from_lockdown"
122
+ )
123
+ self.set_maintenance_mode: APIEvent[bool, MaintenanceResponse] = APIEvent(
124
+ "set_maintenance_mode"
125
+ )
126
+ self.release_from_maintenance_mode: APIEvent[bool, bool] = APIEvent(
127
+ "release_from_maintenance_mode"
128
+ )
129
+
130
+
131
+ class StateMachineEvents:
132
+ def __init__(self) -> None:
133
+ self.start_mission: Event[Mission] = Event("start_mission")
134
+ self.stop_mission: Event[bool] = Event("stop_mission")
135
+ self.pause_mission: Event[bool] = Event("pause_mission")
136
+ self.resume_mission: Event[bool] = Event("resume_mission")
137
+
138
+
139
+ class RobotServiceEvents:
140
+ def __init__(self) -> None:
141
+ self.mission_status_updated: Event[MissionStatus] = Event(
142
+ "mission_status_updated"
143
+ )
144
+ self.mission_started: Event[bool] = Event("mission_started")
145
+ self.mission_failed: Event[ErrorMessage] = Event("mission_failed")
146
+ self.robot_status_changed: Event[bool] = Event("robot_status_changed")
147
+ self.mission_failed_to_stop: Event[ErrorMessage] = Event(
148
+ "mission_failed_to_stop"
149
+ )
150
+ self.mission_successfully_stopped: Event[bool] = Event(
151
+ "mission_successfully_stopped"
152
+ )
153
+ self.mission_failed_to_pause: Event[ErrorMessage] = Event(
154
+ "mission_failed_to_pause"
155
+ )
156
+ self.mission_successfully_paused: Event[bool] = Event(
157
+ "mission_successfully_paused"
158
+ )
159
+ self.mission_failed_to_resume: Event[ErrorMessage] = Event(
160
+ "mission_failed_to_resume"
161
+ )
162
+ self.mission_successfully_resumed: Event[bool] = Event(
163
+ "mission_successfully_resumed"
164
+ )
165
+ self.request_inspection_upload: Event[Tuple[TASKS, Mission]] = Event(
166
+ "request_inspection_upload"
167
+ )
168
+ self.robot_already_home: Event[bool] = Event("robot_already_home")
169
+
170
+
171
+ class SharedState:
172
+ def __init__(self) -> None:
173
+ self.state: Event[State] = Event("state")
174
+ self.robot_status: Event[RobotStatus] = Event("robot_status")
175
+ self.robot_battery_level: Event[float] = Event("robot_battery_level")
176
+ self.mission_id: Event[Optional[str]] = Event("mission_id")
177
+
178
+
179
+ class EventTimeoutError(Exception):
180
+ pass
181
+
182
+
183
+ class EventConflictError(Exception):
184
+ pass
isar/models/status.py ADDED
@@ -0,0 +1,18 @@
1
+ from enum import Enum
2
+
3
+
4
+ class IsarStatus(Enum):
5
+ Available = "available"
6
+ ReturnHomePaused = "returnhomepaused"
7
+ Paused = "paused"
8
+ Busy = "busy"
9
+ Home = "home"
10
+ Offline = "offline"
11
+ BlockedProtectiveStop = "blockedprotectivestop"
12
+ ReturningHome = "returninghome"
13
+ InterventionNeeded = "interventionneeded"
14
+ Recharging = "recharging"
15
+ Lockdown = "lockdown"
16
+ GoingToLockdown = "goingtolockdown"
17
+ GoingToRecharging = "goingtorecharging"
18
+ Maintenance = "maintenance"
isar/modules.py CHANGED
@@ -1,214 +1,133 @@
1
- import logging
1
+ import os
2
2
  from importlib import import_module
3
- from logging import Logger
4
- from types import ModuleType
5
- from typing import Dict, List, Tuple, Union
6
3
 
7
- from injector import Injector, Module, multiprovider, provider, singleton
4
+ from dependency_injector import containers, providers
8
5
 
9
6
  from isar.apis.api import API
7
+ from isar.apis.robot_control.robot_controller import RobotController
10
8
  from isar.apis.schedule.scheduling_controller import SchedulingController
11
9
  from isar.apis.security.authentication import Authenticator
12
10
  from isar.config.keyvault.keyvault_service import Keyvault
13
11
  from isar.config.settings import settings
14
12
  from isar.mission_planner.local_planner import LocalPlanner
15
- from isar.mission_planner.mission_planner_interface import MissionPlannerInterface
16
- from isar.mission_planner.sequential_task_selector import SequentialTaskSelector
17
- from isar.mission_planner.task_selector_interface import TaskSelectorInterface
18
- from isar.models.communication.queues.queues import Queues
19
- from isar.services.service_connections.request_handler import RequestHandler
13
+ from isar.models.events import Events, SharedState
14
+ from isar.robot.robot import Robot
15
+ from isar.services.utilities.robot_utilities import RobotUtilities
20
16
  from isar.services.utilities.scheduling_utilities import SchedulingUtilities
21
17
  from isar.state_machine.state_machine import StateMachine
22
18
  from isar.storage.blob_storage import BlobStorage
23
19
  from isar.storage.local_storage import LocalStorage
24
- from isar.storage.slimm_storage import SlimmStorage
25
- from isar.storage.storage_interface import StorageInterface
26
20
  from isar.storage.uploader import Uploader
27
- from robot_interface.robot_interface import RobotInterface
28
- from robot_interface.telemetry.mqtt_client import MqttClientInterface, MqttPublisher
29
-
30
-
31
- class APIModule(Module):
32
- @provider
33
- @singleton
34
- def provide_api(
35
- self,
36
- authenticator: Authenticator,
37
- scheduling_controller: SchedulingController,
38
- keyvault: Keyvault,
39
- ) -> API:
40
- return API(authenticator, scheduling_controller, keyvault)
41
-
42
- @provider
43
- @singleton
44
- def provide_scheduling_controller(
45
- self,
46
- scheduling_utilities: SchedulingUtilities,
47
- ) -> SchedulingController:
48
- return SchedulingController(scheduling_utilities)
49
-
50
-
51
- class AuthenticationModule(Module):
52
- @provider
53
- @singleton
54
- def provide_authenticator(self) -> Authenticator:
55
- return Authenticator()
56
-
57
-
58
- class RobotModule(Module):
59
- @provider
60
- @singleton
61
- def provide_robot_interface(self) -> RobotInterface:
62
- robot_package_name: str = settings.ROBOT_PACKAGE
63
- robot: ModuleType = import_module(robot_package_name)
64
- return robot.robotinterface.Robot() # type: ignore
65
-
66
-
67
- class QueuesModule(Module):
68
- @provider
69
- @singleton
70
- def provide_queues(self) -> Queues:
71
- return Queues()
72
-
73
-
74
- class RequestHandlerModule(Module):
75
- @provider
76
- @singleton
77
- def provide_request_handler(self) -> RequestHandler:
78
- return RequestHandler()
79
-
80
-
81
- class BlobStorageModule(Module):
82
- @multiprovider
83
- @singleton
84
- def provide_blob_storage(self, keyvault: Keyvault) -> List[StorageInterface]:
85
- return [BlobStorage(keyvault)]
86
-
87
-
88
- class LocalStorageModule(Module):
89
- @multiprovider
90
- @singleton
91
- def provide_local_storage(self) -> List[StorageInterface]:
92
- return [LocalStorage()]
93
-
94
-
95
- class SlimmStorageModule(Module):
96
- @multiprovider
97
- @singleton
98
- def provide_slimm_storage(
99
- self, request_handler: RequestHandler
100
- ) -> List[StorageInterface]:
101
- return [SlimmStorage(request_handler=request_handler)]
102
-
103
-
104
- class LocalPlannerModule(Module):
105
- @provider
106
- @singleton
107
- def provide_local_planner(self) -> MissionPlannerInterface:
108
- return LocalPlanner()
109
-
110
-
111
- class StateMachineModule(Module):
112
- @provider
113
- @singleton
114
- def provide_state_machine(
115
- self,
116
- queues: Queues,
117
- robot: RobotInterface,
118
- mqtt_client: MqttClientInterface,
119
- task_selector: TaskSelectorInterface,
120
- ) -> StateMachine:
121
- return StateMachine(
122
- queues=queues,
123
- robot=robot,
124
- mqtt_publisher=mqtt_client,
125
- task_selector=task_selector,
21
+ from robot_interface.telemetry.mqtt_client import MqttPublisher
22
+
23
+
24
+ class ApplicationContainer(containers.DeclarativeContainer):
25
+ config = providers.Configuration(pydantic_settings=[settings])
26
+
27
+ # Core services
28
+ keyvault = providers.Singleton(
29
+ Keyvault,
30
+ keyvault_name=settings.KEYVAULT_NAME,
31
+ client_id=settings.AZURE_CLIENT_ID,
32
+ client_secret=os.environ.get("AZURE_CLIENT_SECRET"),
33
+ tenant_id=settings.AZURE_TENANT_ID,
34
+ )
35
+
36
+ # Events and shared state
37
+ events = providers.Singleton(Events)
38
+ shared_state = providers.Singleton(SharedState)
39
+
40
+ # Robot-related services
41
+ robot_interface = providers.Singleton(
42
+ lambda: import_module(f"{settings.ROBOT_PACKAGE}.robotinterface").Robot()
43
+ )
44
+ robot_utilities = providers.Singleton(RobotUtilities, robot=robot_interface)
45
+
46
+ # Mqtt client
47
+ mqtt_client = (
48
+ providers.Singleton(
49
+ MqttPublisher,
50
+ mqtt_queue=providers.Callable(events.provided.mqtt_queue),
126
51
  )
127
-
128
-
129
- class UploaderModule(Module):
130
- @provider
131
- @singleton
132
- def provide_uploader(
133
- self,
134
- queues: Queues,
135
- storage_handlers: List[StorageInterface],
136
- mqtt_client: MqttClientInterface,
137
- ) -> Uploader:
138
- return Uploader(
139
- queues=queues,
140
- storage_handlers=storage_handlers,
141
- mqtt_publisher=mqtt_client,
142
- )
143
-
144
-
145
- class UtilitiesModule(Module):
146
- @provider
147
- @singleton
148
- def provide_scheduling_utilities(
149
- self, queues: Queues, mission_planner: MissionPlannerInterface
150
- ) -> SchedulingUtilities:
151
- return SchedulingUtilities(queues, mission_planner)
152
-
153
-
154
- class ServiceModule(Module):
155
- @provider
156
- @singleton
157
- def provide_keyvault(self) -> Keyvault:
158
- return Keyvault(keyvault_name=settings.KEYVAULT_NAME)
159
-
160
-
161
- class MqttModule(Module):
162
- @provider
163
- @singleton
164
- def provide_mqtt_client(self, queues: Queues) -> MqttClientInterface:
165
- if settings.MQTT_ENABLED:
166
- return MqttPublisher(mqtt_queue=queues.mqtt_queue)
167
- return None
168
-
169
-
170
- class SequentialTaskSelectorModule(Module):
171
- @provider
172
- @singleton
173
- def provide_task_selector(self) -> TaskSelectorInterface:
174
- return SequentialTaskSelector()
175
-
176
-
177
- modules: Dict[str, Tuple[Module, Union[str, bool]]] = {
178
- "api": (APIModule, "required"),
179
- "authentication": (AuthenticationModule, "required"),
180
- "queues": (QueuesModule, "required"),
181
- "request_handler": (RequestHandlerModule, "required"),
182
- "robot_package": (RobotModule, settings.ROBOT_PACKAGE),
183
- "isar_id": (RobotModule, settings.ISAR_ID),
184
- "robot_name": (RobotModule, settings.ROBOT_NAME),
185
- "mission_planner": (LocalPlannerModule, settings.MISSION_PLANNER),
186
- "task_selector": (
187
- {"sequential": SequentialTaskSelectorModule}[settings.TASK_SELECTOR],
188
- settings.TASK_SELECTOR,
189
- ),
190
- "service": (ServiceModule, "required"),
191
- "state_machine": (StateMachineModule, "required"),
192
- "storage_local": (LocalStorageModule, settings.STORAGE_LOCAL_ENABLED),
193
- "storage_blob": (BlobStorageModule, settings.STORAGE_BLOB_ENABLED),
194
- "storage_slimm": (SlimmStorageModule, settings.STORAGE_SLIMM_ENABLED),
195
- "mqtt": (MqttModule, "required"),
196
- "utilities": (UtilitiesModule, "required"),
197
- }
198
-
199
-
200
- def get_injector() -> Injector:
201
- injector_modules: List[Module] = []
202
- module_overview: str = ""
203
-
204
- for category, (module, config_option) in modules.items():
205
- if config_option:
206
- injector_modules.append(module)
207
- module_overview += (
208
- f"\n {category:<15} : {config_option:<20} ({module.__name__})"
209
- )
210
-
211
- logger: Logger = logging.getLogger("modules")
212
- logger.info(f"Loaded the following module configurations:{module_overview}")
213
-
214
- return Injector(injector_modules)
52
+ if settings.MQTT_ENABLED
53
+ else None
54
+ )
55
+
56
+ # API and controllers
57
+ authenticator = providers.Singleton(Authenticator)
58
+ scheduling_utilities = providers.Singleton(
59
+ SchedulingUtilities,
60
+ events=events,
61
+ shared_state=shared_state,
62
+ mission_planner=providers.Singleton(LocalPlanner),
63
+ )
64
+ scheduling_controller = providers.Singleton(
65
+ SchedulingController, scheduling_utilities=scheduling_utilities
66
+ )
67
+ robot_controller = providers.Singleton(
68
+ RobotController, robot_utilities=robot_utilities
69
+ )
70
+ api = providers.Singleton(
71
+ API,
72
+ authenticator=authenticator,
73
+ scheduling_controller=scheduling_controller,
74
+ robot_controller=robot_controller,
75
+ keyvault=keyvault,
76
+ mqtt_publisher=mqtt_client,
77
+ )
78
+
79
+ # Storage
80
+ storage_handlers_temp = []
81
+ if settings.STORAGE_LOCAL_ENABLED:
82
+ local_storage = providers.Singleton(LocalStorage)
83
+ storage_handlers_temp.append(local_storage)
84
+ if settings.STORAGE_BLOB_ENABLED:
85
+ blob_storage = providers.Singleton(BlobStorage, keyvault=keyvault)
86
+ storage_handlers_temp.append(blob_storage)
87
+ storage_handlers = providers.List(*storage_handlers_temp)
88
+
89
+ # State machine
90
+ state_machine = providers.Singleton(
91
+ StateMachine,
92
+ events=events,
93
+ shared_state=shared_state,
94
+ robot=robot_interface,
95
+ mqtt_publisher=mqtt_client,
96
+ )
97
+
98
+ # Robot
99
+ robot = providers.Singleton(
100
+ Robot,
101
+ events=events,
102
+ robot=robot_interface,
103
+ shared_state=shared_state,
104
+ mqtt_publisher=mqtt_client,
105
+ )
106
+
107
+ # Uploader
108
+ uploader = providers.Singleton(
109
+ Uploader,
110
+ events=events,
111
+ storage_handlers=storage_handlers,
112
+ mqtt_publisher=mqtt_client,
113
+ )
114
+
115
+
116
+ def get_injector() -> ApplicationContainer:
117
+ container = ApplicationContainer()
118
+ container.init_resources()
119
+ container.wire(modules=[__name__])
120
+ container.config.from_dict(
121
+ {
122
+ "KEYVAULT_NAME": settings.KEYVAULT_NAME,
123
+ "MQTT_ENABLED": settings.MQTT_ENABLED,
124
+ }
125
+ )
126
+
127
+ print("Loaded the following module configurations:")
128
+ for provider_name, provider in container.providers.items():
129
+ provider_repr = repr(provider)
130
+ simplified_provider = provider_repr.split(".")[-1].split(">")[0]
131
+ print(f" {provider_name:<20}: {simplified_provider}")
132
+
133
+ return container