//TODO: razmotriti stanje outage na ako se algoritam enduje sa nekim fejlom.... da li brisati sam outage npr... private async Task OnEndAlgorithmCleanUp(long headBreakerGid) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{headBreakerGid:X16}]"; await StartedIsolationAlgorithms.TryRemoveAsync(headBreakerGid); await MonitoredHeadBreakerMeasurements.TryRemoveAsync(headBreakerGid); var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); var commandedElementsToBeRemoved = enumerableCommandedElements.Values.Where(element => element.CorrespondingHeadElementGid == headBreakerGid); foreach (var element in commandedElementsToBeRemoved) { await CommandedElements.TryRemoveAsync(element.ElementGid); } var enumerableOptimumIsolationPoints = await OptimumIsolationPoints.GetEnumerableDictionaryAsync(); var optimumIsolationPointsToBeRemovedGids = enumerableOptimumIsolationPoints.Where(kvp => kvp.Value == headBreakerGid).Select(kvp => kvp.Key); foreach (var gid in optimumIsolationPointsToBeRemovedGids) { await OptimumIsolationPoints.TryRemoveAsync(gid); } }
private async Task <bool> SendCommands(IsolationAlgorithm algorithm, Dictionary <long, DiscreteCommandingType> commands, Dictionary <long, CommandedElement> commandedElements) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]"; if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, commandedElements, CommandOriginType.ISOLATING_ALGORITHM_COMMAND)) { string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Sending multiple command failed."; Logger.LogError(message); return(false); } commands.Keys.ToList().ForEach(async commandedElementGid => { var commandedElement = new CommandedElement() { ElementGid = commandedElementGid, CorrespondingHeadElementGid = algorithm.HeadBreakerGid, CommandingType = commands[commandedElementGid], }; await CommandedElements.SetAsync(commandedElementGid, commandedElement); await ElementsToBeIgnoredInReportPotentialOutage.SetAsync(commandedElementGid, DateTime.UtcNow); Logger.LogDebug($"{algorithmBaseLogString} SendCommands => Element 0x{commandedElementGid:X16} set to collection '{ReliableDictionaryNames.ElementsToBeIgnoredInReportPotentialOutage}' at {DateTime.UtcNow}."); }); await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm); return(true); }
private async Task <bool> SendCommands(IsolationAlgorithm algorithm, Dictionary <long, DiscreteCommandingType> commands, Dictionary <long, CommandedElement> commandedElements) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]"; if (!await lifecycleHelper.SendMultipleScadaCommandAsync(commands, commandedElements, CommandOriginType.ISOLATING_ALGORITHM_COMMAND)) { string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Sending multiple command failed."; Logger.LogError(message); return(false); } commands.Keys.ToList().ForEach(async commandedElementGid => { var commandedElement = new CommandedElement() { ElementGid = commandedElementGid, CorrespondingHeadElementGid = algorithm.HeadBreakerGid, CommandingType = commands[commandedElementGid], }; await CommandedElements.SetAsync(commandedElementGid, commandedElement); algorithm.ElementsCommandedInCurrentCycle.Add(commandedElementGid); }); await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm); return(true); }
public async Task Start() { while (!ReliableDictionariesInitialized) { await Task.Delay(1000); } var enumerableStartedAlgorithms = await StartedIsolationAlgorithms.GetEnumerableDictionaryAsync(); if (enumerableStartedAlgorithms.Count == 0) { Logger.LogVerbose($"{baseLogString} Start => No started algorithms."); return; } var enumerableTopology = await OutageTopologyModel.GetEnumerableDictionaryAsync(); if (!enumerableTopology.ContainsKey(ReliableDictionaryNames.OutageTopologyModel)) { Logger.LogError($"{baseLogString} Start => Topology not found in Rel Dictionary: {ReliableDictionaryNames.OutageTopologyModel}."); return; } var topology = enumerableTopology[ReliableDictionaryNames.OutageTopologyModel]; var tasks = new List <Task <ConditionalValue <long> > >(); foreach (var algorithm in enumerableStartedAlgorithms.Values) { tasks.Add(StartIndividualAlgorithmCycle(algorithm, topology)); } var tasksArray = tasks.ToArray(); Task.WaitAll(tasksArray); foreach (var task in tasksArray) { //SVESNO SE POGRESNO KORISTI HasValue if (!task.Result.HasValue) { var headBreakerGid = task.Result.Value; await OnEndAlgorithmCleanUp(headBreakerGid); } } }
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); }
/// <summary> /// /// </summary> /// <param name="algorithm"></param> /// <param name="topology"></param> /// <returns>ConditionalValue with HeadElementGid as value - HasValue: false indicates that task ended unsuccessfully, value will never be null and will represent the id of the task -> HeadElementGid</returns> private async Task <ConditionalValue <long> > StartIndividualAlgorithmCycle(IsolationAlgorithm algorithm, OutageTopologyModel topology) { var algorithmBaseLogString = $"{baseLogString} [HeadBreakerGid: 0x{algorithm.HeadBreakerGid:X16}]"; //END CONDITION - poslednji otvoren brejker se nije otvorio vise od 'cycleUpperLimit' milisekundi => on predstavlja prvu optimalnu izolacionu tacku if (algorithm.CycleCounter * CycleInterval >= CycleUpperLimit) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => END CONDITION: {algorithm.CycleCounter} ms * {CycleInterval} ms > {CycleUpperLimit} ms."); var success = await FinishIndividualAlgorithmCycle(algorithm, topology); return(new ConditionalValue <long>(success, algorithm.HeadBreakerGid)); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => END CONDITION NOT MET: {algorithm.CycleCounter} ms * {CycleInterval} ms <= {CycleUpperLimit} ms."); } #region Check if HeadBreaker has OPENED after the last cycle var result = await MonitoredHeadBreakerMeasurements.TryGetValueAsync(algorithm.HeadBreakerMeasurementGid); if (!result.HasValue) { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreakerMeasurement with gid: 0x{algorithm.HeadBreakerMeasurementGid:X16} not found in {ReliableDictionaryNames.MonitoredHeadBreakerMeasurements}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } var headMeasurementData = result.Value; if (headMeasurementData.Value == (ushort)DiscreteCommandingType.CLOSE) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreaker is CLOSED."); //by exiting now we apply the logical WAITING (cycle mechanism in RunAsync): //1) For HeadBreaker to open => moving to next breaker //2) For "time" to run up => FinishIndividualAlgorithmCycle //counting cycles from after the command was successfully executed var commandsCount = await CommandedElements.GetCountAsync(); if (commandsCount == 0) { algorithm.CycleCounter++; await StartedIsolationAlgorithms.SetAsync(algorithm.HeadBreakerGid, algorithm); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => AlgorithCycleCounter set to {algorithm.CycleCounter}."); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Skipping the cycle and waiting for {commandsCount} commands to be executed. HEAD is CLOSED. AlgorithCycleCounter remains set on {algorithm.CycleCounter}."); } return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } else if (headMeasurementData.Value == (ushort)DiscreteCommandingType.OPEN) { //skipping untill all commands were successfully executed var commandsCount = await CommandedElements.GetCountAsync(); if (commandsCount > 0) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Skipping the cycle and waiting for {commandsCount} commands to be executed. HEAD is OPENED. AlgorithCycleCounter remains set on {algorithm.CycleCounter}."); return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } } else { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => headMeasurementData.Value is {headMeasurementData.Value} and cannot be casted to {typeof(DiscreteCommandingType)}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } #endregion Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreaker is OPENED."); //Closing current breaker, before moving to the next breaker var commands = new Dictionary <long, DiscreteCommandingType>(); if (algorithm.CurrentBreakerGid != algorithm.HeadBreakerGid) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to CLOSE the current breaker 0x{algorithm.CurrentBreakerGid:X16}"); commands.Add(algorithm.CurrentBreakerGid, DiscreteCommandingType.CLOSE); } algorithm.CycleCounter = 0; //moving to the next breaker algorithm.CurrentBreakerGid = lifecycleHelper.GetNextBreaker(algorithm.CurrentBreakerGid, topology); Logger.LogDebug($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Next breaker gid is 0x{algorithm.CurrentBreakerGid:X16}."); if (algorithm.CurrentBreakerGid <= 0 || !topology.GetElementByGid(algorithm.CurrentBreakerGid, out _)) { Logger.LogError($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => HeadBreakerMeasurement with gid: 0x{algorithm.HeadBreakerMeasurementGid:X16} not found in {ReliableDictionaryNames.MonitoredHeadBreakerMeasurements}."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } var enumerableCommandedElements = await CommandedElements.GetEnumerableDictionaryAsync(); //reaching the END of the FEEDER - ending the algorithm if (algorithm.CurrentBreakerGid == algorithm.RecloserGid) { string message = $"{algorithmBaseLogString} StartIndividualAlgorithmCycle => End of the feeder, no outage detected."; Logger.LogWarning(message); //TODO: HOW TO HANDEL - archived, deleted.... await SendCommands(algorithm, commands, enumerableCommandedElements); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } if (!commands.ContainsKey(algorithm.CurrentBreakerGid) && !commands.ContainsKey(algorithm.HeadBreakerGid)) { commands.Add(algorithm.CurrentBreakerGid, DiscreteCommandingType.OPEN); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to OPEN the current breaker 0x{algorithm.CurrentBreakerGid:X16}"); commands.Add(algorithm.HeadBreakerGid, DiscreteCommandingType.CLOSE); Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Preaparing command to CLOSE the head breaker 0x{algorithm.HeadBreakerGid:X16}"); } if (await SendCommands(algorithm, commands, enumerableCommandedElements)) { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Commands sent with success."); return(new ConditionalValue <long>(true, algorithm.HeadBreakerGid)); } else { Logger.LogInformation($"{algorithmBaseLogString} StartIndividualAlgorithmCycle => Send commands failed."); return(new ConditionalValue <long>(false, algorithm.HeadBreakerGid)); } }