private async Task ProcessAssetEvents(MachineStatus machine, Guid projectUid, Guid customerUid, IHeaderDictionary headers) { AssetAggregateStatus statusEvent = null; if (machine.AssetUid.HasValue) { // CCSSCOON-85 it's not possible to match radio types in WM cws/ProfileX // var matchingAsset = await _deviceProxy.GetMatching3D2DAssets(new MatchingAssetsDisplayModel() {AssetUID3D = assetList.First().Key.ToString()}, headers); //Change that for the actual matched asset. Since we supplied 3d asset get data for the matching 2d asset. //if there is no 2d asset we should try using SNM asset var(details, summary) = await GetAssetData(machine.AssetUid.ToString(), headers); statusEvent = GenerateEvent(customerUid, projectUid, machine.AssetUid, machine, details, summary); } else { // Cant find some information, build a cut down event statusEvent = GenerateEvent(customerUid, projectUid, null, machine, null, null); } if (statusEvent != null) { await _assetStatusServerHubClient.UpdateAssetLocationsForClient(statusEvent); } }
/// <inheritdoc /> public async Task <bool> UpdateAssetLocationsForClient(AssetAggregateStatus assets) { var connections = await assetState.GetClientsForProject(assets.CustomerUid, assets.ProjectUid); await hub.Clients.Clients(connections).UpdateAssetStatus(assets); return(true); }
/// <summary> /// Trigger an event for a particular Asset - this will cause the signalR hub to notify all relevant UI clients /// </summary> public async Task <bool> UpdateAssetLocationsForClient(AssetAggregateStatus assets) { if (Connected) { return(await Connection.InvokeAsync <bool>(nameof(IAssetStatusServerHub.UpdateAssetLocationsForClient), assets)); } Logger.LogWarning("Not connected - cannot update locations"); return(false); }
public void TestProcessing3dand2dAssets() { var job = serviceProvider.GetService <IJob>(); Assert.IsNotNull(job); var subscription = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("7842662B-F8E5-4752-A64B-261CE7EDA152"), CustomerUid = Guid.Parse("8BB0D3A3-A755-4AD9-A4FA-999D6C1C104C"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; var assetUid = "47C03885-4845-4637-90B5-4CCE5D8DA040"; var machine = new MachineStatus(55743, "Test Machine from 3d", true, "LAST DESIGN FROM 3D", 15215, new DateTime(2018, 1, 2, 3, 4, 5, DateTimeKind.Utc), 0.59915074193701334, // radians -1.470376021323053, // radians null, null, Guid.Parse(assetUid)); var machineResult = new Machine3DStatuses(ContractExecutionStatesEnum.ExecutedSuccessfully); machineResult.MachineStatuses.Add(machine); var assetDetails = new AssetDetails() { AssetId = "55743 - test", AssetUid = assetUid, LastReportedLocationLatitude = 123.45d, LastReportedLocationLongitude = 43.1d, LastLocationUpdateUtc = machine.lastKnownTimeStamp.Value.AddSeconds(1), FuelLevelLastReported = 2.1d, LastPercentFuelRemainingUtc = new DateTime(2019, 1, 1, 23, 41, 23, DateTimeKind.Utc) }; var expectedResult = new AssetAggregateStatus() { CustomerUid = subscription.CustomerUid, ProjectUid = subscription.ProjectUid, LocationLastUpdatedUtc = assetDetails.LastLocationUpdateUtc.ToUniversalTime(), AssetUid = Guid.Parse(assetUid), Design = machine.lastKnownDesignName, FuelLevel = assetDetails.FuelLevelLastReported, FuelLevelLastUpdatedUtc = assetDetails.FuelReportedTimeUtc, Latitude = assetDetails.LastReportedLocationLatitude, Longitude = assetDetails.LastReportedLocationLongitude, LiftNumber = 15215, AssetIdentifier = "55743 - test", // will take this from the 2d data, as a higher priority that the 3d machine name MachineName = "Test Machine from 3d" }; var expectedHeaders = GetExpectedHeaders(subscription.CustomerUid, subscription.AuthorizationHeader, subscription.JWTAssertion); AssetAggregateStatus resultStatus = null; // Keep a reference to the event generated for comparasion // Setup the returns mockAssetStatusServerHubClient .Setup(m => m.GetSubscriptions()) .Returns(Task.FromResult(new List <AssetUpdateSubscriptionModel> { subscription })); mockProductivity3dV2ProxyNotification.Setup(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(machineResult)); mockFleetAssetDetails .Setup(m => m.GetAssetDetails( It.IsAny <string>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(assetDetails)); mockAssetStatusServerHubClient .Setup(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>())) .Returns(Task.FromResult(true)) .Callback <AssetAggregateStatus>((e) => { resultStatus = e; }); // Run the test job.Run(null).Wait(); // Validate the calls // We should have this called for our asset uid which matched to the 3d asset id mockFleetAssetDetails .Verify(m => m.GetAssetDetails( It.Is <string>(s => Guid.Parse(s) == Guid.Parse(assetDetails.AssetUid)), It.Is <IHeaderDictionary>(d => DictionaryContentEquals(d, expectedHeaders))), Times.Once); // We should have received one event mockAssetStatusServerHubClient .Verify(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>()), Times.Once()); // Validate it is the expected result Assert.IsNotNull(resultStatus); resultStatus.Should().BeEquivalentTo(expectedResult); }
public void TestProcessing3dAssetsOnly() { var job = serviceProvider.GetService <IJob>(); Assert.IsNotNull(job); var subscription = new AssetUpdateSubscriptionModel() { ProjectUid = Guid.Parse("038A3ACB-C985-4E3A-AB98-FF3C939B30BF"), CustomerUid = Guid.Parse("12DCFAF5-96A4-4E27-BE53-28A226A7AAB6"), AuthorizationHeader = "TEST AUTH", JWTAssertion = "TEST JWT" }; var machine1 = new MachineStatus(123, "Test Machine1", true, "LAST DESIGN 1", 6433, new DateTime(2010, 1, 2, 3, 4, 5, DateTimeKind.Utc), 0.59915074193701334, // radians -1.470376021323053, // radians null, null); var machineResult = new Machine3DStatuses(ContractExecutionStatesEnum.ExecutedSuccessfully); machineResult.MachineStatuses.Add(machine1); var expectedResult = new AssetAggregateStatus() { AssetIdentifier = "Test Machine1", LiftNumber = 6433, CustomerUid = subscription.CustomerUid, ProjectUid = subscription.ProjectUid, LocationLastUpdatedUtc = machine1.lastKnownTimeStamp, AssetUid = null, Design = machine1.lastKnownDesignName, FuelLevel = null, FuelLevelLastUpdatedUtc = null, Latitude = machine1.lastKnownLatitude * RADIANS_TO_DEGREES, Longitude = machine1.lastKnownLongitude * RADIANS_TO_DEGREES, MachineName = "Test Machine1" }; var expectedHeaders = GetExpectedHeaders(subscription.CustomerUid, subscription.AuthorizationHeader, subscription.JWTAssertion); AssetAggregateStatus resultStatus = null; // Keep a reference to the event generated for comparasion // Setup the returns mockAssetStatusServerHubClient .Setup(m => m.GetSubscriptions()) .Returns(Task.FromResult(new List <AssetUpdateSubscriptionModel> { subscription })); mockProductivity3dV2ProxyNotification.Setup(m => m.ExecuteGenericV2Request <Machine3DStatuses>( It.IsAny <string>(), It.IsAny <HttpMethod>(), It.IsAny <Stream>(), It.IsAny <IHeaderDictionary>())) .Returns(Task.FromResult(machineResult)); mockAssetStatusServerHubClient .Setup(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>())) .Returns(Task.FromResult(true)) .Callback <AssetAggregateStatus>((e) => { resultStatus = e; }); // Run the test job.Run(null).Wait(); // Validate the calls // CCSSSCON-85 not possible with WM devices //// We should not call this if we have not matching 3d/2d assets //mockAssetResolverProxy // .Verify(m => m.GetMatching3D2DAssets(It.IsAny<MatchingAssetsDisplayModel>(), // It.IsAny<IHeaderDictionary>()), // Times.Never); // We should have received one event mockAssetStatusServerHubClient .Verify(m => m.UpdateAssetLocationsForClient(It.IsAny <AssetAggregateStatus>()), Times.Once()); // Validate it is the expected result Assert.IsNotNull(resultStatus); resultStatus.Should().BeEquivalentTo(expectedResult); }
/// <summary> /// Generate a UI Event based on the information passed in /// Add any new fields that need populating to this method /// </summary> private AssetAggregateStatus GenerateEvent(Guid customerUid, Guid projectUid, Guid?assetUid, MachineStatus machineStatus, AssetDetails details, AssetSummary summary) { var result = new AssetAggregateStatus { ProjectUid = projectUid, CustomerUid = customerUid, AssetUid = assetUid, UtilizationSummary = summary }; // This is where all the magic happens, in terms of mapping data we have from 3d / 2d endpoints into an event for the UI // details / summary can be null, machineStatus won't be. var lastLocationTimeUtc = machineStatus.lastKnownTimeStamp; // These values are in radians, where the AssetDetails values are in degrees result.Latitude = machineStatus.lastKnownLatitude?.LatRadiansToDegrees(); result.Longitude = machineStatus.lastKnownLongitude?.LonRadiansToDegrees(); result.Design = machineStatus.lastKnownDesignName; result.LiftNumber = machineStatus.lastKnownLayerId; result.MachineName = machineStatus.MachineName; // If we have a Asset ID (which matches Asset ID in Fleet management) from UF, use that, otherwise machine name result.AssetIdentifier = !string.IsNullOrEmpty(details?.AssetId) ? details.AssetId : machineStatus.MachineName; // Extract data from Asset Details if (details != null) { // Do we have a newer location? if (lastLocationTimeUtc == null || details.LastLocationUpdateUtc > lastLocationTimeUtc) { result.Latitude = details.LastReportedLocationLatitude; result.Longitude = details.LastReportedLocationLongitude; lastLocationTimeUtc = details.LastLocationUpdateUtc; } result.FuelLevel = details.FuelLevelLastReported; result.FuelLevelLastUpdatedUtc = details.FuelReportedTimeUtc; result.AssetIcon = details.AssetIcon; result.AssetSerialNumber = details.AssetSerialNumber; if (details.Devices?.Count > 0) { result.DeviceName = string.Join(", ", details.Devices.Select(d => d.DeviceType)); } } // Clear the values if we don't have everything if (lastLocationTimeUtc == null || result.Latitude == null || result.Longitude == null) { _log.LogWarning($"Clearing event information due to missing data. Lat: {result.Latitude}, Lon: {result.Longitude}, Time: {result.LocationLastUpdatedUtc}"); result.LocationLastUpdatedUtc = null; result.Latitude = null; result.Longitude = null; } else { result.LocationLastUpdatedUtc = lastLocationTimeUtc; } return(result); }