public WriteMultipleFunction(ModbusFunctionCode functionCode, ushort startAddress, int[] commandValues, CommandOriginType commandOrigin)
     : base(functionCode)
 {
     StartAddress  = startAddress;
     CommandValues = commandValues;
     CommandOrigin = commandOrigin;
 }
Beispiel #2
0
 public AnalogModbusData(float value, AlarmType alarm, long measurementGid, CommandOriginType commandOrigin)
 {
     MeasurementGid = measurementGid;
     Value          = value;
     Alarm          = alarm;
     CommandOrigin  = commandOrigin;
 }
Beispiel #3
0
        public async Task <bool> EnqueuePotentialOutageCommand(long elementGid, CommandOriginType commandOriginType, NetworkType networkType)
        {
            Logger.LogDebug($"{baseLogString} EnqueuePotentialOutageCommand method started. Element gid: {elementGid}, command origin type: {commandOriginType}, network type {networkType}");

            while (!ReliableDictionariesInitialized)
            {
                await Task.Delay(1000);
            }

            try
            {
                var command = new PotentialOutageCommand()
                {
                    ElementGid        = elementGid,
                    CommandOriginType = commandOriginType,
                    NetworkType       = networkType,
                };

                await PotentialOutagesQueue.EnqueueAsync(command);

                return(true);
            }
            catch (Exception e)
            {
                string message = "EnqueuePotentialOutageCommand => exception caught";
                Logger.LogError(message, e);
                return(false);
            }
        }
Beispiel #4
0
 public DiscreteModbusData(ushort value, AlarmType alarm, long measurementGid, CommandOriginType commandOrigin)
 {
     MeasurementGid = measurementGid;
     Value          = value;
     Alarm          = alarm;
     CommandOrigin  = commandOrigin;
 }
Beispiel #5
0
 public CommandOriginData(CommandOriginType type, UUID uuid, string requestId, long entityUniqueId)
 {
     Type           = type;
     UUID           = uuid;
     RequestId      = requestId;
     EntityUniqueId = entityUniqueId;
 }
        public void Notify(IPublishableMessage msg)
        {
            Console.WriteLine("Message from PubSub: " + msg);

            if (msg is MultipleAnalogValueSCADAMessage multipleAnalogValue)
            {
                foreach (long gid in multipleAnalogValue.Data.Keys)
                {
                    double            currentValue  = multipleAnalogValue.Data[gid].Value;
                    AlarmType         alarm         = multipleAnalogValue.Data[gid].Alarm;
                    CommandOriginType commandOrigin = multipleAnalogValue.Data[gid].CommandOrigin;
                    Console.WriteLine($"Analog => Gid: 0x{gid:X16} Value: {currentValue}, Alarm: {alarm}, Origin: {commandOrigin}");
                }
            }
            else if (msg is MultipleDiscreteValueSCADAMessage multipleDiscreteValue)
            {
                foreach (long gid in multipleDiscreteValue.Data.Keys)
                {
                    ushort            currentValue  = multipleDiscreteValue.Data[gid].Value;
                    AlarmType         alarm         = multipleDiscreteValue.Data[gid].Alarm;
                    CommandOriginType commandOrigin = multipleDiscreteValue.Data[gid].CommandOrigin;
                    Console.WriteLine($"Discrete => Gid: 0x{gid:X16}, Value: {currentValue}, Alarm: {alarm}, Origin: {commandOrigin}");
                }
            }
            else if (msg is ActiveOutageMessage activeOutage)
            {
                Console.WriteLine($"Active outage id: {activeOutage.OutageId}, affected consumers:{activeOutage.AffectedConsumers}, affected element: 0x{activeOutage.OutageElementGid:x16}");
            }
        }
 public WriteSingleFunction(ModbusFunctionCode functionCode, ushort outputAddress, int commandValue, CommandOriginType commandOrigin)
     : base(functionCode)
 {
     OutputAddress = outputAddress;
     CommandValue  = commandValue;
     CommandOrigin = commandOrigin;
 }
Beispiel #8
0
 public WriteSingleRegisterFunction(ModbusCommandParameters commandParameters, CommandOriginType commandOrigin)
     : base(commandParameters)
 {
     CheckArguments(MethodBase.GetCurrentMethod(), typeof(ModbusWriteCommandParameters));
     CommandOrigin = commandOrigin;
     ModbusWriteCommandParameters = commandParameters as IModbusWriteCommandParameters;
 }
Beispiel #9
0
 private void CommandToRecloser(long measurementGid, int value, CommandOriginType originType, ITopologyElement recloser)
 {
     Thread.Sleep(10000);
     if (!((Recloser)recloser).IsReachedMaximumOfTries())
     {
         scadaCommanding.SendDiscreteCommand(measurementGid, value, originType);
         ((Recloser)recloser).NumberOfTry++;
     }
 }
Beispiel #10
0
        public Dictionary<Topic, SCADAPublication> GetIntegrityUpdate()
        {
            if (IntegrityUpdateService.scadaModel == null)
            {
                string message = $"GetIntegrityUpdate => SCADA model is null.";
                Logger.LogError(message);
                throw new InternalSCADAServiceException(message);
            }

            var currentScadaModel = IntegrityUpdateService.scadaModel.CurrentScadaModel;
            var commandValuesCache = IntegrityUpdateService.scadaModel.CommandedValuesCache;

            Dictionary<long, AnalogModbusData> analogModbusData = new Dictionary<long, AnalogModbusData>();
            Dictionary<long, DiscreteModbusData> discreteModbusData = new Dictionary<long, DiscreteModbusData>();

            foreach(long gid in currentScadaModel.Keys)
            {
                CommandOriginType commandOrigin = CommandOriginType.OTHER_COMMAND;

                if (currentScadaModel[gid] is AnalogSCADAModelPointItem analogPointItem)
                {
                    if (commandValuesCache.ContainsKey(gid) && commandValuesCache[gid].Value == analogPointItem.CurrentRawValue)
                    {
                        commandOrigin = commandValuesCache[gid].CommandOrigin;
                    }

                    AnalogModbusData analogValue = new AnalogModbusData(analogPointItem.CurrentEguValue, analogPointItem.Alarm, gid, commandOrigin);
                    analogModbusData.Add(gid, analogValue);
                }
                else if(currentScadaModel[gid] is DiscreteSCADAModelPointItem discretePointItem)
                {
                    if (commandValuesCache.ContainsKey(gid) && commandValuesCache[gid].Value == discretePointItem.CurrentValue)
                    {
                        commandOrigin = commandValuesCache[gid].CommandOrigin;
                    }

                    DiscreteModbusData discreteValue = new DiscreteModbusData(discretePointItem.CurrentValue, discretePointItem.Alarm, gid, commandOrigin);
                    discreteModbusData.Add(gid, discreteValue);
                }
            }

            MultipleAnalogValueSCADAMessage analogValuesMessage = new MultipleAnalogValueSCADAMessage(analogModbusData);
            SCADAPublication measurementPublication = new SCADAPublication(Topic.MEASUREMENT, analogValuesMessage);

            MultipleDiscreteValueSCADAMessage discreteValuesMessage = new MultipleDiscreteValueSCADAMessage(discreteModbusData);
            SCADAPublication switchStatusPublication = new SCADAPublication(Topic.SWITCH_STATUS, discreteValuesMessage);

            Dictionary<Topic, SCADAPublication> scadaPublications = new Dictionary<Topic, SCADAPublication>
            {
                { Topic.MEASUREMENT, measurementPublication },
                { Topic.SWITCH_STATUS, switchStatusPublication },
            };

            return scadaPublications;
        }
Beispiel #11
0
        public bool ReportPotentialOutage(long elementGid, CommandOriginType commandOriginType)
        {
            bool success;

            try
            {
                success = Channel.ReportPotentialOutage(elementGid, commandOriginType);
            }
            catch (Exception e)
            {
                string message = "Exception in ReportPotentialOutage() proxy method.";
                LoggerWrapper.Instance.LogError(message, e);
                throw e;
            }

            return(success);
        }
Beispiel #12
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 #13
0
        public bool SendDiscreteCommand(long gid, ushort commandingValue, CommandOriginType commandOriginType)
        {
            bool success;

            try
            {
                success = Channel.SendDiscreteCommand(gid, commandingValue, commandOriginType);
            }
            catch (Exception e)
            {
                string message = "Exception in SendDiscreteCommand() proxy method.";
                LoggerWrapper.Instance.LogError(message, e);
                throw e;
            }

            return(success);
        }
Beispiel #14
0
        public bool ReportPotentialOutage(long elementGid, CommandOriginType commandOriginType)
        {
            bool result;

            try
            {
                outageModel.PotentialOutage.Enqueue(new Tuple <long, CommandOriginType>(elementGid, commandOriginType));
                //result = reportOutageService.ReportPotentialOutage(elementGid, commandOriginType); //TODO: enum (error, noAffectedConsumers, success,...)
                result = true;
            }
            catch (Exception e)
            {
                result = false;
                string message = "ReportPotentialOutage => exception caught";
                Logger.LogError(message, e);
                //todo throw;
            }

            return(result);
        }
        private async Task CommandToRecloser(long measurementGid, int value, CommandOriginType originType, ITopologyElement recloser)
        {
            string verboseMessage = $"{baseLogString} CommandToRecloser method called.";

            Logger.LogVerbose(verboseMessage);

            if (recloser == null)
            {
                string message = $"{baseLogString} CommandToRecloser => NULL value has been passed instead of element.";
                Logger.LogError(message);
                throw new Exception(message);
            }

            if (!(recloser is Recloser))
            {
                string message = $"{baseLogString} CommandToRecloser => Element with GID {recloser.Id:X16} is not a recloser.";
                Logger.LogError(message);
                throw new Exception(message);
            }

            Logger.LogDebug($"{baseLogString} CommandToRecloser => Enetring in sleep for 20 seconds.");
            await Task.Delay(recloserInterval);

            Logger.LogDebug($"{baseLogString} CommandToRecloser => Waking up after 20 seconds.");

            var topologyProviderClient = TopologyProviderClient.CreateClient();
            int counter = await topologyProviderClient.GetRecloserCount(recloser.Id);

            if (((Recloser)recloser).MaxNumberOfTries > counter)
            {
                topologyProviderClient = TopologyProviderClient.CreateClient();
                await topologyProviderClient.RecloserOpened(recloser.Id);

                Logger.LogDebug($"{baseLogString} CommandToRecloser => Calling SendDiscreteCommand method from measurement provider. Measurement GID: {measurementGid:X16}, Value: {value}, OriginType {originType}.");
                var measurementProviderClient = MeasurementProviderClient.CreateClient();
                await measurementProviderClient.SendSingleDiscreteCommand(measurementGid, value, originType);

                Logger.LogDebug($"{baseLogString} CommandToRecloser => SendDiscreteCommand method has been successfully called.");
            }
        }
Beispiel #16
0
        public void SendAnalogCommand(long measurementGid, float commandingValue, CommandOriginType commandOrigin)
        {
            try
            {
                ProxyFactory proxyFactory = new ProxyFactory();
                using (SCADACommandProxy proxy = proxyFactory.CreateProxy <SCADACommandProxy, ISCADACommand>(EndpointNames.SCADACommandService))
                {
                    if (proxy == null)
                    {
                        string message = "SendDiscreteCommand => SCADACommandProxy is null.";
                        logger.LogError(message);
                        throw new NullReferenceException(message);
                    }

                    proxy.SendAnalogCommand(measurementGid, commandingValue, commandOrigin);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
        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);
        }
Beispiel #18
0
        public void SendDiscreteCommand(long measurementGid, int value, CommandOriginType commandOrigin)
        {
            try
            {
                if (Provider.Instance.MeasurementProvider.TryGetDiscreteMeasurement(measurementGid, out DiscreteMeasurement measurement) && !(measurement is ArtificalDiscreteMeasurement))
                {
                    ProxyFactory proxyFactory = new ProxyFactory();

                    using (SCADACommandProxy proxy = proxyFactory.CreateProxy <SCADACommandProxy, ISCADACommand>(EndpointNames.SCADACommandService))
                    {
                        if (proxy == null)
                        {
                            string message = "SendDiscreteCommand => SCADACommandProxy is null.";
                            logger.LogError(message);
                            throw new NullReferenceException(message);
                        }

                        proxy.SendDiscreteCommand(measurementGid, (ushort)value, commandOrigin);
                    }
                }
                else
                {
                    //TOOD: DiscreteModbusData prilikom prijema sa skade prepakovati u model podataka koji ce se cuvati na CE, u prilogy AlarmType.NO_ALARM, nije validna stvar, navodi se da se
                    //DiscreteModbusData data = new DiscreteModbusData((ushort)value, AlarmType.NO_ALARM, measurementGid, commandOrigin);
                    Dictionary <long, DiscreteModbusData> data = new Dictionary <long, DiscreteModbusData>(1)
                    {
                        { measurementGid, new DiscreteModbusData((ushort)value, AlarmType.NO_ALARM, measurementGid, commandOrigin) }
                    };
                    Provider.Instance.MeasurementProvider.UpdateDiscreteMeasurement(data);
                    //Provider.Instance.MeasurementProvider.UpdateDiscreteMeasurement(data.MeasurementGid, data.Value, data.CommandOrigin);
                }
            }
            catch (Exception ex)
            {
                logger.LogError($"Sending discrete command for measurement with GID 0x{measurementGid.ToString("X16")} failed. Exception: {ex.Message}");
            }
        }
Beispiel #19
0
        public bool SendAnalogCommand(long gid, float commandingValue, CommandOriginType commandOriginType)
        {
            bool success;

            if (CommandService.scadaModel == null)
            {
                string message = $"SendAnalogCommand => SCADA model is null.";
                Logger.LogError(message);
                throw new InternalSCADAServiceException(message);
            }

            var currentScadaModel = CommandService.scadaModel.CurrentScadaModel;

            if (!currentScadaModel.ContainsKey(gid))
            {
                string message = $"Entity with gid: 0x{gid:X16} does not exist in current SCADA model.";
                Logger.LogError(message);
                throw new ArgumentException(message);
            }

            ISCADAModelPointItem pointItem = currentScadaModel[gid];

            if (pointItem is IAnalogSCADAModelPointItem analogPointItem && pointItem.RegisterType == PointType.ANALOG_OUTPUT)
            {
                try
                {
                    int modbusValue = analogPointItem.EguToRawValueConversion(commandingValue);
                    success = SendCommand(pointItem, modbusValue, commandOriginType);
                }
                catch (Exception e)
                {
                    string message = $"Exception in SendAnalogCommand() method.";
                    Logger.LogError(message, e);
                    throw new InternalSCADAServiceException(message, e);
                }
            }
Beispiel #20
0
 public Task <bool> SendMultipleDiscreteCommand(Dictionary <long, ushort> commandingValues, CommandOriginType commandOriginType)
 {
     return(InvokeWithRetryAsync(client => client.Channel.SendMultipleDiscreteCommand(commandingValues, commandOriginType)));
 }
Beispiel #21
0
 public Task <bool> SendSingleDiscreteCommand(long gid, ushort commandingValue, CommandOriginType commandOriginType)
 {
     return(InvokeWithRetryAsync(client => client.Channel.SendSingleDiscreteCommand(gid, commandingValue, commandOriginType)));
 }
Beispiel #22
0
        public override void Execute(ModbusClient modbusClient)
        {
            ModbusReadCommandParameters mdb_read_comm_pars = this.CommandParameters as ModbusReadCommandParameters;
            ushort startAddress = mdb_read_comm_pars.StartAddress;
            ushort quantity     = mdb_read_comm_pars.Quantity;

            if (quantity <= 0)
            {
                string message = $"Reading Quantity: {quantity} does not make sense.";
                Logger.LogError(message);
                throw new Exception(message);
            }

            if (startAddress + quantity >= ushort.MaxValue || startAddress + quantity == ushort.MinValue || startAddress == ushort.MinValue)
            {
                string message = $"Address is out of bound. Start address: {startAddress}, Quantity: {quantity}";
                Logger.LogError(message);
                throw new Exception(message);
            }

            bool[] data = new bool[0];

            try
            {
                if (modbusClient.Connected)
                {
                    data = modbusClient.ReadDiscreteInputs(startAddress - 1, quantity);
                }
                else
                {
                    Logger.LogError("modbusClient is disconected ");
                }
            }
            catch (Exception e)
            {
                Logger.LogError("Error on ReadDiscreteInputs()", e);
                throw e;
            }

            Data = new Dictionary <long, DiscreteModbusData>(data.Length);

            var currentSCADAModel      = SCADAModel.CurrentScadaModel;
            var currentAddressToGidMap = SCADAModel.CurrentAddressToGidMap;
            var commandValuesCache     = SCADAModel.CommandedValuesCache;

            for (ushort i = 0; i < data.Length; i++)
            {
                ushort address = (ushort)(startAddress + i);
                ushort value   = (ushort)(data[i] ? 1 : 0);

                //for commands enqueued during model update
                if (!currentAddressToGidMap[PointType.DIGITAL_INPUT].ContainsKey(address))
                {
                    Logger.LogWarn($"ReadDiscreteInputsFunction execute => trying to read value on address {address}, Point type: {PointType.DIGITAL_INPUT}, which is not in the current SCADA Model.");
                    continue;
                }

                long gid = currentAddressToGidMap[PointType.DIGITAL_INPUT][address];

                //for commands enqueued during model update
                if (!currentSCADAModel.ContainsKey(gid))
                {
                    Logger.LogWarn($"ReadDiscreteInputsFunction execute => trying to read value for measurement with gid: 0x{gid:X16}, which is not in the current SCADA Model.");
                    continue;
                }

                if (!(currentSCADAModel[gid] is DiscreteSCADAModelPointItem pointItem))
                {
                    string message = $"PointItem [Gid: 0x{gid:X16}] is not type DiscreteSCADAModelPointItem.";
                    Logger.LogError(message);
                    throw new Exception(message);
                }

                if (pointItem.CurrentValue != value)
                {
                    pointItem.CurrentValue = value;
                    Logger.LogInfo($"Alarm for Point [Gid: 0x{pointItem.Gid:X16}, Point type: {PointType.DIGITAL_INPUT}, Address: {pointItem.Address}] set to {pointItem.Alarm}.");
                }

                CommandOriginType commandOrigin = CommandOriginType.OTHER_COMMAND;

                if (commandValuesCache.ContainsKey(gid) && commandValuesCache[gid].Value == value)
                {
                    commandOrigin = commandValuesCache[gid].CommandOrigin;
                    commandValuesCache.Remove(gid);
                    Logger.LogDebug($"[ReadDiscreteInputsFunction] Command origin of command address: {pointItem.Address} is set to {commandOrigin}.");
                }

                DiscreteModbusData digitalData = new DiscreteModbusData(value, pointItem.Alarm, gid, commandOrigin);
                Data.Add(gid, digitalData);
                //Logger.LogDebug($"ReadDiscreteInputsFunction execute => Current value: {value} from address: {address}, point type: {PointType.DIGITAL_INPUT}, gid: 0x{gid:X16}.");
            }

            //Logger.LogDebug($"ReadDiscreteInputsFunction executed SUCCESSFULLY. StartAddress: {startAddress}, Quantity: {quantity}");
        }
Beispiel #23
0
        public async Task <bool> SendMultipleAnalogCommand(Dictionary <long, float> commandingValues, CommandOriginType commandOriginType)
        {
            if (commandingValues.Count == 0)
            {
                string warnMessage = $"{baseLogString} SendMultipleAnalogCommand => commandingValues is empty and thus aborting the call.";
                Logger.LogWarning(warnMessage);
                return(false);
            }

            ushort startAddress = 1; //EasyModbus spec
            IScadaModelReadAccessContract           scadaModelReadAccessClient = ScadaModelReadAccessClient.CreateClient();
            Dictionary <long, IScadaModelPointItem> gidToPointItemMap          = await scadaModelReadAccessClient.GetGidToPointItemMap();

            Dictionary <short, Dictionary <ushort, long> > addressToGidMap = await scadaModelReadAccessClient.GetAddressToGidMap();

            if (gidToPointItemMap == null)
            {
                string message = $"{baseLogString} SendMultipleAnalogCommand => SCADA model is null.";
                Logger.LogError(message);
                //throw new InternalSCADAServiceException(message);
                return(false);
            }

            int analogOutputCount = addressToGidMap[(short)PointType.ANALOG_OUTPUT].Count;

            int[] multipleCommandingValues = new int[addressToGidMap[(short)PointType.ANALOG_OUTPUT].Count];

            //for (ushort address = 1; address <= analogOutputCount; address++)
            //{
            foreach (ushort address in addressToGidMap[(short)PointType.ANALOG_OUTPUT].Keys)
            {
                long gid = addressToGidMap[(short)PointType.ANALOG_OUTPUT][address];

                if (!gidToPointItemMap.ContainsKey(gid))
                {
                    string message = $"{baseLogString} SendMultipleAnalogCommand => Entity with gid: 0x{gid:X16} does not exist in current SCADA model.";
                    Logger.LogError(message);
                    //throw new ArgumentException(message);
                    return(false);
                }
                else if (!(gidToPointItemMap[gid] is IAnalogPointItem analogPointItem))
                {
                    string message = $"{baseLogString} SendMultipleAnalogCommand => Entity with gid: 0x{gid:X16} does not implement IAnalogPointItem interface.";
                    Logger.LogError(message);
                    //throw new InternalSCADAServiceException(message);
                    return(false);
                }
        public async Task <ScadaPublication> GetIntegrityUpdateForSpecificTopic(Topic topic)
        {
            while (!ReliableDictionariesInitialized)
            {
                await Task.Delay(1000);
            }

            if (GidToPointItemMap == null)
            {
                string message = $"GetIntegrityUpdate => GidToPointItemMap is null.";
                Logger.LogError(message);
                throw new InternalSCADAServiceException(message);
            }

            if (CommandDescriptionCache == null)
            {
                string message = $"GetIntegrityUpdate => CommandDescriptionCache is null.";
                Logger.LogError(message);
                throw new InternalSCADAServiceException(message);
            }

            Dictionary <long, AnalogModbusData>   analogModbusData   = new Dictionary <long, AnalogModbusData>();
            Dictionary <long, DiscreteModbusData> discreteModbusData = new Dictionary <long, DiscreteModbusData>();

            var enumerableGidToPointItemMap = await GidToPointItemMap.GetEnumerableDictionaryAsync();

            foreach (long gid in enumerableGidToPointItemMap.Keys)
            {
                CommandOriginType commandOrigin = CommandOriginType.UNKNOWN_ORIGIN;

                if (topic == Topic.MEASUREMENT && enumerableGidToPointItemMap[gid] is IAnalogPointItem analogPointItem)
                {
                    var result = await CommandDescriptionCache.TryGetValueAsync(gid);

                    if (result.HasValue && result.Value.Value == analogPointItem.CurrentRawValue)
                    {
                        commandOrigin = result.Value.CommandOrigin;
                    }

                    AnalogModbusData analogValue = new AnalogModbusData(analogPointItem.CurrentEguValue, analogPointItem.Alarm, gid, commandOrigin);
                    analogModbusData.Add(gid, analogValue);
                }
                else if (topic == Topic.SWITCH_STATUS && enumerableGidToPointItemMap[gid] is IDiscretePointItem discretePointItem)
                {
                    var result = await CommandDescriptionCache.TryGetValueAsync(gid);

                    if (result.HasValue && result.Value.Value == discretePointItem.CurrentValue)
                    {
                        commandOrigin = result.Value.CommandOrigin;
                    }


                    DiscreteModbusData discreteValue = new DiscreteModbusData(discretePointItem.CurrentValue, discretePointItem.Alarm, gid, commandOrigin);
                    discreteModbusData.Add(gid, discreteValue);
                }
            }

            ScadaPublication scadaPublication;

            if (topic == Topic.MEASUREMENT)
            {
                MultipleAnalogValueSCADAMessage analogValuesMessage = new MultipleAnalogValueSCADAMessage(analogModbusData);
                scadaPublication = new ScadaPublication(Topic.MEASUREMENT, analogValuesMessage);
            }
            else if (topic == Topic.SWITCH_STATUS)
            {
                MultipleDiscreteValueSCADAMessage discreteValuesMessage = new MultipleDiscreteValueSCADAMessage(discreteModbusData);
                scadaPublication = new ScadaPublication(Topic.SWITCH_STATUS, discreteValuesMessage);
            }
            else
            {
                string message = $"GetIntegrityUpdate => argument topic is neither Topic.MEASUREMENT nor Topic.SWITCH_STATUS.";
                Logger.LogError(message);
                throw new ArgumentException(message);
            }

            return(scadaPublication);
        }
Beispiel #25
0
        public async Task <bool> SendSingleAnalogCommand(long gid, float commandingValue, CommandOriginType commandOriginType)
        {
            string verboseMessage = $"{baseLogString} SendSingleAnalogCommand method called. gid: {gid:X16}, commandingValue: {commandingValue}, commandOriginType: {commandOriginType}";

            Logger.LogVerbose(verboseMessage);

            IScadaModelReadAccessContract           scadaModelReadAccessClient = ScadaModelReadAccessClient.CreateClient();
            Dictionary <long, IScadaModelPointItem> gidToPointItemMap          = await scadaModelReadAccessClient.GetGidToPointItemMap();

            if (gidToPointItemMap == null)
            {
                string message = $"{baseLogString} SendSingleAnalogCommand => SendSingleAnalogCommand => SCADA model is null.";
                Logger.LogError(message);
                //throw new InternalSCADAServiceException(message);
                return(false);
            }

            if (!gidToPointItemMap.ContainsKey(gid))
            {
                string message = $"{baseLogString} SendSingleAnalogCommand => Entity with gid: 0x{gid:X16} does not exist in current SCADA model.";
                Logger.LogError(message);
                //throw new ArgumentException(message);
                return(false);
            }

            IScadaModelPointItem pointItem = gidToPointItemMap[gid];

            if (!(pointItem is IAnalogPointItem analogPointItem && pointItem.RegisterType == PointType.ANALOG_OUTPUT))
            {
                string message = $"{baseLogString} SendSingleAnalogCommand => Either RegistarType of entity with gid: 0x{gid:X16} is not ANALOG_OUTPUT or entity does not implement IAnalogPointItem interface.";
                Logger.LogError(message);
                //throw new ArgumentException(message);
                return(false);
            }

            try
            {
                if (!analogPointItem.Initialized)
                {
                    string errorMessage = $"{baseLogString} SendSingleAnalogCommand => PointItem was initialized. Gid: 0x{analogPointItem.Gid:X16}, Addres: {analogPointItem.Address}, Name: {analogPointItem.Name}, RegisterType: {analogPointItem.RegisterType}, Initialized: {analogPointItem.Initialized}";
                    Logger.LogError(errorMessage);
                }

                //LOGIC
                int modbusValue = analogPointItem.EguToRawValueConversion(commandingValue);

                string debugMessage = $"{baseLogString} SendSingleAnalogCommand => Calling SendSingleCommand({pointItem}, {modbusValue}, {commandOriginType})";
                Logger.LogDebug(verboseMessage);

                //KEY LOGIC
                await SendSingleCommand(pointItem, modbusValue, commandOriginType);

                debugMessage = $"{baseLogString} SendSingleAnalogCommand => SendSingleCommand() executed SUCCESSFULLY";
                Logger.LogDebug(debugMessage);

                return(true);
            }
            catch (Exception e)
            {
                string message = $"{baseLogString} SendSingleAnalogCommand => Exception in SendAnalogCommand() method.";
                Logger.LogError(message, e);
                //throw new InternalSCADAServiceException(message, e);
                return(false);
            }
        }
Beispiel #26
0
        public async Task <bool> ReportPotentialOutage(long elementGid, CommandOriginType commandOriginType, NetworkType networkType)
        {
            Logger.LogVerbose($"{baseLogString} ReportPotentialOutage method started. ElementGid: 0x{elementGid:X16}, CommandOriginType: {commandOriginType}, NetworkType: {networkType}");

            while (!ReliableDictionariesInitialized)
            {
                await Task.Delay(1000);
            }

            try
            {
                #region Preconditions
                var ceModelProviderClient = CeModelProviderClient.CreateClient();
                if (await ceModelProviderClient.IsRecloser(elementGid))
                {
                    Logger.LogWarning($"{baseLogString} ReportPotentialOutage => Element with gid 0x{elementGid:X16} is a Recloser. Call to ReportPotentialOutage aborted.");
                    return(false);
                }

                var enumerableTopology = await OutageTopologyModel.GetEnumerableDictionaryAsync();

                if (!enumerableTopology.ContainsKey(ReliableDictionaryNames.OutageTopologyModel))
                {
                    Logger.LogError($"{baseLogString} ReportPotentialOutage => Topology not found in Rel Dictionary: {ReliableDictionaryNames.OutageTopologyModel}.");
                    return(false);
                }

                var topology = enumerableTopology[ReliableDictionaryNames.OutageTopologyModel];
                var affectedConsumersGids = lifecycleHelper.GetAffectedConsumers(elementGid, topology, networkType);

                var historyDBManagerClient = HistoryDBManagerClient.CreateClient();

                if (!(await CheckPreconditions(elementGid, commandOriginType, affectedConsumersGids, historyDBManagerClient)))
                {
                    Logger.LogWarning($"{baseLogString} ReportPotentialOutage => Parameters do not satisfy required preconditions. ElementId: 0x{elementGid:X16}, CommandOriginType: {commandOriginType}");
                    return(false);
                }
                #endregion Preconditions

                Logger.LogInformation($"{baseLogString} ReportPotentialOutage => Reporting outage for gid: 0x{elementGid:X16}, CommandOriginType: {commandOriginType}");

                var result = await StoreActiveOutage(elementGid, affectedConsumersGids, topology);

                if (!result.HasValue)
                {
                    Logger.LogError($"{baseLogString} ReportPotentialOutage => Storing outage on element 0x{elementGid:X16} FAILED.");
                    return(false);
                }

                var createdOutage = result.Value;
                Logger.LogInformation($"{baseLogString} ReportPotentialOutage => Outage on element with gid: 0x{createdOutage.OutageElementGid:x16} is successfully stored in database.");

                //await historyDBManagerClient.OnSwitchOpened(elementGid, createdOutage.OutageId);
                //await historyDBManagerClient.OnConsumerBlackedOut(affectedConsumersGids, createdOutage.OutageId);

                return(await lifecycleHelper.PublishOutageAsync(Topic.ACTIVE_OUTAGE, outageMessageMapper.MapOutageEntity(createdOutage)));
            }
            catch (Exception e)
            {
                string message = $"{baseLogString} ReportPotentialOutage =>  exception: {e.Message}";
                Logger.LogError(message, e);
                return(false);
            }
        }
        public async Task <bool> SendMultipleScadaCommandAsync(Dictionary <long, DiscreteCommandingType> elementGidCommandMap, Dictionary <long, CommandedElement> commandedElements, CommandOriginType commandOriginType)
        {
            var measurementMapClient    = MeasurementMapClient.CreateClient();
            var elementToMeasurementMap = await measurementMapClient.GetElementToMeasurementMap();

            var commands = new Dictionary <long, int>();

            foreach (var elementGid in elementGidCommandMap.Keys)
            {
                var discreteCommandingType = elementGidCommandMap[elementGid];

                int reTryCount = 30;
                while (commandedElements.ContainsKey(elementGid) && commandedElements[elementGid].CommandingType == discreteCommandingType)
                {
                    Logger.LogDebug($"{baseLogString} SendMultipleScadaCommandAsync => Trying to send duplicate command. Entering delay for 1000 ms and retrying the call.");

                    await Task.Delay(1000);

                    if (--reTryCount <= 0)
                    {
                        Logger.LogError($"{baseLogString} SendMultipleScadaCommandAsync => Trying to send duplicate command. ReTryCount reached 60 calls.");
                        return(false);
                    }
                }

                if (!elementToMeasurementMap.TryGetValue(elementGid, out List <long> measurementGids) || measurementGids.Count == 0)
                {
                    Logger.LogWarning($"{baseLogString} SendMultipleScadaCommandAsync => Element with gid: 0x{elementGid:X16} has no measurements.");
                    return(false);
                }

                var measurementGid = measurementGids.FirstOrDefault();
                if (measurementGid == 0)
                {
                    Logger.LogWarning($"{baseLogString} SendMultipleScadaCommandAsync => Measurement gid is 0.");
                    return(false);
                }

                commands.Add(measurementGid, (int)elementGidCommandMap[elementGid]);
            }

            var measurementProviderClient = MeasurementProviderClient.CreateClient();

            return(await measurementProviderClient.SendMultipleDiscreteCommand(commands, commandOriginType));
        }
        public async Task <bool> SendSingleScadaCommandAsync(long breakerGid, DiscreteCommandingType discreteCommandingType, Dictionary <long, CommandedElement> commandedElements, CommandOriginType commandOriginType)
        {
            if (commandedElements.ContainsKey(breakerGid) && commandedElements[breakerGid].CommandingType == discreteCommandingType)
            {
                Logger.LogDebug($"{baseLogString} SendSingleScadaCommandAsync => Trying to send duplicate command. Aborting call.");
                return(false);
            }

            var         measurementMapClient = MeasurementMapClient.CreateClient();
            List <long> measurementGids      = await measurementMapClient.GetMeasurementsOfElement(breakerGid);

            if (measurementGids.Count == 0)
            {
                Logger.LogWarning($"{baseLogString} SendSingleScadaCommandAsync => Element with gid: 0x{breakerGid:X16} has no measurements.");
                return(false);
            }

            var measurementGid = measurementGids.FirstOrDefault();

            if (measurementGid == 0)
            {
                Logger.LogWarning($"{baseLogString} SendSingleScadaCommandAsync => Measurement gid is 0.");
                return(false);
            }

            var switchStatusCommandingClient = SwitchStatusCommandingClient.CreateClient();

            bool sendCommandSuccess = false;

            if (discreteCommandingType == DiscreteCommandingType.OPEN)
            {
                sendCommandSuccess = await switchStatusCommandingClient.SendOpenCommand(measurementGid);
            }
            else if (discreteCommandingType == DiscreteCommandingType.CLOSE)
            {
                sendCommandSuccess = await switchStatusCommandingClient.SendCloseCommand(measurementGid);
            }

            return(sendCommandSuccess);
        }
        private async Task ExecuteAnalogReadCommand(ModbusFunctionCode functionCode, ushort startAddress, ushort quantity)
        {
            string verboseMessage = $"{baseLogString} entering ExecuteAnalogReadCommand method, command's functionCode: {functionCode}, startAddress: {startAddress}, quantity:{quantity}.";

            Logger.LogVerbose(verboseMessage);

            int[]     data;
            PointType pointType;

            if (functionCode == ModbusFunctionCode.READ_HOLDING_REGISTERS)
            {
                verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => about to call ModbusClient.ReadHoldingRegisters({startAddress - 1}, {quantity}) method.";
                Logger.LogVerbose(verboseMessage);

                //KEY LOGIC
                pointType = PointType.ANALOG_OUTPUT;
                data      = modbusClient.ReadHoldingRegisters(startAddress - 1, quantity);

                verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => ModbusClient.ReadHoldingRegisters({startAddress - 1}, {quantity}) method SUCCESSFULLY executed. Resulting data count: {data.Length}.";
                Logger.LogVerbose(verboseMessage);
            }
            else if (functionCode == ModbusFunctionCode.READ_INPUT_REGISTERS)
            {
                verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => about to call ModbusClient.ReadInputRegisters({startAddress - 1}, {quantity}) method.";
                Logger.LogVerbose(verboseMessage);

                //KEY LOGIC
                pointType = PointType.ANALOG_INPUT;
                data      = modbusClient.ReadInputRegisters(startAddress - 1, quantity);

                verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => ModbusClient.ReadInputRegisters({startAddress - 1}, {quantity}) method SUCCESSFULLY executed. Resulting data count: {data.Length}.";
                Logger.LogVerbose(verboseMessage);
            }
            else
            {
                string message = $"{baseLogString} ExecuteAnalogReadCommand => function code is neither ModbusFunctionCode.READ_HOLDING_REGISTERS nor ModbusFunctionCode.READ_INPUT_REGISTERS";
                Logger.LogError(message);
                throw new ArgumentException(message);
            }

            //this.analogMeasurementCache = new Dictionary<long, AnalogModbusData>(data.Length);
            this.analogMeasurementCache.Clear();

            var modelReadAccessClient   = ScadaModelReadAccessClient.CreateClient();
            var modelUpdateAccessClient = ScadaModelUpdateAccessClient.CreateClient();

            var gidToPointItemMap = await modelReadAccessClient.GetGidToPointItemMap();

            var addressToGidMap = await modelReadAccessClient.GetAddressToGidMap();

            var commandDescriptionCache = await modelReadAccessClient.GetCommandDescriptionCache();

            for (ushort i = 0; i < data.Length; i++)
            {
                ushort address  = (ushort)(startAddress + i);
                int    rawValue = data[i];

                if (!addressToGidMap.ContainsKey((short)pointType))
                {
                    Logger.LogWarning($"{baseLogString} ExecuteAnalogReadCommand => Point type: {pointType} is not in the current addressToGidMap.");
                    continue;
                }

                //for commands enqueued during model update, that are not valid
                if (!addressToGidMap[(short)pointType].ContainsKey(address))
                {
                    Logger.LogWarning($"{baseLogString} ExecuteAnalogReadCommand => trying to read value on address {address}, Point type: {pointType}, which is not in the current addressToGidMap.");
                    continue;
                }

                long gid = addressToGidMap[(short)pointType][address];

                //for commands enqueued during model update, that are not valid
                if (!gidToPointItemMap.ContainsKey(gid))
                {
                    Logger.LogWarning($"{baseLogString} ExecuteAnalogReadCommand => trying to read value for measurement with gid: 0x{gid:X16}, which is not in the current SCADA Model.");
                    continue;
                }

                if (!(gidToPointItemMap[gid] is IAnalogPointItem pointItem))
                {
                    string message = $"{baseLogString} ExecuteAnalogReadCommand => PointItem [Gid: 0x{gid:X16}] does not implement {typeof(IAnalogPointItem)}.";
                    Logger.LogError(message);
                    throw new Exception(message);
                }

                //KEY LOGIC
                if (pointItem.CurrentRawValue != rawValue)
                {
                    pointItem = (IAnalogPointItem)(await modelUpdateAccessClient.UpdatePointItemRawValue(pointItem.Gid, rawValue));
                    Logger.LogInformation($"{baseLogString} ExecuteAnalogReadCommand => Alarm for Point [Gid: 0x{pointItem.Gid:X16}, Address: {pointItem.Address}] set to {pointItem.Alarm}.");
                }

                //LOGIC
                CommandOriginType commandOrigin = CommandOriginType.UNKNOWN_ORIGIN;

                if (commandDescriptionCache.ContainsKey(gid) && commandDescriptionCache[gid].Value == pointItem.CurrentRawValue)
                {
                    commandOrigin = commandDescriptionCache[gid].CommandOrigin;
                    await modelUpdateAccessClient.RemoveCommandDescription(gid);

                    Logger.LogDebug($"{baseLogString} ExecuteAnalogReadCommand => Command origin of command address: {pointItem.Address} is set to {commandOrigin}.");

                    //LOGIC
                    AnalogModbusData analogData = new AnalogModbusData(pointItem.CurrentEguValue, pointItem.Alarm, gid, commandOrigin);
                    this.analogMeasurementCache.Add(gid, analogData);

                    verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => AnalogModbusData added to measurementCache. MeasurementGid: {analogData.MeasurementGid:X16}, Value: {analogData.Value}, Alarm: {analogData.Alarm}, CommandOrigin: {analogData.CommandOrigin} .";
                    Logger.LogVerbose(verboseMessage);
                }
            }

            //LOGIC
            await modelUpdateAccessClient.MakeAnalogEntryToMeasurementCache(this.analogMeasurementCache, true);

            verboseMessage = $"{baseLogString} ExecuteAnalogReadCommand => MakeAnalogEntryToMeasurementCache method called. measurementCache count: {this.analogMeasurementCache.Count}.";
            Logger.LogVerbose(verboseMessage);
        }
        private async Task ExecuteWriteMultipleAnalogCommand(ushort startAddress, int[] commandValues, CommandOriginType commandOrigin)
        {
            StringBuilder commandValuesSB = new StringBuilder();

            commandValuesSB.Append("[ ");
            foreach (int value in commandValues)
            {
                commandValuesSB.Append(value);
                commandValuesSB.Append(" ");
            }
            commandValuesSB.Append("]");

            string verboseMessage = $"{baseLogString} entering ExecuteWriteMultipleAnalogCommand method, command's startAddress: {startAddress}, commandValues: {commandValuesSB}, commandOrigin: {commandOrigin}.";

            Logger.LogVerbose(verboseMessage);

            //LOGIC
            var modelReadAccessClient   = ScadaModelReadAccessClient.CreateClient();
            var modelUpdateAccessClient = ScadaModelUpdateAccessClient.CreateClient();

            int quantity        = commandValues.Length;
            var addressToGidMap = await modelReadAccessClient.GetAddressToGidMap();

            //this.commandDescriptions = new Dictionary<long, CommandDescription>();
            this.commandDescriptions.Clear();

            //LOGIC
            for (ushort index = 0; index < quantity; index++)
            {
                ushort address = (ushort)(startAddress + index);

                var pointType = (short)PointType.ANALOG_OUTPUT;

                if (!addressToGidMap.ContainsKey(pointType))
                {
                    Logger.LogWarning($"{baseLogString} ExecuteWriteMultipleAnalogCommand => Point type: {pointType} is not in the current addressToGidMap.");
                    continue;
                }

                if (addressToGidMap[pointType].ContainsKey(address))
                {
                    long gid = addressToGidMap[pointType][address];

                    CommandDescription commandDescription = new CommandDescription()
                    {
                        Gid           = gid,
                        Address       = address,
                        Value         = commandValues[index],
                        CommandOrigin = commandOrigin,
                    };

                    //LOGIC
                    this.commandDescriptions.Add(gid, commandDescription);

                    string message = $"{baseLogString} ExecuteWriteMultipleAnalogCommand => CommandDescription added to the collection of commandDescriptions. Gid: {commandDescription.Gid:X16}, Address: {commandDescription.Address}, Value: {commandDescription.Value}, CommandOrigin: {commandDescription.CommandOrigin}";
                    Logger.LogInformation(message);
                }
            }

            string debugMessage = $"{baseLogString} ExecuteWriteMultipleAnalogCommand => About to send collection of CommandDescriptions to CommandDescriptionCache. collection count: {commandDescriptions.Count}";

            Logger.LogDebug(debugMessage);

            //LOGIC
            await modelUpdateAccessClient.AddOrUpdateMultipleCommandDescriptions(this.commandDescriptions);

            debugMessage = $"{baseLogString} ExecuteWriteMultipleAnalogCommand => about to call ModbusClient.WriteMultipleRegisters({startAddress - 1}, {commandValuesSB}) method. StartAddress: {startAddress}, Quantity: {quantity}";
            Logger.LogDebug(debugMessage);

            //KEY LOGIC
            modbusClient.WriteMultipleRegisters(startAddress - 1, commandValues);

            string infoMessage = $"{baseLogString} ExecuteWriteMultipleAnalogCommand => ModbusClient.WriteMultipleRegisters() method SUCCESSFULLY executed. StartAddress: {startAddress}, Quantity: {quantity}";

            Logger.LogInformation(infoMessage);
        }