Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stop all robots button #1045

Merged
merged 22 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cd53b9b
Add stop all button functionality
aeshub Aug 18, 2023
29e1295
Add stop all robots backend endpoints
mrica-equinor Sep 1, 2023
38be124
Add stop all button on frontend
mrica-equinor Sep 1, 2023
9c884ac
Move entityframework interactions to scoped service
mrica-equinor Sep 4, 2023
24b1886
Fix dismiss robots from safe zone functionality
mrica-equinor Sep 8, 2023
092161b
Add ongoing mission to queue in emergency state
mrica-equinor Sep 11, 2023
c7b8243
Fix formatting
andchiind Sep 18, 2023
806d512
Update unit tests with new mocks and URLs
andchiind Sep 19, 2023
82bb719
Remove excess comments and code
andchiind Sep 19, 2023
40ac3fe
Fix stop all robots button on the frontend
aeshub Sep 19, 2023
aa8dc6b
Improve dismiss robots from safe zones
mrica-equinor Sep 20, 2023
40ad0b7
Add robot status chip for safe zone
mrica-equinor Oct 5, 2023
a8787bb
Refactoring of the code
mrica-equinor Oct 10, 2023
7de511d
Add defaultlocalisationposeservice to tests
andchiind Oct 18, 2023
dc0b8c4
Improve code quality
mrica-equinor Oct 18, 2023
20381a3
Simplfy Emergency Action Controller
mrica-equinor Oct 18, 2023
710b9fd
Create Mission Scheduling Service
mrica-equinor Oct 18, 2023
dd94a2d
Add MissionSchedulingService to event handler test
mrica-equinor Oct 18, 2023
bee11f5
Improve add ongoing mission back to the queue
mrica-equinor Oct 31, 2023
206038d
Improve frontend when pressing the stop all button
mrica-equinor Oct 31, 2023
682ec73
Add safe zone exception
mrica-equinor Nov 1, 2023
c503816
Fix variable types for inspection overview
mrica-equinor Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 2 additions & 16 deletions backend/api.test/EndpointTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,27 +558,13 @@ public async Task SafePositionTest()
var area = await areaResponse.Content.ReadFromJsonAsync<Area>(_serializerOptions);
Assert.True(area != null);

// Arrange - Get a Robot
string url = "/robots";
var robotResponse = await _client.GetAsync(url);
Assert.True(robotResponse.IsSuccessStatusCode);
var robots = await robotResponse.Content.ReadFromJsonAsync<List<Robot>>(_serializerOptions);
Assert.True(robots != null);
var robot = robots[0];
string robotId = robot.Id;

// Act
string goToSafePositionUrl = $"/robots/{robotId}/{testInstallation}/{testArea}/go-to-safe-position";
string goToSafePositionUrl = $"/emergency-action/{testInstallation}/abort-current-missions-and-send-all-robots-to-safe-zone";
var missionResponse = await _client.PostAsync(goToSafePositionUrl, null);

// Assert
Assert.True(missionResponse.IsSuccessStatusCode);
var missionRun = await missionResponse.Content.ReadFromJsonAsync<MissionRun>(_serializerOptions);
Assert.True(missionRun != null);
Assert.True(
JsonSerializer.Serialize(missionRun.Tasks[0].RobotPose.Position) ==
JsonSerializer.Serialize(testPosition)
);

}

[Fact]
Expand Down
22 changes: 22 additions & 0 deletions backend/api.test/EventHandlers/TestMissionEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,23 @@ public class TestMissionEventHandler : IDisposable
private readonly RobotControllerMock _robotControllerMock;
private readonly IRobotModelService _robotModelService;
private readonly IRobotService _robotService;
private readonly IMissionScheduling _missionScheduling;
private readonly IIsarService _isarServiceMock;
private readonly IInstallationService _installationService;
private readonly IDefaultLocalizationPoseService _defaultLocalisationPoseService;
private readonly IPlantService _plantService;
private readonly IDeckService _deckService;
private readonly IAreaService _areaService;
private readonly IMissionSchedulingService _missionSchedulingService;

public TestMissionEventHandler(DatabaseFixture fixture)
{
var missionEventHandlerLogger = new Mock<ILogger<MissionEventHandler>>().Object;
var mqttServiceLogger = new Mock<ILogger<MqttService>>().Object;
var mqttEventHandlerLogger = new Mock<ILogger<MqttEventHandler>>().Object;
var missionLogger = new Mock<ILogger<MissionRunService>>().Object;
var missionSchedulingLogger = new Mock<ILogger<MissionScheduling>>().Object;
var missionSchedulingServiceLogger = new Mock<ILogger<MissionSchedulingService>>().Object;

var configuration = WebApplication.CreateBuilder().Configuration;

Expand All @@ -65,6 +75,14 @@ public TestMissionEventHandler(DatabaseFixture fixture)
_robotService = new RobotService(_context, _robotModelService);
_robotModelService = new RobotModelService(_context);
_robotControllerMock = new RobotControllerMock();
_isarServiceMock = new MockIsarService();
_installationService = new InstallationService(_context);
_defaultLocalisationPoseService = new DefaultLocalizationPoseService(_context);
_plantService = new PlantService(_context, _installationService);
_deckService = new DeckService(_context, _defaultLocalisationPoseService, _installationService, _plantService);
_areaService = new AreaService(_context, _installationService, _plantService, _deckService, _defaultLocalisationPoseService);
_missionSchedulingService = new MissionSchedulingService(missionSchedulingServiceLogger, _missionRunService, _robotService, _robotControllerMock.Mock.Object);
_missionScheduling = new MissionScheduling(missionSchedulingLogger, _missionRunService, _isarServiceMock, _robotService, _areaService, _missionSchedulingService);

var mockServiceProvider = new Mock<IServiceProvider>();

Expand All @@ -75,6 +93,9 @@ public TestMissionEventHandler(DatabaseFixture fixture)
mockServiceProvider
.Setup(p => p.GetService(typeof(IRobotService)))
.Returns(_robotService);
mockServiceProvider
.Setup(p => p.GetService(typeof(IMissionScheduling)))
.Returns(_missionScheduling);
mockServiceProvider
.Setup(p => p.GetService(typeof(RobotController)))
.Returns(_robotControllerMock.Mock.Object);
Expand Down Expand Up @@ -119,6 +140,7 @@ public TestMissionEventHandler(DatabaseFixture fixture)
{
Name = "testMission",
MissionId = Guid.NewGuid().ToString(),
MissionRunPriority = MissionRunPriority.Normal,
Status = MissionStatus.Pending,
DesiredStartTime = DateTimeOffset.Now,
Area = NewArea,
Expand Down
5 changes: 1 addition & 4 deletions backend/api.test/Mocks/RobotControllerMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ internal class RobotControllerMock
public Mock<IMissionRunService> MissionServiceMock;
public Mock<RobotController> Mock;
public Mock<IAreaService> AreaServiceMock;
public Mock<IEchoService> EchoServiceMock;

public RobotControllerMock()
{
Expand All @@ -22,7 +21,6 @@ public RobotControllerMock()
RobotServiceMock = new Mock<IRobotService>();
RobotModelServiceMock = new Mock<IRobotModelService>();
AreaServiceMock = new Mock<IAreaService>();
EchoServiceMock = new Mock<IEchoService>();

var mockLoggerController = new Mock<ILogger<RobotController>>();

Expand All @@ -32,8 +30,7 @@ public RobotControllerMock()
IsarServiceMock.Object,
MissionServiceMock.Object,
RobotModelServiceMock.Object,
AreaServiceMock.Object,
EchoServiceMock.Object
AreaServiceMock.Object
)
{
CallBase = true
Expand Down
85 changes: 85 additions & 0 deletions backend/api/Controllers/EmergencyActionController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System.Globalization;
using Api.Controllers.Models;
using Api.Services;
using Api.Services.Events;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Api.Controllers
{
[ApiController]
[Route("emergency-action")]
public class EmergencyActionController : ControllerBase
{
private readonly IEmergencyActionService _emergencyActionService;
private readonly IRobotService _robotService;

public EmergencyActionController(IRobotService robotService, IEmergencyActionService emergencyActionService)
{
_robotService = robotService;
_emergencyActionService = emergencyActionService;
}

/// <summary>
/// This endpoint will abort the current running mission run and attempt to return the robot to a safe position in the
/// area. The mission run queue for the robot will be frozen and no further missions will run until the emergency
/// action has been reversed.
/// </summary>
/// <remarks>
/// <para> The endpoint fires an event which is then processed to stop the robot and schedule the next mission </para>
/// </remarks>
[HttpPost]
[Route("{installationCode}/abort-current-missions-and-send-all-robots-to-safe-zone")]
[Authorize(Roles = Role.User)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public ActionResult<string> AbortCurrentMissionAndSendAllRobotsToSafeZone(
[FromRoute] string installationCode)
{

var robots = _robotService.ReadAll().Result.ToList().FindAll(a =>
a.CurrentInstallation.ToLower(CultureInfo.CurrentCulture).Equals(installationCode.ToLower(CultureInfo.CurrentCulture), StringComparison.Ordinal) &&
a.CurrentArea != null);

foreach (var robot in robots)
{
_emergencyActionService.TriggerEmergencyButtonPressedForRobot(new EmergencyButtonPressedForRobotEventArgs(robot.Id));

}

return NoContent();

}

/// <summary>
/// This query will clear the emergency state that is introduced by aborting the current mission and returning to a
/// safe zone. Clearing the emergency state means that mission runs that may be in the robots queue will start."
/// </summary>
[HttpPost]
[Route("{installationCode}/clear-emergency-state")]
[Authorize(Roles = Role.User)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
public ActionResult<string> ClearEmergencyStateForAllRobots(
[FromRoute] string installationCode)
{
var robots = _robotService.ReadAll().Result.ToList().FindAll(a =>
a.CurrentInstallation.ToLower(CultureInfo.CurrentCulture).Equals(installationCode.ToLower(CultureInfo.CurrentCulture), StringComparison.Ordinal) &&
a.CurrentArea != null);

foreach (var robot in robots)
{
_emergencyActionService.TriggerEmergencyButtonDepressedForRobot(new EmergencyButtonPressedForRobotEventArgs(robot.Id));
}

return NoContent();
}
}
}
12 changes: 7 additions & 5 deletions backend/api/Controllers/MissionSchedulingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class MissionSchedulingController : ControllerBase
private readonly IMapService _mapService;
private readonly IMissionDefinitionService _missionDefinitionService;
private readonly IMissionRunService _missionRunService;
private readonly IMissionSchedulingService _missionSchedulingService;
private readonly ICustomMissionSchedulingService _customMissionSchedulingService;
private readonly IRobotService _robotService;
private readonly ISourceService _sourceService;
private readonly IStidService _stidService;
Expand All @@ -35,7 +35,7 @@ public MissionSchedulingController(
IMapService mapService,
IStidService stidService,
ISourceService sourceService,
IMissionSchedulingService missionSchedulingService
ICustomMissionSchedulingService customMissionSchedulingService
)
{
_missionDefinitionService = missionDefinitionService;
Expand All @@ -48,7 +48,7 @@ IMissionSchedulingService missionSchedulingService
_stidService = stidService;
_sourceService = sourceService;
_missionDefinitionService = missionDefinitionService;
_missionSchedulingService = missionSchedulingService;
_customMissionSchedulingService = customMissionSchedulingService;
_logger = logger;
}

Expand Down Expand Up @@ -96,6 +96,7 @@ [FromBody] ScheduleMissionQuery scheduledMissionQuery
Robot = robot,
MissionId = missionDefinition.Id,
Status = MissionStatus.Pending,
MissionRunPriority = MissionRunPriority.Normal,
DesiredStartTime = scheduledMissionQuery.DesiredStartTime,
Tasks = missionTasks,
InstallationCode = missionDefinition.InstallationCode,
Expand Down Expand Up @@ -228,6 +229,7 @@ [FromBody] ScheduledMissionQuery scheduledMissionQuery
Robot = robot,
MissionId = scheduledMissionDefinition.Id,
Status = MissionStatus.Pending,
MissionRunPriority = MissionRunPriority.Normal,
DesiredStartTime = scheduledMissionQuery.DesiredStartTime,
Tasks = missionTasks,
InstallationCode = scheduledMissionQuery.InstallationCode,
Expand Down Expand Up @@ -287,11 +289,11 @@ [FromBody] CustomMissionQuery customMissionQuery
var missionTasks = customMissionQuery.Tasks.Select(task => new MissionTask(task)).ToList();

MissionDefinition? customMissionDefinition;
try { customMissionDefinition = await _missionSchedulingService.FindExistingOrCreateCustomMissionDefinition(customMissionQuery, missionTasks); }
try { customMissionDefinition = await _customMissionSchedulingService.FindExistingOrCreateCustomMissionDefinition(customMissionQuery, missionTasks); }
catch (SourceException e) { return StatusCode(StatusCodes.Status502BadGateway, e.Message); }

MissionRun? newMissionRun;
try { newMissionRun = await _missionSchedulingService.QueueCustomMissionRun(customMissionQuery, customMissionDefinition.Id, robot.Id, missionTasks); }
try { newMissionRun = await _customMissionSchedulingService.QueueCustomMissionRun(customMissionQuery, customMissionDefinition.Id, robot.Id, missionTasks); }
catch (Exception e) when (e is RobotNotFoundException or MissionNotFoundException) { return NotFound(e.Message); }

return CreatedAtAction(nameof(Create), new
Expand Down
Loading
Loading