isar 1.33.5__tar.gz → 1.33.7__tar.gz

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.

Files changed (226) hide show
  1. {isar-1.33.5 → isar-1.33.7}/PKG-INFO +1 -1
  2. isar-1.33.7/docs/full_state_machine_diagram.png +0 -0
  3. isar-1.33.7/docs/mission_state_machine_diagram.png +0 -0
  4. isar-1.33.7/docs/robot_status_state_machine_diagram.png +0 -0
  5. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/api.py +34 -0
  6. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/models/models.py +5 -0
  7. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/schedule/scheduling_controller.py +34 -0
  8. {isar-1.33.5 → isar-1.33.7}/src/isar/config/settings.py +4 -0
  9. {isar-1.33.5 → isar-1.33.7}/src/isar/models/events.py +19 -1
  10. {isar-1.33.5 → isar-1.33.7}/src/isar/robot/robot.py +50 -1
  11. isar-1.33.5/src/isar/robot/robot_status.py → isar-1.33.7/src/isar/robot/robot_battery.py +17 -15
  12. isar-1.33.7/src/isar/robot/robot_pause_mission.py +63 -0
  13. isar-1.33.7/src/isar/robot/robot_status.py +71 -0
  14. {isar-1.33.5 → isar-1.33.7}/src/isar/robot/robot_stop_mission.py +1 -1
  15. {isar-1.33.5 → isar-1.33.7}/src/isar/services/utilities/scheduling_utilities.py +50 -4
  16. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/state_machine.py +27 -7
  17. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/await_next_mission.py +19 -1
  18. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/blocked_protective_stop.py +9 -9
  19. isar-1.33.7/src/isar/state_machine/states/going_to_lockdown.py +80 -0
  20. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/home.py +27 -4
  21. isar-1.33.7/src/isar/state_machine/states/lockdown.py +37 -0
  22. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/monitor.py +16 -0
  23. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/offline.py +9 -10
  24. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/paused.py +19 -1
  25. isar-1.33.7/src/isar/state_machine/states/pausing.py +74 -0
  26. isar-1.33.7/src/isar/state_machine/states/pausing_return_home.py +74 -0
  27. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/recharging.py +16 -0
  28. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/return_home_paused.py +17 -1
  29. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/returning_home.py +18 -2
  30. isar-1.33.7/src/isar/state_machine/states/stopping_go_to_lockdown.py +79 -0
  31. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states_enum.py +5 -0
  32. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/fail_mission.py +7 -0
  33. isar-1.33.7/src/isar/state_machine/transitions/functions/pause.py +31 -0
  34. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/robot_status.py +15 -0
  35. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/mission.py +55 -10
  36. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/return_home.py +62 -0
  37. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/utils/common_event_handlers.py +5 -2
  38. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/PKG-INFO +1 -1
  39. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/SOURCES.txt +7 -0
  40. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/mission/status.py +2 -0
  41. {isar-1.33.5 → isar-1.33.7}/tests/isar/state_machine/test_state_machine.py +478 -4
  42. {isar-1.33.5 → isar-1.33.7}/tests/test_double/robot_interface.py +38 -1
  43. isar-1.33.5/docs/full_state_machine_diagram.png +0 -0
  44. isar-1.33.5/docs/mission_state_machine_diagram.png +0 -0
  45. isar-1.33.5/docs/robot_status_state_machine_diagram.png +0 -0
  46. isar-1.33.5/src/isar/state_machine/transitions/functions/pause.py +0 -91
  47. {isar-1.33.5 → isar-1.33.7}/.dockerignore +0 -0
  48. {isar-1.33.5 → isar-1.33.7}/.env.test +0 -0
  49. {isar-1.33.5 → isar-1.33.7}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  50. {isar-1.33.5 → isar-1.33.7}/.github/ISSUE_TEMPLATE/feature.md +0 -0
  51. {isar-1.33.5 → isar-1.33.7}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
  52. {isar-1.33.5 → isar-1.33.7}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  53. {isar-1.33.5 → isar-1.33.7}/.github/release.yml +0 -0
  54. {isar-1.33.5 → isar-1.33.7}/.github/workflows/compile_requirements.yml +0 -0
  55. {isar-1.33.5 → isar-1.33.7}/.github/workflows/project_automations.yml +0 -0
  56. {isar-1.33.5 → isar-1.33.7}/.github/workflows/pythonpackage.yml +0 -0
  57. {isar-1.33.5 → isar-1.33.7}/.github/workflows/pythonpublish.yml +0 -0
  58. {isar-1.33.5 → isar-1.33.7}/.github/workflows/stale.yml +0 -0
  59. {isar-1.33.5 → isar-1.33.7}/.gitignore +0 -0
  60. {isar-1.33.5 → isar-1.33.7}/.pre-commit-config.yaml +0 -0
  61. {isar-1.33.5 → isar-1.33.7}/LICENSE +0 -0
  62. {isar-1.33.5 → isar-1.33.7}/README.md +0 -0
  63. {isar-1.33.5 → isar-1.33.7}/SECURITY.md +0 -0
  64. {isar-1.33.5 → isar-1.33.7}/docs/Makefile +0 -0
  65. {isar-1.33.5 → isar-1.33.7}/docs/make.bat +0 -0
  66. {isar-1.33.5 → isar-1.33.7}/docs/rst_processing.py +0 -0
  67. {isar-1.33.5 → isar-1.33.7}/docs/source/conf.py +0 -0
  68. {isar-1.33.5 → isar-1.33.7}/docs/source/index.rst +0 -0
  69. {isar-1.33.5 → isar-1.33.7}/docs/source/readme_link.md +0 -0
  70. {isar-1.33.5 → isar-1.33.7}/docs/update_state_diagram.py +0 -0
  71. {isar-1.33.5 → isar-1.33.7}/main.py +0 -0
  72. {isar-1.33.5 → isar-1.33.7}/pyproject.toml +0 -0
  73. {isar-1.33.5 → isar-1.33.7}/radixconfig.yml +0 -0
  74. {isar-1.33.5 → isar-1.33.7}/requirements.txt +0 -0
  75. {isar-1.33.5 → isar-1.33.7}/setup.cfg +0 -0
  76. {isar-1.33.5 → isar-1.33.7}/src/isar/__init__.py +0 -0
  77. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/__init__.py +0 -0
  78. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/models/__init__.py +0 -0
  79. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/models/start_mission_definition.py +0 -0
  80. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/robot_control/robot_controller.py +0 -0
  81. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/schedule/__init__.py +0 -0
  82. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/security/__init__.py +0 -0
  83. {isar-1.33.5 → isar-1.33.7}/src/isar/apis/security/authentication.py +0 -0
  84. {isar-1.33.5 → isar-1.33.7}/src/isar/config/__init__.py +0 -0
  85. {isar-1.33.5 → isar-1.33.7}/src/isar/config/certs/ca-cert.pem +0 -0
  86. {isar-1.33.5 → isar-1.33.7}/src/isar/config/configuration_error.py +0 -0
  87. {isar-1.33.5 → isar-1.33.7}/src/isar/config/keyvault/__init__.py +0 -0
  88. {isar-1.33.5 → isar-1.33.7}/src/isar/config/keyvault/keyvault_error.py +0 -0
  89. {isar-1.33.5 → isar-1.33.7}/src/isar/config/keyvault/keyvault_service.py +0 -0
  90. {isar-1.33.5 → isar-1.33.7}/src/isar/config/log.py +0 -0
  91. {isar-1.33.5 → isar-1.33.7}/src/isar/config/logging.conf +0 -0
  92. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/JSP1_intermediate_deck.json +0 -0
  93. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/JSP1_weather_deck.json +0 -0
  94. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/default_map.json +0 -0
  95. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/klab_b.json +0 -0
  96. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/klab_compressor.json +0 -0
  97. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/klab_turtlebot.json +0 -0
  98. {isar-1.33.5 → isar-1.33.7}/src/isar/config/maps/turtleworld.json +0 -0
  99. {isar-1.33.5 → isar-1.33.7}/src/isar/config/open_telemetry.py +0 -0
  100. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_mission_definition/__init__.py +0 -0
  101. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_exr.json +0 -0
  102. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_mission.json +0 -0
  103. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_mission_definition/default_turtlebot.json +0 -0
  104. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_missions/__init__.py +0 -0
  105. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_missions/default.json +0 -0
  106. {isar-1.33.5 → isar-1.33.7}/src/isar/config/predefined_missions/default_turtlebot.json +0 -0
  107. {isar-1.33.5 → isar-1.33.7}/src/isar/eventhandlers/eventhandler.py +0 -0
  108. {isar-1.33.5 → isar-1.33.7}/src/isar/mission_planner/__init__.py +0 -0
  109. {isar-1.33.5 → isar-1.33.7}/src/isar/mission_planner/local_planner.py +0 -0
  110. {isar-1.33.5 → isar-1.33.7}/src/isar/mission_planner/mission_planner_interface.py +0 -0
  111. {isar-1.33.5 → isar-1.33.7}/src/isar/mission_planner/sequential_task_selector.py +0 -0
  112. {isar-1.33.5 → isar-1.33.7}/src/isar/mission_planner/task_selector_interface.py +0 -0
  113. {isar-1.33.5 → isar-1.33.7}/src/isar/models/__init__.py +0 -0
  114. {isar-1.33.5 → isar-1.33.7}/src/isar/modules.py +0 -0
  115. {isar-1.33.5 → isar-1.33.7}/src/isar/robot/robot_start_mission.py +0 -0
  116. {isar-1.33.5 → isar-1.33.7}/src/isar/robot/robot_task_status.py +0 -0
  117. {isar-1.33.5 → isar-1.33.7}/src/isar/script.py +0 -0
  118. {isar-1.33.5 → isar-1.33.7}/src/isar/services/__init__.py +0 -0
  119. {isar-1.33.5 → isar-1.33.7}/src/isar/services/auth/__init__.py +0 -0
  120. {isar-1.33.5 → isar-1.33.7}/src/isar/services/auth/azure_credentials.py +0 -0
  121. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/__init__.py +0 -0
  122. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/mqtt/__init__.py +0 -0
  123. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/mqtt/mqtt_client.py +0 -0
  124. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +0 -0
  125. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/mqtt/robot_info_publisher.py +0 -0
  126. {isar-1.33.5 → isar-1.33.7}/src/isar/services/service_connections/request_handler.py +0 -0
  127. {isar-1.33.5 → isar-1.33.7}/src/isar/services/utilities/__init__.py +0 -0
  128. {isar-1.33.5 → isar-1.33.7}/src/isar/services/utilities/robot_utilities.py +0 -0
  129. {isar-1.33.5 → isar-1.33.7}/src/isar/services/utilities/threaded_request.py +0 -0
  130. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/__init__.py +0 -0
  131. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/__init__.py +0 -0
  132. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/intervention_needed.py +0 -0
  133. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/stopping.py +0 -0
  134. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/stopping_return_home.py +0 -0
  135. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/states/unknown_status.py +0 -0
  136. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/finish_mission.py +0 -0
  137. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/resume.py +0 -0
  138. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/return_home.py +0 -0
  139. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/start_mission.py +0 -0
  140. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/stop.py +0 -0
  141. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/functions/utils.py +0 -0
  142. {isar-1.33.5 → isar-1.33.7}/src/isar/state_machine/transitions/robot_status.py +0 -0
  143. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/__init__.py +0 -0
  144. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/blob_storage.py +0 -0
  145. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/local_storage.py +0 -0
  146. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/storage_interface.py +0 -0
  147. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/uploader.py +0 -0
  148. {isar-1.33.5 → isar-1.33.7}/src/isar/storage/utilities.py +0 -0
  149. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/dependency_links.txt +0 -0
  150. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/entry_points.txt +0 -0
  151. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/requires.txt +0 -0
  152. {isar-1.33.5 → isar-1.33.7}/src/isar.egg-info/top_level.txt +0 -0
  153. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/__init__.py +0 -0
  154. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/__init__.py +0 -0
  155. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/exceptions/__init__.py +0 -0
  156. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/exceptions/robot_exceptions.py +0 -0
  157. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/initialize/__init__.py +0 -0
  158. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/inspection/__init__.py +0 -0
  159. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/inspection/inspection.py +0 -0
  160. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/mission/__init__.py +0 -0
  161. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/mission/mission.py +0 -0
  162. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/mission/task.py +0 -0
  163. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/robots/__init__.py +0 -0
  164. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/robots/battery_state.py +0 -0
  165. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/robots/media.py +0 -0
  166. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/models/robots/robot_model.py +0 -0
  167. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/robot_interface.py +0 -0
  168. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/telemetry/__init__.py +0 -0
  169. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/telemetry/mqtt_client.py +0 -0
  170. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/telemetry/payloads.py +0 -0
  171. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/test_robot_interface.py +0 -0
  172. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/utilities/__init__.py +0 -0
  173. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/utilities/json_service.py +0 -0
  174. {isar-1.33.5 → isar-1.33.7}/src/robot_interface/utilities/uuid_string_factory.py +0 -0
  175. {isar-1.33.5 → isar-1.33.7}/tests/__init__.py +0 -0
  176. {isar-1.33.5 → isar-1.33.7}/tests/conftest.py +0 -0
  177. {isar-1.33.5 → isar-1.33.7}/tests/integration/__init__.py +0 -0
  178. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/__init__.py +0 -0
  179. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/config/__init__.py +0 -0
  180. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/config/maps/__init__.py +0 -0
  181. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/config/maps/turtleworld.json +0 -0
  182. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/config/missions/__init__.py +0 -0
  183. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/config/missions/default.json +0 -0
  184. {isar-1.33.5 → isar-1.33.7}/tests/integration/turtlebot/test_successful_mission.py +0 -0
  185. {isar-1.33.5 → isar-1.33.7}/tests/isar/__init__.py +0 -0
  186. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/__init__.py +0 -0
  187. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/models/__init__.py +0 -0
  188. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/models/example_mission_definition.json +0 -0
  189. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/models/test_start_mission_definition.py +0 -0
  190. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/scheduler/__init__.py +0 -0
  191. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/scheduler/test_scheduler_router.py +0 -0
  192. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/security/__init__.py +0 -0
  193. {isar-1.33.5 → isar-1.33.7}/tests/isar/apis/security/test_authentication.py +0 -0
  194. {isar-1.33.5 → isar-1.33.7}/tests/isar/mission/__init__.py +0 -0
  195. {isar-1.33.5 → isar-1.33.7}/tests/isar/mission/test_mission.py +0 -0
  196. {isar-1.33.5 → isar-1.33.7}/tests/isar/models/__init__.py +0 -0
  197. {isar-1.33.5 → isar-1.33.7}/tests/isar/models/communication/__init__.py +0 -0
  198. {isar-1.33.5 → isar-1.33.7}/tests/isar/models/communication/test_events.py +0 -0
  199. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/__init__.py +0 -0
  200. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/readers/__init__.py +0 -0
  201. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/readers/test_mission_reader.py +0 -0
  202. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/service_connections/__init__.py +0 -0
  203. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/service_connections/echo/__init__.py +0 -0
  204. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/service_connections/test_base_request_handler.py +0 -0
  205. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/utilities/__init__.py +0 -0
  206. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/utilities/test_queue_utilities.py +0 -0
  207. {isar-1.33.5 → isar-1.33.7}/tests/isar/services/utilities/test_scheduling_utilities.py +0 -0
  208. {isar-1.33.5 → isar-1.33.7}/tests/isar/state_machine/__init__.py +0 -0
  209. {isar-1.33.5 → isar-1.33.7}/tests/isar/state_machine/states/__init__.py +0 -0
  210. {isar-1.33.5 → isar-1.33.7}/tests/isar/state_machine/states/test_monitor.py +0 -0
  211. {isar-1.33.5 → isar-1.33.7}/tests/isar/storage/test_blob_storage.py +0 -0
  212. {isar-1.33.5 → isar-1.33.7}/tests/isar/storage/test_uploader.py +0 -0
  213. {isar-1.33.5 → isar-1.33.7}/tests/test_data/test_map_config/test_map_config.json +0 -0
  214. {isar-1.33.5 → isar-1.33.7}/tests/test_data/test_mission_not_working.json +0 -0
  215. {isar-1.33.5 → isar-1.33.7}/tests/test_data/test_mission_working.json +0 -0
  216. {isar-1.33.5 → isar-1.33.7}/tests/test_data/test_mission_working_no_tasks.json +0 -0
  217. {isar-1.33.5 → isar-1.33.7}/tests/test_data/test_thermal_image_mission.json +0 -0
  218. {isar-1.33.5 → isar-1.33.7}/tests/test_double/__init__.py +0 -0
  219. {isar-1.33.5 → isar-1.33.7}/tests/test_double/blob_storage.py +0 -0
  220. {isar-1.33.5 → isar-1.33.7}/tests/test_double/mission_definition.py +0 -0
  221. {isar-1.33.5 → isar-1.33.7}/tests/test_double/mqtt_client.py +0 -0
  222. {isar-1.33.5 → isar-1.33.7}/tests/test_double/pose.py +0 -0
  223. {isar-1.33.5 → isar-1.33.7}/tests/test_double/request.py +0 -0
  224. {isar-1.33.5 → isar-1.33.7}/tests/test_double/status.py +0 -0
  225. {isar-1.33.5 → isar-1.33.7}/tests/test_double/task.py +0 -0
  226. {isar-1.33.5 → isar-1.33.7}/tests/test_double/token.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: isar
3
- Version: 1.33.5
3
+ Version: 1.33.7
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
@@ -245,6 +245,40 @@ class API:
245
245
  },
246
246
  },
247
247
  )
248
+ router.add_api_route(
249
+ path="/schedule/lockdown",
250
+ endpoint=self.scheduling_controller.lockdown,
251
+ methods=["POST"],
252
+ dependencies=[authentication_dependency],
253
+ summary="Send the robot to dock and ensure that it stays there",
254
+ responses={
255
+ HTTPStatus.OK.value: {"description": "Robot going to dock"},
256
+ HTTPStatus.CONFLICT.value: {
257
+ "description": "Conflict - Invalid command in the current state"
258
+ },
259
+ HTTPStatus.INTERNAL_SERVER_ERROR.value: {
260
+ "description": "Internal Server Error - Current state of state machine unknown"
261
+ },
262
+ },
263
+ )
264
+ router.add_api_route(
265
+ path="/schedule/release-lockdown",
266
+ endpoint=self.scheduling_controller.release_lockdown,
267
+ methods=["POST"],
268
+ dependencies=[authentication_dependency],
269
+ summary="Allow the robot to start missions again",
270
+ responses={
271
+ HTTPStatus.OK.value: {
272
+ "description": "Robot is able to receive missions again"
273
+ },
274
+ HTTPStatus.CONFLICT.value: {
275
+ "description": "Conflict - Invalid command in the current state"
276
+ },
277
+ HTTPStatus.INTERNAL_SERVER_ERROR.value: {
278
+ "description": "Internal Server Error - Current state of state machine unknown"
279
+ },
280
+ },
281
+ )
248
282
  router.add_api_route(
249
283
  path="/schedule/release-intervention-needed",
250
284
  endpoint=self.scheduling_controller.release_intervention_needed,
@@ -32,6 +32,11 @@ class MissionStartResponse(BaseModel):
32
32
  mission_not_started_reason: Optional[str] = None
33
33
 
34
34
 
35
+ class LockdownResponse(BaseModel):
36
+ lockdown_started: bool
37
+ failure_reason: Optional[str] = None
38
+
39
+
35
40
  class RobotInfoResponse(BaseModel):
36
41
  robot_package: str
37
42
  isar_id: str
@@ -254,6 +254,40 @@ class SchedulingController:
254
254
  self.scheduling_utilities.release_intervention_needed()
255
255
  self.logger.info("Released intervention needed state successfully")
256
256
 
257
+ @tracer.start_as_current_span("lockdown")
258
+ def lockdown(self) -> None:
259
+ self.logger.info("Received request to lockdown robot")
260
+
261
+ state: States = self.scheduling_utilities.get_state()
262
+
263
+ if state == States.Lockdown:
264
+ error_message = "Conflict - Lockdown command received in lockdown state"
265
+ self.logger.warning(error_message)
266
+ raise HTTPException(
267
+ status_code=HTTPStatus.CONFLICT,
268
+ detail=error_message,
269
+ )
270
+
271
+ self.scheduling_utilities.lock_down_robot()
272
+ self.logger.info("Lockdown started successfully")
273
+
274
+ @tracer.start_as_current_span("release_lockdown")
275
+ def release_lockdown(self) -> None:
276
+ self.logger.info("Received request to release robot lockdown")
277
+
278
+ state: States = self.scheduling_utilities.get_state()
279
+
280
+ if state != States.Lockdown:
281
+ error_message = f"Conflict - Release lockdown command received in invalid state - State: {state}"
282
+ self.logger.warning(error_message)
283
+ raise HTTPException(
284
+ status_code=HTTPStatus.CONFLICT,
285
+ detail=error_message,
286
+ )
287
+
288
+ self.scheduling_utilities.release_robot_lockdown()
289
+ self.logger.info("Released lockdown successfully")
290
+
257
291
  def _api_response(self, mission: Mission) -> StartMissionResponse:
258
292
  return StartMissionResponse(
259
293
  id=mission.id,
@@ -59,6 +59,9 @@ class Settings(BaseSettings):
59
59
  # issues
60
60
  REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY: float = Field(default=10)
61
61
 
62
+ # Time allowed to clear the robot status before giving up
63
+ CLEAR_ROBOT_STATUS_TIMEOUT: int = Field(default=3)
64
+
62
65
  # Number of attempts for state transitions resume and pause if failed
63
66
  STATE_TRANSITION_NUM_RETIRES: int = Field(default=10)
64
67
 
@@ -78,6 +81,7 @@ class Settings(BaseSettings):
78
81
  ROBOT_STATUS_PUBLISH_INTERVAL: float = Field(default=1)
79
82
  ROBOT_HEARTBEAT_PUBLISH_INTERVAL: float = Field(default=1)
80
83
  ROBOT_INFO_PUBLISH_INTERVAL: float = Field(default=5)
84
+ ROBOT_API_BATTERY_POLL_INTERVAL: float = Field(default=5)
81
85
  ROBOT_API_STATUS_POLL_INTERVAL: float = Field(default=5)
82
86
  THREAD_CHECK_INTERVAL: float = Field(default=0.01)
83
87
 
@@ -4,7 +4,11 @@ from typing import Generic, Optional, TypeVar
4
4
 
5
5
  from transitions import State
6
6
 
7
- from isar.apis.models.models import ControlMissionResponse, MissionStartResponse
7
+ from isar.apis.models.models import (
8
+ ControlMissionResponse,
9
+ LockdownResponse,
10
+ MissionStartResponse,
11
+ )
8
12
  from isar.config.settings import settings
9
13
  from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
10
14
  from robot_interface.models.mission.mission import Mission
@@ -105,6 +109,12 @@ class APIRequests:
105
109
  self.release_intervention_needed: APIEvent[bool, bool] = APIEvent(
106
110
  "release_intervention_needed"
107
111
  )
112
+ self.send_to_lockdown: APIEvent[bool, LockdownResponse] = APIEvent(
113
+ "send_to_lockdown"
114
+ )
115
+ self.release_from_lockdown: APIEvent[bool, bool] = APIEvent(
116
+ "release_from_lockdown"
117
+ )
108
118
 
109
119
 
110
120
  class StateMachineEvents:
@@ -113,6 +123,7 @@ class StateMachineEvents:
113
123
  self.stop_mission: Event[bool] = Event("stop_mission")
114
124
  self.pause_mission: Event[bool] = Event("pause_mission")
115
125
  self.task_status_request: Event[str] = Event("task_status_request")
126
+ self.clear_robot_status: Event[bool] = Event("clear_robot_status")
116
127
 
117
128
 
118
129
  class RobotServiceEvents:
@@ -122,12 +133,19 @@ class RobotServiceEvents:
122
133
  self.mission_started: Event[bool] = Event("mission_started")
123
134
  self.mission_failed: Event[ErrorMessage] = Event("mission_failed")
124
135
  self.robot_status_changed: Event[bool] = Event("robot_status_changed")
136
+ self.robot_status_cleared: Event[bool] = Event("robot_status_cleared")
125
137
  self.mission_failed_to_stop: Event[ErrorMessage] = Event(
126
138
  "mission_failed_to_stop"
127
139
  )
128
140
  self.mission_successfully_stopped: Event[bool] = Event(
129
141
  "mission_successfully_stopped"
130
142
  )
143
+ self.mission_failed_to_pause: Event[ErrorMessage] = Event(
144
+ "mission_failed_to_pause"
145
+ )
146
+ self.mission_successfully_paused: Event[bool] = Event(
147
+ "mission_successfully_paused"
148
+ )
131
149
 
132
150
 
133
151
  class SharedState:
@@ -9,6 +9,8 @@ from isar.models.events import (
9
9
  SharedState,
10
10
  StateMachineEvents,
11
11
  )
12
+ from isar.robot.robot_battery import RobotBatteryThread
13
+ from isar.robot.robot_pause_mission import RobotPauseMissionThread
12
14
  from isar.robot.robot_start_mission import RobotStartMissionThread
13
15
  from isar.robot.robot_status import RobotStatusThread
14
16
  from isar.robot.robot_stop_mission import RobotStopMissionThread
@@ -28,15 +30,22 @@ class Robot(object):
28
30
  self.shared_state: SharedState = shared_state
29
31
  self.robot: RobotInterface = robot
30
32
  self.start_mission_thread: Optional[RobotStartMissionThread] = None
33
+ self.robot_battery_thread: Optional[RobotBatteryThread] = None
31
34
  self.robot_status_thread: Optional[RobotStatusThread] = None
32
35
  self.robot_task_status_thread: Optional[RobotTaskStatusThread] = None
33
36
  self.stop_mission_thread: Optional[RobotStopMissionThread] = None
37
+ self.pause_mission_thread: Optional[RobotPauseMissionThread] = None
34
38
  self.signal_thread_quitting: ThreadEvent = ThreadEvent()
35
39
 
36
40
  def stop(self) -> None:
37
41
  self.signal_thread_quitting.set()
38
42
  if self.robot_status_thread is not None and self.robot_status_thread.is_alive():
39
43
  self.robot_status_thread.join()
44
+ if (
45
+ self.robot_battery_thread is not None
46
+ and self.robot_battery_thread.is_alive()
47
+ ):
48
+ self.robot_battery_thread.join()
40
49
  if (
41
50
  self.robot_task_status_thread is not None
42
51
  and self.robot_task_status_thread.is_alive()
@@ -50,6 +59,7 @@ class Robot(object):
50
59
  if self.stop_mission_thread is not None and self.stop_mission_thread.is_alive():
51
60
  self.stop_mission_thread.join()
52
61
  self.robot_status_thread = None
62
+ self.robot_battery_thread = None
53
63
  self.robot_task_status_thread = None
54
64
  self.start_mission_thread = None
55
65
 
@@ -111,12 +121,49 @@ class Robot(object):
111
121
  )
112
122
  self.stop_mission_thread.start()
113
123
 
124
+ def _pause_mission_request_handler(self, event: Event[bool]) -> None:
125
+ if event.consume_event():
126
+ if (
127
+ self.pause_mission_thread is not None
128
+ and self.pause_mission_thread.is_alive()
129
+ ):
130
+ self.logger.warning(
131
+ "Received pause mission event while trying to pause a mission. Aborting pause attempt."
132
+ )
133
+ return
134
+ if (
135
+ self.start_mission_thread is not None
136
+ and self.start_mission_thread.is_alive()
137
+ ):
138
+ error_description = "Received pause mission event while trying to start a mission. Aborting pause attempt."
139
+ error_message = ErrorMessage(
140
+ error_reason=ErrorReason.RobotStillStartingMissionException,
141
+ error_description=error_description,
142
+ )
143
+ self.robot_service_events.mission_failed_to_stop.trigger_event(
144
+ error_message
145
+ )
146
+ return
147
+ self.pause_mission_thread = RobotPauseMissionThread(
148
+ self.robot_service_events, self.robot, self.signal_thread_quitting
149
+ )
150
+ self.pause_mission_thread.start()
151
+
114
152
  def run(self) -> None:
115
153
  self.robot_status_thread = RobotStatusThread(
116
- self.robot, self.signal_thread_quitting, self.shared_state
154
+ robot=self.robot,
155
+ signal_thread_quitting=self.signal_thread_quitting,
156
+ shared_state=self.shared_state,
157
+ state_machine_events=self.state_machine_events,
158
+ robot_service_events=self.robot_service_events,
117
159
  )
118
160
  self.robot_status_thread.start()
119
161
 
162
+ self.robot_battery_thread = RobotBatteryThread(
163
+ self.robot, self.signal_thread_quitting, self.shared_state
164
+ )
165
+ self.robot_battery_thread.start()
166
+
120
167
  while not self.signal_thread_quitting.wait(0):
121
168
  self._start_mission_event_handler(self.state_machine_events.start_mission)
122
169
 
@@ -124,6 +171,8 @@ class Robot(object):
124
171
  self.state_machine_events.task_status_request
125
172
  )
126
173
 
174
+ self._pause_mission_request_handler(self.state_machine_events.pause_mission)
175
+
127
176
  self._stop_mission_request_handler(self.state_machine_events.stop_mission)
128
177
 
129
178
  self.logger.info("Exiting robot service main thread")
@@ -8,7 +8,7 @@ from robot_interface.models.exceptions.robot_exceptions import RobotException
8
8
  from robot_interface.robot_interface import RobotInterface
9
9
 
10
10
 
11
- class RobotStatusThread(Thread):
11
+ class RobotBatteryThread(Thread):
12
12
  def __init__(
13
13
  self,
14
14
  robot: RobotInterface,
@@ -19,20 +19,24 @@ class RobotStatusThread(Thread):
19
19
  self.shared_state: SharedState = shared_state
20
20
  self.robot: RobotInterface = robot
21
21
  self.signal_thread_quitting: Event = signal_thread_quitting
22
- self.last_robot_status_poll_time: float = (
23
- time.time() - settings.ROBOT_API_STATUS_POLL_INTERVAL
24
- )
25
- Thread.__init__(self, name="Robot status thread")
22
+ self.last_robot_battery_poll_time: float = time.time()
23
+ self.force_battery_poll_next_iteration: bool = True
24
+ Thread.__init__(self, name="Robot battery thread")
26
25
 
27
26
  def stop(self) -> None:
28
27
  return
29
28
 
30
- def _is_ready_to_poll_for_status(self) -> bool:
31
- time_since_last_robot_status_poll = (
32
- time.time() - self.last_robot_status_poll_time
29
+ def _is_ready_to_poll_for_battery(self) -> bool:
30
+ if self.force_battery_poll_next_iteration:
31
+ self.force_battery_poll_next_iteration = False
32
+ return True
33
+
34
+ time_since_last_robot_battery_poll = (
35
+ time.time() - self.last_robot_battery_poll_time
33
36
  )
34
37
  return (
35
- time_since_last_robot_status_poll > settings.ROBOT_API_STATUS_POLL_INTERVAL
38
+ time_since_last_robot_battery_poll
39
+ > settings.ROBOT_API_BATTERY_POLL_INTERVAL
36
40
  )
37
41
 
38
42
  def run(self):
@@ -42,17 +46,15 @@ class RobotStatusThread(Thread):
42
46
  thread_check_interval = settings.THREAD_CHECK_INTERVAL
43
47
 
44
48
  while not self.signal_thread_quitting.wait(thread_check_interval):
45
- if not self._is_ready_to_poll_for_status():
49
+ if not self._is_ready_to_poll_for_battery():
46
50
  continue
47
51
  try:
48
- self.last_robot_status_poll_time = time.time()
52
+ self.last_robot_battery_poll_time = time.time()
49
53
 
50
- robot_status = self.robot.robot_status()
51
54
  robot_battery_level = self.robot.get_battery_level()
52
55
 
53
- self.shared_state.robot_status.update(robot_status)
54
56
  self.shared_state.robot_battery_level.update(robot_battery_level)
55
57
  except RobotException as e:
56
- self.logger.error(f"Failed to retrieve robot status: {e}")
58
+ self.logger.error(f"Failed to retrieve robot battery level: {e}")
57
59
  continue
58
- self.logger.info("Exiting robot status thread")
60
+ self.logger.info("Exiting robot battery thread")
@@ -0,0 +1,63 @@
1
+ import logging
2
+ import time
3
+ from threading import Event, Thread
4
+ from typing import Optional
5
+
6
+ from isar.config.settings import settings
7
+ from isar.models.events import RobotServiceEvents
8
+ from robot_interface.models.exceptions.robot_exceptions import (
9
+ ErrorMessage,
10
+ RobotActionException,
11
+ RobotException,
12
+ )
13
+ from robot_interface.robot_interface import RobotInterface
14
+
15
+
16
+ class RobotPauseMissionThread(Thread):
17
+ def __init__(
18
+ self,
19
+ robot_service_events: RobotServiceEvents,
20
+ robot: RobotInterface,
21
+ signal_thread_quitting: Event,
22
+ ):
23
+ self.logger = logging.getLogger("robot")
24
+ self.robot_service_events: RobotServiceEvents = robot_service_events
25
+ self.robot: RobotInterface = robot
26
+ self.signal_thread_quitting: Event = signal_thread_quitting
27
+ Thread.__init__(self, name="Robot pause mission thread")
28
+
29
+ def run(self) -> None:
30
+ retries = 0
31
+ error: Optional[ErrorMessage] = None
32
+ while retries < settings.STATE_TRANSITION_NUM_RETIRES:
33
+ if self.signal_thread_quitting.wait(0):
34
+ return
35
+
36
+ try:
37
+ self.robot.pause()
38
+ except (RobotActionException, RobotException) as e:
39
+ self.logger.warning(
40
+ f"\nFailed to pause robot because: {e.error_description}"
41
+ f"\nAttempting to pause the robot again"
42
+ )
43
+ retries += 1
44
+ error = ErrorMessage(
45
+ error_reason=e.error_reason, error_description=e.error_description
46
+ )
47
+ time.sleep(settings.FSM_SLEEP_TIME)
48
+ continue
49
+ self.robot_service_events.mission_successfully_paused.trigger_event(True)
50
+ return
51
+
52
+ error_description = (
53
+ f"\nFailed to pause the robot after {retries} attempts because: "
54
+ f"{error.error_description}"
55
+ f"\nBe aware that the robot may still be moving even though a pause has "
56
+ "been attempted"
57
+ )
58
+
59
+ error_message = ErrorMessage(
60
+ error_reason=error.error_reason,
61
+ error_description=error_description,
62
+ )
63
+ self.robot_service_events.mission_failed_to_pause.trigger_event(error_message)
@@ -0,0 +1,71 @@
1
+ import logging
2
+ import time
3
+ from threading import Event, Thread
4
+
5
+ from isar.config.settings import settings
6
+ from isar.models.events import RobotServiceEvents, SharedState, StateMachineEvents
7
+ from robot_interface.models.exceptions.robot_exceptions import RobotException
8
+ from robot_interface.robot_interface import RobotInterface
9
+
10
+
11
+ class RobotStatusThread(Thread):
12
+ def __init__(
13
+ self,
14
+ robot: RobotInterface,
15
+ signal_thread_quitting: Event,
16
+ shared_state: SharedState,
17
+ robot_service_events: RobotServiceEvents,
18
+ state_machine_events: StateMachineEvents,
19
+ ):
20
+ self.logger = logging.getLogger("robot")
21
+ self.shared_state: SharedState = shared_state
22
+ self.robot_service_events: RobotServiceEvents = robot_service_events
23
+ self.state_machine_events: StateMachineEvents = state_machine_events
24
+ self.robot: RobotInterface = robot
25
+ self.signal_thread_quitting: Event = signal_thread_quitting
26
+ self.robot_status_poll_interval: float = settings.ROBOT_API_STATUS_POLL_INTERVAL
27
+ self.last_robot_status_poll_time: float = time.time()
28
+ self.force_status_poll_next_iteration: bool = True
29
+ Thread.__init__(self, name="Robot status thread")
30
+
31
+ def stop(self) -> None:
32
+ return
33
+
34
+ def _is_ready_to_poll_for_status(self) -> bool:
35
+ if self.force_status_poll_next_iteration:
36
+ self.force_status_poll_next_iteration = False
37
+ return True
38
+
39
+ time_since_last_robot_status_poll = (
40
+ time.time() - self.last_robot_status_poll_time
41
+ )
42
+ return time_since_last_robot_status_poll > self.robot_status_poll_interval
43
+
44
+ def run(self):
45
+ if self.signal_thread_quitting.is_set():
46
+ return
47
+
48
+ thread_check_interval = settings.THREAD_CHECK_INTERVAL
49
+
50
+ while not self.signal_thread_quitting.wait(thread_check_interval):
51
+ if self.state_machine_events.clear_robot_status.consume_event() is not None:
52
+ self.shared_state.robot_status.clear_event()
53
+ self.robot_service_events.robot_status_changed.clear_event()
54
+ self.robot_service_events.robot_status_cleared.trigger_event(True)
55
+ self.force_status_poll_next_iteration = True
56
+
57
+ if not self._is_ready_to_poll_for_status():
58
+ continue
59
+
60
+ try:
61
+ self.last_robot_status_poll_time = time.time()
62
+
63
+ robot_status = self.robot.robot_status()
64
+
65
+ if robot_status is not self.shared_state.robot_status.check():
66
+ self.shared_state.robot_status.update(robot_status)
67
+ self.robot_service_events.robot_status_changed.trigger_event(True)
68
+ except RobotException as e:
69
+ self.logger.error(f"Failed to retrieve robot status: {e}")
70
+ continue
71
+ self.logger.info("Exiting robot status thread")
@@ -24,7 +24,7 @@ class RobotStopMissionThread(Thread):
24
24
  self.robot_service_events: RobotServiceEvents = robot_service_events
25
25
  self.robot: RobotInterface = robot
26
26
  self.signal_thread_quitting: Event = signal_thread_quitting
27
- Thread.__init__(self, name="Robot start mission thread")
27
+ Thread.__init__(self, name="Robot stop mission thread")
28
28
 
29
29
  def run(self) -> None:
30
30
  retries = 0
@@ -322,14 +322,60 @@ class SchedulingUtilities:
322
322
  try:
323
323
  self._send_command(True, self.api_events.release_intervention_needed)
324
324
  self.logger.info("OK - Intervention needed state released")
325
+ except EventConflictError:
326
+ error_message = (
327
+ "Previous release intervention needed request is still being processed"
328
+ )
329
+ self.logger.warning(error_message)
330
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
325
331
  except EventTimeoutError:
332
+ error_message = "Cannot release intervention needed as it is not in intervention needed state"
333
+ self.logger.warning(error_message)
334
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
335
+
336
+ def lock_down_robot(self) -> None:
337
+ """Lock down robot
338
+
339
+ Raises
340
+ ------
341
+ HTTPException 500 Internal Server Error
342
+ If the robot could not be locked down
343
+ """
344
+ try:
345
+ self._send_command(True, self.api_events.send_to_lockdown)
346
+ self.logger.info("OK - Robot sent into lockdown")
347
+ except EventConflictError:
348
+ error_message = "Previous lockdown request is still being processed"
349
+ self.logger.warning(error_message)
350
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
351
+ except EventTimeoutError:
352
+ error_message = "Cannot send robot to lockdown as it is already in lockdown"
353
+ self.logger.warning(error_message)
354
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
355
+
356
+ def release_robot_lockdown(self) -> None:
357
+ """Release robot from lockdown
358
+
359
+ Raises
360
+ ------
361
+ HTTPException 500 Internal Server Error
362
+ If the robot could not be released from lockdown
363
+ """
364
+ try:
365
+ self._send_command(True, self.api_events.release_from_lockdown)
366
+ self.logger.info("OK - Robot released form lockdown")
367
+ except EventConflictError:
326
368
  error_message = (
327
- "Internal Server Error - Failed to release intervention needed state"
369
+ "Previous release robot from lockdown request is still being processed"
328
370
  )
329
- self.logger.error(error_message)
330
- raise HTTPException(
331
- status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=error_message
371
+ self.logger.warning(error_message)
372
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
373
+ except EventTimeoutError:
374
+ error_message = (
375
+ "Cannot release robot from lockdown as it is not in lockdown"
332
376
  )
377
+ self.logger.warning(error_message)
378
+ raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
333
379
 
334
380
  def _send_command(self, input: T1, api_event: APIEvent[T1, T2]) -> T2:
335
381
  if api_event.request.has_event():
@@ -18,15 +18,20 @@ from isar.models.events import Events, SharedState
18
18
  from isar.services.service_connections.mqtt.mqtt_client import props_expiry
19
19
  from isar.state_machine.states.await_next_mission import AwaitNextMission
20
20
  from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
21
+ from isar.state_machine.states.going_to_lockdown import GoingToLockdown
21
22
  from isar.state_machine.states.home import Home
22
23
  from isar.state_machine.states.intervention_needed import InterventionNeeded
24
+ from isar.state_machine.states.lockdown import Lockdown
23
25
  from isar.state_machine.states.monitor import Monitor
24
26
  from isar.state_machine.states.offline import Offline
25
27
  from isar.state_machine.states.paused import Paused
28
+ from isar.state_machine.states.pausing import Pausing
29
+ from isar.state_machine.states.pausing_return_home import PausingReturnHome
26
30
  from isar.state_machine.states.recharging import Recharging
27
31
  from isar.state_machine.states.return_home_paused import ReturnHomePaused
28
32
  from isar.state_machine.states.returning_home import ReturningHome
29
33
  from isar.state_machine.states.stopping import Stopping
34
+ from isar.state_machine.states.stopping_go_to_lockdown import StoppingGoToLockdown
30
35
  from isar.state_machine.states.stopping_return_home import StoppingReturnHome
31
36
  from isar.state_machine.states.unknown_status import UnknownStatus
32
37
  from isar.state_machine.states_enum import States
@@ -102,8 +107,12 @@ class StateMachine(object):
102
107
  self.returning_home_state: State = ReturningHome(self)
103
108
  self.stopping_state: State = Stopping(self)
104
109
  self.paused_state: State = Paused(self)
110
+ self.pausing_state: State = Pausing(self)
105
111
  self.return_home_paused_state: State = ReturnHomePaused(self)
106
112
  self.stopping_return_home_state: State = StoppingReturnHome(self)
113
+ self.pausing_return_home_state: State = PausingReturnHome(self)
114
+ self.stopping_go_to_lockdown_state: State = StoppingGoToLockdown(self)
115
+ self.going_to_lockdown_state: State = GoingToLockdown(self)
107
116
 
108
117
  # States Waiting for mission
109
118
  self.await_next_mission_state: State = AwaitNextMission(self)
@@ -114,6 +123,7 @@ class StateMachine(object):
114
123
  self.offline_state: State = Offline(self)
115
124
  self.blocked_protective_stopping_state: State = BlockedProtectiveStop(self)
116
125
  self.recharging_state: State = Recharging(self)
126
+ self.lockdown_state: State = Lockdown(self)
117
127
 
118
128
  # Error and special status states
119
129
  self.unknown_status_state: State = UnknownStatus(self)
@@ -123,7 +133,9 @@ class StateMachine(object):
123
133
  self.returning_home_state,
124
134
  self.stopping_state,
125
135
  self.stopping_return_home_state,
136
+ self.pausing_return_home_state,
126
137
  self.paused_state,
138
+ self.pausing_state,
127
139
  self.return_home_paused_state,
128
140
  self.await_next_mission_state,
129
141
  self.home_state,
@@ -132,6 +144,9 @@ class StateMachine(object):
132
144
  self.unknown_status_state,
133
145
  self.intervention_needed_state,
134
146
  self.recharging_state,
147
+ self.stopping_go_to_lockdown_state,
148
+ self.going_to_lockdown_state,
149
+ self.lockdown_state,
135
150
  ]
136
151
 
137
152
  self.machine = Machine(
@@ -288,13 +303,14 @@ class StateMachine(object):
288
303
  timestamp=datetime.now(timezone.utc),
289
304
  )
290
305
 
291
- self.mqtt_publisher.publish(
292
- topic=settings.TOPIC_ISAR_MISSION + f"/{self.current_mission.id}",
293
- payload=json.dumps(payload, cls=EnhancedJSONEncoder),
294
- qos=1,
295
- retain=True,
296
- properties=props_expiry(settings.MQTT_MISSION_AND_TASK_EXPIRY),
297
- )
306
+ if self.current_mission:
307
+ self.mqtt_publisher.publish(
308
+ topic=settings.TOPIC_ISAR_MISSION + f"/{self.current_mission.id}",
309
+ payload=json.dumps(payload, cls=EnhancedJSONEncoder),
310
+ qos=1,
311
+ retain=True,
312
+ properties=props_expiry(settings.MQTT_MISSION_AND_TASK_EXPIRY),
313
+ )
298
314
 
299
315
  def publish_task_status(self, task: TASKS) -> None:
300
316
  """Publishes the task status to the MQTT Broker"""
@@ -384,6 +400,10 @@ class StateMachine(object):
384
400
  return RobotStatus.InterventionNeeded
385
401
  elif self.current_state == States.Recharging:
386
402
  return RobotStatus.Recharging
403
+ elif self.current_state == States.Lockdown:
404
+ return RobotStatus.Lockdown
405
+ elif self.current_state == States.GoingToLockdown:
406
+ return RobotStatus.GoingToLockdown
387
407
  else:
388
408
  return RobotStatus.Busy
389
409