isar 1.33.1__tar.gz → 1.33.3__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 (216) hide show
  1. {isar-1.33.1 → isar-1.33.3}/PKG-INFO +2 -2
  2. {isar-1.33.1 → isar-1.33.3}/README.md +1 -1
  3. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/schedule/scheduling_controller.py +3 -1
  4. {isar-1.33.1 → isar-1.33.3}/src/isar/config/settings.py +5 -0
  5. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/mqtt/mqtt_client.py +46 -10
  6. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +3 -0
  7. {isar-1.33.1 → isar-1.33.3}/src/isar/services/utilities/scheduling_utilities.py +5 -9
  8. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/state_machine.py +16 -9
  9. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/home.py +14 -5
  10. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/paused.py +24 -1
  11. isar-1.33.3/src/isar/state_machine/states/return_home_paused.py +66 -0
  12. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/returning_home.py +10 -5
  13. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/stopping.py +5 -22
  14. isar-1.33.3/src/isar/state_machine/states/stopping_return_home.py +73 -0
  15. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states_enum.py +2 -1
  16. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/pause.py +38 -0
  17. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/robot_status.py +2 -7
  18. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/mission.py +46 -19
  19. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/return_home.py +1 -7
  20. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/robot_status.py +2 -17
  21. isar-1.33.3/src/isar/storage/blob_storage.py +101 -0
  22. {isar-1.33.1 → isar-1.33.3}/src/isar/storage/local_storage.py +21 -11
  23. {isar-1.33.1 → isar-1.33.3}/src/isar/storage/storage_interface.py +27 -6
  24. {isar-1.33.1 → isar-1.33.3}/src/isar/storage/uploader.py +30 -13
  25. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/PKG-INFO +2 -2
  26. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/SOURCES.txt +2 -1
  27. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/mission/status.py +2 -1
  28. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/telemetry/mqtt_client.py +62 -6
  29. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/telemetry/payloads.py +4 -2
  30. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/utilities/json_service.py +6 -0
  31. {isar-1.33.1 → isar-1.33.3}/tests/conftest.py +12 -4
  32. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/test_successful_mission.py +1 -1
  33. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/scheduler/test_scheduler_router.py +13 -51
  34. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/utilities/test_scheduling_utilities.py +0 -3
  35. {isar-1.33.1 → isar-1.33.3}/tests/isar/state_machine/test_state_machine.py +119 -205
  36. {isar-1.33.1 → isar-1.33.3}/tests/test_double/robot_interface.py +2 -19
  37. {isar-1.33.1 → isar-1.33.3}/tests/test_double/status.py +1 -1
  38. isar-1.33.1/src/isar/state_machine/states/robot_standing_still.py +0 -52
  39. isar-1.33.1/src/isar/storage/blob_storage.py +0 -79
  40. {isar-1.33.1 → isar-1.33.3}/.dockerignore +0 -0
  41. {isar-1.33.1 → isar-1.33.3}/.env.test +0 -0
  42. {isar-1.33.1 → isar-1.33.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  43. {isar-1.33.1 → isar-1.33.3}/.github/ISSUE_TEMPLATE/feature.md +0 -0
  44. {isar-1.33.1 → isar-1.33.3}/.github/ISSUE_TEMPLATE/improvement.md +0 -0
  45. {isar-1.33.1 → isar-1.33.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  46. {isar-1.33.1 → isar-1.33.3}/.github/release.yml +0 -0
  47. {isar-1.33.1 → isar-1.33.3}/.github/workflows/compile_requirements.yml +0 -0
  48. {isar-1.33.1 → isar-1.33.3}/.github/workflows/project_automations.yml +0 -0
  49. {isar-1.33.1 → isar-1.33.3}/.github/workflows/pythonpackage.yml +0 -0
  50. {isar-1.33.1 → isar-1.33.3}/.github/workflows/pythonpublish.yml +0 -0
  51. {isar-1.33.1 → isar-1.33.3}/.github/workflows/stale.yml +0 -0
  52. {isar-1.33.1 → isar-1.33.3}/.gitignore +0 -0
  53. {isar-1.33.1 → isar-1.33.3}/.pre-commit-config.yaml +0 -0
  54. {isar-1.33.1 → isar-1.33.3}/LICENSE +0 -0
  55. {isar-1.33.1 → isar-1.33.3}/SECURITY.md +0 -0
  56. {isar-1.33.1 → isar-1.33.3}/docs/Makefile +0 -0
  57. {isar-1.33.1 → isar-1.33.3}/docs/full_state_machine_diagram.png +0 -0
  58. {isar-1.33.1 → isar-1.33.3}/docs/make.bat +0 -0
  59. {isar-1.33.1 → isar-1.33.3}/docs/mission_state_machine_diagram.png +0 -0
  60. {isar-1.33.1 → isar-1.33.3}/docs/robot_status_state_machine_diagram.png +0 -0
  61. {isar-1.33.1 → isar-1.33.3}/docs/rst_processing.py +0 -0
  62. {isar-1.33.1 → isar-1.33.3}/docs/source/conf.py +0 -0
  63. {isar-1.33.1 → isar-1.33.3}/docs/source/index.rst +0 -0
  64. {isar-1.33.1 → isar-1.33.3}/docs/source/readme_link.md +0 -0
  65. {isar-1.33.1 → isar-1.33.3}/docs/update_state_diagram.py +0 -0
  66. {isar-1.33.1 → isar-1.33.3}/main.py +0 -0
  67. {isar-1.33.1 → isar-1.33.3}/pyproject.toml +0 -0
  68. {isar-1.33.1 → isar-1.33.3}/radixconfig.yml +0 -0
  69. {isar-1.33.1 → isar-1.33.3}/requirements.txt +0 -0
  70. {isar-1.33.1 → isar-1.33.3}/setup.cfg +0 -0
  71. {isar-1.33.1 → isar-1.33.3}/src/isar/__init__.py +0 -0
  72. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/__init__.py +0 -0
  73. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/api.py +0 -0
  74. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/models/__init__.py +0 -0
  75. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/models/models.py +0 -0
  76. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/models/start_mission_definition.py +0 -0
  77. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/robot_control/robot_controller.py +0 -0
  78. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/schedule/__init__.py +0 -0
  79. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/security/__init__.py +0 -0
  80. {isar-1.33.1 → isar-1.33.3}/src/isar/apis/security/authentication.py +0 -0
  81. {isar-1.33.1 → isar-1.33.3}/src/isar/config/__init__.py +0 -0
  82. {isar-1.33.1 → isar-1.33.3}/src/isar/config/certs/ca-cert.pem +0 -0
  83. {isar-1.33.1 → isar-1.33.3}/src/isar/config/configuration_error.py +0 -0
  84. {isar-1.33.1 → isar-1.33.3}/src/isar/config/keyvault/__init__.py +0 -0
  85. {isar-1.33.1 → isar-1.33.3}/src/isar/config/keyvault/keyvault_error.py +0 -0
  86. {isar-1.33.1 → isar-1.33.3}/src/isar/config/keyvault/keyvault_service.py +0 -0
  87. {isar-1.33.1 → isar-1.33.3}/src/isar/config/log.py +0 -0
  88. {isar-1.33.1 → isar-1.33.3}/src/isar/config/logging.conf +0 -0
  89. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/JSP1_intermediate_deck.json +0 -0
  90. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/JSP1_weather_deck.json +0 -0
  91. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/default_map.json +0 -0
  92. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/klab_b.json +0 -0
  93. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/klab_compressor.json +0 -0
  94. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/klab_turtlebot.json +0 -0
  95. {isar-1.33.1 → isar-1.33.3}/src/isar/config/maps/turtleworld.json +0 -0
  96. {isar-1.33.1 → isar-1.33.3}/src/isar/config/open_telemetry.py +0 -0
  97. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_mission_definition/__init__.py +0 -0
  98. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_mission_definition/default_exr.json +0 -0
  99. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_mission_definition/default_mission.json +0 -0
  100. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_mission_definition/default_turtlebot.json +0 -0
  101. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_missions/__init__.py +0 -0
  102. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_missions/default.json +0 -0
  103. {isar-1.33.1 → isar-1.33.3}/src/isar/config/predefined_missions/default_turtlebot.json +0 -0
  104. {isar-1.33.1 → isar-1.33.3}/src/isar/eventhandlers/eventhandler.py +0 -0
  105. {isar-1.33.1 → isar-1.33.3}/src/isar/mission_planner/__init__.py +0 -0
  106. {isar-1.33.1 → isar-1.33.3}/src/isar/mission_planner/local_planner.py +0 -0
  107. {isar-1.33.1 → isar-1.33.3}/src/isar/mission_planner/mission_planner_interface.py +0 -0
  108. {isar-1.33.1 → isar-1.33.3}/src/isar/mission_planner/sequential_task_selector.py +0 -0
  109. {isar-1.33.1 → isar-1.33.3}/src/isar/mission_planner/task_selector_interface.py +0 -0
  110. {isar-1.33.1 → isar-1.33.3}/src/isar/models/__init__.py +0 -0
  111. {isar-1.33.1 → isar-1.33.3}/src/isar/models/events.py +0 -0
  112. {isar-1.33.1 → isar-1.33.3}/src/isar/modules.py +0 -0
  113. {isar-1.33.1 → isar-1.33.3}/src/isar/robot/robot.py +0 -0
  114. {isar-1.33.1 → isar-1.33.3}/src/isar/robot/robot_start_mission.py +0 -0
  115. {isar-1.33.1 → isar-1.33.3}/src/isar/robot/robot_status.py +0 -0
  116. {isar-1.33.1 → isar-1.33.3}/src/isar/robot/robot_stop_mission.py +0 -0
  117. {isar-1.33.1 → isar-1.33.3}/src/isar/robot/robot_task_status.py +0 -0
  118. {isar-1.33.1 → isar-1.33.3}/src/isar/script.py +0 -0
  119. {isar-1.33.1 → isar-1.33.3}/src/isar/services/__init__.py +0 -0
  120. {isar-1.33.1 → isar-1.33.3}/src/isar/services/auth/__init__.py +0 -0
  121. {isar-1.33.1 → isar-1.33.3}/src/isar/services/auth/azure_credentials.py +0 -0
  122. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/__init__.py +0 -0
  123. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/mqtt/__init__.py +0 -0
  124. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/mqtt/robot_info_publisher.py +0 -0
  125. {isar-1.33.1 → isar-1.33.3}/src/isar/services/service_connections/request_handler.py +0 -0
  126. {isar-1.33.1 → isar-1.33.3}/src/isar/services/utilities/__init__.py +0 -0
  127. {isar-1.33.1 → isar-1.33.3}/src/isar/services/utilities/robot_utilities.py +0 -0
  128. {isar-1.33.1 → isar-1.33.3}/src/isar/services/utilities/threaded_request.py +0 -0
  129. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/__init__.py +0 -0
  130. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/__init__.py +0 -0
  131. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/await_next_mission.py +0 -0
  132. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/blocked_protective_stop.py +0 -0
  133. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/intervention_needed.py +0 -0
  134. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/monitor.py +0 -0
  135. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/offline.py +0 -0
  136. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/recharging.py +0 -0
  137. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/states/unknown_status.py +0 -0
  138. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/fail_mission.py +0 -0
  139. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/finish_mission.py +0 -0
  140. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/resume.py +0 -0
  141. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/return_home.py +0 -0
  142. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/start_mission.py +0 -0
  143. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/stop.py +0 -0
  144. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/transitions/functions/utils.py +0 -0
  145. {isar-1.33.1 → isar-1.33.3}/src/isar/state_machine/utils/common_event_handlers.py +0 -0
  146. {isar-1.33.1 → isar-1.33.3}/src/isar/storage/__init__.py +0 -0
  147. {isar-1.33.1 → isar-1.33.3}/src/isar/storage/utilities.py +0 -0
  148. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/dependency_links.txt +0 -0
  149. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/entry_points.txt +0 -0
  150. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/requires.txt +0 -0
  151. {isar-1.33.1 → isar-1.33.3}/src/isar.egg-info/top_level.txt +0 -0
  152. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/__init__.py +0 -0
  153. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/__init__.py +0 -0
  154. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/exceptions/__init__.py +0 -0
  155. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/exceptions/robot_exceptions.py +0 -0
  156. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/initialize/__init__.py +0 -0
  157. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/inspection/__init__.py +0 -0
  158. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/inspection/inspection.py +0 -0
  159. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/mission/__init__.py +0 -0
  160. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/mission/mission.py +0 -0
  161. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/mission/task.py +0 -0
  162. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/robots/__init__.py +0 -0
  163. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/robots/battery_state.py +0 -0
  164. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/robots/media.py +0 -0
  165. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/models/robots/robot_model.py +0 -0
  166. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/robot_interface.py +0 -0
  167. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/telemetry/__init__.py +0 -0
  168. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/test_robot_interface.py +0 -0
  169. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/utilities/__init__.py +0 -0
  170. {isar-1.33.1 → isar-1.33.3}/src/robot_interface/utilities/uuid_string_factory.py +0 -0
  171. {isar-1.33.1 → isar-1.33.3}/tests/__init__.py +0 -0
  172. {isar-1.33.1 → isar-1.33.3}/tests/integration/__init__.py +0 -0
  173. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/__init__.py +0 -0
  174. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/config/__init__.py +0 -0
  175. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/config/maps/__init__.py +0 -0
  176. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/config/maps/turtleworld.json +0 -0
  177. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/config/missions/__init__.py +0 -0
  178. {isar-1.33.1 → isar-1.33.3}/tests/integration/turtlebot/config/missions/default.json +0 -0
  179. {isar-1.33.1 → isar-1.33.3}/tests/isar/__init__.py +0 -0
  180. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/__init__.py +0 -0
  181. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/models/__init__.py +0 -0
  182. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/models/example_mission_definition.json +0 -0
  183. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/models/test_start_mission_definition.py +0 -0
  184. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/scheduler/__init__.py +0 -0
  185. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/security/__init__.py +0 -0
  186. {isar-1.33.1 → isar-1.33.3}/tests/isar/apis/security/test_authentication.py +0 -0
  187. {isar-1.33.1 → isar-1.33.3}/tests/isar/mission/__init__.py +0 -0
  188. {isar-1.33.1 → isar-1.33.3}/tests/isar/mission/test_mission.py +0 -0
  189. {isar-1.33.1 → isar-1.33.3}/tests/isar/models/__init__.py +0 -0
  190. {isar-1.33.1 → isar-1.33.3}/tests/isar/models/communication/__init__.py +0 -0
  191. {isar-1.33.1 → isar-1.33.3}/tests/isar/models/communication/test_events.py +0 -0
  192. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/__init__.py +0 -0
  193. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/readers/__init__.py +0 -0
  194. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/readers/test_mission_reader.py +0 -0
  195. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/service_connections/__init__.py +0 -0
  196. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/service_connections/echo/__init__.py +0 -0
  197. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/service_connections/test_base_request_handler.py +0 -0
  198. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/utilities/__init__.py +0 -0
  199. {isar-1.33.1 → isar-1.33.3}/tests/isar/services/utilities/test_queue_utilities.py +0 -0
  200. {isar-1.33.1 → isar-1.33.3}/tests/isar/state_machine/__init__.py +0 -0
  201. {isar-1.33.1 → isar-1.33.3}/tests/isar/state_machine/states/__init__.py +0 -0
  202. {isar-1.33.1 → isar-1.33.3}/tests/isar/state_machine/states/test_monitor.py +0 -0
  203. {isar-1.33.1 → isar-1.33.3}/tests/isar/storage/test_blob_storage.py +0 -0
  204. {isar-1.33.1 → isar-1.33.3}/tests/isar/storage/test_uploader.py +0 -0
  205. {isar-1.33.1 → isar-1.33.3}/tests/test_data/test_map_config/test_map_config.json +0 -0
  206. {isar-1.33.1 → isar-1.33.3}/tests/test_data/test_mission_not_working.json +0 -0
  207. {isar-1.33.1 → isar-1.33.3}/tests/test_data/test_mission_working.json +0 -0
  208. {isar-1.33.1 → isar-1.33.3}/tests/test_data/test_mission_working_no_tasks.json +0 -0
  209. {isar-1.33.1 → isar-1.33.3}/tests/test_data/test_thermal_image_mission.json +0 -0
  210. {isar-1.33.1 → isar-1.33.3}/tests/test_double/__init__.py +0 -0
  211. {isar-1.33.1 → isar-1.33.3}/tests/test_double/blob_storage.py +0 -0
  212. {isar-1.33.1 → isar-1.33.3}/tests/test_double/mission_definition.py +0 -0
  213. {isar-1.33.1 → isar-1.33.3}/tests/test_double/pose.py +0 -0
  214. {isar-1.33.1 → isar-1.33.3}/tests/test_double/request.py +0 -0
  215. {isar-1.33.1 → isar-1.33.3}/tests/test_double/task.py +0 -0
  216. {isar-1.33.1 → isar-1.33.3}/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.1
3
+ Version: 1.33.3
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
@@ -369,7 +369,7 @@ States.Paused,
369
369
  indicates that the state machine is already running. For running a mission the state machine need to be in the states
370
370
 
371
371
  ```
372
- States.Home, States.RobotStandingStill, States.AwaitNextMission or States.ReturningHome
372
+ States.Home, States.AwaitNextMission or States.ReturningHome
373
373
  ```
374
374
 
375
375
  ### FastAPI
@@ -225,7 +225,7 @@ States.Paused,
225
225
  indicates that the state machine is already running. For running a mission the state machine need to be in the states
226
226
 
227
227
  ```
228
- States.Home, States.RobotStandingStill, States.AwaitNextMission or States.ReturningHome
228
+ States.Home, States.AwaitNextMission or States.ReturningHome
229
229
  ```
230
230
 
231
231
  ### FastAPI
@@ -115,6 +115,7 @@ class SchedulingController:
115
115
 
116
116
  if state not in [
117
117
  States.Monitor,
118
+ States.ReturningHome,
118
119
  ]:
119
120
  error_message = (
120
121
  f"Conflict - Pause command received in invalid state - State: {state}"
@@ -135,7 +136,7 @@ class SchedulingController:
135
136
 
136
137
  state: States = self.scheduling_utilities.get_state()
137
138
 
138
- if state != States.Paused:
139
+ if state not in [States.Paused, States.ReturnHomePaused]:
139
140
  error_message = (
140
141
  f"Conflict - Resume command received in invalid state - State: {state}"
141
142
  )
@@ -167,6 +168,7 @@ class SchedulingController:
167
168
  or state == States.BlockedProtectiveStop
168
169
  or state == States.Offline
169
170
  or state == States.Home
171
+ or state == States.ReturningHome
170
172
  ):
171
173
  error_message = (
172
174
  f"Conflict - Stop command received in invalid state - State: {state}"
@@ -244,6 +244,11 @@ class Settings(BaseSettings):
244
244
  default="intervention_needed", validate_default=True
245
245
  )
246
246
 
247
+ # List of MQTT Topics Expiry
248
+ MQTT_ROBOT_HEARTBEAT_EXPIRY: int = Field(default=5)
249
+ MQTT_TELEMETRY_EXPIRY: int = Field(default=10)
250
+ MQTT_MISSION_AND_TASK_EXPIRY: int = Field(default=86400)
251
+
247
252
  # Logging
248
253
 
249
254
  # Log handlers
@@ -1,15 +1,24 @@
1
1
  import logging
2
2
  import os
3
+ import time
3
4
  from queue import Empty, Queue
4
5
 
5
6
  import backoff
6
7
  from paho.mqtt import client as mqtt
7
8
  from paho.mqtt.client import Client
9
+ from paho.mqtt.packettypes import PacketTypes
10
+ from paho.mqtt.properties import Properties
8
11
 
9
12
  from isar.config.settings import settings
10
13
  from robot_interface.telemetry.mqtt_client import MqttClientInterface
11
14
 
12
15
 
16
+ def props_expiry(seconds: int) -> Properties:
17
+ p = Properties(PacketTypes.PUBLISH)
18
+ p.MessageExpiryInterval = seconds
19
+ return p
20
+
21
+
13
22
  def _on_success(data: dict) -> None:
14
23
  logging.getLogger("mqtt_client").info("Connected to MQTT Broker")
15
24
  logging.getLogger("mqtt_client").debug(
@@ -53,7 +62,9 @@ class MqttClient(MqttClientInterface):
53
62
 
54
63
  self.port: int = settings.MQTT_PORT
55
64
 
56
- self.client: Client = Client(mqtt.CallbackAPIVersion.VERSION1)
65
+ self.client: Client = Client(
66
+ protocol=mqtt.MQTTv5, callback_api_version=mqtt.CallbackAPIVersion.VERSION2
67
+ )
57
68
 
58
69
  self.client.enable_logger(logger=self.logger)
59
70
 
@@ -74,20 +85,36 @@ class MqttClient(MqttClientInterface):
74
85
 
75
86
  while True:
76
87
  if not self.client.is_connected():
88
+ time.sleep(0) # avoid CPU spin
77
89
  continue
78
90
  try:
79
- topic, payload, qos, retain = self.mqtt_queue.get(timeout=1)
91
+ item = self.mqtt_queue.get(timeout=1)
92
+ if len(item) == 4:
93
+ topic, payload, qos, retain = item
94
+ properties = None
95
+ else:
96
+ topic, payload, qos, retain, properties = item
80
97
  except Empty:
81
98
  continue
82
99
 
83
- self.publish(topic=topic, payload=payload, qos=qos, retain=retain)
100
+ self.publish(
101
+ topic=topic,
102
+ payload=payload,
103
+ qos=qos,
104
+ retain=retain,
105
+ properties=properties,
106
+ )
84
107
 
85
- def on_connect(self, client, userdata, flags, rc):
86
- self.logger.info("Connection returned result: " + mqtt.connack_string(rc))
108
+ def on_connect(self, client, userdata, flags, reason_code, properties):
109
+ self.logger.info(
110
+ "Connection returned result: " + mqtt.connack_string(reason_code)
111
+ )
87
112
 
88
- def on_disconnect(self, client, userdata, rc):
89
- if rc != 0:
90
- self.logger.warning("Unexpected disconnection from MQTT Broker")
113
+ def on_disconnect(self, client, userdata, reason_code, properties):
114
+ if reason_code != 0:
115
+ self.logger.warning(
116
+ f"Unexpected disconnection from MQTT Broker, {reason_code}"
117
+ )
91
118
 
92
119
  @backoff.on_exception(
93
120
  backoff.expo,
@@ -102,6 +129,15 @@ class MqttClient(MqttClientInterface):
102
129
  self.logger.info("Host: %s, Port: %s", host, port)
103
130
  self.client.connect(host=host, port=port)
104
131
 
105
- def publish(self, topic: str, payload: str, qos: int = 0, retain: bool = False):
132
+ def publish(
133
+ self,
134
+ topic: str,
135
+ payload: str,
136
+ qos: int = 0,
137
+ retain: bool = False,
138
+ properties=None,
139
+ ):
106
140
  self.logger.debug("Publishing message to topic: %s", topic)
107
- self.client.publish(topic=topic, payload=payload, qos=qos, retain=retain)
141
+ self.client.publish(
142
+ topic=topic, payload=payload, qos=qos, retain=retain, properties=properties
143
+ )
@@ -4,6 +4,7 @@ from datetime import datetime, timezone
4
4
  from queue import Queue
5
5
 
6
6
  from isar.config.settings import settings
7
+ from isar.services.service_connections.mqtt.mqtt_client import props_expiry
7
8
  from robot_interface.telemetry.mqtt_client import MqttPublisher
8
9
  from robot_interface.telemetry.payloads import RobotHeartbeatPayload
9
10
  from robot_interface.utilities.json_service import EnhancedJSONEncoder
@@ -24,6 +25,8 @@ class RobotHeartbeatPublisher:
24
25
  self.mqtt_publisher.publish(
25
26
  topic=settings.TOPIC_ISAR_ROBOT_HEARTBEAT,
26
27
  payload=json.dumps(payload, cls=EnhancedJSONEncoder),
28
+ retain=True,
29
+ properties=props_expiry(settings.MQTT_ROBOT_HEARTBEAT_EXPIRY),
27
30
  )
28
31
 
29
32
  time.sleep(settings.ROBOT_HEARTBEAT_PUBLISH_INTERVAL)
@@ -129,13 +129,13 @@ class SchedulingUtilities:
129
129
  ------
130
130
  HTTPException 409 Conflict
131
131
  If state machine is not home, robot standing still, awaiting next mission
132
- or returning home and therefore cannot start a new mission
132
+ return home paused or returning home and therefore cannot start a new mission
133
133
  """
134
134
  if (
135
- state == States.RobotStandingStill
136
- or state == States.Home
135
+ state == States.Home
137
136
  or state == States.AwaitNextMission
138
137
  or state == States.ReturningHome
138
+ or state == States.ReturnHomePaused
139
139
  ):
140
140
  return True
141
141
 
@@ -154,11 +154,7 @@ class SchedulingUtilities:
154
154
  If state machine is not home, robot standing still or awaiting next mission
155
155
  and therefore cannot start a new return home mission
156
156
  """
157
- if (
158
- state == States.RobotStandingStill
159
- or state == States.Home
160
- or state == States.AwaitNextMission
161
- ):
157
+ if state == States.Home or state == States.AwaitNextMission:
162
158
  return True
163
159
 
164
160
  error_message = f"Conflict - Robot is not home, robot standing still or awaiting next mission - State: {state}"
@@ -336,7 +332,7 @@ class SchedulingUtilities:
336
332
  )
337
333
 
338
334
  def _send_command(self, input: T1, api_event: APIEvent[T1, T2]) -> T2:
339
- if api_event.request.has_event() or api_event.response.has_event():
335
+ if api_event.request.has_event():
340
336
  raise EventConflictError("API event has already been sent")
341
337
 
342
338
  try:
@@ -15,6 +15,7 @@ from isar.mission_planner.task_selector_interface import (
15
15
  TaskSelectorStop,
16
16
  )
17
17
  from isar.models.events import Events, SharedState
18
+ from isar.services.service_connections.mqtt.mqtt_client import props_expiry
18
19
  from isar.state_machine.states.await_next_mission import AwaitNextMission
19
20
  from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
20
21
  from isar.state_machine.states.home import Home
@@ -23,9 +24,10 @@ from isar.state_machine.states.monitor import Monitor
23
24
  from isar.state_machine.states.offline import Offline
24
25
  from isar.state_machine.states.paused import Paused
25
26
  from isar.state_machine.states.recharging import Recharging
27
+ from isar.state_machine.states.return_home_paused import ReturnHomePaused
26
28
  from isar.state_machine.states.returning_home import ReturningHome
27
- from isar.state_machine.states.robot_standing_still import RobotStandingStill
28
29
  from isar.state_machine.states.stopping import Stopping
30
+ from isar.state_machine.states.stopping_return_home import StoppingReturnHome
29
31
  from isar.state_machine.states.unknown_status import UnknownStatus
30
32
  from isar.state_machine.states_enum import States
31
33
  from isar.state_machine.transitions.mission import get_mission_transitions
@@ -100,11 +102,12 @@ class StateMachine(object):
100
102
  self.returning_home_state: State = ReturningHome(self)
101
103
  self.stopping_state: State = Stopping(self)
102
104
  self.paused_state: State = Paused(self)
105
+ self.return_home_paused_state: State = ReturnHomePaused(self)
106
+ self.stopping_return_home_state: State = StoppingReturnHome(self)
103
107
 
104
108
  # States Waiting for mission
105
109
  self.await_next_mission_state: State = AwaitNextMission(self)
106
110
  self.home_state: State = Home(self)
107
- self.robot_standing_still_state: State = RobotStandingStill(self)
108
111
  self.intervention_needed_state: State = InterventionNeeded(self)
109
112
 
110
113
  # Status states
@@ -119,10 +122,11 @@ class StateMachine(object):
119
122
  self.monitor_state,
120
123
  self.returning_home_state,
121
124
  self.stopping_state,
125
+ self.stopping_return_home_state,
122
126
  self.paused_state,
127
+ self.return_home_paused_state,
123
128
  self.await_next_mission_state,
124
129
  self.home_state,
125
- self.robot_standing_still_state,
126
130
  self.offline_state,
127
131
  self.blocked_protective_stopping_state,
128
132
  self.unknown_status_state,
@@ -285,10 +289,11 @@ class StateMachine(object):
285
289
  )
286
290
 
287
291
  self.mqtt_publisher.publish(
288
- topic=settings.TOPIC_ISAR_MISSION,
292
+ topic=settings.TOPIC_ISAR_MISSION + f"/{self.current_mission.id}",
289
293
  payload=json.dumps(payload, cls=EnhancedJSONEncoder),
290
294
  qos=1,
291
295
  retain=True,
296
+ properties=props_expiry(settings.MQTT_MISSION_AND_TASK_EXPIRY),
292
297
  )
293
298
 
294
299
  def publish_task_status(self, task: TASKS) -> None:
@@ -316,10 +321,11 @@ class StateMachine(object):
316
321
  )
317
322
 
318
323
  self.mqtt_publisher.publish(
319
- topic=settings.TOPIC_ISAR_TASK,
324
+ topic=settings.TOPIC_ISAR_TASK + f"/{task.id}",
320
325
  payload=json.dumps(payload, cls=EnhancedJSONEncoder),
321
326
  qos=1,
322
327
  retain=True,
328
+ properties=props_expiry(settings.MQTT_MISSION_AND_TASK_EXPIRY),
323
329
  )
324
330
 
325
331
  def publish_intervention_needed(self, error_message: str) -> None:
@@ -360,11 +366,12 @@ class StateMachine(object):
360
366
  )
361
367
 
362
368
  def _current_status(self) -> RobotStatus:
363
- if (
364
- self.current_state == States.RobotStandingStill
365
- or self.current_state == States.AwaitNextMission
366
- ):
369
+ if self.current_state == States.AwaitNextMission:
367
370
  return RobotStatus.Available
371
+ elif self.current_state == States.ReturnHomePaused:
372
+ return RobotStatus.ReturnHomePaused
373
+ elif self.current_state == States.Paused:
374
+ return RobotStatus.Paused
368
375
  elif self.current_state == States.Home:
369
376
  return RobotStatus.Home
370
377
  elif self.current_state == States.ReturningHome:
@@ -1,9 +1,9 @@
1
- from typing import TYPE_CHECKING, List
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
2
 
3
3
  from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
4
5
  from isar.state_machine.utils.common_event_handlers import (
5
6
  return_home_event_handler,
6
- robot_status_event_handler,
7
7
  start_mission_event_handler,
8
8
  stop_mission_event_handler,
9
9
  )
@@ -19,6 +19,17 @@ class Home(EventHandlerBase):
19
19
  events = state_machine.events
20
20
  shared_state = state_machine.shared_state
21
21
 
22
+ def _robot_status_event_handler(
23
+ event: Event[RobotStatus],
24
+ ) -> Optional[Callable]:
25
+ robot_status: RobotStatus = event.check()
26
+ if not (
27
+ robot_status == RobotStatus.Available
28
+ or robot_status == RobotStatus.Home
29
+ ):
30
+ return state_machine.robot_status_changed # type: ignore
31
+ return None
32
+
22
33
  event_handlers: List[EventHandlerMapping] = [
23
34
  EventHandlerMapping(
24
35
  name="start_mission_event",
@@ -40,9 +51,7 @@ class Home(EventHandlerBase):
40
51
  EventHandlerMapping(
41
52
  name="robot_status_event",
42
53
  event=shared_state.robot_status,
43
- handler=lambda event: robot_status_event_handler(
44
- state_machine, RobotStatus.Home, event
45
- ),
54
+ handler=_robot_status_event_handler,
46
55
  ),
47
56
  ]
48
57
  super().__init__(
@@ -1,6 +1,8 @@
1
- from typing import TYPE_CHECKING, List
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
2
 
3
+ from isar.config.settings import settings
3
4
  from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
4
6
 
5
7
  if TYPE_CHECKING:
6
8
  from isar.state_machine.state_machine import StateMachine
@@ -10,6 +12,22 @@ class Paused(EventHandlerBase):
10
12
 
11
13
  def __init__(self, state_machine: "StateMachine"):
12
14
  events = state_machine.events
15
+ shared_state = state_machine.shared_state
16
+
17
+ def _robot_battery_level_updated_handler(
18
+ event: Event[float],
19
+ ) -> Optional[Callable]:
20
+ battery_level: float = event.check()
21
+ if battery_level < settings.ROBOT_MISSION_BATTERY_START_THRESHOLD:
22
+ state_machine.publish_mission_aborted(
23
+ "Robot battery too low to continue mission", True
24
+ )
25
+ state_machine._finalize()
26
+ state_machine.logger.warning(
27
+ "Cancelling current mission due to low battery"
28
+ )
29
+ return state_machine.stop # type: ignore
30
+ return None
13
31
 
14
32
  event_handlers: List[EventHandlerMapping] = [
15
33
  EventHandlerMapping(
@@ -22,6 +40,11 @@ class Paused(EventHandlerBase):
22
40
  event=events.api_requests.resume_mission.request,
23
41
  handler=lambda event: state_machine.resume if event.consume_event() else None, # type: ignore
24
42
  ),
43
+ EventHandlerMapping(
44
+ name="robot_battery_update_event",
45
+ event=shared_state.robot_battery_level,
46
+ handler=_robot_battery_level_updated_handler,
47
+ ),
25
48
  ]
26
49
  super().__init__(
27
50
  state_name="paused",
@@ -0,0 +1,66 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import MissionStartResponse
4
+ from isar.config.settings import settings
5
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
6
+ from isar.models.events import Event
7
+ from robot_interface.models.mission.mission import Mission
8
+
9
+ if TYPE_CHECKING:
10
+ from isar.state_machine.state_machine import StateMachine
11
+
12
+
13
+ class ReturnHomePaused(EventHandlerBase):
14
+
15
+ def __init__(self, state_machine: "StateMachine"):
16
+ events = state_machine.events
17
+ shared_state = state_machine.shared_state
18
+
19
+ def _robot_battery_level_updated_handler(
20
+ event: Event[float],
21
+ ) -> Optional[Callable]:
22
+ battery_level: float = event.check()
23
+ if battery_level < settings.ROBOT_MISSION_BATTERY_START_THRESHOLD:
24
+ return state_machine.resume # type: ignore
25
+ return None
26
+
27
+ def _start_mission_event_handler(
28
+ event: Event[Mission],
29
+ ) -> Optional[Callable]:
30
+ if event.has_event():
31
+ if not state_machine.battery_level_is_above_mission_start_threshold():
32
+ state_machine.events.api_requests.start_mission.request.consume_event()
33
+ response = MissionStartResponse(
34
+ mission_id=None,
35
+ mission_started=False,
36
+ mission_not_started_reason="Robot battery too low",
37
+ )
38
+ state_machine.events.api_requests.start_mission.response.trigger_event(
39
+ response
40
+ )
41
+ return None
42
+ return state_machine.stop_return_home # type: ignore
43
+ return None
44
+
45
+ event_handlers: List[EventHandlerMapping] = [
46
+ EventHandlerMapping(
47
+ name="resume_return_home_event",
48
+ event=events.api_requests.resume_mission.request,
49
+ handler=lambda event: state_machine.resume if event.consume_event() else None, # type: ignore
50
+ ),
51
+ EventHandlerMapping(
52
+ name="robot_battery_update_event",
53
+ event=shared_state.robot_battery_level,
54
+ handler=_robot_battery_level_updated_handler,
55
+ ),
56
+ EventHandlerMapping(
57
+ name="start_mission_event",
58
+ event=events.api_requests.start_mission.request,
59
+ handler=_start_mission_event_handler,
60
+ ),
61
+ ]
62
+ super().__init__(
63
+ state_name="return_home_paused",
64
+ state_machine=state_machine,
65
+ event_handler_mappings=event_handlers,
66
+ )
@@ -6,7 +6,6 @@ from isar.models.events import Event
6
6
  from isar.state_machine.utils.common_event_handlers import (
7
7
  mission_failed_event_handler,
8
8
  mission_started_event_handler,
9
- stop_mission_event_handler,
10
9
  task_status_event_handler,
11
10
  task_status_failed_event_handler,
12
11
  )
@@ -24,6 +23,11 @@ class ReturningHome(EventHandlerBase):
24
23
  self.failed_return_home_attemps: int = 0
25
24
  events = state_machine.events
26
25
 
26
+ def _pause_mission_event_handler(event: Event[bool]) -> Optional[Callable]:
27
+ if event.consume_event():
28
+ return state_machine.pause # type: ignore
29
+ return None
30
+
27
31
  def _handle_task_completed(status: TaskStatus):
28
32
  if status != TaskStatus.Successful:
29
33
  state_machine.current_mission.error_message = ErrorMessage(
@@ -43,6 +47,7 @@ class ReturningHome(EventHandlerBase):
43
47
  ) -> Optional[Callable]:
44
48
  if event.has_event():
45
49
  if not state_machine.battery_level_is_above_mission_start_threshold():
50
+ state_machine.events.api_requests.start_mission.request.consume_event()
46
51
  response = MissionStartResponse(
47
52
  mission_id=None,
48
53
  mission_started=False,
@@ -52,14 +57,14 @@ class ReturningHome(EventHandlerBase):
52
57
  response
53
58
  )
54
59
  return None
55
- return state_machine.stop # type: ignore
60
+ return state_machine.stop_return_home # type: ignore
56
61
  return None
57
62
 
58
63
  event_handlers: List[EventHandlerMapping] = [
59
64
  EventHandlerMapping(
60
- name="stop_mission_event",
61
- event=events.api_requests.stop_mission.request,
62
- handler=lambda event: stop_mission_event_handler(state_machine, event),
65
+ name="pause_mission_event",
66
+ event=events.api_requests.pause_mission.request,
67
+ handler=_pause_mission_event_handler,
63
68
  ),
64
69
  EventHandlerMapping(
65
70
  name="mission_started_event",
@@ -1,4 +1,3 @@
1
- import logging
2
1
  from typing import TYPE_CHECKING, Callable, List, Optional
3
2
 
4
3
  from isar.apis.models.models import ControlMissionResponse
@@ -14,7 +13,6 @@ if TYPE_CHECKING:
14
13
  class Stopping(EventHandlerBase):
15
14
 
16
15
  def __init__(self, state_machine: "StateMachine"):
17
- logger = logging.getLogger("state_machine")
18
16
  events = state_machine.events
19
17
 
20
18
  def _stop_mission_cleanup() -> None:
@@ -48,30 +46,15 @@ class Stopping(EventHandlerBase):
48
46
  ) -> Optional[Callable]:
49
47
  error_message: Optional[ErrorMessage] = event.consume_event()
50
48
  if error_message is not None:
51
- logger.warning(error_message.error_description)
52
- if (
53
- state_machine.current_mission is not None
54
- and state_machine.current_mission._is_return_to_home_mission()
55
- ):
56
- return state_machine.return_home_mission_stopping_failed # type: ignore
57
- else:
58
- return state_machine.mission_stopping_failed # type: ignore
49
+ return state_machine.mission_stopping_failed # type: ignore
59
50
  return None
60
51
 
61
52
  def _successful_stop_event_handler(event: Event[bool]) -> Optional[Callable]:
62
53
  if event.consume_event():
63
- if (
64
- state_machine.current_mission is not None
65
- and state_machine.current_mission._is_return_to_home_mission()
66
- ):
67
- return state_machine.return_home_mission_stopped # type: ignore
68
- else:
69
- _stop_mission_cleanup()
70
- if (
71
- not state_machine.battery_level_is_above_mission_start_threshold()
72
- ):
73
- return state_machine.request_return_home # type: ignore
74
- return state_machine.mission_stopped # type: ignore
54
+ _stop_mission_cleanup()
55
+ if not state_machine.battery_level_is_above_mission_start_threshold():
56
+ return state_machine.request_return_home # type: ignore
57
+ return state_machine.mission_stopped # type: ignore
75
58
  return None
76
59
 
77
60
  event_handlers: List[EventHandlerMapping] = [
@@ -0,0 +1,73 @@
1
+ import logging
2
+ from typing import TYPE_CHECKING, Callable, List, Optional
3
+
4
+ from isar.apis.models.models import MissionStartResponse
5
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
6
+ from isar.models.events import Event
7
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
8
+ from robot_interface.models.mission.mission import Mission
9
+
10
+ if TYPE_CHECKING:
11
+ from isar.state_machine.state_machine import StateMachine
12
+
13
+
14
+ class StoppingReturnHome(EventHandlerBase):
15
+
16
+ def __init__(self, state_machine: "StateMachine"):
17
+ logger = logging.getLogger("state_machine")
18
+ events = state_machine.events
19
+
20
+ def _failed_stop_event_handler(
21
+ event: Event[ErrorMessage],
22
+ ) -> Optional[Callable]:
23
+ error_message: Optional[ErrorMessage] = event.consume_event()
24
+ if error_message is not None:
25
+ logger.warning(error_message.error_description)
26
+ mission: Mission = (
27
+ state_machine.events.api_requests.start_mission.request.consume_event()
28
+ )
29
+ state_machine.events.api_requests.start_mission.response.trigger_event(
30
+ MissionStartResponse(
31
+ mission_id=mission.id,
32
+ mission_started=False,
33
+ mission_not_started_reason="Failed to cancel return home mission",
34
+ )
35
+ )
36
+ return state_machine.return_home_mission_stopping_failed # type: ignore
37
+ return None
38
+
39
+ def _successful_stop_event_handler(event: Event[bool]) -> Optional[Callable]:
40
+ if event.consume_event():
41
+ mission: Mission = (
42
+ state_machine.events.api_requests.start_mission.request.consume_event()
43
+ )
44
+
45
+ state_machine.reset_state_machine()
46
+
47
+ if mission:
48
+ state_machine.start_mission(mission=mission)
49
+ return state_machine.request_mission_start # type: ignore
50
+
51
+ state_machine.logger.error(
52
+ "Stopped return home without a new mission to start"
53
+ )
54
+ return state_machine.request_return_home # type: ignore
55
+ return None
56
+
57
+ event_handlers: List[EventHandlerMapping] = [
58
+ EventHandlerMapping(
59
+ name="failed_stop_event",
60
+ event=events.robot_service_events.mission_failed_to_stop,
61
+ handler=_failed_stop_event_handler,
62
+ ),
63
+ EventHandlerMapping(
64
+ name="successful_stop_event",
65
+ event=events.robot_service_events.mission_successfully_stopped,
66
+ handler=_successful_stop_event_handler,
67
+ ),
68
+ ]
69
+ super().__init__(
70
+ state_name="stopping_return_home",
71
+ state_machine=state_machine,
72
+ event_handler_mappings=event_handlers,
73
+ )
@@ -5,10 +5,11 @@ class States(str, Enum):
5
5
  Monitor = "monitor"
6
6
  ReturningHome = "returning_home"
7
7
  Stopping = "stopping"
8
+ StoppingReturnHome = "stopping_return_home"
8
9
  Paused = "paused"
10
+ ReturnHomePaused = "return_home_paused"
9
11
  AwaitNextMission = "await_next_mission"
10
12
  Home = "home"
11
- RobotStandingStill = "robot_standing_still"
12
13
  Offline = "offline"
13
14
  BlockedProtectiveStop = "blocked_protective_stop"
14
15
  UnknownStatus = "unknown_status"