private async void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
            {
                //MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
                //Console.WriteLine("Notification Received for Variable \"{0}\" and Value = {1} type {2}.", item.DisplayName, notification.Value, notification.TypeId);

                foreach (var value in item.DequeueValues())
                {
                    if (value != null)
                    {
                        string tp = "unknown";

                        try
                        {
                            if (value.WrappedValue.TypeInfo != null)
                            {
                                tp = value.WrappedValue.TypeInfo.BuiltInType.ToString();
                                // Log(conn_name + " - " + item.ResolvedNodeId + "TYPE: " + tp, LogLevelDetailed);
                            }
                            else
                            {
                                Log(conn_name + " - " + item.ResolvedNodeId + " TYPE: ?????", LogLevelDetailed);
                            }

                            Log(conn_name + " - " + item.ResolvedNodeId + " " + item.DisplayName + " " + value.Value + " " + value.SourceTimestamp + " " + value.StatusCode, LogLevelDetailed);

                            if (value.Value != null)
                            {
                                Double dblValue = 0.0;
                                string strValue = "";

                                try
                                {
                                    if (tp == "Variant")
                                    {
                                        try
                                        {
                                            dblValue = System.Convert.ToDouble(value.Value);
                                        }
                                        catch
                                        {
                                            try
                                            {
                                                dblValue = System.Convert.ToInt64(value.Value);
                                            }
                                            catch
                                            {
                                                try
                                                {
                                                    dblValue = System.Convert.ToInt32(value.Value);
                                                }
                                                catch
                                                {
                                                    dblValue = 0;
                                                    try
                                                    {
                                                        var opt = new JsonSerializerOptions
                                                        {
                                                            NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString
                                                        };
                                                        strValue = JsonSerializer.Serialize(value.Value, opt);
                                                    }
                                                    catch
                                                    {
                                                        strValue = value.Value.ToString();
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    else
                                    if (tp == "DateTime")
                                    {
                                        dblValue = ((DateTimeOffset)System.Convert.ToDateTime(value.Value)).ToUnixTimeMilliseconds();
                                        strValue = System.Convert.ToDateTime(value.Value).ToString("o");
                                    }
                                    else
                                    {
                                        dblValue = System.Convert.ToDouble(value.Value);
                                        strValue = value.Value.ToString();
                                    }
                                }
                                catch (Exception excpt)
                                {
                                    strValue = value.Value.ToString();
                                }

                                var options = new JsonSerializerOptions
                                {
                                    NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString
                                };

                                OPC_Value iv =
                                    new OPC_Value()
                                {
                                    valueJson          = JsonSerializer.Serialize(value, options),
                                    selfPublish        = true,
                                    address            = item.ResolvedNodeId.ToString(),
                                    asdu               = tp,
                                    isDigital          = true,
                                    value              = dblValue,
                                    valueString        = strValue,
                                    hasSourceTimestamp = value.SourceTimestamp != DateTime.MinValue,
                                    sourceTimestamp    = value.SourceTimestamp,
                                    serverTimestamp    = DateTime.Now,
                                    quality            = StatusCode.IsGood(value.StatusCode),
                                    cot            = 3,
                                    conn_number    = conn_number,
                                    conn_name      = conn_name,
                                    common_address = "",
                                    display_name   = item.DisplayName
                                };
                                OPCDataQueue.Enqueue(iv);
                            }
                        }
                        catch (Exception excpt)
                        {
                            Log(conn_name + " - " + excpt.Message);
                            Log(conn_name + " - " + "TYPE:" + tp);
                            Log(conn_name + " - " + item.ResolvedNodeId + " " + item.DisplayName + " " + value.Value + " " + value.SourceTimestamp + " " + value.StatusCode);
                        }
                    }
                    else
                    {
                        Log(conn_name + " - " + item.ResolvedNodeId + " " + item.DisplayName + " NULL VALUE!", LogLevelDetailed);
                    }

                    Thread.Yield();
                    Thread.Sleep(1);
                    //if ((OPCDataQueue.Count % 50) == 0)
                    //{
                    //    await Task.Delay(200);
                    //}
                }
            }
Exemple #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);
        }
Exemple #3
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);
        }