Ejemplo n.º 1
0
        static MongoClient ConnectMongoClient(JSONSCADAConfig jsConfig)
        {
            // connect to MongoDB Database server
            MongoClientSettings settings = MongoClientSettings.FromUrl(new MongoUrl(jsConfig.mongoConnectionString));

            if (jsConfig.tlsClientPfxFile != null && jsConfig.tlsClientPfxFile != "")
            {
                var    pem        = System.IO.File.ReadAllText(jsConfig.tlsCaPemFile);
                byte[] certBuffer = GetBytesFromPEM(pem, "CERTIFICATE");
                var    caCert     = new X509Certificate2(certBuffer);

                var cliCert = new X509Certificate2(jsConfig.tlsClientPfxFile, jsConfig.tlsClientKeyPassword);
                settings.UseTls           = true;
                settings.AllowInsecureTls = true;
                settings.SslSettings      = new SslSettings
                {
                    ClientCertificates                  = new[] { caCert, cliCert },
                    CheckCertificateRevocation          = false,
                    ServerCertificateValidationCallback = CertificateValidationCallBack
                };
            }

            return(new MongoClient(settings));
        }
Ejemplo n.º 2
0
        static public int AutoKeyMultiplier = 1000000; // maximum number of points on each connection self-published (auto numbered points)

        // This process updates acquired values in the mongodb collection for realtime data
        static public async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collectionId =
                        DB.GetCollection <rtDataId>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    Log("MongoDB Update Thread Started...");

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        //if (LogLevel >= LogLevelBasic && OPCDataQueue.Count > 0)
                        //  Log("MongoDB - Data queue size: " +  OPCDataQueue.Count, LogLevelBasic);

                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(2500);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        Stopwatch stopWatch = new Stopwatch();
                        stopWatch.Start();

                        OPC_Value iv;
                        while (!OPCDataQueue.IsEmpty && OPCDataQueue.TryPeek(out iv) && OPCDataQueue.TryDequeue(out iv))
                        {
                            DateTime  tt     = DateTime.MinValue;
                            BsonValue bsontt = BsonNull.Value;
                            try
                            {
                                if (iv.hasSourceTimestamp)
                                {
                                    bsontt = BsonValue.Create(iv.sourceTimestamp);
                                }
                            }
                            catch
                            {
                                tt     = DateTime.MinValue;
                                bsontt = BsonNull.Value;
                            }

                            BsonDocument valJSON = new BsonDocument();
                            try
                            {
                                valJSON = BsonDocument.Parse(iv.valueJson);
                            }
                            catch (Exception e)
                            {
                                Log(iv.conn_name + " - " + e.Message);
                            }

                            if (iv.selfPublish)
                            {
                                // find the json-scada connection for this received value
                                int conn_index = 0;
                                for (int index = 0; index < OPCUAconns.Count; index++)
                                {
                                    if (OPCUAconns[index].protocolConnectionNumber == iv.conn_number)
                                    {
                                        conn_index = index;
                                    }
                                }

                                string tag = TagFromOPCParameters(iv);
                                if (!OPCUAconns[conn_index].InsertedTags.Contains(tag))
                                { // tag not yet inserted
                                  // put the tag in the list of inserted, then insert it

                                    OPCUAconns[conn_index].InsertedTags.Add(tag);

                                    Log(iv.conn_name + " - INSERT NEW TAG: " + tag + " - Addr:" + iv.address);

                                    // find a new freee _id key based on the connection number
                                    if (OPCUAconns[conn_index].LastNewKeyCreated == 0)
                                    {
                                        Double AutoKeyId = iv.conn_number * AutoKeyMultiplier;
                                        var    results   = collectionId.Find <rtDataId>(new BsonDocument {
                                            { "_id", new BsonDocument {
                                                  { "$gt", AutoKeyId },
                                                  { "$lt", (iv.conn_number + 1) * AutoKeyMultiplier }
                                              } }
                                        }).Sort(Builders <rtDataId> .Sort.Descending("_id"))
                                                           .Limit(1)
                                                           .ToList();

                                        if (results.Count > 0)
                                        {
                                            OPCUAconns[conn_index].LastNewKeyCreated = results[0]._id.ToDouble() + 1;
                                        }
                                        else
                                        {
                                            OPCUAconns[conn_index].LastNewKeyCreated = AutoKeyId;
                                        }
                                    }
                                    else
                                    {
                                        OPCUAconns[conn_index].LastNewKeyCreated = OPCUAconns[conn_index].LastNewKeyCreated + 1;
                                    }

                                    var id = OPCUAconns[conn_index].LastNewKeyCreated;

                                    // will enqueue to insert the new tag into mongo DB
                                    var insert = newRealtimeDoc(iv, id);
                                    insert.protocolSourcePublishingInterval = OPCUAconns[conn_index].autoCreateTagPublishingInterval;
                                    insert.protocolSourceSamplingInterval   = OPCUAconns[conn_index].autoCreateTagSamplingInterval;
                                    insert.protocolSourceQueueSize          = OPCUAconns[conn_index].autoCreateTagQueueSize;
                                    listWrites
                                    .Add(new InsertOneModel <rtData>(insert));

                                    // will imediatelly be followed by an update below (to the same tag)
                                }
                            }

                            // update one existing document with received tag value (realtimeData)
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueBsonAtSource", valJSON
                                                },
                                                {
                                                    "valueAtSource",
                                                    BsonDouble
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonString
                                                    .Create(iv.valueString)
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonString
                                                    .Create(iv.asdu.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonString.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTagAtSource",
                                                    bsontt
                                                },
                                                {
                                                    "timeTagAtSourceOk",
                                                    BsonBoolean
                                                    .Create(iv.hasSourceTimestamp)
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv
                                                            .serverTimestamp)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonBoolean
                                                    .Create(!iv
                                                            .quality
                                                            )
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            // update filter, avoids updating commands that can have the same address as supervised points
                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceObjectAddress = iv.address,
                                origin = "supervised"
                            };
                            Log("MongoDB - ADD " + iv.address + " " + iv.value,
                                LogLevelDebug);

                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));

                            if (listWrites.Count >= BulkWriteLimit)
                            {
                                break;
                            }

                            if (stopWatch.ElapsedMilliseconds > 400)
                            {
                                break;
                            }

                            // Log("Write buffer " + listWrites.Count + " Data " + OPCDataQueue.Count);

                            // give time to breath each 250 dequeues
                            //if ((listWrites.Count % 250)==0)
                            //{
                            //   await Task.Delay(10);
                            //Thread.Yield();
                            //Thread.Sleep(1);
                            //}
                        }

                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk writing " + listWrites.Count + ", Total enqueued data " + OPCDataQueue.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();

                            Log($"MongoDB - OK:{bulkWriteResult.IsAcknowledged} - Inserted:{bulkWriteResult.InsertedCount} - Updated:{bulkWriteResult.ModifiedCount}");

                            //Thread.Yield();
                            //Thread.Sleep(1);
                        }

                        if (OPCDataQueue.IsEmpty)
                        {
                            await Task.Delay(250);
                        }
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    Thread.Sleep(1000);

                    while (OPCDataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("MongoDB - Dequeue Data", LogLevelDetailed);
                        OPC_Value iv;
                        OPCDataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Ejemplo n.º 3
0
        // This process monitor and updates redundancy control of the driver instance in mongodb
        static async void ProcessRedundancyMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var lastActiveNodeKeepAliveTimeTag = DateTime.MinValue;
                    var countKeepAliveUpdates          = 0;
                    var countKeepAliveUpdatesLimit     = 4;
                    var Client = ConnectMongoClient(jsConfig);
                    var DB     = Client.GetDatabase(jsConfig.mongoDatabaseName);

                    // read and process instances configuration
                    var collinsts =
                        DB
                        .GetCollection
                        <protocolDriverInstancesClass
                        >(ProtocolDriverInstancesCollectionName);
                    do
                    {
                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        var collconns =
                            DB
                            .GetCollection
                            <PLC_connection
                            >(ProtocolConnectionsCollectionName);
                        var instances =
                            collinsts
                            .Find(inst =>
                                  inst.protocolDriver == ProtocolDriverName &&
                                  inst.protocolDriverInstanceNumber == ProtocolDriverInstanceNumber)
                            .ToList();
                        var foundinstance = false;
                        foreach (protocolDriverInstancesClass inst in instances)
                        {
                            foundinstance = true;

                            if (!inst.enabled)
                            {
                                Log("Instance disabled!");
                                Environment.Exit(-1);
                            }

                            var nodefound = false;
                            foreach (var name in inst.nodeNames)
                            {
                                if (JSConfig.nodeName == name)
                                {
                                    nodefound = true;
                                }
                            }
                            if (!nodefound)
                            {
                                Log("Node '" +
                                    JSConfig.nodeName +
                                    "' not found in instances configuration!");
                                Environment.Exit(-1);
                            }

                            if (inst.activeNodeName == JSConfig.nodeName)
                            {
                                if (!Active) // will go active
                                {
                                    Log("Redundancy - ACTIVATING this Node!");
                                }
                                Active = true;
                                countKeepAliveUpdates = 0;
                            }
                            else
                            {
                                if (Active) // will go inactive
                                {           // wait a random time
                                    Log("Redundancy - DEACTIVATING this Node (other node active)!");
                                    countKeepAliveUpdates = 0;
                                    Random rnd = new Random();
                                    Thread.Sleep(rnd.Next(1000, 5000));
                                }
                                Active = false;
                                if (lastActiveNodeKeepAliveTimeTag == inst.activeNodeKeepAliveTimeTag)
                                {
                                    countKeepAliveUpdates++;
                                }
                                lastActiveNodeKeepAliveTimeTag = inst.activeNodeKeepAliveTimeTag;
                                if (countKeepAliveUpdates > countKeepAliveUpdatesLimit)
                                { // time exceeded, be active
                                    Log("Redundancy - ACTIVATING this Node!");
                                    Active = true;
                                }
                            }

                            if (Active)
                            {
                                Log("Redundancy - This node is active.");

                                // update keep alive time
                                var filter1 =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .Eq(m => m.protocolDriver,
                                        ProtocolDriverName);

                                var filter2 =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .Eq(m => m.protocolDriverInstanceNumber,
                                        ProtocolDriverInstanceNumber);

                                var filter =
                                    Builders <protocolDriverInstancesClass>
                                    .Filter
                                    .And(filter1, filter2);

                                var update =
                                    Builders <protocolDriverInstancesClass>
                                    .Update
                                    .Set(m => m.activeNodeName, JSConfig.nodeName)
                                    .Set(m => m.activeNodeKeepAliveTimeTag, DateTime.Now);

                                var options =
                                    new FindOneAndUpdateOptions <protocolDriverInstancesClass, protocolDriverInstancesClass
                                                                 >();
                                options.IsUpsert = false;
                                await collinsts
                                .FindOneAndUpdateAsync(filter, update, options);

                                // update statistics for connections
                                // foreach (PLC_connection srv in IEC10Xconns)
                                // {
                                //     if (!(srv.connection is null))
                                //     {
                                //         var stats = srv.connection.GetStatistics();
                                //         var filt =
                                //             new BsonDocument(new BsonDocument("protocolConnectionNumber",
                                //                 srv.protocolConnectionNumber));
                                //         var upd =
                                //             new BsonDocument("$set", new BsonDocument{
                                //             {"stats", new BsonDocument{
                                //                 { "nodeName", JSConfig.nodeName },
                                //                 { "timeTag", BsonDateTime.Create(DateTime.Now) },
                                //                 { "isConnected", BsonBoolean.Create(srv.connection.IsRunning) },
                                //                 { "rcvdMsgCounter", BsonDouble.Create(stats.RcvdMsgCounter) },
                                //                 { "sentMsgCounter", BsonDouble.Create(stats.SentMsgCounter) },
                                //                 { "rcvdTestFrActCounter", BsonDouble.Create(stats.RcvdTestFrActCounter) },
                                //                 { "rcvdTestFrConCounter", BsonDouble.Create(stats.RcvdTestFrConCounter) }
                                //                 }},
                                //                 });
                                //         var res = collconns.UpdateOneAsync(filt, upd);
                                //     }
                                // }
                            }
                            else
                            {
                                if (inst.activeNodeName != "")
                                {
                                    Log("Redundancy - This node is INACTIVE! Node '" + inst.activeNodeName + "' is active, wait...");
                                }
                                else
                                {
                                    Log("Redundancy - This node is INACTIVE! No node is active, wait...");
                                }
                            }

                            break; // process just first result
                        }

                        if (!foundinstance)
                        {
                            if (Active) // will go inactive
                            {           // wait a random time
                                Log("Redundancy - DEACTIVATING this Node (no instance found)!");
                                countKeepAliveUpdates = 0;
                                Random rnd = new Random();
                                Thread.Sleep(rnd.Next(1000, 5000));
                            }
                            Active = false;
                        }

                        Thread.Sleep(5000);
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);
                }
            }while (true);
        }
Ejemplo n.º 4
0
        // This process updates acquired values in the mongodb collection for realtime data
        static async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        PLC_Value iv;
                        while (PLCDataQueue.TryDequeue(out iv))
                        {
                            //below code will update one record of the data
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueAtSource",
                                                    BsonValue
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonValue
                                                    .Create(iv.value.ToString())
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonValue
                                                    .Create(iv.asdu.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonValue.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv.time_tag)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonValue
                                                    .Create(false)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonValue
                                                    .Create(false)
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonValue
                                                    .Create(false)
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonValue
                                                    .Create(false)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonValue
                                                    .Create(false)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceCommonAddress =
                                    iv.common_address,
                                protocolSourceObjectAddress = iv.address
                            };
                            Log("MongoDB - ADD " + iv.address + " " + iv.value,
                                LogLevelDetailed);

                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));
                        }

                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk write " + listWrites.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();
                        }
                        else
                        {
                            Thread.Sleep(100);
                        }
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);

                    while (PLCDataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("Dequeue Data", LogLevelDetailed);
                        PLC_Value iv;
                        PLCDataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Ejemplo n.º 5
0
        // This process updates acquired values in the mongodb collection for realtime data
        static async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }
                        DNP3_Value iv;
                        while (DNP3DataQueue.TryDequeue(out iv))
                        {
                            DateTime  tt     = DateTime.MinValue;
                            BsonValue bsontt = BsonNull.Value;
                            try
                            {
                                if (iv.hasSourceTimestamp)
                                {
                                    bsontt = BsonValue.Create(iv.sourceTimestamp);
                                }
                            }
                            catch
                            {
                                tt     = DateTime.MinValue;
                                bsontt = BsonNull.Value;
                            }

                            string valueString;
                            if (iv.valueString == "")
                            {
                                valueString = iv.value.ToString();
                            }
                            else
                            {
                                valueString = iv.valueString;
                            }

                            //below code will update one record of the data
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueAtSource",
                                                    BsonValue
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonValue
                                                    .Create(valueString)
                                                },
                                                {
                                                    "valueJSONAtSource", iv.valueBSON
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonValue
                                                    .Create(iv.group.ToString() + " " + iv.variation.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonValue.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTagAtSource",
                                                    bsontt
                                                },
                                                {
                                                    "timeTagAtSourceOk",
                                                    BsonValue
                                                    .Create(iv.timeStampQuality == TimestampQuality.SYNCHRONIZED)
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv.serverTimestamp)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonValue
                                                    .Create(iv.qCommLost)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonValue
                                                    .Create(iv.qCommLost || iv.qReferenceError || !iv.qOnline)
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonValue
                                                    .Create(iv.qOverrange)
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonValue
                                                    .Create(!iv.qOnline)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonValue
                                                    .Create(iv.qRemoteForced || iv.qLocalForced)
                                                },
                                                {
                                                    "carryAtSource",
                                                    BsonValue
                                                    .Create(iv.qRollover)
                                                },
                                                {
                                                    "transientAtSource",
                                                    BsonValue
                                                    .Create(iv.qTransient)
                                                },
                                                {
                                                    "originator",
                                                    BsonValue
                                                    .Create(ProtocolDriverName + "|" + iv.conn_number)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceCommonAddress =
                                    iv.base_group,
                                protocolSourceObjectAddress = iv.address
                            };
                            Log("MongoDB - ADD - Connection: " + iv.conn_number +
                                " Group: " + iv.base_group +
                                " Address: " + iv.address +
                                " Value: " + iv.value,
                                LogLevelDetailed);
                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));
                        }
                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk write " + listWrites.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();
                        }
                        else
                        {
                            Thread.Sleep(100);
                        }
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);

                    while (DNP3DataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("Dequeue Data", LogLevelDetailed);
                        DNP3_Value iv;
                        DNP3DataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Ejemplo n.º 6
0
        // This process watches (via change stream) for commands inserted to a commands collection
        // When the command is considered valid it is forwarded to the RTU
        static async void ProcessMongoCmd(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    bool isMongoLive =
                        DB
                        .RunCommandAsync((Command <BsonDocument>) "{ping:1}")
                        .Wait(1000);
                    if (!isMongoLive)
                    {
                        throw new Exception("Error on connection " + jsConfig.mongoConnectionString);
                    }

                    Log("MongoDB CMD CS - Start listening for commands via changestream...");
                    var filter = "{ operationType: 'insert' }";

                    var pipeline =
                        new EmptyPipelineDefinition <ChangeStreamDocument <rtCommand
                                                                           >
                                                     >().Match(filter);
                    using (var cursor = await collection.WatchAsync(pipeline))
                    {
                        await cursor
                        .ForEachAsync(async change =>
                        {
                            if (!Active)
                            {
                                return;
                            }

                            // process change event, only process inserts
                            if (
                                change.OperationType ==
                                ChangeStreamOperationType.Insert
                                )
                            {
                                // consider only commands for this driver
                                {
                                    Log("MongoDB CMD CS - Looking for connection " +
                                        change
                                        .FullDocument
                                        .protocolSourceConnectionNumber +
                                        "...");
                                    var found = false;
                                    foreach (IEC10X_connection
                                             srv
                                             in
                                             IEC10Xconns
                                             )
                                    {
                                        if (
                                            srv.protocolConnectionNumber ==
                                            change
                                            .FullDocument
                                            .protocolSourceConnectionNumber
                                            )
                                        {
                                            found = true;
                                            if (
                                                srv.connection.IsRunning &&
                                                srv.commandsEnabled
                                                )
                                            {
                                                InformationObject sc =
                                                    BuildInfoObj(System
                                                                 .Convert
                                                                 .ToInt32(change
                                                                          .FullDocument
                                                                          .protocolSourceASDU),
                                                                 System
                                                                 .Convert
                                                                 .ToInt32(change
                                                                          .FullDocument
                                                                          .protocolSourceObjectAddress),
                                                                 System
                                                                 .Convert
                                                                 .ToDouble(change
                                                                           .FullDocument
                                                                           .value),
                                                                 System
                                                                 .Convert
                                                                 .ToBoolean(change
                                                                            .FullDocument
                                                                            .protocolSourceCommandUseSBO),
                                                                 System
                                                                 .Convert
                                                                 .ToByte(change
                                                                         .FullDocument
                                                                         .protocolSourceCommandDuration));
                                                if (sc != null)
                                                {
                                                    if (
                                                        DateTime
                                                        .Now
                                                        .ToLocalTime()
                                                        .Subtract(change
                                                                  .FullDocument
                                                                  .timeTag
                                                                  .ToLocalTime(
                                                                      ))
                                                        .Seconds <
                                                        10
                                                        )
                                                    {
                                                        // execute
                                                        srv
                                                        .connection
                                                        .SendControlCommand(CauseOfTransmission
                                                                            .ACTIVATION,
                                                                            System
                                                                            .Convert
                                                                            .ToInt32(change
                                                                                     .FullDocument
                                                                                     .protocolSourceCommonAddress),
                                                                            sc);
                                                        Log("MongoDB CMD CS - " +
                                                            srv.name +
                                                            " - " +
                                                            sc.ToString() +
                                                            " OA " +
                                                            change
                                                            .FullDocument
                                                            .protocolSourceObjectAddress +
                                                            " Delivered");

                                                        // update as delivered
                                                        var filter =
                                                            new BsonDocument(new BsonDocument("_id",
                                                                                              change
                                                                                              .FullDocument
                                                                                              .id));
                                                        var update =
                                                            new BsonDocument("$set",
                                                                             new BsonDocument("delivered",
                                                                                              true));
                                                        var result =
                                                            await collection
                                                            .UpdateOneAsync(filter,
                                                                            update);
                                                    }
                                                    else
                                                    {
                                                        // update as expired
                                                        Log("MongoDB CMD CS - " +
                                                            srv.name +
                                                            " - " +
                                                            sc.ToString() +
                                                            " OA " +
                                                            change
                                                            .FullDocument
                                                            .protocolSourceObjectAddress +
                                                            " value " +
                                                            change
                                                            .FullDocument
                                                            .value +
                                                            " Expired");
                                                        var filter =
                                                            new BsonDocument(new BsonDocument("_id",
                                                                                              change
                                                                                              .FullDocument
                                                                                              .id));
                                                        var update =
                                                            new BsonDocument("$set",
                                                                             new BsonDocument("cancelReason",
                                                                                              "expired"));
                                                        var result =
                                                            await collection
                                                            .UpdateOneAsync(filter,
                                                                            update);
                                                    }
                                                }
                                                else
                                                {
                                                    // update as canceled (asdu not implemented)
                                                    Log("MongoDB CMD CS - " +
                                                        srv.name +
                                                        " - " +
                                                        " OA " +
                                                        change
                                                        .FullDocument
                                                        .protocolSourceObjectAddress +
                                                        " value " +
                                                        change
                                                        .FullDocument
                                                        .value +
                                                        " ASDU Not Implemented");
                                                    var filter =
                                                        new BsonDocument(new BsonDocument("_id",
                                                                                          change
                                                                                          .FullDocument
                                                                                          .id));
                                                    var update =
                                                        new BsonDocument("$set",
                                                                         new BsonDocument("cancelReason",
                                                                                          "asdu not implemented"));
                                                    var result =
                                                        await collection
                                                        .UpdateOneAsync(filter,
                                                                        update);
                                                }
                                            }
                                            else
                                            {
                                                // update as canceled (not connected)
                                                Log("MongoDB CMD CS - " +
                                                    srv.name +
                                                    " OA " +
                                                    change
                                                    .FullDocument
                                                    .protocolSourceObjectAddress +
                                                    " value " +
                                                    change.FullDocument.value +
                                                    (
                                                        srv.commandsEnabled
                                                        ? " Not Connected"
                                                        : " Commands Disabled"
                                                    ));
                                                var filter =
                                                    new BsonDocument(new BsonDocument("_id",
                                                                                      change
                                                                                      .FullDocument
                                                                                      .id));
                                                var update =
                                                    new BsonDocument("$set",
                                                                     new BsonDocument("cancelReason",
                                                                                      (
                                                                                          srv
                                                                                          .commandsEnabled
                                                                    ? "not connected"
                                                                    : "commands disabled"
                                                                                      )));
                                                var result =
                                                    await collection
                                                    .UpdateOneAsync(filter,
                                                                    update);
                                            }
                                            break;
                                        }
                                    }
                                    if (!found)
                                    {
                                        // update as canceled command (not found)
                                        Log("MongoDB CMD CS - " +
                                            change
                                            .FullDocument
                                            .protocolSourceConnectionNumber
                                            .ToString() +
                                            " OA " +
                                            change
                                            .FullDocument
                                            .protocolSourceObjectAddress +
                                            " value " +
                                            change.FullDocument.value +
                                            " Not Found");
                                        var filter =
                                            new BsonDocument(new BsonDocument("_id",
                                                                              change
                                                                              .FullDocument
                                                                              .id));
                                        var update =
                                            new BsonDocument("$set",
                                                             new BsonDocument("cancelReason",
                                                                              "connection not found"));
                                        var result =
                                            await collection
                                            .UpdateOneAsync(filter,
                                                            update);
                                    }
                                }
                            }
                        });
                    }
                }
                catch (Exception e)
                {
                    Log("Exception MongoCmd");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);
                }
            }while (true);
        }
Ejemplo n.º 7
0
        // This process updates acquired values in the mongodb collection for realtime data
        static async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        IEC_CmdAck ia;
                        while (IECCmdAckQueue.TryDequeue(out ia))
                        {
                            var filter1 =
                                Builders <rtCommand>
                                .Filter
                                .Eq(m => m.protocolSourceConnectionNumber,
                                    ia.conn_number);

                            var filter2 =
                                Builders <rtCommand>
                                .Filter
                                .Eq(m => m.protocolSourceObjectAddress,
                                    ia.object_address);

                            var filter =
                                Builders <rtCommand>
                                .Filter
                                .And(filter1, filter2);

                            var update =
                                Builders <rtCommand>
                                .Update
                                .Set(m => m.ack, ia.ack)
                                .Set(m => m.ackTimeTag, ia.ack_time_tag);

                            // sort by priority then by insert order
                            var sort =
                                Builders <rtCommand> .Sort.Descending("$natural");

                            var options =
                                new FindOneAndUpdateOptions <rtCommand, rtCommand
                                                             >();
                            options.IsUpsert = false;
                            options.Sort     = sort;
                            await collection_cmd
                            .FindOneAndUpdateAsync(filter, update, options);
                        }

                        IEC_Value iv;
                        while (IECDataQueue.TryDequeue(out iv))
                        {
                            DateTime  tt     = DateTime.MinValue;
                            BsonValue bsontt = BsonNull.Value;
                            try
                            {
                                if (iv.hasSourceTimestampCP24)
                                {
                                    var dtnow = DateTime.Now;
                                    tt =
                                        new DateTime(
                                            dtnow.Year,
                                            dtnow.Month,
                                            dtnow.Day,
                                            dtnow.Hour,
                                            iv.sourceTimestampCP24.Minute,
                                            iv.sourceTimestampCP24.Second,
                                            iv.sourceTimestampCP24.Millisecond,
                                            DateTimeKind.Local);
                                    bsontt = BsonValue.Create(tt);
                                }
                                else
                                if (iv.hasSourceTimestampCP56)
                                {
                                    tt =
                                        new DateTime(iv
                                                     .sourceTimestampCP56
                                                     .Year +
                                                     2000,
                                                     iv.sourceTimestampCP56.Month,
                                                     iv.sourceTimestampCP56.DayOfMonth,
                                                     iv.sourceTimestampCP56.Hour,
                                                     iv.sourceTimestampCP56.Minute,
                                                     iv.sourceTimestampCP56.Second,
                                                     iv.sourceTimestampCP56.Millisecond,
                                                     DateTimeKind.Local);
                                    bsontt = BsonValue.Create(tt);
                                }
                            }
                            catch
                            {
                                tt     = DateTime.MinValue;
                                bsontt = BsonNull.Value;
                            }

                            //below code will update one record of the data
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueAtSource",
                                                    BsonValue
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonValue
                                                    .Create(iv.value.ToString())
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonValue
                                                    .Create(iv.asdu.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonValue.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTagAtSource",
                                                    bsontt
                                                },
                                                {
                                                    "timeTagAtSourceOk",
                                                    BsonValue
                                                    .Create(!iv
                                                            .sourceTimestampCP56
                                                            .Invalid)
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv
                                                            .serverTimestamp)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonValue
                                                    .Create(iv
                                                            .quality
                                                            .NonTopical)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonValue
                                                    .Create(iv
                                                            .quality
                                                            .Invalid)
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonValue
                                                    .Create(iv
                                                            .quality.
                                                            Overflow
                                                            )
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonValue
                                                    .Create(iv
                                                            .quality
                                                            .Blocked)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonValue
                                                    .Create(iv
                                                            .quality
                                                            .Substituted)
                                                },
                                                {
                                                    "originator",
                                                    BsonValue
                                                    .Create(ProtocolDriverName + "|" + iv.conn_number)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceCommonAddress =
                                    iv.common_address,
                                protocolSourceObjectAddress = iv.address
                            };
                            Log("MongoDB - ADD " + iv.address + " " + iv.value,
                                LogLevelDetailed);

                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));
                        }

                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk write " + listWrites.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();
                        }
                        else
                        {
                            Thread.Sleep(100);
                        }
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);

                    while (IECDataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("Dequeue Data", LogLevelDetailed);
                        IEC_Value iv;
                        IECDataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Ejemplo n.º 8
0
        // This process watches (via change stream) for commands inserted to a commands collection
        // When the command is considered valid it is forwarded to the RTU
        static async void ProcessMongoCmd(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    bool isMongoLive =
                        DB
                        .RunCommandAsync((Command <BsonDocument>) "{ping:1}")
                        .Wait(1000);
                    if (!isMongoLive)
                    {
                        throw new Exception("Error on connection " + jsConfig.mongoConnectionString);
                    }

                    Log("MongoDB CMD CS - Start listening for commands via changestream...");
                    var filter = "{ operationType: 'insert' }";

                    var pipeline =
                        new EmptyPipelineDefinition <ChangeStreamDocument <rtCommand
                                                                           >
                                                     >().Match(filter);
                    using (var cursor = await collection.WatchAsync(pipeline))
                    {
                        await cursor
                        .ForEachAsync(async change =>
                        {
                            if (!Active)
                            {
                                return;
                            }

                            // process change event, only process inserts
                            if (
                                change.OperationType ==
                                ChangeStreamOperationType.Insert
                                )
                            {
                                // consider only commands for this driver
                                {
                                    Log("MongoDB CMD CS - Looking for connection " +
                                        change
                                        .FullDocument
                                        .protocolSourceConnectionNumber +
                                        "...");
                                    var found = false;
                                    foreach (DNP3_connection
                                             srv
                                             in
                                             DNP3conns
                                             )
                                    {
                                        if (
                                            srv.protocolConnectionNumber ==
                                            change
                                            .FullDocument
                                            .protocolSourceConnectionNumber
                                            )
                                        {
                                            found  = true;
                                            var cs = srv.channel.GetChannelStatistics();
                                            if (
                                                srv.isConnected &&
                                                srv.commandsEnabled
                                                )
                                            {
                                                var group     = change.FullDocument.protocolSourceCommonAddress;
                                                var variation = change.FullDocument.protocolSourceASDU;
                                                if (group == 41 || group == 12)
                                                {
                                                    if (         // check for command expired
                                                        DateTime
                                                        .Now
                                                        .ToLocalTime()
                                                        .Subtract(change
                                                                  .FullDocument
                                                                  .timeTag
                                                                  .ToLocalTime(
                                                                      ))
                                                        .Seconds <
                                                        10
                                                        )
                                                    {         // can execute
                                                        System.Threading.Tasks.Task <CommandTaskResult> cmdTask = null;

                                                        if (group == 12)
                                                        {
                                                            OperationType ot = OperationType.NUL;

                                                            TripCloseCode tc = TripCloseCode.NUL;
                                                            switch (System.Convert.ToUInt16(change.FullDocument.protocolSourceCommandDuration))
                                                            {
                                                            default:
                                                            case 0:
                                                                ot = OperationType.NUL;
                                                                break;

                                                            case 1:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.PULSE_ON;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.PULSE_OFF;
                                                                }
                                                                break;

                                                            case 2:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.PULSE_OFF;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.PULSE_ON;
                                                                }
                                                                break;

                                                            case 3:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.LATCH_ON;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.LATCH_OFF;
                                                                }
                                                                break;

                                                            case 4:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.LATCH_OFF;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.LATCH_ON;
                                                                }
                                                                break;

                                                            case 11:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.PULSE_ON;
                                                                    tc = TripCloseCode.CLOSE;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.PULSE_OFF;
                                                                    tc = TripCloseCode.TRIP;
                                                                }
                                                                break;

                                                            case 13:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.LATCH_ON;
                                                                    tc = TripCloseCode.CLOSE;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.LATCH_OFF;
                                                                    tc = TripCloseCode.TRIP;
                                                                }
                                                                break;

                                                            case 21:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.PULSE_ON;
                                                                    tc = TripCloseCode.TRIP;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.PULSE_OFF;
                                                                    tc = TripCloseCode.CLOSE;
                                                                }
                                                                break;

                                                            case 23:
                                                                if (change.FullDocument.value != 0)
                                                                {
                                                                    ot = OperationType.LATCH_ON;
                                                                    tc = TripCloseCode.TRIP;
                                                                }
                                                                else
                                                                {
                                                                    ot = OperationType.LATCH_OFF;
                                                                    tc = TripCloseCode.CLOSE;
                                                                }
                                                                break;
                                                            }
                                                            ControlRelayOutputBlock crob = new ControlRelayOutputBlock(ot, tc, false, 1, 0, 0);
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    crob,
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    crob,
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }
                                                        else if (group == 41 && variation == 1)
                                                        {
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    new AnalogOutputInt32(System.Convert.ToInt32(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    new AnalogOutputInt32(System.Convert.ToInt32(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }
                                                        else if (group == 41 && variation == 2)
                                                        {
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    new AnalogOutputInt16(System.Convert.ToInt16(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    new AnalogOutputInt16(System.Convert.ToInt16(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }
                                                        else if (group == 41 && variation == 3)
                                                        {
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    new AnalogOutputFloat32(System.Convert.ToSingle(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    new AnalogOutputFloat32(System.Convert.ToSingle(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }
                                                        else if (group == 41 && variation == 4)
                                                        {
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    new AnalogOutputDouble64(System.Convert.ToDouble(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    new AnalogOutputDouble64(System.Convert.ToDouble(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }
                                                        else if (group == 41)     // group 41, other variations defaults to float32
                                                        {
                                                            if (System.Convert.ToBoolean(change.FullDocument.protocolSourceCommandUseSBO))
                                                            {
                                                                cmdTask = srv.master.SelectAndOperate(
                                                                    new AnalogOutputFloat32(System.Convert.ToSingle(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                            else
                                                            {
                                                                cmdTask = srv.master.DirectOperate(
                                                                    new AnalogOutputFloat32(System.Convert.ToSingle(change.FullDocument.value)),
                                                                    System.Convert.ToUInt16(change.FullDocument.protocolSourceObjectAddress),
                                                                    TaskConfig.Default);
                                                            }
                                                        }

                                                        if (cmdTask != null)
                                                        {
                                                            _ = cmdTask.ContinueWith((result) =>
                                                            {
                                                                Console.WriteLine("Result: " + result.Result);
                                                                Log("MongoDB CMD CS - " +
                                                                    srv.name +
                                                                    " - Command " +
                                                                    " TAG:" + change.FullDocument.tag +
                                                                    " GRP:" + change.FullDocument.protocolSourceCommonAddress +
                                                                    " VAR:" + change.FullDocument.protocolSourceASDU +
                                                                    " OBJ:" + change.FullDocument.protocolSourceObjectAddress +
                                                                    " Value:" + change.FullDocument.value +
                                                                    " Delivered");

                                                                // update as delivered
                                                                var filter =
                                                                    new BsonDocument(new BsonDocument("_id",
                                                                                                      change.FullDocument.id));
                                                                var update =
                                                                    new BsonDocument("$set", new BsonDocument {
                                                                    { "delivered", true },
                                                                    { "ack",
                                                                      result.Result.Results.FirstOrDefault().PointState == CommandPointState.SUCCESS &&
                                                                      result.Result.Results.FirstOrDefault().Status == CommandStatus.SUCCESS },
                                                                    { "ackTimeTag", BsonValue.Create(DateTime.Now) },
                                                                    { "resultDescription", result.Result.ToString() }
                                                                });
                                                                var res =
                                                                    collection
                                                                    .UpdateOneAsync(filter,
                                                                                    update);
                                                            });
                                                        }
                                                        else
                                                        {
                                                            Console.WriteLine("Command Error");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        // update as expired
                                                        Log("MongoDB CMD CS - " +
                                                            srv.name +
                                                            " - Command " +
                                                            " TAG:" + change.FullDocument.tag +
                                                            " GRP:" + change.FullDocument.protocolSourceCommonAddress +
                                                            " VAR:" + change.FullDocument.protocolSourceASDU +
                                                            " OBJ:" + change.FullDocument.protocolSourceObjectAddress +
                                                            " Value:" + change.FullDocument.value +
                                                            " Expired");
                                                        var filter =
                                                            new BsonDocument(new BsonDocument("_id",
                                                                                              change
                                                                                              .FullDocument
                                                                                              .id));
                                                        var update =
                                                            new BsonDocument("$set",
                                                                             new BsonDocument("cancelReason",
                                                                                              "expired"));
                                                        var result =
                                                            await collection
                                                            .UpdateOneAsync(filter,
                                                                            update);
                                                    }
                                                }
                                                else
                                                {
                                                    // update as canceled (asdu not implemented)
                                                    Log("MongoDB CMD CS - " +
                                                        srv.name +
                                                        " - Command " +
                                                        " TAG:" + change.FullDocument.tag +
                                                        " GRP:" + change.FullDocument.protocolSourceCommonAddress +
                                                        " VAR:" + change.FullDocument.protocolSourceASDU +
                                                        " OBJ:" + change.FullDocument.protocolSourceObjectAddress +
                                                        " Value:" + change.FullDocument.value +
                                                        " ASDU Not Implemented");
                                                    var filter =
                                                        new BsonDocument(new BsonDocument("_id",
                                                                                          change
                                                                                          .FullDocument
                                                                                          .id));
                                                    var update =
                                                        new BsonDocument("$set",
                                                                         new BsonDocument("cancelReason",
                                                                                          "asdu not implemented"));
                                                    var result =
                                                        await collection
                                                        .UpdateOneAsync(filter,
                                                                        update);
                                                }
                                            }
                                            else
                                            {
                                                // update as canceled (not connected)
                                                Log("MongoDB CMD CS - " +
                                                    srv.name +
                                                    " - Command " +
                                                    " TAG:" + change.FullDocument.tag +
                                                    " GRP:" + change.FullDocument.protocolSourceCommonAddress +
                                                    " VAR:" + change.FullDocument.protocolSourceASDU +
                                                    " OBJ:" + change.FullDocument.protocolSourceObjectAddress +
                                                    " Value:" + change.FullDocument.value +
                                                    change.FullDocument.value +
                                                    (
                                                        srv.commandsEnabled
                                                            ? " Not Connected"
                                                            : " Commands Disabled"
                                                    ));
                                                var filter =
                                                    new BsonDocument(new BsonDocument("_id",
                                                                                      change
                                                                                      .FullDocument
                                                                                      .id));
                                                var update =
                                                    new BsonDocument("$set",
                                                                     new BsonDocument("cancelReason",
                                                                                      (
                                                                                          srv
                                                                                          .commandsEnabled
                                                                        ? "not connected"
                                                                        : "commands disabled"
                                                                                      )));
                                                var result =
                                                    await collection
                                                    .UpdateOneAsync(filter,
                                                                    update);
                                            }
                                            break;
                                        }
                                    }
                                    if (!found)
                                    {
                                        // update as canceled command (not found)
                                        Log("MongoDB CMD CS - " +
                                            change
                                            .FullDocument
                                            .protocolSourceConnectionNumber
                                            .ToString() +
                                            " - Command " +
                                            " TAG:" + change.FullDocument.tag +
                                            " GRP:" + change.FullDocument.protocolSourceCommonAddress +
                                            " VAR:" + change.FullDocument.protocolSourceASDU +
                                            " OBJ:" + change.FullDocument.protocolSourceObjectAddress +
                                            " Value:" + change.FullDocument.value +
                                            " Not Found");
                                        var filter =
                                            new BsonDocument(new BsonDocument("_id",
                                                                              change
                                                                              .FullDocument
                                                                              .id));
                                        var update =
                                            new BsonDocument("$set",
                                                             new BsonDocument("cancelReason",
                                                                              "connection not found"));
                                        var result =
                                            await collection
                                            .UpdateOneAsync(filter,
                                                            update);
                                    }
                                }
                            }
                        });
                    }
                }
                catch (Exception e)
                {
                    Log("Exception MongoCmd");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    System.Threading.Thread.Sleep(3000);
                }
            }while (true);
        }
Ejemplo n.º 9
0
        // This process watches (via change stream) for point updates
        // Forward data to its connections
        static async void ProcessMongoCS(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB
                        .GetCollection
                        <rtData>(RealtimeDataCollectionName);

                    bool isMongoLive =
                        DB
                        .RunCommandAsync((Command <BsonDocument>) "{ping:1}")
                        .Wait(1000);
                    if (!isMongoLive)
                    {
                        throw new Exception("Error on connection " + jsConfig.mongoConnectionString);
                    }

                    Log("MongoDB CMD CS - Start listening for realtime data updates via changestream...");
                    // observe updates and replaces, avoid updates with sourceDataUpdateField (those are handled by cs_data_processor.js)
                    var filter = "{ $or: [{ $and:[{ 'updateDescription.updatedFields.sourceDataUpdate': { $exists: false } },{ operationType: 'update' }] }, { operationType: 'replace'}] }";

                    var pipeline =
                        new EmptyPipelineDefinition <ChangeStreamDocument <rtData
                                                                           >
                                                     >().Match(filter);
                    var changeStreamOptions = new ChangeStreamOptions
                    {
                        FullDocument = ChangeStreamFullDocumentOption.UpdateLookup
                    };
                    using (var cursor = await collection.WatchAsync(pipeline, changeStreamOptions))
                    {
                        await cursor
                        .ForEachAsync(change =>
                        {
                            // process change event, only process updates and replaces
                            if (
                                change.OperationType == ChangeStreamOperationType.Update ||
                                change.OperationType == ChangeStreamOperationType.Replace
                                )
                            {
                                if (change.FullDocument != null)
                                {
                                    if (change.FullDocument.protocolDestinations != null)
                                    {
                                        foreach (var dst in change.FullDocument.protocolDestinations)
                                        {
                                            foreach (IEC10X_connection
                                                     srv
                                                     in
                                                     IEC10Xconns
                                                     )
                                            {
                                                if (dst.protocolDestinationConnectionNumber == srv.protocolConnectionNumber)
                                                {
                                                    var conNameStr  = srv.name + " - ";
                                                    var quality     = new QualityDescriptor();
                                                    quality.Invalid = false;
                                                    if (change.FullDocument.invalid != null)
                                                    {
                                                        quality.Invalid |= change.FullDocument.invalid.ToBoolean();
                                                    }
                                                    if (change.FullDocument.overflow != null)
                                                    {
                                                        quality.Invalid |= change.FullDocument.overflow.ToBoolean();
                                                    }
                                                    if (change.FullDocument.transient != null)
                                                    {
                                                        quality.Invalid |= change.FullDocument.transient.ToBoolean();
                                                    }
                                                    if (change.FullDocument.substituted != null)
                                                    {
                                                        quality.Substituted = change.FullDocument.substituted.ToBoolean();
                                                    }
                                                    quality.Blocked        = false;
                                                    quality.NonTopical     = false;
                                                    CP56Time2a cp56timesrc = null;
                                                    if (change.FullDocument.timeTagAtSource != null)
                                                    {
                                                        cp56timesrc         = new CP56Time2a(System.Convert.ToDateTime(change.FullDocument.timeTagAtSource).AddHours(dst.protocolDestinationHoursShift.ToDouble()));
                                                        cp56timesrc.Invalid = false;
                                                        if (change.FullDocument.timeTagAtSourceOk != null)
                                                        {
                                                            cp56timesrc.Invalid = !change.FullDocument.timeTagAtSourceOk.ToBoolean();
                                                        }
                                                        else
                                                        {
                                                            cp56timesrc.Invalid = true;
                                                        }
                                                    }
                                                    var io = BuildInfoObj(
                                                        dst.protocolDestinationASDU.ToInt32(),
                                                        dst.protocolDestinationObjectAddress.ToInt32(),
                                                        change.FullDocument.value.ToDouble(),
                                                        false,
                                                        0,
                                                        quality,
                                                        cp56timesrc
                                                        );
                                                    if (io != null)
                                                    {
                                                        // queue data to make possible to assemble an ASDU with many elements, will send on DequeueIecInfo
                                                        InfoCA ica = new InfoCA()
                                                        {
                                                            io = io,
                                                            ca = dst.protocolDestinationCommonAddress.ToInt32()
                                                        };
                                                        srv.infoCAQueue.Enqueue(ica);

                                                        if (LogLevel >= LogLevelDetailed)
                                                        {
                                                            Log(conNameStr + "Spont Tag:" +
                                                                change.FullDocument.tag + " Value:" + change.FullDocument.value +
                                                                " Key:" + change.FullDocument._id + " TI:" + dst.protocolDestinationASDU.ToInt32() + " CA:" + dst.protocolDestinationCommonAddress + (cp56timesrc == null ? "" : " " + cp56timesrc.ToString()),
                                                                LogLevelDetailed);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        });
                    }
                }
                catch (Exception e)
                {
                    Log("Exception MongoCS");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    Thread.Sleep(3000);
                }
            }while (true);
        }
Ejemplo n.º 10
0
        // This process updates acquired values in the mongodb collection for realtime data
        static public async void ProcessMongo(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB.GetCollection <rtData>(RealtimeDataCollectionName);
                    var collection_cmd =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    Log("MongoDB Update Thread Started...");

                    var listWrites = new List <WriteModel <rtData> >();
                    do
                    {
                        //if (LogLevel >= LogLevelBasic && OPCDataQueue.Count > 0)
                        //  Log("MongoDB - Data queue size: " +  OPCDataQueue.Count, LogLevelBasic);

                        // Log("1");

                        bool isMongoLive =
                            DB
                            .RunCommandAsync((Command <BsonDocument>)
                                             "{ping:1}")
                            .Wait(1000);
                        if (!isMongoLive)
                        {
                            throw new Exception("Error on MongoDB connection ");
                        }

                        // Log("2");
                        IEC_CmdAck ia;
                        if (OPCCmdAckQueue.Count > 0)
                        {
                            while (OPCCmdAckQueue.TryDequeue(out ia))
                            {
                                var filter1 =
                                    Builders <rtCommand>
                                    .Filter
                                    .Eq(m => m.protocolSourceConnectionNumber,
                                        ia.conn_number);

                                var filter2 =
                                    Builders <rtCommand>
                                    .Filter
                                    .Eq(m => m.protocolSourceObjectAddress,
                                        ia.object_address);

                                var filter =
                                    Builders <rtCommand>
                                    .Filter
                                    .And(filter1, filter2);

                                var update =
                                    Builders <rtCommand>
                                    .Update
                                    .Set(m => m.ack, ia.ack)
                                    .Set(m => m.ackTimeTag, ia.ack_time_tag);

                                // sort by priority then by insert order
                                var sort =
                                    Builders <rtCommand> .Sort.Descending("$natural");

                                var options =
                                    new FindOneAndUpdateOptions <rtCommand, rtCommand
                                                                 >();
                                options.IsUpsert = false;
                                options.Sort     = sort;
                                await collection_cmd
                                .FindOneAndUpdateAsync(filter, update, options);
                            }
                        }
                        // Log("3");

                        Stopwatch stopWatch = new Stopwatch();
                        stopWatch.Start();

                        OPC_Value iv;
                        while (!OPCDataQueue.IsEmpty && OPCDataQueue.TryPeek(out iv) && OPCDataQueue.TryDequeue(out iv))
                        {
                            // Log("3.1");
                            DateTime  tt     = DateTime.MinValue;
                            BsonValue bsontt = BsonNull.Value;
                            try
                            {
                                if (iv.hasSourceTimestamp)
                                {
                                    bsontt = BsonValue.Create(iv.sourceTimestamp);
                                }
                            }
                            catch
                            {
                                tt     = DateTime.MinValue;
                                bsontt = BsonNull.Value;
                            }

                            BsonDocument valJSON = new BsonDocument();
                            try
                            {
                                valJSON = BsonDocument.Parse(iv.valueJson);
                            }
                            catch (Exception e)
                            {
                                Log(iv.conn_name + " - " + e.Message);
                            }

                            // Log("3.2");

                            if (iv.selfPublish)
                            {
                                string tag = TagFromOPCParameters(iv);
                                if (!InsertedTags.Contains(tag))
                                {
                                    // look for the tag
                                    var task = await collection.FindAsync <rtData>(new BsonDocument {
                                        {
                                            "tag", TagFromOPCParameters(iv)
                                        }
                                    });

                                    List <rtData> list = await task.ToListAsync();

                                    // await Task.Delay(10);
                                    //Thread.Yield();
                                    //Thread.Sleep(1);

                                    InsertedTags.Add(tag);
                                    if (list.Count == 0)
                                    {
                                        Log(iv.conn_name + " - INSERT - " + iv.address);
                                        // hash to create keys
                                        var id         = HashStringToInt(iv.address);
                                        var insert     = newRealtimeDoc(iv, id);
                                        int conn_index = 0;
                                        // normal for loop
                                        for (int index = 0; index < OPCUAconns.Count; index++)
                                        {
                                            if (OPCUAconns[index].protocolConnectionNumber == iv.conn_number)
                                            {
                                                conn_index = index;
                                            }
                                        }
                                        insert.protocolSourcePublishingInterval = OPCUAconns[conn_index].autoCreateTagPublishingInterval;
                                        insert.protocolSourceSamplingInterval   = OPCUAconns[conn_index].autoCreateTagSamplingInterval;
                                        insert.protocolSourceQueueSize          = OPCUAconns[conn_index].autoCreateTagQueueSize;
                                        listWrites
                                        .Add(new InsertOneModel <rtData>(insert));
                                    }
                                }
                            }

                            //below code will update one record of the data
                            var update =
                                new BsonDocument {
                                {
                                    "$set",
                                    new BsonDocument {
                                        {
                                            "sourceDataUpdate",
                                            new BsonDocument {
                                                {
                                                    "valueBsonAtSource", valJSON
                                                },
                                                {
                                                    "valueAtSource",
                                                    BsonDouble
                                                    .Create(iv.value)
                                                },
                                                {
                                                    "valueStringAtSource",
                                                    BsonString
                                                    .Create(iv.valueString)
                                                },
                                                {
                                                    "asduAtSource",
                                                    BsonString
                                                    .Create(iv.asdu.ToString())
                                                },
                                                {
                                                    "causeOfTransmissionAtSource",
                                                    BsonString.Create(iv.cot.ToString())
                                                },
                                                {
                                                    "timeTagAtSource",
                                                    bsontt
                                                },
                                                {
                                                    "timeTagAtSourceOk",
                                                    BsonBoolean
                                                    .Create(iv.hasSourceTimestamp)
                                                },
                                                {
                                                    "timeTag",
                                                    BsonValue
                                                    .Create(iv
                                                            .serverTimestamp)
                                                },
                                                {
                                                    "notTopicalAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "invalidAtSource",
                                                    BsonBoolean
                                                    .Create(!iv
                                                            .quality
                                                            )
                                                },
                                                {
                                                    "overflowAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "blockedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                },
                                                {
                                                    "substitutedAtSource",
                                                    BsonBoolean
                                                    .Create(false)
                                                }
                                            }
                                        }
                                    }
                                }
                            };

                            var filt =
                                new rtFilt
                            {
                                protocolSourceConnectionNumber =
                                    iv.conn_number,
                                protocolSourceCommonAddress =
                                    iv.common_address,
                                protocolSourceObjectAddress = iv.address
                            };
                            Log("MongoDB - ADD " + iv.address + " " + iv.value,
                                LogLevelDebug);
                            // Log("3.3");

                            listWrites
                            .Add(new UpdateOneModel <rtData>(filt
                                                             .ToBsonDocument(),
                                                             update));

                            if (listWrites.Count >= BulkWriteLimit)
                            {
                                break;
                            }

                            if (stopWatch.ElapsedMilliseconds > 400)
                            {
                                break;
                            }

                            // Log("3.4 - Write buffer " + listWrites.Count + " Data " + OPCDataQueue.Count);

                            // give time to breath each 250 dequeues
                            //if ((listWrites.Count % 250)==0)
                            //{
                            //   await Task.Delay(10);
                            //Thread.Yield();
                            //Thread.Sleep(1);
                            //}
                        }

                        // Log("4");
                        if (listWrites.Count > 0)
                        {
                            Log("MongoDB - Bulk write " + listWrites.Count + " Data " + OPCDataQueue.Count);
                            var bulkWriteResult =
                                await collection.BulkWriteAsync(listWrites);

                            listWrites.Clear();

                            //Thread.Yield();
                            //Thread.Sleep(1);
                        }

                        if (OPCDataQueue.IsEmpty)
                        {
                            await Task.Delay(250);
                        }
                        // Log("6");
                    }while (true);
                }
                catch (Exception e)
                {
                    Log("Exception Mongo");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    Thread.Sleep(1000);

                    while (OPCDataQueue.Count > DataBufferLimit // do not let data queue grow more than a limit
                           )
                    {
                        Log("MongoDB - Dequeue Data", LogLevelDetailed);
                        OPC_Value iv;
                        OPCDataQueue.TryDequeue(out iv);
                    }
                }
            }while (true);
        }
Ejemplo n.º 11
0
        // This process watches (via change stream) for commands inserted to a commands collection
        // When the command is considered valid it is forwarded to the RTU
        static async void ProcessMongoCmd(JSONSCADAConfig jsConfig)
        {
            do
            {
                try
                {
                    var Client     = ConnectMongoClient(jsConfig);
                    var DB         = Client.GetDatabase(jsConfig.mongoDatabaseName);
                    var collection =
                        DB
                        .GetCollection
                        <rtCommand>(CommandsQueueCollectionName);

                    bool isMongoLive =
                        DB
                        .RunCommandAsync((Command <BsonDocument>) "{ping:1}")
                        .Wait(1000);
                    if (!isMongoLive)
                    {
                        throw new Exception("Error on connection " + jsConfig.mongoConnectionString);
                    }

                    Log("MongoDB CMD CS - Start listening for commands via changestream...");
                    var filter = "{ operationType: 'insert' }";

                    var pipeline =
                        new EmptyPipelineDefinition <ChangeStreamDocument <rtCommand
                                                                           >
                                                     >().Match(filter);
                    using (var cursor = await collection.WatchAsync(pipeline))
                    {
                        await cursor
                        .ForEachAsync(async change =>
                        {
                            if (!Active)
                            {
                                return;
                            }

                            // process change event, only process inserts
                            if (
                                change.OperationType ==
                                ChangeStreamOperationType.Insert
                                )
                            {
                                Log("MongoDB CMD CS - Looking for connection " +
                                    change
                                    .FullDocument
                                    .protocolSourceConnectionNumber +
                                    "...");
                                var found = false;
                                foreach (OPCUA_connection
                                         srv
                                         in
                                         OPCUAconns
                                         )
                                {
                                    if (
                                        srv.protocolConnectionNumber ==
                                        change
                                        .FullDocument
                                        .protocolSourceConnectionNumber
                                        )
                                    {
                                        found = true;

                                        int timeDif = DateTime
                                                      .Now
                                                      .ToLocalTime()
                                                      .Subtract(change
                                                                .FullDocument
                                                                .timeTag
                                                                .ToLocalTime(
                                                                    ))
                                                      .Seconds;

                                        // test for command expired
                                        if (timeDif > 10)
                                        {
                                            // update as expired
                                            Log("MongoDB CMD CS - " +
                                                srv.name +
                                                " - " +
                                                " Address " +
                                                change
                                                .FullDocument
                                                .protocolSourceObjectAddress +
                                                " value " +
                                                change
                                                .FullDocument
                                                .value +
                                                " Expired, " + timeDif + " Seconds old");
                                            var filter =
                                                new BsonDocument(new BsonDocument("_id",
                                                                                  change
                                                                                  .FullDocument
                                                                                  .id));
                                            var update =
                                                new BsonDocument("$set",
                                                                 new BsonDocument("cancelReason",
                                                                                  "expired"));
                                            var result =
                                                await collection
                                                .UpdateOneAsync(filter,
                                                                update);

                                            break;
                                        }

                                        if (
                                            srv.connection.session.Connected &&
                                            srv.commandsEnabled
                                            )
                                        {
                                            WriteValueCollection nodesToWrite = new WriteValueCollection();
                                            WriteValue WriteVal = new WriteValue();
                                            WriteVal.NodeId     =
                                                new NodeId(System
                                                           .Convert
                                                           .ToString(change.FullDocument.protocolSourceObjectAddress));
                                            WriteVal.AttributeId = Attributes.Value;
                                            WriteVal.Value       = new DataValue();

                                            switch (change.FullDocument.protocolSourceASDU.ToString().ToLower())
                                            {
                                            case "boolean":
                                                WriteVal.Value.Value = System.Convert.ToBoolean(System
                                                                                                .Convert.ToDouble(change.FullDocument.value) != 0.0);
                                                break;

                                            case "sbyte":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToSByte(change.FullDocument.value);
                                                break;

                                            case "byte":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToByte(change.FullDocument.value);
                                                break;

                                            case "int16":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToInt16(change.FullDocument.value);
                                                break;

                                            case "uint16":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToUInt16(change.FullDocument.value);
                                                break;

                                            case "int32":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToInt16(change.FullDocument.value);
                                                break;

                                            case "uint32":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToUInt16(change.FullDocument.value);
                                                break;

                                            case "int64":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToInt16(change.FullDocument.value);
                                                break;

                                            case "uint64":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToUInt16(change.FullDocument.value);
                                                break;

                                            case "float":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToSingle(change.FullDocument.value);
                                                break;

                                            case "double":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToDouble(change.FullDocument.value);
                                                break;

                                            case "datetime":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToDateTime(change.FullDocument.value);
                                                break;

                                            case "string":
                                                WriteVal.Value.Value = System
                                                                       .Convert
                                                                       .ToString(change.FullDocument.value);
                                                break;
                                            }

                                            nodesToWrite.Add(WriteVal);

                                            // Write the node attributes
                                            StatusCodeCollection results = null;
                                            DiagnosticInfoCollection diagnosticInfos;

                                            Log("MongoDB CMD CS - " + srv.name + " - Writing node...");

                                            // Call Write Service
                                            srv.connection.session.Write(null,
                                                                         nodesToWrite,
                                                                         out results,
                                                                         out diagnosticInfos);

                                            var okres             = false;
                                            var resultDescription = "";
                                            if (results.Count > 0)
                                            {
                                                resultDescription = results[0].ToString();
                                                if (StatusCode.IsGood(results[0]))
                                                {
                                                    okres = true;
                                                }
                                            }

                                            Log("MongoDB CMD CS - " +
                                                srv.name +
                                                " - " +
                                                " Address: " +
                                                change
                                                .FullDocument
                                                .protocolSourceObjectAddress +
                                                " - Command delivered - " + results[0].ToString());

                                            // update as delivered
                                            var filter =
                                                new BsonDocument(new BsonDocument("_id",
                                                                                  change
                                                                                  .FullDocument
                                                                                  .id));
                                            var update =
                                                new BsonDocument
                                            {
                                                { "$set",
                                                  new BsonDocument {
                                                      { "delivered", true },
                                                      { "ack", okres },
                                                      { "ackTimeTag", new BsonDateTime(DateTime.Now) },
                                                      { "resultDescription", resultDescription }
                                                  } }
                                            };
                                            var result =
                                                await collection
                                                .UpdateOneAsync(filter,
                                                                update);
                                        }
                                        else
                                        {
                                            // update as canceled (not connected)
                                            Log("MongoDB CMD CS - " +
                                                srv.name +
                                                " OA " +
                                                change
                                                .FullDocument
                                                .protocolSourceObjectAddress +
                                                " value " +
                                                change.FullDocument.value +
                                                (
                                                    srv.commandsEnabled
                                                    ? " Not Connected"
                                                    : " Commands Disabled"
                                                ));
                                            var filter =
                                                new BsonDocument(new BsonDocument("_id",
                                                                                  change
                                                                                  .FullDocument
                                                                                  .id));
                                            var update =
                                                new BsonDocument("$set",
                                                                 new BsonDocument("cancelReason",
                                                                                  (
                                                                                      srv
                                                                                      .commandsEnabled
                                                                ? "not connected"
                                                                : "commands disabled"
                                                                                  )));
                                            var result =
                                                await collection
                                                .UpdateOneAsync(filter,
                                                                update);
                                        }
                                        break;
                                    }
                                }
                                if (!found)
                                {
                                    // not for a connection managed by this driver instance, just ignore
                                }
                            }
                        });
                    }
                }
                catch (Exception e)
                {
                    Log("Exception MongoCmd");
                    Log(e);
                    Log(e
                        .ToString()
                        .Substring(0,
                                   e.ToString().IndexOf(Environment.NewLine)));
                    Thread.Sleep(3000);
                }
            }while (true);
        }