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);
            }
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
            }
        }