public async Task <ConditionalValue <OutageEntity> > GetOutageEntity(long outageId) { var outageModelAccessClient = OutageModelAccessClient.CreateClient(); var outageDbEntity = await outageModelAccessClient.GetOutage(outageId); if (outageDbEntity == null) { Logger.LogError($"{baseLogString} GetOutageEntity => Outage with id 0x{outageId:X16} is not found in database."); return(new ConditionalValue <OutageEntity>(false, null)); } return(new ConditionalValue <OutageEntity>(true, outageDbEntity)); }
public async Task <bool> SendRepairCrew(long outageId) { Logger.LogDebug($"{baseLogString} SendRepairCrew method started. OutageId {outageId}"); while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } try { var result = await lifecycleHelper.GetIsolatedOutage(outageId); if (!result.HasValue) { Logger.LogError($"{baseLogString} SendRepairCrew => Isolated Outage is null. OutageId {outageId}"); return(false); } var outageEntity = result.Value; Logger.LogInformation($"{baseLogString} SendRepairCrew => Entering 10 sec delay."); await Task.Delay(10_000); Logger.LogInformation($"{baseLogString} SendRepairCrew => 10 sec delay ended."); var outageSimulatorClient = OutageSimulatorClient.CreateClient(); if (!await outageSimulatorClient.StopOutageSimulation(outageEntity.OutageElementGid)) { string message = $"{baseLogString} SendRepairCrew => StopOutageSimulation for element 0x{outageEntity.OutageElementGid:X16} failed. OutageId {outageId}"; Logger.LogError(message); return(false); } outageEntity.OutageState = OutageState.REPAIRED; outageEntity.RepairedTime = DateTime.UtcNow; var outageModelAccessClient = OutageModelAccessClient.CreateClient(); await outageModelAccessClient.UpdateOutage(outageEntity); return(await lifecycleHelper.PublishOutageAsync(Topic.ACTIVE_OUTAGE, this.outageMessageMapper.MapOutageEntity(outageEntity))); } catch (Exception e) { string message = $"{baseLogString} SendRepairCrew => Exception: {e.Message}"; Logger.LogError(message, e); return(false); } }
private async Task <ConditionalValue <OutageEntity> > StoreActiveOutage(long elementGid, List <long> affectedConsumersGids, OutageTopologyModel topology) { var outageModelAccessClient = OutageModelAccessClient.CreateClient(); var allOutages = await outageModelAccessClient.GetAllOutages(); var targetedOutages = allOutages.Where(outage => outage.OutageElementGid == elementGid && outage.OutageState != OutageState.ARCHIVED); if (targetedOutages.FirstOrDefault() != null) { Logger.LogWarning($"{baseLogString} StoreActiveOutage => Malfunction on element with gid: 0x{elementGid:x16} has already been reported."); return(new ConditionalValue <OutageEntity>(false, null)); } List <Consumer> consumerDbEntities = await lifecycleHelper.GetAffectedConsumersFromDatabase(affectedConsumersGids); if (consumerDbEntities.Count != affectedConsumersGids.Count) { Logger.LogWarning($"{baseLogString} StoreActiveOutage => Some of affected consumers are not present in database."); return(new ConditionalValue <OutageEntity>(false, null)); } long recloserId = GetRecloserForHeadBreaker(elementGid, topology); List <Equipment> defaultIsolationPoints = await lifecycleHelper.GetEquipmentEntityAsync(new List <long> { elementGid, recloserId }); OutageEntity createdActiveOutage = new OutageEntity { OutageElementGid = elementGid, AffectedConsumers = consumerDbEntities, OutageState = OutageState.CREATED, ReportTime = DateTime.UtcNow, DefaultIsolationPoints = defaultIsolationPoints, }; var activeOutageDbEntity = await outageModelAccessClient.AddOutage(createdActiveOutage); if (activeOutageDbEntity == null) { Logger.LogError($"{baseLogString} StoreActiveOutage => activeOutageDbEntity is null."); return(new ConditionalValue <OutageEntity>(false, null)); } await UpdateRecloserOutageMap(recloserId, affectedConsumersGids, activeOutageDbEntity); return(new ConditionalValue <OutageEntity>(true, activeOutageDbEntity)); }
private async Task <bool> CheckPreconditions(long elementGid, CommandOriginType commandOriginType, List <long> affectedConsumersGids, IHistoryDBManagerContract historyDBManagerClient) { if (this.ignorableCommandOriginTypes.Contains(commandOriginType)) { Logger.LogDebug($"{baseLogString} CheckPreconditions => ignorable command origin type: {commandOriginType}"); return(false); } if (await ElementsToBeIgnoredInReportPotentialOutage.ContainsKeyAsync(elementGid)) { Logger.LogWarning($"{baseLogString} CheckPreconditions => ElementGid 0x{elementGid:X16} found in '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}'."); if ((await ElementsToBeIgnoredInReportPotentialOutage.TryRemoveAsync(elementGid)).HasValue) { Logger.LogDebug($"{baseLogString} CheckPreconditions => ElementGid 0x{elementGid:X16} removed form '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}'"); } return(false); } if (await OptimumIsolationPoints.ContainsKeyAsync(elementGid)) { Logger.LogWarning($"{baseLogString} CheckPreconditions => ElementGid 0x{elementGid:X16} found in '{ReliableDictionaryNames.OptimumIsolationPoints}'."); return(false); } if (affectedConsumersGids.Count == 0) { await OnZeroAffectedConsumersCase(elementGid, historyDBManagerClient); Logger.LogWarning($"{baseLogString} ReportPotentialOutage => There is no affected consumers => outage report is not valid. ElementGid: 0x{elementGid:X16}, CommandOriginType: {commandOriginType}"); return(false); } var outageModelAccessClient = OutageModelAccessClient.CreateClient(); var activeOutages = await outageModelAccessClient.GetAllActiveOutages(); if (activeOutages.Any(active => (active.OutageState == OutageState.CREATED && active.OutageElementGid == elementGid) || (active.OutageState != OutageState.CREATED && active.DefaultIsolationPoints.Any(point => point.EquipmentId == elementGid)))) { Logger.LogWarning($"{baseLogString} ReportPotentialOutage => duplicate... ElementGID: 0x{elementGid:X16}"); return(false); } return(true); }
public async Task <IEnumerable <ArchivedOutageViewModel> > Handle(GetArchivedOutagesQuery request, CancellationToken cancellationToken) { try { Logger.LogInformation("[OutageQueryHandler::GetArchivedOutages] Sending a GET query to Outage service for archived outages."); var outageAccessClient = OutageModelAccessClient.CreateClient(); var archivedOutages = await outageAccessClient.GetAllArchivedOutages(); var archivedOutageViewModels = _mapper.MapArchivedOutages(archivedOutages); return(archivedOutageViewModels); } catch (Exception ex) { Logger.LogError("[OutageQueryHandler::GetArchivedOutages] Failed to GET archived outages from Outage service.", ex); throw ex; } }
public async Task <bool> ResolveOutage(long outageId) { Logger.LogVerbose($"{baseLogString} ResolveOutage method started. OutageId: {outageId}"); while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } try { var result = await lifecycleHelper.GetValidatedRepairedOutage(outageId); if (!result.HasValue) { Logger.LogError($"{baseLogString} ResolveOutage => GetValidatedRepairedOutage did not return a value. OutageId: {outageId}"); return(false); } var outageDbEntity = result.Value; outageDbEntity.ArchivedTime = DateTime.UtcNow; outageDbEntity.OutageState = OutageState.ARCHIVED; var outageModelAccessClient = OutageModelAccessClient.CreateClient(); await outageModelAccessClient.UpdateOutage(outageDbEntity); Logger.LogInformation($"{baseLogString} ResolveOutage => Outage on element with gid: 0x{outageDbEntity.OutageElementGid:x16} is SUCCESSFULLY archived."); return(await lifecycleHelper.PublishOutageAsync(Topic.ARCHIVED_OUTAGE, outageMessageMapper.MapOutageEntity(outageDbEntity))); } catch (Exception e) { string message = $"{baseLogString} ResolveOutage => Exception: {e.Message}"; Logger.LogError(message, e); return(false); } }
private async Task <bool> CheckPreconditions(long elementGid, CommandOriginType commandOriginType, List <long> affectedConsumersGids, IHistoryDBManagerContract historyDBManagerClient) { if (this.ignorableCommandOriginTypes.Contains(commandOriginType)) { Logger.LogDebug($"{baseLogString} CheckPreconditions => ignorable command origin type: {commandOriginType}"); return(false); } var enumerableStartedAlgorithms = await StartedIsolationAlgorithms.GetEnumerableDictionaryAsync(); var enumerableOptimumIsolationPoints = await OptimumIsolationPoints.GetEnumerableDictionaryAsync(); if (enumerableStartedAlgorithms.Values.Any(algorithm => algorithm.ElementsCommandedInCurrentCycle.Contains(elementGid)) || enumerableOptimumIsolationPoints.ContainsKey(elementGid)) { Logger.LogWarning($"{baseLogString} CheckPreconditions => ElementGid 0x{elementGid:X16} found in elements commanded in current isolating algorithm cycle or in optimumIsolationPoints."); return(false); } if (affectedConsumersGids.Count == 0) { await OnZeroAffectedConsumersCase(elementGid, historyDBManagerClient); Logger.LogWarning($"{baseLogString} ReportPotentialOutage => There is no affected consumers => outage report is not valid. ElementGid: 0x{elementGid:X16}, CommandOriginType: {commandOriginType}"); return(false); } var outageModelAccessClient = OutageModelAccessClient.CreateClient(); var activeOutages = await outageModelAccessClient.GetAllActiveOutages(); if (activeOutages.Any(active => (active.OutageState == OutageState.CREATED && active.OutageElementGid == elementGid) || (active.OutageState != OutageState.CREATED && active.DefaultIsolationPoints.Any(point => point.EquipmentId == elementGid)))) { Logger.LogWarning($"{baseLogString} ReportPotentialOutage => duplicate... ElementGID: 0x{elementGid:X16}"); return(false); } return(true); }
private async Task <bool> FinishIndividualAlgorithmCycle(IsolationAlgorithm algorithm, OutageTopologyModel topology) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]"; Logger.LogInformation($"{algorithmBaseLogString} entering FinishIndividualAlgorithmCycle."); if (algorithm.CurrentBreakerGid <= 0 || algorithm.CurrentBreakerGid == algorithm.RecloserGid) { string message = $"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => End of the feeder, no outage detected."; Logger.LogWarning(message); return(false); } var getCreatedOutageResult = await lifecycleHelper.GetCreatedOutage(algorithm.OutageId); if (!getCreatedOutageResult.HasValue) { Logger.LogError($"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => Created Outage is null. OutageId: {algorithm.OutageId}"); return(false); } var outageToIsolate = getCreatedOutageResult.Value; await SetDefaultIsolationPoints(outageToIsolate, algorithm); await SetOptimumIsolationPoints(outageToIsolate, algorithm, topology); //ISOLATE on optimum points var firstOptimumPoint = outageToIsolate.OptimumIsolationPoints[0]; var secondOptimumPoint = outageToIsolate.OptimumIsolationPoints[1]; var commands = new Dictionary <long, DiscreteCommandingType> { { algorithm.HeadBreakerGid, DiscreteCommandingType.CLOSE }, { firstOptimumPoint.EquipmentId, DiscreteCommandingType.OPEN }, { secondOptimumPoint.EquipmentId, DiscreteCommandingType.OPEN }, { algorithm.RecloserGid, DiscreteCommandingType.CLOSE }, }; var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); if (!await SendCommands(algorithm, commands, enumerableCommandedElements)) { string message = $"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => Failed on SendMultipleScadaCommandAsync."; Logger.LogError(message); return(false); } long outageElementGid = topology.OutageTopology[secondOptimumPoint.EquipmentId].FirstEnd; //element iznad donjeg pointa - moze biti samo jedan gornji element (parent) if (!topology.OutageTopology[firstOptimumPoint.EquipmentId].SecondEnd.Contains(outageElementGid)) { string message = $"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => Outage element with gid: 0x{outageElementGid:X16} is not on a second end of current breaker id"; Logger.LogError(message); return(false); } outageToIsolate.IsolatedTime = DateTime.UtcNow; outageToIsolate.OutageElementGid = outageElementGid; outageToIsolate.OutageState = OutageState.ISOLATED; var outageModelAccessClient = OutageModelAccessClient.CreateClient(); await outageModelAccessClient.UpdateOutage(outageToIsolate); Logger.LogInformation($"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => Isolation of outage with id: {outageToIsolate.OutageId}. Optimum isolation points: 0x{outageToIsolate.OptimumIsolationPoints[0].EquipmentId:X16} and 0x{outageToIsolate.OptimumIsolationPoints[1].EquipmentId:X16}, and outage element id is 0x{outageElementGid:X16}"); await lifecycleHelper.PublishOutageAsync(Topic.ACTIVE_OUTAGE, outageMessageMapper.MapOutageEntity(outageToIsolate)); Logger.LogInformation($"{algorithmBaseLogString} FinishIndividualAlgorithmCycle => Outage with id: 0x{outageToIsolate.OutageId:x16} is successfully published."); await OnEndAlgorithmCleanUp(algorithm.HeadBreakerGid); return(true); }
private async Task <bool> StartLocationAndIsolationAlgorithm(OutageEntity outageEntity, OutageTopologyModel topology) { long reportedGid = outageEntity.DefaultIsolationPoints.First().EquipmentId; if (!topology.GetElementByGid(reportedGid, out OutageTopologyElement topologyElement)) { Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => element with gid 0x{reportedGid:X16} not found in outage topology model."); return(false); } long upBreaker; long outageElementGid = -1; Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => Entering 10 sec delay."); await Task.Delay(10_000); Logger.LogInformation($"{baseLogString} StartLocationAndIsolationAlgorithm => 10 sec delay ended."); var outageSimulatorClient = OutageSimulatorClient.CreateClient(); var outageModelAccessClient = OutageModelAccessClient.CreateClient(); //Da li je prijaveljen element OutageElement if (await outageSimulatorClient.IsOutageElement(reportedGid)) { outageElementGid = reportedGid; } //Da li je mozda na ACL-novima ispod prijavljenog elementa else { for (int i = 0; i < topologyElement.SecondEnd.Count; i++) { var potentialOutageElementGid = topologyElement.SecondEnd[i]; if (!(await outageSimulatorClient.IsOutageElement(potentialOutageElementGid))) { continue; } if (outageElementGid == -1) { outageElementGid = potentialOutageElementGid; outageEntity.OutageElementGid = outageElementGid; //outageEntity.AffectedConsumers = await lifecycleHelper.GetAffectedConsumersFromDatabase(lifecycleHelper.GetAffectedConsumers(outageElementGid, topology, NetworkType.NON_SCADA_NETWORK)); } else { //KAKO SE ULAZI U OVAJ ELSE? => u else se ulazi tako sto se ide kroz for i prvi element se oznaci kao outage element, zatim se pronaje jos neki... znaci ovo je nacin da se kreira drugi, treci outage, na racvanju ispod elementa, po for-u.... var entity = new OutageEntity() { OutageElementGid = potentialOutageElementGid, ReportTime = DateTime.UtcNow }; await outageModelAccessClient.AddOutage(entity); } } } //Tragamo za ACL-om gore ka source-u while (outageElementGid == -1 && !topologyElement.IsRemote && topologyElement.DmsType != "ENERGYSOURCE") { if (await outageSimulatorClient.IsOutageElement(topologyElement.Id)) { outageElementGid = topologyElement.Id; outageEntity.OutageElementGid = outageElementGid; } topology.GetElementByGid(topologyElement.FirstEnd, out topologyElement); } if (outageElementGid == -1) { outageEntity.OutageState = OutageState.REMOVED; await outageModelAccessClient.RemoveOutage(outageEntity); Logger.LogError($"{baseLogString} StartLocationAndIsolationAlgorithm => End of feeder no outage detected."); return(false); } topology.GetElementByGidFirstEnd(outageEntity.OutageElementGid, out topologyElement); while (topologyElement.DmsType != "BREAKER") { topology.GetElementByGidFirstEnd(topologyElement.Id, out topologyElement); } upBreaker = topologyElement.Id; long nextBreaker = lifecycleHelper.GetNextBreaker(outageEntity.OutageElementGid, topology); if (!topology.OutageTopology.ContainsKey(nextBreaker)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Breaker (next breaker) with id: 0x{nextBreaker:X16} is not in topology"; Logger.LogError(message); throw new Exception(message); } long outageElement = topology.OutageTopology[nextBreaker].FirstEnd; if (!topology.OutageTopology[upBreaker].SecondEnd.Contains(outageElement)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Outage element with gid: 0x{outageElement:X16} is not on a second end of current breaker id"; Logger.LogError(message); throw new Exception(message); } outageEntity.OptimumIsolationPoints = await lifecycleHelper.GetEquipmentEntityAsync(new List <long>() { upBreaker, nextBreaker }); outageEntity.IsolatedTime = DateTime.UtcNow; outageEntity.OutageState = OutageState.ISOLATED; await outageModelAccessClient.UpdateOutage(outageEntity); var commands = new Dictionary <long, DiscreteCommandingType> { { upBreaker, DiscreteCommandingType.OPEN }, { nextBreaker, DiscreteCommandingType.OPEN }, }; var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, enumerableCommandedElements, CommandOriginType.LOCATION_AND_ISOLATING_ALGORITHM_COMMAND)) { string message = $"{baseLogString} StartLocationAndIsolationAlgorithm => Sending multiple command failed."; Logger.LogError(message); return(false); } commands.Keys.ToList().ForEach(async commandedElementGid => { await ElementsToBeIgnoredInReportPotentialOutage.SetAsync(commandedElementGid, DateTime.UtcNow); Logger.LogDebug($"{baseLogString} SendCommands => Element 0x{commandedElementGid:X16} set to collection '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}' at {DateTime.UtcNow}."); }); return(true); }
public async Task <bool> ValidateResolveConditions(long outageId) { Logger.LogVerbose($"{baseLogString} ValidateResolveConditions method started. OutageId: {outageId}"); while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } try { var result = await lifecycleHelper.GetRepairedOutage(outageId); if (!result.HasValue) { Logger.LogError($"{baseLogString} ValidateResolveConditions => GetRepairedOutage did not return a value. OutageId: {outageId}"); return(false); } var outageDbEntity = result.Value; var isolationPoints = new List <Equipment>(); isolationPoints.AddRange(outageDbEntity.DefaultIsolationPoints); isolationPoints.AddRange(outageDbEntity.OptimumIsolationPoints); var enumerableTopology = await OutageTopologyModel.GetEnumerableDictionaryAsync(); if (!enumerableTopology.ContainsKey(ReliableDictionaryNames.OutageTopologyModel)) { Logger.LogError($"{baseLogString} Start => Topology not found in Rel Dictionary: {ReliableDictionaryNames.OutageTopologyModel}."); return(false); } var topology = enumerableTopology[ReliableDictionaryNames.OutageTopologyModel]; bool resolveCondition = true; foreach (Equipment isolationPoint in isolationPoints) { if (!topology.GetElementByGid(isolationPoint.EquipmentId, out OutageTopologyElement element)) { string errorMessage = $"{baseLogString} ValidateResolveConditions => element with gid 0x{isolationPoint.EquipmentId:X16} not found in current {ReliableDictionaryNames.OutageTopologyModel}"; Logger.LogError(errorMessage); resolveCondition = false; break; } //NoReclosing == True (nije recloser) && element.IsActive == false - nije recloser i kroz njega ne ide struja => nevalidno //NoReclosing == False (jeste recloser) && element.IsActive == true - jeste recloser i ide struja => nevalidno //uglavnom, uslov je dobar, ali neintuitivan if (element.NoReclosing != element.IsActive) { resolveCondition = false; break; } } outageDbEntity.IsResolveConditionValidated = resolveCondition; var outageModelAccessClient = OutageModelAccessClient.CreateClient(); await outageModelAccessClient.UpdateOutage(outageDbEntity); return(await lifecycleHelper.PublishOutageAsync(Topic.ACTIVE_OUTAGE, outageMessageMapper.MapOutageEntity(outageDbEntity))); } catch (Exception e) { string message = $"{baseLogString} ValidateResolveConditions => Exception: {e.Message}"; Logger.LogError(message, e); return(false); } }