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,13 +1,13 @@
1
1
  from abc import ABCMeta, abstractmethod
2
2
  from queue import Queue
3
3
  from threading import Thread
4
- from typing import List, Sequence
4
+ from typing import Callable, List, Optional
5
5
 
6
- from robot_interface.models.initialize import InitializeParams
7
6
  from robot_interface.models.inspection.inspection import Inspection
8
7
  from robot_interface.models.mission.mission import Mission
9
- from robot_interface.models.mission.status import MissionStatus, RobotStatus, StepStatus
10
- from robot_interface.models.mission.step import InspectionStep, Step
8
+ from robot_interface.models.mission.status import MissionStatus, RobotStatus, TaskStatus
9
+ from robot_interface.models.mission.task import InspectionTask
10
+ from robot_interface.models.robots.media import MediaConfig
11
11
 
12
12
 
13
13
  class RobotInterface(metaclass=ABCMeta):
@@ -17,10 +17,6 @@ class RobotInterface(metaclass=ABCMeta):
17
17
  def initiate_mission(self, mission: Mission) -> None:
18
18
  """Send a mission to the robot and initiate execution of the mission
19
19
 
20
- This function should be used in combination with the mission_status function
21
- if the robot is designed to run full missions and not in a stepwise
22
- configuration.
23
-
24
20
  Parameters
25
21
  ----------
26
22
  mission: Mission
@@ -31,55 +27,66 @@ class RobotInterface(metaclass=ABCMeta):
31
27
 
32
28
  Raises
33
29
  ------
30
+ RobotAlreadyHomeException
31
+ If the mission is a return home mission and the robot wish to disregard the
32
+ mission as it is already at home
34
33
  RobotInfeasibleMissionException
35
34
  If the mission input is infeasible and the mission fails to be scheduled in
36
35
  a way that means attempting to schedule again is not necessary
37
36
  RobotException
38
37
  Will catch all RobotExceptions not previously listed and retry scheduling of
39
38
  the mission until the number of allowed retries is exceeded
40
- NotImplementedError
41
- If the robot is designed for stepwise mission execution
42
39
 
43
40
  """
44
41
  raise NotImplementedError
45
42
 
46
- def mission_status(self) -> MissionStatus:
47
- """Gets the status of the currently active mission on the robot
43
+ @abstractmethod
44
+ def task_status(self, task_id: str) -> TaskStatus:
45
+ """Gets the status of the currently active task on robot.
46
+
47
+ Returns
48
+ -------
49
+ TaskStatus
50
+ Status of the execution of current task.
51
+
52
+ Raises
53
+ ------
54
+ RobotCommunicationTimeoutException or RobotCommunicationException
55
+ If the robot package is unable to communicate with the robot API the fetching
56
+ of task status will be attempted again until a certain number of retries
57
+ RobotTaskStatusException
58
+ If there was an error when retrieving the task status
59
+ RobotException
60
+ If the task status could not be retrieved.
61
+
62
+ """
63
+ raise NotImplementedError
48
64
 
49
- This function should be used in combination with the initiate_mission function
50
- if the robot is designed to run full missions and not in a stepwise
51
- configuration.
65
+ @abstractmethod
66
+ def mission_status(self, mission_id: str) -> MissionStatus:
67
+ """Gets the status of the mission with ID mission_id on robot.
52
68
 
53
69
  Returns
54
70
  -------
55
71
  MissionStatus
56
- Status of the executing mission on the robot.
72
+ Status of the execution of mission.
57
73
 
58
74
  Raises
59
75
  ------
76
+ RobotCommunicationTimeoutException or RobotCommunicationException
77
+ If the robot package is unable to communicate with the robot API the fetching
78
+ of mission status will be attempted again until a certain number of retries
60
79
  RobotMissionStatusException
61
- If the mission status could not be collected this will lead to the mission
62
- being marked as failed
80
+ If there was an error when retrieving the mission status
63
81
  RobotException
64
- An uncaught RobotException in the robot package while retrieving the status
65
- will cause the mission to be marked as failed
66
- NotImplementedError
67
- If the robot is designed for stepwise mission execution
82
+ If the mission status could not be retrieved.
68
83
 
69
84
  """
85
+ raise NotImplementedError
70
86
 
71
87
  @abstractmethod
72
- def initiate_step(self, step: Step) -> None:
73
- """Send a step to the robot and initiate the execution of the step
74
-
75
- This function should be used in combination with the step_status function
76
- if the robot is designed to run stepwise missions and not in a full mission
77
- configuration.
78
-
79
- Parameters
80
- ----------
81
- step : Step
82
- The step that should be initiated on the robot.
88
+ def stop(self) -> None:
89
+ """Stops the execution of the current task and corresponding mission.
83
90
 
84
91
  Returns
85
92
  -------
@@ -87,45 +94,37 @@ class RobotInterface(metaclass=ABCMeta):
87
94
 
88
95
  Raises
89
96
  ------
90
- RobotInfeasibleStepException
91
- If the step input is infeasible and the step fails to be scheduled in
92
- a way that means attempting to schedule again is not necessary
97
+ RobotActionException
98
+ If the robot fails to perform the requested action to stop mission execution
99
+ the action to stop will be attempted again until a certain number of retries
93
100
  RobotException
94
- Will catch all RobotExceptions not previously listed and retry scheduling
95
- of the step until the number of allowed retries is exceeded before the step
96
- will be marked as failed and the mission cancelled
97
- NotImplementedError
98
- If the robot is designed for full mission execution.
101
+ Will catch other RobotExceptions and retry to stop the mission
99
102
 
100
103
  """
101
104
  raise NotImplementedError
102
105
 
103
106
  @abstractmethod
104
- def step_status(self) -> StepStatus:
105
- """Gets the status of the currently active step on robot.
106
-
107
- This function should be used in combination with the initiate_step function
108
- if the robot is designed to run stepwise missions and not in a full mission
109
- configuration.
107
+ def pause(self) -> None:
108
+ """Pauses the execution of the current task and stops the movement of the robot.
110
109
 
111
110
  Returns
112
111
  -------
113
- StepStatus
114
- Status of the execution of current step.
112
+ None
115
113
 
116
114
  Raises
117
115
  ------
116
+ RobotActionException
117
+ If the robot fails to perform the requested action to pause mission execution
118
+ the action to pause will be attempted again until a certain number of retries
118
119
  RobotException
119
- If the step status could not be retrieved.
120
- NotImplementedError
121
- If the robot is designed for full mission execution.
120
+ Will catch other RobotExceptions and retry to pause the mission
122
121
 
123
122
  """
124
123
  raise NotImplementedError
125
124
 
126
125
  @abstractmethod
127
- def stop(self) -> None:
128
- """Stops the execution of the current step and stops the movement of the robot.
126
+ def resume(self) -> None:
127
+ """Resumes the execution of the current task and continues the rest of the mission.
129
128
 
130
129
  Returns
131
130
  -------
@@ -134,32 +133,34 @@ class RobotInterface(metaclass=ABCMeta):
134
133
  Raises
135
134
  ------
136
135
  RobotActionException
137
- If the robot fails to perform the requested action to stop mission execution
138
- the action to stop will be attempted again until a certain number of retries
136
+ If the robot fails to perform the requested action to resume mission execution
137
+ the action to resume will be attempted again until a certain number of retries
139
138
  RobotException
140
- Will catch other RobotExceptions and retry to stop the mission
139
+ Will catch other RobotExceptions and retry to resume the mission
141
140
 
142
141
  """
143
142
  raise NotImplementedError
144
143
 
145
144
  @abstractmethod
146
- def get_inspections(self, step: InspectionStep) -> Sequence[Inspection]:
147
- """Return the inspections connected to the given step.
145
+ def get_inspection(self, task: InspectionTask) -> Inspection:
146
+ """Return the inspection connected to the given task.
148
147
 
149
148
  Parameters
150
149
  ----------
151
- step : Step
150
+ task : InspectionTask
152
151
 
153
152
  Returns
154
153
  -------
155
- Sequence[InspectionResult]
156
- List containing all the inspection results connected to the given step
154
+ Inspection
155
+ The inspection connected to the given task.
156
+ get_inspection has responsibility to assign the inspection_id of the task
157
+ to the inspection that it returns.
157
158
 
158
159
  Raises
159
160
  ------
160
161
  RobotRetrieveInspectionException
161
162
  If the robot package is unable to retrieve the inspections for the relevant
162
- mission or step an error message is logged and the state machine continues
163
+ mission or task an error message is logged and the state machine continues
163
164
  RobotException
164
165
  Catches other RobotExceptions that lead to the same result as a
165
166
  RobotRetrieveInspectionException
@@ -168,27 +169,33 @@ class RobotInterface(metaclass=ABCMeta):
168
169
  raise NotImplementedError
169
170
 
170
171
  @abstractmethod
171
- def initialize(self, params: InitializeParams) -> None:
172
- """Initializes the robot. The initialization needed is robot dependent and the
173
- function can be a simple return statement if no initialization is needed for the
174
- robot.
172
+ def register_inspection_callback(
173
+ self, callback_function: Callable[[Inspection, Mission], None]
174
+ ) -> None:
175
+ """Register a function which should be run when inspection data is received
176
+ asynchronously. This function should expect to receive an Inspection from.
175
177
 
176
178
  Parameters
177
179
  ----------
178
- params: InitializeParams
180
+ callback_function : Callable[[Inspection, Mission], None]
179
181
 
180
182
  Returns
181
183
  -------
182
184
  None
183
185
 
184
- Raises
185
- ------
186
- RobotInitializeException
187
- If the robot package is unable to initialize the robot correctly the mission
188
- will be cancelled
189
- RobotException
190
- Catches other RobotExceptions that might have occurred during initialization
191
- where the result is that the mission is cancelled
186
+ """
187
+ raise NotImplementedError
188
+
189
+ @abstractmethod
190
+ def generate_media_config(self) -> Optional[MediaConfig]:
191
+ """
192
+ Generate a JSON containing the url and token needed to establish a media stream
193
+ connection to a robot.
194
+
195
+ Returns
196
+ -------
197
+ MediaConfig
198
+ An object containing the connection information for a media stream connection
192
199
 
193
200
  """
194
201
  raise NotImplementedError
@@ -212,16 +219,14 @@ class RobotInterface(metaclass=ABCMeta):
212
219
  -------
213
220
  List[Thread]
214
221
  List containing all threads that will be started to publish telemetry.
222
+
215
223
  """
216
224
  raise NotImplementedError
217
225
 
218
226
  @abstractmethod
219
227
  def robot_status(self) -> RobotStatus:
220
228
  """
221
- Method which returns an enum indicating if the robot package is able to reach
222
- the interface which is used to communicate with the robot. This is further used
223
- by ISAR to indicate whether the ISAR instance is fully functional and may be
224
- used by other systems.
229
+ Method which returns an enum indicating the status of the robot.
225
230
 
226
231
  Returns
227
232
  -------
@@ -231,13 +236,43 @@ class RobotInterface(metaclass=ABCMeta):
231
236
  Raises
232
237
  -------
233
238
  RobotCommunicationException
234
- Raised if the robot package is unable to communicate with the robot API
239
+ Raised if the robot package is unable to communicate with the robot API.
240
+ The fetching of robot status will be attempted again until success
241
+ RobotAPIException
242
+ Raised if the robot package is able to communicate with the API but an error
243
+ occurred while interpreting the response. The fetching of robot status will
244
+ be attempted again until success
245
+ RobotException
246
+ Catches other RobotExceptions that may have occurred while retrieving the
247
+ robot status. The fetching of robot status will be attempted again until
248
+ success
249
+
250
+ """
251
+ raise NotImplementedError
252
+
253
+ @abstractmethod
254
+ def get_battery_level(self) -> float:
255
+ """
256
+ Method which returns the percent charge remaining in the robot battery.
257
+
258
+ Returns
259
+ -------
260
+ float
261
+ The battery percentage on the robot
262
+
263
+ Raises
264
+ -------
265
+ RobotCommunicationException
266
+ Raised if the robot package is unable to communicate with the robot API.
267
+ The fetching of robot battery level will be attempted again until success
235
268
  RobotAPIException
236
269
  Raised if the robot package is able to communicate with the API but an error
237
- occurred while interpreting the response
270
+ occurred while interpreting the response. The fetching of robot battery level
271
+ will be attempted again until success
238
272
  RobotException
239
273
  Catches other RobotExceptions that may have occurred while retrieving the
240
- robot status
241
- At this point ISAR will attempt to request the robot status again
274
+ robot battery level. The fetching of robot battery level will
275
+ be attempted again until success
276
+
242
277
  """
243
278
  raise NotImplementedError
@@ -1,19 +1,38 @@
1
1
  import json
2
2
  import time
3
3
  from abc import ABCMeta, abstractmethod
4
- from datetime import UTC, datetime
4
+ from datetime import datetime, timezone
5
5
  from queue import Queue
6
6
  from typing import Callable, Tuple
7
7
 
8
- from robot_interface.models.exceptions.robot_exceptions import RobotTelemetryException
8
+ from paho.mqtt.packettypes import PacketTypes
9
+ from paho.mqtt.properties import Properties
10
+
11
+ from isar.config.settings import settings
12
+ from robot_interface.models.exceptions.robot_exceptions import (
13
+ RobotTelemetryException,
14
+ RobotTelemetryNoUpdateException,
15
+ RobotTelemetryPoseException,
16
+ )
9
17
  from robot_interface.telemetry.payloads import CloudHealthPayload
10
18
  from robot_interface.utilities.json_service import EnhancedJSONEncoder
11
19
 
12
20
 
21
+ def props_expiry(seconds: int) -> Properties:
22
+ p = Properties(PacketTypes.PUBLISH)
23
+ p.MessageExpiryInterval = seconds
24
+ return p
25
+
26
+
13
27
  class MqttClientInterface(metaclass=ABCMeta):
14
28
  @abstractmethod
15
29
  def publish(
16
- self, topic: str, payload: str, qos: int = 0, retain: bool = False
30
+ self,
31
+ topic: str,
32
+ payload: str,
33
+ qos: int = 0,
34
+ retain: bool = False,
35
+ properties: Properties = None,
17
36
  ) -> None:
18
37
  """
19
38
  Parameters
@@ -29,7 +48,6 @@ class MqttClientInterface(metaclass=ABCMeta):
29
48
 
30
49
  Returns
31
50
  -------
32
-
33
51
  """
34
52
  pass
35
53
 
@@ -39,9 +57,20 @@ class MqttPublisher(MqttClientInterface):
39
57
  self.mqtt_queue: Queue = mqtt_queue
40
58
 
41
59
  def publish(
42
- self, topic: str, payload: str, qos: int = 0, retain: bool = False
60
+ self,
61
+ topic: str,
62
+ payload: str,
63
+ qos: int = 0,
64
+ retain: bool = False,
65
+ properties: Properties = None,
43
66
  ) -> None:
44
- queue_message: Tuple[str, str, int, bool] = (topic, payload, qos, retain)
67
+ queue_message: Tuple[str, str, int, bool, Properties] = (
68
+ topic,
69
+ payload,
70
+ qos,
71
+ retain,
72
+ properties,
73
+ )
45
74
  self.mqtt_queue.put(queue_message)
46
75
 
47
76
 
@@ -54,6 +83,7 @@ class MqttTelemetryPublisher(MqttClientInterface):
54
83
  interval: float,
55
84
  qos: int = 0,
56
85
  retain: bool = False,
86
+ properties: Properties = None,
57
87
  ) -> None:
58
88
  self.mqtt_queue: Queue = mqtt_queue
59
89
  self.telemetry_method: Callable = telemetry_method
@@ -61,9 +91,13 @@ class MqttTelemetryPublisher(MqttClientInterface):
61
91
  self.interval: float = interval
62
92
  self.qos: int = qos
63
93
  self.retain: bool = retain
94
+ self.properties: Properties = properties
64
95
 
65
96
  def run(self, isar_id: str, robot_name: str) -> None:
66
- self.cloud_healt_topic: str = f"isar/{isar_id}/cloud_health"
97
+ self.cloud_health_topic: str = f"isar/{isar_id}/cloud_health"
98
+ self.battery_topic: str = f"isar/{isar_id}/battery"
99
+ self.pose_topic: str = f"isar/{isar_id}/pose"
100
+ self.pressure_topic: str = f"isar/{isar_id}/pressure"
67
101
  topic: str
68
102
  payload: str
69
103
 
@@ -71,19 +105,47 @@ class MqttTelemetryPublisher(MqttClientInterface):
71
105
  try:
72
106
  payload = self.telemetry_method(isar_id=isar_id, robot_name=robot_name)
73
107
  topic = self.topic
108
+ except (RobotTelemetryPoseException, RobotTelemetryNoUpdateException):
109
+ time.sleep(self.interval)
110
+ continue
74
111
  except RobotTelemetryException:
75
112
  payload = json.dumps(
76
- CloudHealthPayload(isar_id, robot_name, datetime.now(UTC)),
113
+ CloudHealthPayload(isar_id, robot_name, datetime.now(timezone.utc)),
77
114
  cls=EnhancedJSONEncoder,
78
115
  )
79
- topic = self.cloud_healt_topic
116
+ topic = self.cloud_health_topic
117
+
118
+ publish_properties = self.properties
80
119
 
81
- self.publish(topic=topic, payload=payload, qos=self.qos, retain=self.retain)
120
+ if topic in (
121
+ self.battery_topic,
122
+ self.pose_topic,
123
+ self.pressure_topic,
124
+ ):
125
+ publish_properties = props_expiry(settings.MQTT_TELEMETRY_EXPIRY)
82
126
 
127
+ self.publish(
128
+ topic=topic,
129
+ payload=payload,
130
+ qos=self.qos,
131
+ retain=self.retain,
132
+ properties=publish_properties,
133
+ )
83
134
  time.sleep(self.interval)
84
135
 
85
136
  def publish(
86
- self, topic: str, payload: str, qos: int = 0, retain: bool = False
137
+ self,
138
+ topic: str,
139
+ payload: str,
140
+ qos: int = 0,
141
+ retain: bool = False,
142
+ properties: Properties = None,
87
143
  ) -> None:
88
- queue_message: Tuple[str, str, int, bool] = (topic, payload, qos, retain)
144
+ queue_message: Tuple[str, str, int, bool, Properties] = (
145
+ topic,
146
+ payload,
147
+ qos,
148
+ retain,
149
+ properties,
150
+ )
89
151
  self.mqtt_queue.put(queue_message)
@@ -1,11 +1,15 @@
1
1
  from dataclasses import dataclass
2
2
  from datetime import datetime
3
- from typing import List
3
+ from typing import List, Optional
4
4
 
5
5
  from alitra import Pose
6
- from transitions import State
7
6
 
8
- from robot_interface.models.mission.status import RobotStatus
7
+ from isar.models.status import IsarStatus
8
+ from isar.storage.storage_interface import BlobStoragePath
9
+ from robot_interface.models.exceptions.robot_exceptions import ErrorReason
10
+ from robot_interface.models.mission.status import MissionStatus, TaskStatus
11
+ from robot_interface.models.mission.task import TaskTypes
12
+ from robot_interface.models.robots.battery_state import BatteryState
9
13
 
10
14
 
11
15
  @dataclass
@@ -30,6 +34,7 @@ class TelemetryPosePayload(TelemetryPayload):
30
34
  @dataclass
31
35
  class TelemetryBatteryPayload(TelemetryPayload):
32
36
  battery_level: float
37
+ battery_state: Optional[BatteryState] = None
33
38
 
34
39
 
35
40
  @dataclass
@@ -43,22 +48,16 @@ class TelemetryPressurePayload(TelemetryPayload):
43
48
 
44
49
 
45
50
  @dataclass
46
- class VideoStream:
51
+ class DocumentInfo:
47
52
  name: str
48
53
  url: str
49
- type: str
50
54
 
51
55
 
52
56
  @dataclass
53
- class RobotStatusPayload:
57
+ class IsarStatusPayload:
54
58
  isar_id: str
55
59
  robot_name: str
56
- robot_status: RobotStatus
57
- previous_robot_status: RobotStatus
58
- current_isar_state: State
59
- current_mission_id: str
60
- current_task_id: str
61
- current_step_id: str
60
+ status: IsarStatus
62
61
  timestamp: datetime
63
62
 
64
63
 
@@ -69,7 +68,7 @@ class RobotInfoPayload:
69
68
  robot_model: str
70
69
  robot_serial_number: str
71
70
  robot_asset: str
72
- video_streams: List[VideoStream]
71
+ documentation: List[DocumentInfo]
73
72
  host: str
74
73
  port: int
75
74
  capabilities: List[str]
@@ -81,3 +80,82 @@ class RobotHeartbeatPayload:
81
80
  isar_id: str
82
81
  robot_name: str
83
82
  timestamp: datetime
83
+
84
+
85
+ @dataclass
86
+ class MissionPayload:
87
+ isar_id: str
88
+ robot_name: str
89
+ mission_id: Optional[str]
90
+ status: Optional[MissionStatus]
91
+ error_reason: Optional[ErrorReason]
92
+ error_description: Optional[str]
93
+ timestamp: datetime
94
+
95
+
96
+ @dataclass
97
+ class MissionAbortedPayload:
98
+ isar_id: str
99
+ robot_name: str
100
+ mission_id: str
101
+ can_be_continued: bool
102
+ timestamp: datetime
103
+ reason: Optional[str]
104
+
105
+
106
+ @dataclass
107
+ class TaskPayload:
108
+ isar_id: str
109
+ robot_name: str
110
+ mission_id: Optional[str]
111
+ task_id: Optional[str]
112
+ status: Optional[TaskStatus]
113
+ task_type: Optional[TaskTypes]
114
+ error_reason: Optional[ErrorReason]
115
+ error_description: Optional[str]
116
+ timestamp: datetime
117
+
118
+
119
+ @dataclass
120
+ class InspectionResultPayload:
121
+ isar_id: str
122
+ robot_name: str
123
+ inspection_id: str
124
+ blob_storage_data_path: BlobStoragePath
125
+ blob_storage_metadata_path: BlobStoragePath
126
+ installation_code: str
127
+ tag_id: Optional[str]
128
+ inspection_type: Optional[str]
129
+ inspection_description: Optional[str]
130
+ timestamp: datetime
131
+
132
+
133
+ @dataclass
134
+ class InspectionValuePayload:
135
+ isar_id: str
136
+ robot_name: str
137
+ inspection_id: str
138
+ installation_code: str
139
+ tag_id: Optional[str]
140
+ inspection_type: Optional[str]
141
+ inspection_description: Optional[str]
142
+ value: float
143
+ unit: str
144
+ x: float
145
+ y: float
146
+ z: float
147
+ timestamp: datetime
148
+
149
+
150
+ @dataclass
151
+ class StartUpMessagePayload:
152
+ isar_id: str
153
+ timestamp: datetime
154
+
155
+
156
+ @dataclass
157
+ class InterventionNeededPayload:
158
+ isar_id: str
159
+ robot_name: str
160
+ reason: str
161
+ timestamp: datetime
@@ -7,6 +7,7 @@ from uuid import UUID
7
7
 
8
8
  import numpy as np
9
9
  from alitra import Orientation
10
+ from pydantic import BaseModel
10
11
 
11
12
 
12
13
  class EnhancedJSONEncoder(json.JSONEncoder):
@@ -15,8 +16,13 @@ class EnhancedJSONEncoder(json.JSONEncoder):
15
16
  """
16
17
 
17
18
  def default(self, o):
19
+ if isinstance(o, BaseModel):
20
+ dump = getattr(o, "model_dump", None)
21
+ if callable(dump):
22
+ return dump()
23
+ return o.__dict__
18
24
  if is_dataclass(o):
19
- return asdict(o)
25
+ return asdict(o) # type: ignore
20
26
  if isinstance(o, UUID):
21
27
  return str(o)
22
28
  if isinstance(o, Orientation):