isar 1.21.0__py3-none-any.whl → 1.22.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.

@@ -2,7 +2,7 @@ import time
2
2
  from enum import Enum
3
3
  from typing import Any, Dict, List, Optional, Union
4
4
 
5
- from alitra import Position, Pose, Orientation, Frame
5
+ from alitra import Frame, Orientation, Pose, Position
6
6
  from pydantic import BaseModel, Field
7
7
 
8
8
  from isar.apis.models.models import InputPose, InputPosition
@@ -62,6 +62,8 @@ class StartMissionDefinition(BaseModel):
62
62
  id: Optional[str] = None
63
63
  name: Optional[str] = None
64
64
  start_pose: Optional[InputPose] = None
65
+ dock: Optional[bool] = None
66
+ undock: Optional[bool] = None
65
67
 
66
68
 
67
69
  def to_isar_mission(mission_definition: StartMissionDefinition) -> Mission:
@@ -85,6 +87,9 @@ def to_isar_mission(mission_definition: StartMissionDefinition) -> Mission:
85
87
 
86
88
  isar_mission: Mission = Mission(tasks=isar_tasks)
87
89
 
90
+ isar_mission.dock = mission_definition.dock
91
+ isar_mission.undock = mission_definition.undock
92
+
88
93
  if mission_definition.name:
89
94
  isar_mission.name = mission_definition.name
90
95
  else:
@@ -127,20 +132,21 @@ def check_for_duplicate_ids(items: Union[List[Task], List[STEPS]]):
127
132
 
128
133
  def generate_steps(task) -> List[STEPS]:
129
134
  steps: List[STEPS] = []
130
- try:
131
- match task.type:
132
- case TaskType.Inspection:
133
- steps.extend(generate_steps_for_inspection_task(task=task))
134
- case TaskType.DriveTo:
135
- steps.append(generate_steps_for_drive_to_task(task=task))
136
- case TaskType.Localization:
137
- steps.append(generate_steps_for_localization_task(task=task))
138
- case TaskType.ReturnToHome:
139
- steps.append(generate_steps_for_return_to_home_task(task=task))
140
- case TaskType.Dock:
141
- steps.append(generate_steps_for_dock_task())
142
- except ValueError as e:
143
- raise MissionPlannerError(f"Failed to create task: {str(e)}")
135
+
136
+ if task.type == TaskType.Inspection:
137
+ steps.extend(generate_steps_for_inspection_task(task=task))
138
+ elif task.type == TaskType.DriveTo:
139
+ steps.append(generate_steps_for_drive_to_task(task=task))
140
+ elif task.type == TaskType.Localization:
141
+ steps.append(generate_steps_for_localization_task(task=task))
142
+ elif task.type == TaskType.ReturnToHome:
143
+ steps.append(generate_steps_for_return_to_home_task(task=task))
144
+ elif task.type == TaskType.Dock:
145
+ steps.append(generate_steps_for_dock_task())
146
+ else:
147
+ raise MissionPlannerError(
148
+ f"Failed to create task: '{task.type}' is not a valid"
149
+ )
144
150
 
145
151
  return steps
146
152
 
isar/config/settings.py CHANGED
@@ -8,7 +8,7 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
8
8
 
9
9
  from isar.config import predefined_missions
10
10
  from robot_interface.models.robots.robot_model import RobotModel
11
- from robot_interface.telemetry.payloads import VideoStream
11
+ from robot_interface.telemetry.payloads import VideoStream, DocumentInfo
12
12
 
13
13
 
14
14
  class Settings(BaseSettings):
@@ -190,6 +190,9 @@ class Settings(BaseSettings):
190
190
  # Serial number of the robot ISAR is connected to
191
191
  SERIAL_NUMBER: str = Field(default="0001")
192
192
 
193
+ # Info about robot documentation
194
+ DOCUMENTATION: List[DocumentInfo] = Field(default=[])
195
+
193
196
  # Endpoints to reach video streams for the robot
194
197
  VIDEO_STREAMS: List[VideoStream] = Field(
195
198
  default=[
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import time
3
- from datetime import UTC, datetime
3
+ from datetime import datetime, timezone
4
4
  from queue import Queue
5
5
 
6
6
  from isar.config.settings import settings
@@ -18,7 +18,7 @@ class RobotHeartbeatPublisher:
18
18
  payload: RobotHeartbeatPayload = RobotHeartbeatPayload(
19
19
  isar_id=settings.ISAR_ID,
20
20
  robot_name=settings.ROBOT_NAME,
21
- timestamp=datetime.now(UTC),
21
+ timestamp=datetime.now(timezone.utc),
22
22
  )
23
23
 
24
24
  self.mqtt_publisher.publish(
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import time
3
- from datetime import UTC, datetime
3
+ from datetime import datetime, timezone
4
4
  from queue import Queue
5
5
 
6
6
  from isar.config.settings import robot_settings, settings
@@ -21,11 +21,12 @@ class RobotInfoPublisher:
21
21
  robot_model=robot_settings.ROBOT_MODEL, # type: ignore
22
22
  robot_serial_number=settings.SERIAL_NUMBER,
23
23
  robot_asset=settings.PLANT_SHORT_NAME,
24
+ documentation=settings.DOCUMENTATION,
24
25
  video_streams=settings.VIDEO_STREAMS,
25
26
  host=settings.API_HOST_VIEWED_EXTERNALLY,
26
27
  port=settings.API_PORT,
27
28
  capabilities=robot_settings.CAPABILITIES,
28
- timestamp=datetime.now(UTC),
29
+ timestamp=datetime.now(timezone.utc),
29
30
  )
30
31
 
31
32
  self.mqtt_publisher.publish(
@@ -2,7 +2,7 @@ import json
2
2
  import logging
3
3
  import queue
4
4
  from collections import deque
5
- from datetime import UTC, datetime
5
+ from datetime import datetime, timezone
6
6
  from typing import Deque, List, Optional
7
7
 
8
8
  from alitra import Pose
@@ -292,7 +292,7 @@ class StateMachine(object):
292
292
  self.queues.resume_mission.output.put(resume_mission_response)
293
293
 
294
294
  self.current_task.reset_task()
295
- self.update_current_step()
295
+ self.iterate_current_step()
296
296
 
297
297
  self.robot.resume()
298
298
 
@@ -337,12 +337,14 @@ class StateMachine(object):
337
337
  else:
338
338
  self.current_task.status = TaskStatus.InProgress
339
339
  self.publish_task_status(task=self.current_task)
340
- self.update_current_step()
340
+ self.iterate_current_step()
341
341
 
342
342
  def _step_finished(self) -> None:
343
343
  self.publish_step_status(step=self.current_step)
344
- self.update_current_task()
345
- self.update_current_step()
344
+ self.current_task.update_task_status()
345
+ self.publish_task_status(task=self.current_task)
346
+ self.iterate_current_task()
347
+ self.iterate_current_step()
346
348
 
347
349
  def _full_mission_finished(self) -> None:
348
350
  self.current_task = None
@@ -379,8 +381,10 @@ class StateMachine(object):
379
381
  if self.stepwise_mission:
380
382
  self.current_step.status = StepStatus.Failed
381
383
  self.publish_step_status(step=self.current_step)
382
- self.update_current_task()
383
- self.update_current_step()
384
+ self.current_task.update_task_status()
385
+ self.publish_task_status(task=self.current_task)
386
+ self.iterate_current_task()
387
+ self.iterate_current_step()
384
388
 
385
389
  def _mission_stopped(self) -> None:
386
390
  self.current_mission.status = MissionStatus.Cancelled
@@ -427,10 +431,8 @@ class StateMachine(object):
427
431
  """
428
432
  self.to_idle()
429
433
 
430
- def update_current_task(self):
434
+ def iterate_current_task(self):
431
435
  if self.current_task.is_finished():
432
- self.current_task.update_task_status()
433
- self.publish_task_status(task=self.current_task)
434
436
  try:
435
437
  self.current_task = self.task_selector.next_task()
436
438
  self.current_task.status = TaskStatus.InProgress
@@ -439,7 +441,7 @@ class StateMachine(object):
439
441
  # Indicates that all tasks are finished
440
442
  self.current_task = None
441
443
 
442
- def update_current_step(self):
444
+ def iterate_current_step(self):
443
445
  if self.current_task != None:
444
446
  self.current_step = self.current_task.next_step()
445
447
 
@@ -524,7 +526,7 @@ class StateMachine(object):
524
526
  "error_description": (
525
527
  error_message.error_description if error_message else None
526
528
  ),
527
- "timestamp": datetime.now(UTC),
529
+ "timestamp": datetime.now(timezone.utc),
528
530
  },
529
531
  cls=EnhancedJSONEncoder,
530
532
  )
@@ -557,7 +559,7 @@ class StateMachine(object):
557
559
  "error_description": (
558
560
  error_message.error_description if error_message else None
559
561
  ),
560
- "timestamp": datetime.now(UTC),
562
+ "timestamp": datetime.now(timezone.utc),
561
563
  },
562
564
  cls=EnhancedJSONEncoder,
563
565
  )
@@ -592,7 +594,7 @@ class StateMachine(object):
592
594
  "error_description": (
593
595
  error_message.error_description if error_message else None
594
596
  ),
595
- "timestamp": datetime.now(UTC),
597
+ "timestamp": datetime.now(timezone.utc),
596
598
  },
597
599
  cls=EnhancedJSONEncoder,
598
600
  )
@@ -612,7 +614,7 @@ class StateMachine(object):
612
614
  "isar_id": settings.ISAR_ID,
613
615
  "robot_name": settings.ROBOT_NAME,
614
616
  "status": self._current_status(),
615
- "timestamp": datetime.now(UTC),
617
+ "timestamp": datetime.now(timezone.utc),
616
618
  },
617
619
  cls=EnhancedJSONEncoder,
618
620
  )
@@ -71,37 +71,14 @@ class Monitor(State):
71
71
  thread_name="State Machine Monitor Get Step Status",
72
72
  )
73
73
  try:
74
- status: Union[StepStatus, MissionStatus] = (
75
- self.step_status_thread.get_output()
76
- )
74
+ status: StepStatus = self.step_status_thread.get_output()
77
75
  except ThreadedRequestNotFinishedError:
78
76
  time.sleep(self.state_machine.sleep_time)
79
77
  continue
80
78
 
81
79
  except RobotCommunicationTimeoutException as e:
82
- self.state_machine.current_mission.error_message = ErrorMessage(
83
- error_reason=e.error_reason, error_description=e.error_description
84
- )
85
- self.step_status_thread = None
86
- self.request_status_failure_counter += 1
87
- self.logger.warning(
88
- f"Monitoring step {self.state_machine.current_step.id} failed #: "
89
- f"{self.request_status_failure_counter} failed because: {e.error_description}"
90
- )
91
-
92
- if (
93
- self.request_status_failure_counter
94
- >= self.request_status_failure_counter_limit
95
- ):
96
- self.state_machine.current_step.error_message = ErrorMessage(
97
- error_reason=e.error_reason,
98
- error_description=e.error_description,
99
- )
100
- self.logger.error(
101
- f"Step will be cancelled after failing to get step status "
102
- f"{self.request_status_failure_counter} times because: "
103
- f"{e.error_description}"
104
- )
80
+ step_failed: bool = self._handle_communication_timeout(e)
81
+ if step_failed:
105
82
  status = StepStatus.Failed
106
83
  else:
107
84
  continue
@@ -116,16 +93,6 @@ class Monitor(State):
116
93
  )
117
94
  status = StepStatus.Failed
118
95
 
119
- except RobotMissionStatusException as e:
120
- self.state_machine.current_mission.error_message = ErrorMessage(
121
- error_reason=e.error_reason, error_description=e.error_description
122
- )
123
- self.logger.error(
124
- f"Monitoring mission {self.state_machine.current_mission.id} "
125
- f"failed because: {e.error_description}"
126
- )
127
- status = MissionStatus.Failed
128
-
129
96
  except RobotException as e:
130
97
  self._set_error_message(e)
131
98
  status = StepStatus.Failed
@@ -134,13 +101,18 @@ class Monitor(State):
134
101
  f"Retrieving the status failed because: {e.error_description}"
135
102
  )
136
103
 
137
- if isinstance(status, StepStatus):
138
- self.state_machine.current_step.status = status
139
- elif isinstance(status, MissionStatus):
140
- self.state_machine.current_mission.status = status
104
+ if not isinstance(status, StepStatus):
141
105
  self.logger.error(
142
106
  f"Received an invalid status update when monitoring mission. Only StepStatus is expected."
143
107
  )
108
+ break
109
+
110
+ if self.state_machine.current_task == None:
111
+ self.state_machine.iterate_current_task()
112
+ if self.state_machine.current_step == None:
113
+ self.state_machine.iterate_current_step()
114
+
115
+ self.state_machine.current_step.status = status
144
116
 
145
117
  if self._should_upload_inspections():
146
118
  get_inspections_thread = ThreadedRequest(
@@ -153,38 +125,37 @@ class Monitor(State):
153
125
  )
154
126
 
155
127
  if self.state_machine.stepwise_mission:
156
- if self._step_finished(self.state_machine.current_step):
128
+ if self._is_step_finished(self.state_machine.current_step):
129
+ self._report_step_status(self.state_machine.current_step)
157
130
  transition = self.state_machine.step_finished # type: ignore
158
131
  break
159
132
  else:
160
- if isinstance(status, StepStatus):
161
- if self._step_finished(self.state_machine.current_step):
162
- self.state_machine.update_current_task()
133
+ if self._is_step_finished(self.state_machine.current_step):
134
+ self._report_step_status(self.state_machine.current_step)
135
+
136
+ if self.state_machine.current_task.is_finished():
137
+ # Report and update finished task
138
+ self.state_machine.current_task.update_task_status() # Uses the updated step status to set the task status
139
+ self.state_machine.publish_task_status(
140
+ task=self.state_machine.current_task
141
+ )
142
+
143
+ self.state_machine.iterate_current_task()
144
+
163
145
  if self.state_machine.current_task == None:
164
146
  transition = self.state_machine.full_mission_finished # type: ignore
165
147
  break
166
- self.state_machine.update_current_step()
148
+
149
+ # Report and update next task
167
150
  self.state_machine.current_task.update_task_status()
168
- else: # If not all steps are done
169
- self.state_machine.current_task.status = TaskStatus.InProgress
170
-
171
- self.state_machine.publish_task_status(
172
- self.state_machine.current_task
173
- )
174
- if self.state_machine.current_task.status == TaskStatus.Successful:
175
- try:
176
- self.state_machine.current_task = (
177
- self.state_machine.task_selector.next_task()
178
- )
179
- except TaskSelectorStop:
180
- # Indicates that all tasks are finished
181
- self.state_machine.current_task = None
182
- transition = self.state_machine.full_mission_finished # type: ignore
183
- break
184
- self.state_machine.update_current_step()
185
- elif self._mission_finished(self.state_machine.current_mission):
186
- transition = self.state_machine.full_mission_finished # type: ignore
187
- break
151
+ self.state_machine.publish_task_status(
152
+ task=self.state_machine.current_task
153
+ )
154
+
155
+ self.state_machine.iterate_current_step()
156
+
157
+ else: # If not all steps are done
158
+ self.state_machine.current_task.status = TaskStatus.InProgress
188
159
 
189
160
  self.step_status_thread = None
190
161
  time.sleep(self.state_machine.sleep_time)
@@ -227,34 +198,28 @@ class Monitor(State):
227
198
  self.state_machine.queues.upload_queue.put(message)
228
199
  self.logger.info(f"Inspection: {str(inspection.id)[:8]} queued for upload")
229
200
 
230
- def _step_finished(self, step: Step) -> bool:
201
+ def _is_step_finished(self, step: Step) -> bool:
231
202
  finished: bool = False
203
+ if step.status == StepStatus.Failed:
204
+ finished = True
205
+ elif step.status == StepStatus.Successful:
206
+ finished = True
207
+ return finished
208
+
209
+ def _report_step_status(self, step: Step) -> None:
232
210
  if step.status == StepStatus.Failed:
233
211
  self.logger.warning(
234
212
  f"Step: {str(step.id)[:8]} was reported as failed by the robot"
235
213
  )
236
- finished = True
237
214
  elif step.status == StepStatus.Successful:
238
215
  self.logger.info(
239
216
  f"{type(step).__name__} step: {str(step.id)[:8]} completed"
240
217
  )
241
- finished = True
242
- return finished
243
-
244
- @staticmethod
245
- def _mission_finished(mission: Mission) -> bool:
246
- if (
247
- mission.status == MissionStatus.Successful
248
- or mission.status == MissionStatus.PartiallySuccessful
249
- or mission.status == MissionStatus.Failed
250
- ):
251
- return True
252
- return False
253
218
 
254
219
  def _should_upload_inspections(self) -> bool:
255
220
  step: Step = self.state_machine.current_step
256
221
  return (
257
- self._step_finished(step)
222
+ self._is_step_finished(step)
258
223
  and step.status == StepStatus.Successful
259
224
  and isinstance(step, InspectionStep)
260
225
  )
@@ -264,3 +229,33 @@ class Monitor(State):
264
229
  error_reason=e.error_reason, error_description=e.error_description
265
230
  )
266
231
  self.state_machine.current_step.error_message = error_message
232
+
233
+ def _handle_communication_timeout(
234
+ self, e: RobotCommunicationTimeoutException
235
+ ) -> bool:
236
+ self.state_machine.current_mission.error_message = ErrorMessage(
237
+ error_reason=e.error_reason, error_description=e.error_description
238
+ )
239
+ self.step_status_thread = None
240
+ self.request_status_failure_counter += 1
241
+ self.logger.warning(
242
+ f"Monitoring step {self.state_machine.current_step.id} failed #: "
243
+ f"{self.request_status_failure_counter} failed because: {e.error_description}"
244
+ )
245
+
246
+ if (
247
+ self.request_status_failure_counter
248
+ >= self.request_status_failure_counter_limit
249
+ ):
250
+ self.state_machine.current_step.error_message = ErrorMessage(
251
+ error_reason=e.error_reason,
252
+ error_description=e.error_description,
253
+ )
254
+ self.logger.error(
255
+ f"Step will be cancelled after failing to get step status "
256
+ f"{self.request_status_failure_counter} times because: "
257
+ f"{e.error_description}"
258
+ )
259
+ return True
260
+
261
+ return False
isar/storage/uploader.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  from dataclasses import dataclass
4
- from datetime import UTC, datetime, timedelta
4
+ from datetime import datetime, timedelta, timezone
5
5
  from queue import Empty, Queue
6
6
  from typing import List, Union
7
7
 
@@ -22,12 +22,12 @@ class UploaderQueueItem:
22
22
  mission: Mission
23
23
  storage_handler: StorageInterface
24
24
  _retry_count: int
25
- _next_retry_time: datetime = datetime.now(UTC)
25
+ _next_retry_time: datetime = datetime.now(timezone.utc)
26
26
 
27
27
  def increment_retry(self, max_wait_time: int) -> None:
28
28
  self._retry_count += 1
29
29
  seconds_until_retry: int = min(2**self._retry_count, max_wait_time)
30
- self._next_retry_time = datetime.now(UTC) + timedelta(
30
+ self._next_retry_time = datetime.now(timezone.utc) + timedelta(
31
31
  seconds=seconds_until_retry
32
32
  )
33
33
 
@@ -35,10 +35,12 @@ class UploaderQueueItem:
35
35
  return self._retry_count
36
36
 
37
37
  def is_ready_for_upload(self) -> bool:
38
- return datetime.now(UTC) >= self._next_retry_time
38
+ return datetime.now(timezone.utc) >= self._next_retry_time
39
39
 
40
40
  def seconds_until_retry(self) -> int:
41
- return max(0, int((self._next_retry_time - datetime.now(UTC)).total_seconds()))
41
+ return max(
42
+ 0, int((self._next_retry_time - datetime.now(timezone.utc)).total_seconds())
43
+ )
42
44
 
43
45
 
44
46
  class Uploader:
@@ -154,7 +156,7 @@ class Uploader:
154
156
  "inspection_id": inspection.id,
155
157
  "inspection_path": inspection_path,
156
158
  "analysis_type": inspection.metadata.analysis_type,
157
- "timestamp": datetime.now(UTC),
159
+ "timestamp": datetime.now(timezone.utc),
158
160
  },
159
161
  cls=EnhancedJSONEncoder,
160
162
  )
isar/storage/utilities.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import time
3
- from datetime import UTC, datetime
3
+ from datetime import datetime, timezone
4
4
  from pathlib import Path
5
5
  from typing import Tuple
6
6
 
@@ -37,7 +37,7 @@ def construct_metadata_file(
37
37
  "mission_id": mission.id,
38
38
  "mission_name": mission.name,
39
39
  "plant_name": settings.PLANT_NAME,
40
- "mission_date": datetime.now(UTC).date(),
40
+ "mission_date": datetime.now(timezone.utc).date(),
41
41
  "isar_id": settings.ISAR_ID,
42
42
  "robot_name": settings.ROBOT_NAME,
43
43
  "analysis_type": (
@@ -80,4 +80,4 @@ def get_filename(
80
80
 
81
81
  def get_foldername(mission: Mission) -> str:
82
82
  mission_name: str = mission.name.replace(" ", "-")
83
- return f"{datetime.now(UTC).date()}__{settings.PLANT_SHORT_NAME}__{mission_name}__{mission.id}"
83
+ return f"{datetime.now(timezone.utc).date()}__{settings.PLANT_SHORT_NAME}__{mission_name}__{mission.id}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: isar
3
- Version: 1.21.0
3
+ Version: 1.22.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
@@ -91,12 +91,14 @@ Classifier: Intended Audience :: Science/Research
91
91
  Classifier: License :: OSI Approved :: Eclipse Public License 2.0 (EPL-2.0)
92
92
  Classifier: Natural Language :: English
93
93
  Classifier: Programming Language :: Python :: 3
94
+ Classifier: Programming Language :: Python :: 3.9
95
+ Classifier: Programming Language :: Python :: 3.10
94
96
  Classifier: Programming Language :: Python :: 3.11
95
97
  Classifier: Programming Language :: Python :: 3.12
96
98
  Classifier: Topic :: Scientific/Engineering
97
99
  Classifier: Topic :: Scientific/Engineering :: Physics
98
100
  Classifier: Topic :: Software Development :: Libraries
99
- Requires-Python: >=3.11
101
+ Requires-Python: >=3.9
100
102
  Description-Content-Type: text/markdown
101
103
  License-File: LICENSE
102
104
  Requires-Dist: alitra >=1.1.3
@@ -5,7 +5,7 @@ isar/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  isar/apis/api.py,sha256=vSXfkWR7iITWbh4BsDzjEDtQrz6KS-vi2S8AeaeDc3Q,13112
6
6
  isar/apis/models/__init__.py,sha256=NI1BYyN__Ogr00Qqe0XJ-9gEVPva2brXo2RJsbrS4tM,52
7
7
  isar/apis/models/models.py,sha256=BRm3Wl6TJHdHEKLRQ2SGDx6Y54qq8IesMbBuVO7RuxE,1757
8
- isar/apis/models/start_mission_definition.py,sha256=GuihnkVRXjzopMEiRQ4rOfeCGw98IFK9EYylB-5S0aI,7253
8
+ isar/apis/models/start_mission_definition.py,sha256=Ch8625e-ZDWQv5L-cVlpotTHm1b42ZrDBx2recvTIjM,7394
9
9
  isar/apis/schedule/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  isar/apis/schedule/scheduling_controller.py,sha256=w2F-6IKBgVN9HVopAOWBb3KUgPjhsnuPLQ3eqjDNfOg,11888
11
11
  isar/apis/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -15,7 +15,7 @@ isar/config/configuration_error.py,sha256=rO6WOhafX6xvVib8WxV-eY483Z0PpN-9PxGsq5
15
15
  isar/config/log.py,sha256=zHFLmGWQRn8TrcsxUS6KHpJt2JE86kYazU7b-bkcN9o,2285
16
16
  isar/config/logging.conf,sha256=mYO1xf27gAopEMHhGzY7-mwyfN16rwRLkPNMvy3zn2g,1127
17
17
  isar/config/settings.env,sha256=-kivj0osAAKlInnY81ugySTlcImhVABbnj9kUoBDLu8,535
18
- isar/config/settings.py,sha256=yU1Zgc1Sbby3vHqv2JeIFAK8nXV_8ZAhuE7HzsZiqxc,13368
18
+ isar/config/settings.py,sha256=RUsQr4ZFhsMGQRmBQFYxYZkowsP82UG2EDisenLQXes,13478
19
19
  isar/config/certs/ca-cert.pem,sha256=gSBTyY0tKSFnssyvrvbFvHpQwii0kEkBryklVmevdtc,2029
20
20
  isar/config/keyvault/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  isar/config/keyvault/keyvault_error.py,sha256=zvPCsZLjboxsxthYkxpRERCTFxYV8R5WmACewAUQLwk,41
@@ -59,21 +59,21 @@ isar/services/service_connections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
59
59
  isar/services/service_connections/request_handler.py,sha256=0LxC0lu_HXeEf_xmJWjfEsh14oAUI97cpG1IWtBlcs4,4278
60
60
  isar/services/service_connections/mqtt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  isar/services/service_connections/mqtt/mqtt_client.py,sha256=Aib0lqaddxW9aVXXYD7wGL9jIpr2USCCH91SQgFdIG4,3548
62
- isar/services/service_connections/mqtt/robot_heartbeat_publisher.py,sha256=0Qjo2wRZZoooXG-UE4z8YJc9QCCz6v-9YAqHRJgx-kE,1005
63
- isar/services/service_connections/mqtt/robot_info_publisher.py,sha256=f1vhBNPlx6p3Au8l7OsWIJXRM_xjA8qcLHvnkwCtRBM,1388
62
+ isar/services/service_connections/mqtt/robot_heartbeat_publisher.py,sha256=_bUOG7CfqBlCRvG4vh2XGoMXucBxsJarFIeXIKOH1aw,1019
63
+ isar/services/service_connections/mqtt/robot_info_publisher.py,sha256=5G6ahslydhO2Z4Ug3abf5KVHeOiWdWBMxwraRbJZS_I,1456
64
64
  isar/services/service_connections/stid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  isar/services/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  isar/services/utilities/queue_utilities.py,sha256=Pw3hehSwkXJNeDv-bDVDfs58VOwtt3i5hpiJ2ZpphuQ,1225
67
67
  isar/services/utilities/scheduling_utilities.py,sha256=LFimEmacML3J9q-FNLfKPhcAr-R3f2rkYkbsoro0Gyo,8434
68
68
  isar/services/utilities/threaded_request.py,sha256=py4G-_RjnIdHljmKFAcQ6ddqMmp-ZYV39Ece-dqRqjs,1874
69
69
  isar/state_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
- isar/state_machine/state_machine.py,sha256=UcCQEEscwrOgWqjWVhkeEqRGFm2pLEomud3ROl96qro,24204
70
+ isar/state_machine/state_machine.py,sha256=JrVwo3tU5lzWKlUE5oMpoE8aEte3HcVOHbjCGMIdv_c,24357
71
71
  isar/state_machine/states_enum.py,sha256=BlrUcBWkM5K6D_UZXRwTaUgGpAagWmVZH6HhDBGzVU4,278
72
72
  isar/state_machine/states/__init__.py,sha256=kErbKPDTwNfCLijvdyN6_AuOqDwR23nu9F0Qovsnir4,218
73
73
  isar/state_machine/states/idle.py,sha256=_nrM17s4artaHezanl28_WcNyJod1_hkCyzAqZlPQiE,3034
74
74
  isar/state_machine/states/initialize.py,sha256=KUuyXVwzWK5bJNspA1JnYO_Xwu8fPPK6bnHK4mtwf5A,2359
75
75
  isar/state_machine/states/initiate.py,sha256=WqBROOGAh0DVB0f39RFkpqzkr0qrHMyrBGkh2svBbKw,5652
76
- isar/state_machine/states/monitor.py,sha256=KdCPzE6JrnJg3wk936AxWFzp4IuR9a43Dq3-8mL0qAI,11043
76
+ isar/state_machine/states/monitor.py,sha256=Jc1ZZ4mOJQU-VI5-UQJLbKNQGqHMBruvurHeJOlGnD0,10277
77
77
  isar/state_machine/states/off.py,sha256=jjqN_oJMpBtWuY7hP-c9f0w3p2CYCfe-NpmYHHPnmyI,544
78
78
  isar/state_machine/states/offline.py,sha256=wEMMIwM4JWfmDjI7pe9yKce_Mfz9aXqs6WEkxn8cx5I,2125
79
79
  isar/state_machine/states/paused.py,sha256=qFSauRwalyws8K5bDZ5wkcRDVYyevTDVRtbXkiF9rZc,1174
@@ -83,34 +83,34 @@ isar/storage/blob_storage.py,sha256=oKdml1VVN8iTr-d_5H4Lz5E7zrhJRknCzOxHD-tO7m8,
83
83
  isar/storage/local_storage.py,sha256=Bnmoi5gyN8r-oRh0aHrOdGqaH3JqRScFKMRXYojW5kY,1855
84
84
  isar/storage/slimm_storage.py,sha256=Hp7ZIgZgIR4KAFjzxDKfgMZjPZwP2kmdc1gG8zVcsMk,8966
85
85
  isar/storage/storage_interface.py,sha256=DYDry4I7aZpDHJhsBF6s8zrgokFAc7fdKJKfA8AvL7o,828
86
- isar/storage/uploader.py,sha256=te3GyiSeu96MhbiqQ7ueIMUPLSKblx3UqYAshkxfVIE,6368
87
- isar/storage/utilities.py,sha256=eTyY56WCTda5YswE9znWNeNEoTbT3jokNbwcLVmmQjA,3113
86
+ isar/storage/uploader.py,sha256=_f-uIiL5ye6GLc7nYQxHrqDXrIquoL_t5tt9SSaYoDA,6440
87
+ isar/storage/utilities.py,sha256=AGqOzhnyPXSStpJjBstqQ4QgUoHJioQB2DJ1NqeWn_w,3136
88
88
  robot_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
89
  robot_interface/robot_interface.py,sha256=pY1Wuka0fTP-kCmkEndAcFytkS73cEE2zIHv-v5Fm1E,9466
90
90
  robot_interface/test_robot_interface.py,sha256=FV1urn7SbsMyWBIcTKjsBwAG4IsXeZ6pLHE0mA9EGGs,692
91
91
  robot_interface/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
92
  robot_interface/models/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
93
- robot_interface/models/exceptions/robot_exceptions.py,sha256=l1h62gq7lfLzWoHh2ytdEWgn_4lS4M-GPxHkjgAXcP4,9036
93
+ robot_interface/models/exceptions/robot_exceptions.py,sha256=DNlecQm2m4ld5mLLFQl1EkQ4b9XgX9H7g-b5c1EuUf4,9549
94
94
  robot_interface/models/initialize/__init__.py,sha256=rz5neEDr59GDbzzI_FF0DId-C-I-50l113P-h-C_QBY,48
95
95
  robot_interface/models/initialize/initialize_params.py,sha256=2eG5Aq5bDKU6tVkaUMAoc46GERBgyaKkqv6yLupdRLc,164
96
96
  robot_interface/models/inspection/__init__.py,sha256=14wfuj4XZazrigKD7fL98khFKz-eckIpEgPcYRj40Kg,227
97
97
  robot_interface/models/inspection/inspection.py,sha256=TVqUl5o3d3fp8IravOMwJIuRoEU8y4BltFrF1IkwvTA,2176
98
98
  robot_interface/models/mission/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
- robot_interface/models/mission/mission.py,sha256=xJ7i79TQkmO0Tv2IQeguhyliNP2J42ziS5iO-FyBpW0,839
99
+ robot_interface/models/mission/mission.py,sha256=r_tYqhZeKASdJ_YIN0ZhCl6YdokuuDySI0o9IT2Qe7M,905
100
100
  robot_interface/models/mission/status.py,sha256=R5jLmmn6M7oNX907QvbrhoAqAo4C1zB653Ed1PcxAtg,922
101
101
  robot_interface/models/mission/step.py,sha256=DEzU-LD-i3RTAaXBy5KwJZ6OnN5S0F3wwDaqX2DZ72M,5587
102
- robot_interface/models/mission/task.py,sha256=JJ062AIdwVoj3PUkWYmJDvRl5B7Tcu9S11J2F_0tfjE,4695
102
+ robot_interface/models/mission/task.py,sha256=Nup8e_M_KYhtEtGNeV4FzVzaRH4YpDWiKfMMkLJu0ms,4788
103
103
  robot_interface/models/robots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
104
  robot_interface/models/robots/robot_model.py,sha256=pZQsqhn9hh6XE3EjMZhWMzYqg5oJ4CJ4CXeOASKvEf8,452
105
105
  robot_interface/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
- robot_interface/telemetry/mqtt_client.py,sha256=AHBmOpVvoo6pY5uXwyBY7SooN_cnpuS0DMkfLUPwpl8,2743
107
- robot_interface/telemetry/payloads.py,sha256=eMK7mjZPsLY6yvu7AK-OcdvkeUpChzDrySDY7IjQ9RM,1464
106
+ robot_interface/telemetry/mqtt_client.py,sha256=um7j7XDSAlY6-wWLpBl6ZYjmQ-G0lY7f2_NaZ3ciZ7U,2757
107
+ robot_interface/telemetry/payloads.py,sha256=JM5E_IHkZpim_zdwc-w52D7dYFBeP4iO1-xupOkHcFQ,1562
108
108
  robot_interface/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
109
  robot_interface/utilities/json_service.py,sha256=nU2Q_3P9Fq9hs6F_wtUjWtHfl_g1Siy-yDhXXSKwHwg,1018
110
110
  robot_interface/utilities/uuid_string_factory.py,sha256=_NQIbBQ56w0qqO0MUDP6aPpHbxW7ATRhK8HnQiBSLkc,76
111
- isar-1.21.0.dist-info/LICENSE,sha256=3fc2-ebLwHWwzfQbulGNRdcNob3SBQeCfEVUDYxsuqw,14058
112
- isar-1.21.0.dist-info/METADATA,sha256=6vIZ_8bCeYRnMyMp6Fod4KXHjcxFsncfsmbX4fuATgg,30574
113
- isar-1.21.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
114
- isar-1.21.0.dist-info/entry_points.txt,sha256=TFam7uNNw7J0iiDYzsH2gfG0u1eV1wh3JTw_HkhgKLk,49
115
- isar-1.21.0.dist-info/top_level.txt,sha256=UwIML2RtuQKCyJJkatcSnyp6-ldDjboB9k9JgKipO-U,21
116
- isar-1.21.0.dist-info/RECORD,,
111
+ isar-1.22.1.dist-info/LICENSE,sha256=3fc2-ebLwHWwzfQbulGNRdcNob3SBQeCfEVUDYxsuqw,14058
112
+ isar-1.22.1.dist-info/METADATA,sha256=XlWkAOiQDpPAUiShyCpojSATloy3CHCj1xT78hP6dAk,30674
113
+ isar-1.22.1.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
114
+ isar-1.22.1.dist-info/entry_points.txt,sha256=TFam7uNNw7J0iiDYzsH2gfG0u1eV1wh3JTw_HkhgKLk,49
115
+ isar-1.22.1.dist-info/top_level.txt,sha256=UwIML2RtuQKCyJJkatcSnyp6-ldDjboB9k9JgKipO-U,21
116
+ isar-1.22.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (75.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -21,6 +21,9 @@ class ErrorReason(str, Enum):
21
21
  RobotUnknownErrorException: str = "robot_unknown_error_exception"
22
22
  RobotDisconnectedException: str = "robot_disconnected_exception"
23
23
  RobotMissionNotSupportedException: str = "robot_mission_not_supported_exception"
24
+ RobotMissionMissingStartPoseException: str = (
25
+ "robot_mission_missing_start_pose_exception"
26
+ )
24
27
 
25
28
 
26
29
  @dataclass
@@ -244,3 +247,14 @@ class RobotMissionNotSupportedException(RobotException):
244
247
  )
245
248
 
246
249
  pass
250
+
251
+
252
+ # An exception which should be thrown by the robot package if the mission is missing start pose and it needed it
253
+ class RobotMissionMissingStartPoseException(RobotException):
254
+ def __init__(self, error_description: str) -> None:
255
+ super().__init__(
256
+ error_reason=ErrorReason.RobotMissionMissingStartPoseException,
257
+ error_description=error_description,
258
+ )
259
+
260
+ pass
@@ -15,6 +15,8 @@ class Mission:
15
15
  id: str = field(default_factory=uuid4_string, init=True)
16
16
  name: str = ""
17
17
  start_pose: Optional[Pose] = None
18
+ dock: Optional[bool] = None
19
+ undock: Optional[bool] = None
18
20
  status: MissionStatus = MissionStatus.NotStarted
19
21
  error_message: Optional[ErrorMessage] = field(default=None, init=False)
20
22
 
@@ -22,11 +22,14 @@ class Task:
22
22
  id: str = field(default_factory=uuid4_string, init=True)
23
23
  _iterator: Iterator = None
24
24
 
25
- def next_step(self) -> Step:
26
- step: Step = next(self._iterator)
27
- while step.status != StepStatus.NotStarted:
28
- step = next(self._iterator)
29
- return step
25
+ def next_step(self) -> Optional[Step]:
26
+ try:
27
+ step: Step = next(self._iterator)
28
+ while step.status != StepStatus.NotStarted:
29
+ step = next(self._iterator)
30
+ return step
31
+ except StopIteration:
32
+ return None
30
33
 
31
34
  def is_finished(self) -> bool:
32
35
  for step in self.steps:
@@ -1,7 +1,7 @@
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
 
@@ -73,7 +73,7 @@ class MqttTelemetryPublisher(MqttClientInterface):
73
73
  topic = self.topic
74
74
  except RobotTelemetryException:
75
75
  payload = json.dumps(
76
- CloudHealthPayload(isar_id, robot_name, datetime.now(UTC)),
76
+ CloudHealthPayload(isar_id, robot_name, datetime.now(timezone.utc)),
77
77
  cls=EnhancedJSONEncoder,
78
78
  )
79
79
  topic = self.cloud_healt_topic
@@ -42,6 +42,12 @@ class TelemetryPressurePayload(TelemetryPayload):
42
42
  pressure_level: float
43
43
 
44
44
 
45
+ @dataclass
46
+ class DocumentInfo:
47
+ name: str
48
+ url: str
49
+
50
+
45
51
  @dataclass
46
52
  class VideoStream:
47
53
  name: str
@@ -69,6 +75,7 @@ class RobotInfoPayload:
69
75
  robot_model: str
70
76
  robot_serial_number: str
71
77
  robot_asset: str
78
+ documentation: List[DocumentInfo]
72
79
  video_streams: List[VideoStream]
73
80
  host: str
74
81
  port: int
File without changes