예제 #1
0
        public async Task SavePackageAsync(MeasurementPackage item, bool isNewItem = true)
        {
            var uri = new Uri(string.Format(samiImportHandler, string.Empty));

            try
            {
                var json = JsonConvert.SerializeObject(item);
                Debug.WriteLine(@"      Json: " + json);

                var content = new StringContent(json, Encoding.UTF8, "application/x-www-form-urlencoded");

                HttpResponseMessage response = null;
                if (isNewItem)
                {
                    response = await client.PostAsync(uri, content);

                    if (response.IsSuccessStatusCode)
                    {
                        Debug.WriteLine(@"      TodoItem succesfully saved");
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(@"				ERROR {0}", ex.Message);
            }
        }
예제 #2
0
        public MeasurementPackage GetSaveMeasurementPackageTemplate()
        {
            MeasurementPackage model = new MeasurementPackage();

            model.Key          = "your-key-goes-here";
            model.Measurements = new List <MeasurementModel>();
            MeasurementModel mm = new MeasurementModel();

            mm.Object    = "your-measurement-object";
            mm.Tag       = "your-measurement-tag";
            mm.Timestamp = DateTimeOffset.Now;
            mm.Note      = "if this measurement has a note";

            mm.Data = new List <DataModel>();
            DataModel dm = new DataModel();

            dm.Tag       = "This is your sensor identification. This is unique to you.";
            dm.Value     = 3.14;
            dm.TextValue = "your sensor can have some textual values also.";

            mm.Data.Add(dm);

            model.Measurements.Add(mm);

            return(model);
        }
예제 #3
0
        // json uri for service in sami.savonia.fi/Service
        // public const string JSONSaveMeasurementPackageUri = "YOURDOMAIN/Service/1.0/MeasurementsService.svc/json/measurementpackage/save";

        public static MeasurementPackage GetMeasurementPackage(this DateTimeOffset measurementTime, string measurementTag)
        {
            MeasurementPackage package = new MeasurementPackage();

            package.Key = TestHelper.TestKey;

            List <MeasurementModel> measurements = new List <MeasurementModel>();
            MeasurementModel        m            = new MeasurementModel()
            {
                Object    = TestHelper.TestMeasurementObject,
                Tag       = measurementTag,
                Timestamp = measurementTime,
                Location  = new Location()
                {
                    Latitude  = 62.8989,
                    Longitude = 27.6630
                }
            };
            DataModel d = new DataModel()
            {
                Tag   = TestHelper.TestDataTag,
                Value = 3.14
            };

            m.Data    = new DataModel[1];
            m.Data[0] = d;
            measurements.Add(m);

            package.Measurements = measurements.ToArray();

            return(package);
        }
예제 #4
0
 /// <summary>
 /// Sets up the required class variables. Take note of the write key: do not change this.
 /// This is the key granted for this project by Mikko.
 /// </summary>
 public SaMi(string patientName)
 {
     rest         = new RestService();
     package      = new MeasurementPackage();
     package.Key  = "SK507-2017305DCC94F130F11-01";
     measurements = new List <MeasurementModel>();
     modelTag     = patientName;
 }
예제 #5
0
파일: PilotLib.cs 프로젝트: SavoniaUAS/SaMi
        /// <summary>
        /// Main public method for getting the measurementpackage
        /// </summary>
        /// <returns>Final (hopefully) fully formed MeasurementPackage</returns>
        public MeasurementPackage GetMeasurementPackage()
        {
            MeasurementPackage mp = new MeasurementPackage();

            mp.Key          = Config.SamiWriteKey;
            mp.Measurements = GetMeasurements();
            return(mp);
        }
예제 #6
0
        public async Task <SaveResult> SaveMeasurementPackageAsync(MeasurementPackage measurementPackage)
        {
            var key = null != measurementPackage ? measurementPackage.Key : null;

            MeasurementModel[] measurements = null;
            if (null != measurementPackage && null != measurementPackage.Measurements)
            {
                measurements = measurementPackage.Measurements.ToArray();
            }
            return(await this.SaveMeasurementsInternalAsync(key, measurements));
        }
예제 #7
0
        public MeasurementPersistResult Persist(MeasurementPackage package)
        {
            // persist directly to measurements database
            MeasurementPersistResult persisted;

            using (Savonia.Measurements.Database.Repository r = new Database.Repository())
            {
                var result = r.SaveMeasurementsAsync(package.Key, package.Measurements.ToArray());
                persisted = new MeasurementPersistResult(result.Result);
            }

            return(persisted);
        }
예제 #8
0
        public static MeasurementPackage GetMeasurementPackageWithXMeasurementsAndYDataWithTextValue(this DateTimeOffset measurementTime, string measurementTag, int measurementsCount, int dataCount, bool useLocation)
        {
            MeasurementPackage package = new MeasurementPackage();

            package.Key = TestHelper.TestKey;

            if (dataCount < 1)
            {
                dataCount = 1;
            }

            List <MeasurementModel> measurements = new List <MeasurementModel>();
            MeasurementModel        m;

            for (int i = 0; i < measurementsCount; i++)
            {
                m = new MeasurementModel()
                {
                    Object    = TestHelper.TestMeasurementObject,
                    Tag       = measurementTag,
                    Timestamp = measurementTime.AddSeconds(i)
                };
                if (useLocation)
                {
                    m.Location = new Location()
                    {
                        Latitude  = 62.8989,
                        Longitude = 27.6630
                    };
                }
                m.Data = new DataModel[dataCount];
                //var xml = Savonia.Measurements.Providers.Models.SerializeHelper.SerializeToString<MeasurementModel>(m);
                for (int j = 0; j < dataCount; j++)
                {
                    DataModel d = new DataModel()
                    {
                        Tag       = TestHelper.TestDataTag + j.ToString(),
                        Value     = 3.14,
                        TextValue = "text_" + i.ToString()
                    };
                    m.Data[j] = d;
                }
                measurements.Add(m);
            }
            package.Measurements = measurements.ToArray();

            return(package);
        }
예제 #9
0
        /// <summary>
        /// The MeasurerService calls Process method periodically as defined in plugin's config ExecuteInterval element. The time is seconds.
        /// Note that the same instance of this class is alive the whole time as the service is alive! So make this process as sleek and lean as possible.
        /// </summary>
        public void Process()
        {
            //library takes the config and a Logger instance
            PilotLib pl = new PilotLib(pc, Log);

            //librarys only public facing method return a MeasurementPackage
            MeasurementPackage mp = pl.GetMeasurementPackage();

            // When your plugin has something to save raise ProcessCompleted event. The Name property can be used as ProcessCompletedEventArgs source parameter.
            // If at some point your plugin has nothing to save, then don't raise the event.
            if (mp != null && mp.Measurements != null && mp.Measurements.Count > 0)
            {
                //Update and save the configuration files LastMeasurementTime for each file
                pc.UpdateLastMeasurementTime(pl.NewLastMeasurementTime);
                PilotConfig.SavePilotConfig(ConfigurationFile.GetPluginRootedPath(), pc);

                this.OnProcessCompleted(new ProcessCompletedEventArgs(this.Name, mp));
            }
        }
예제 #10
0
        /// <summary>
        /// The MeasurerService calls Process method periodically as defined in plugin's config ExecuteInterval element. The time is seconds.
        /// Note that the same instance of this class is alive the whole time as the service is alive! So make this process as sleek and lean as possible.
        /// </summary>
        public void Process()
        {
            // Do the measurement reading here... and then create a MeasurementPackage object with a proper key to enable saving measurements to SAMI system.
            Random             rnd = new Random();
            MeasurementPackage p   = new MeasurementPackage()
            {
                Key          = this.settings.Key,
                Measurements = new List <MeasurementModel>()
            };

            MeasurementModel mm = new MeasurementModel()
            {
                Object    = settings.Object,
                Tag       = settings.Tag,
                Timestamp = DateTimeOffset.Now,
                Data      = new List <DataModel>()
            };

            foreach (var item in this.settings.SensorTags)
            {
                mm.Data.Add(new DataModel()
                {
                    Tag   = item,
                    Value = rnd.NextDouble() * 100
                });
            }

            p.Measurements.Add(mm);

            this.Log.Append("Test message to log...");

            // your plugin may throw exceptions and those will be logged in the service, but you can also handle your exceptions and log them if needed.
            // throw exception or do not handle possible exceptions...
            // throw new Exception("some info...");
            // or handle exceptions and log the info...
            // Log.Append("some info...");

            // When your plugin has something to save raise ProcessCompleted event. The Name property can be used as ProcessCompletedEventArgs source parameter.
            // If at some point your plugin has nothing to save, then don't raise the event.
            this.OnProcessCompleted(new ProcessCompletedEventArgs(this.Name, p));
        }
예제 #11
0
        public void SendMeasurementPackage()
        {
            // init the client
            MeasurementsServiceClient client = new MeasurementsServiceClient();
            // create the measurement package and populate it
            MeasurementPackage package = new MeasurementPackage();

            package.Key = "your-key-goes-here";

            // create a collection of measurements
            List <MeasurementModel> measurements = new List <MeasurementModel>();
            // create a measurement
            MeasurementModel m = new MeasurementModel()
            {
                Object    = "your-measurement-object",
                Tag       = "your-measurement-tag",
                Timestamp = DateTimeOffset.Now,
                Location  = new Location()
                {
                    Latitude  = 62.8989,
                    Longitude = 27.6630
                }
            };
            // add some data to your measurement
            DataModel d = new DataModel()
            {
                Tag   = "your-data-tag",
                Value = 3.14
            };

            // add data to measurement
            m.Data    = new DataModel[1];
            m.Data[0] = d;
            // add measurement to measurements collection
            measurements.Add(m);
            // add measurements collection to measurement package
            package.Measurements = measurements.ToArray();
            // save the measurement package and check the result
            SaveResult result = client.SaveMeasurementPackage(package);
        }
예제 #12
0
        public void LocalStoreSerializationTest()
        {
            Random             rnd = new Random();
            MeasurementPackage p   = new MeasurementPackage()
            {
                Key          = "testing...",
                Measurements = new List <MeasurementModel>()
            };

            MeasurementModel mm = new MeasurementModel()
            {
                Object    = "testing",
                Timestamp = DateTimeOffset.Now,
                Data      = new List <DataModel>()
            };

            string[] tags = new string[] { "tag1", "tag2" };
            foreach (var item in tags)
            {
                mm.Data.Add(new DataModel()
                {
                    Tag   = item,
                    Value = rnd.NextDouble() * 100
                });
            }

            p.Measurements.Add(mm);

            string xml = SerializeHelper.SerializeToStringWithDCS <MeasurementPackage>(p);

            Trace.WriteLine(xml);

            Assert.IsNotNull(xml);

            MeasurementPackage dps = SerializeHelper.DeserializeWithDCS <MeasurementPackage>(xml);

            Assert.IsNotNull(dps);
            Assert.AreEqual(dps.Key, p.Key);
            Assert.AreEqual(dps.Measurements.Count, p.Measurements.Count);
        }
예제 #13
0
        public MeasurementPersistResult Persist(MeasurementPackage package)
        {
            MeasurementPersistResult persisted = new MeasurementPersistResult();

            MeasurementsServiceV1.MeasurementsServiceClient client = new MeasurementsServiceV1.MeasurementsServiceClient();
            try
            {
                var result = client.SaveMeasurementPackage(package);
                persisted.SaveResult = result;
                client.Close();
            }
            catch (Exception ex)
            {
                persisted.Exception = ex;
                if (client.State != System.ServiceModel.CommunicationState.Closed)
                {
                    client.Abort();
                }
            }
            client = null;
            return(persisted);
        }
예제 #14
0
        public async Task SendPackages()
        {
            CalculatePackagesAndPause();

            for (var i = 0; i < Packages; ++i)
            {
                var model = new MeasurementPackage(MeasurementId, Type, Id)
                {
                    PackageId   = i + 1,
                    Data        = SessionData.Take(_samples).Skip(i * _samples).ToList(),
                    LastPackage = i + 1 == Packages
                };

                await _deviceService.SendDeviceToCloudMessageAsync(model);

                Logger.WriteInfo(_logger, $"MeasurementId: {MeasurementId}, " +
                                 $"SessionId: {Id},  " +
                                 $"PackageId: {model.PackageId} sent. " +
                                 $"Body: {model}");

                Thread.Sleep(Pause);
            }
        }
예제 #15
0
        public static MeasurementPackage GetMeasurementPackageWithISO(this DateTime measurementTime, string measurementTag)
        {
            MeasurementPackage package = new MeasurementPackage();

            package.Key = TestHelper.TestKey;

            List <MeasurementModel> measurements = new List <MeasurementModel>();
            // string ISO = measurementTime.ToString();
            string           ISO = "11/02/03 15:03:06";
            MeasurementModel m   = new MeasurementModel()
            {
                Object           = TestHelper.TestMeasurementObject,
                Tag              = measurementTag,
                TimestampISO8601 = ISO,
                Location         = new Location()
                {
                    Latitude  = 62.8989,
                    Longitude = 27.6630
                }
            };

            DataModel d = new DataModel()
            {
                Tag   = TestHelper.TestDataTag,
                Value = 3.14
            };

            m.Data    = new DataModel[1];
            m.Data[0] = d;
            measurements.Add(m);
            measurements.Add(m);

            package.Measurements = measurements.ToArray();

            return(package);
        }
예제 #16
0
 public ProcessCompletedEventArgs(string source, MeasurementPackage measurements)
 {
     this.Source             = source;
     this.MeasurementPackage = measurements;
 }
예제 #17
0
        // POST: api/Measurement
        public void Post([FromBody] MeasurementPackage value)
        {
            //Repository r = new Repository();

            //r.SaveMeasurements(value);
        }
예제 #18
0
        /// <summary>
        /// The MeasurerService calls Process method periodically as defined in plugin's config ExecuteInterval element. The time is seconds.
        /// Note that the same instance of this class is alive the whole time as the service is alive! So make this process as sleek and lean as possible.
        /// </summary>
        public void Process()
        {
            var        readConfigFile = this.settings.ReadConfigPath.GetPluginRootedPath();
            ReadConfig readConfig     = null;

            if (System.IO.File.Exists(readConfigFile))
            {
                readConfig = SerializeHelper.DeserializeWithDCS <ReadConfig>(System.IO.File.ReadAllText(readConfigFile));
            }
            else
            {
                readConfig = new ReadConfig();
            }

            RemoteMXService.site response      = null;
            DateTime             readStartDate = readConfig.LatestValueRead.AddSeconds(1.0); // set startDate to latest value read + one second to not read the latest value again.
            // set endDate to start date + timespan of max time to read measurements or current time which ever is smaller.
            DateTime readEndDate = new DateTime(Math.Min(DateTime.Now.Ticks, readStartDate.Add(this.settings.MaxTimeToReadAtOnce).Ticks));

            using (RemoteMXService.RdmSitesClient client = new RemoteMXService.RdmSitesClient())
            {
                var sites = client.getSites(new RemoteMXService.user()
                {
                    password = this.settings.Password, username = this.settings.UserName
                });
                if (null == sites || sites.Length == 0)
                {
                    Log.Append(string.Format("No sites found from RemoteMX for user {0}", this.settings.UserName));
                }
                else
                {
                    if (sites.Any(s => s.id == this.settings.SiteId))
                    {
                        RemoteMXService.datareq request = new RemoteMXService.datareq()
                        {
                            siteId    = this.settings.SiteId,
                            username  = this.settings.UserName,
                            password  = this.settings.Password,
                            startDate = readStartDate,
                            endDate   = readEndDate
                        };
                        response = client.getData(request);
                    }
                    else
                    {
                        string sitesString = "";
                        sites.ToList().ForEach(s =>
                        {
                            sitesString += string.Format("Site id: {0}, name: {1}{2}", s.id, s.name, Environment.NewLine);
                        });
                        throw new Exception(string.Format("Configured site id (SiteId: {1}) was not found from RemoteMX service with username {2}. {0}RemoteMX sites found:{0}{3}",
                                                          Environment.NewLine,
                                                          this.settings.SiteId,
                                                          this.settings.UserName,
                                                          sitesString));
                    }
                }
            }

            string serialized = string.Empty;

            if (null == response || null == response.data || response.data.Length == 0)
            {
                string messageTemplate = "No measurements found from RemoteMX for user {0} with site id {1} between {2} and {3}. Next reading will try with the same start time ({2}).";
                // No data --> update latest read value to readEndDate when the readEndDate is old enough.
                // This adds a little redundancy to data reading to allow service breaks etc.
                // Try to read the same time period for twice the duration of MaxTimeToReadAtOnce setting and after that move on.
                if (readEndDate.Add(this.settings.MaxTimeToReadAtOnce.Add(this.settings.MaxTimeToReadAtOnce)) < DateTime.Now)
                {
                    readConfig.LatestValueRead = readEndDate;
                    serialized = SerializeHelper.SerializeToStringWithDCS <ReadConfig>(readConfig);
                    System.IO.File.WriteAllText(readConfigFile, serialized);
                    messageTemplate = "No measurements found from RemoteMX for user {0} with site id {1} between {2} and {3}. Next reading will start with updated start time ({3}).";
                }
                Log.Append(string.Format(messageTemplate,
                                         this.settings.UserName,
                                         this.settings.SiteId,
                                         readStartDate,
                                         readEndDate));
                return;
            }

            // we have data!

            // Do the measurement reading here... and then create a MeasurementPackage object with a proper key to enable saving measurements to SAMI system.
            MeasurementPackage p = new MeasurementPackage()
            {
                Key          = this.settings.SamiKey,
                Measurements = new List <MeasurementModel>(response.data.Length)
            };

            MeasurementModel mm = null;
            DateTime         newestReadValue = readConfig.LatestValueRead;

            foreach (var item in response.data)
            {
                mm = new MeasurementModel()
                {
                    Object    = settings.MeasurementObject,
                    Tag       = settings.MeasurementTag,
                    Timestamp = item.timestamp
                };
                if (item.timestamp > newestReadValue)
                {
                    newestReadValue = item.timestamp;
                }

                if (null != item.variables && item.variables.Length > 0)
                {
                    mm.Data = new List <DataModel>(item.variables.Length);
                    bool save = false;
                    foreach (var val in item.variables)
                    {
                        // when SaveMappedValuesOnly == true --> save = false. Data is saved only when ChannelMap contains a map for the channel.
                        // when SaveMappedValuesOnly == false --> save = true. Data is saved with or without ChannelMap info.
                        save = !this.settings.SaveMappedValuesOnly;
                        var tag = val.channel;
                        if (this.settings.ChannelMap.ContainsKey(tag))
                        {
                            tag  = this.settings.ChannelMap[tag];
                            save = true;
                        }
                        if (save)
                        {
                            mm.Data.Add(new DataModel()
                            {
                                Tag   = tag,
                                Value = val.value
                            });
                        }
                    }
                }
                // NOTE! a measurement might not contain any Data items.
                p.Measurements.Add(mm);
            }

            readConfig.LatestValueRead = newestReadValue;
            serialized = SerializeHelper.SerializeToStringWithDCS <ReadConfig>(readConfig);

            System.IO.File.WriteAllText(readConfigFile, serialized);

            // When your plugin has something to save raise ProcessCompleted event. The Name property can be used as ProcessCompletedEventArgs source parameter.
            // If at some point your plugin has nothing to save, then don't raise the event.
            this.OnProcessCompleted(new ProcessCompletedEventArgs(this.Name, p));
        }
예제 #19
0
        /// <summary>
        /// The MeasurerService calls Process method periodically as defined in plugin's config ExecuteInterval element. The time is seconds.
        /// Note that the same instance of this class is alive the whole time as the service is alive! So make this process as sleek and lean as possible.
        /// </summary>
        public void Process()
        {
            m_Server = new Server();
            m_Server.CertificateEvent += new certificateValidation(opcUaServer_CertificateEvent);
            // Connect with URL from Server URL
            m_Server.Connect(this.settings.OpcUAServiceUrl);
            ReadNamespaceFromServer();

            // read values

            NodeIdCollection    nodesToRead = new NodeIdCollection();
            DataValueCollection results;
            int expectedResultsCount = this.settings.OPCUAItemMap.Count;
            Dictionary <string, OPCUAItem> itemMap = new Dictionary <string, OPCUAItem>(expectedResultsCount);

            this.settings.OPCUAItemMap.ForEach(m =>
            {
                itemMap.Add(m.Identifier, m);
                nodesToRead.Add(new NodeId(m.Identifier, m_NameSpaceIndex));
            });

            // Read the values
            m_Server.ReadValues(nodesToRead, out results);

            if (results.Count != expectedResultsCount)
            {
                throw new Exception("Reading value returned unexptected number of result");
            }

            //// we have data!

            // Do the measurement reading here... and then create a MeasurementPackage object with a proper key to enable saving measurements to SAMI system.
            MeasurementPackage p = new MeasurementPackage()
            {
                Key          = this.settings.SamiKey,
                Measurements = new List <MeasurementModel>(results.Count)
            };

            MeasurementModel mm = null;

            mm = new MeasurementModel()
            {
                Object    = settings.MeasurementObject,
                Tag       = settings.MeasurementTag,
                Timestamp = results[0].SourceTimestamp.ToLocalTime(),
                Data      = new List <DataModel>(results.Count)
            };
            ValueLinearScale scale     = null;
            OPCUAItem        opcUAItem = null;

            for (int i = 0; i < results.Count; i++)
            {
                scale = null;
                var tag = this.settings.OPCUAItemMap[i].Identifier;
                if (itemMap.ContainsKey(tag))
                {
                    opcUAItem = itemMap[tag];
                    tag       = opcUAItem.SamiTag;
                    scale     = opcUAItem.Scale;
                }
                var dm = new DataModel()
                {
                    Tag = tag
                };
                if (null != results[i].Value)
                {
                    if (null == scale)
                    {
                        dm.Value = Convert.ToDouble(results[i].Value);
                    }
                    else
                    {
                        dm.Value = scale.ScaleValue(Convert.ToDouble(results[i].Value));
                    }
                }
                mm.Data.Add(dm);
            }
            p.Measurements.Add(mm);
            // your plugin may throw exceptions and those will be logged in the service, but you can also handle your exceptions and log them if needed.

            // When your plugin has something to save raise ProcessCompleted event. The Name property can be used as ProcessCompletedEventArgs source parameter.
            // If at some point your plugin has nothing to save, then don't raise the event.
            this.OnProcessCompleted(new ProcessCompletedEventArgs(this.Name, p));

            m_Server.Disconnect();
            m_Server.CertificateEvent -= new certificateValidation(opcUaServer_CertificateEvent);
            m_Server = null;
        }
예제 #20
0
        /// <summary>
        /// The MeasurerService calls Process method periodically as defined in plugin's config ExecuteInterval element. The time is seconds.
        /// Note that the same instance of this class is alive the whole time as the service is alive! So make this process as sleek and lean as possible.
        /// </summary>
        public void Process()
        {
            // read values
            var        readConfigFile = this.settings.ReadConfigPath.GetPluginRootedPath();
            ReadConfig readConfig     = null;

            if (System.IO.File.Exists(readConfigFile))
            {
                readConfig = SerializeHelper.DeserializeWithDCS <ReadConfig>(System.IO.File.ReadAllText(readConfigFile));
            }
            else
            {
                readConfig = new ReadConfig();
                // substract one second from current time when ReadConfig is not read from file because readStartDate is readConfig.LatestValueRead plus one second
                // this way when the config file does not exist we start from current time.
                readConfig.LatestValueRead = DateTime.Now.AddSeconds(-1.0);
            }



            DateTime readStartDate = readConfig.LatestValueRead.AddSeconds(1.0); // set startDate to latest value read + one second to not read the latest value again.
            // set endDate to start date + timespan of max time to read measurements or current time which ever is smaller.
            DateTime readEndDate = new DateTime(Math.Min(DateTime.Now.Ticks, readStartDate.Add(this.settings.MaxTimeToReadAtOnce).Ticks));

            string csvDataString = this.GetCsvData(readStartDate, readEndDate);

            if (string.IsNullOrEmpty(csvDataString))
            {
                return;
            }
            // Do the measurement reading here... and then create a MeasurementPackage object with a proper key to enable saving measurements to SAMI system.
            MeasurementPackage p = new MeasurementPackage()
            {
                Key          = this.settings.SamiKey,
                Measurements = new List <MeasurementModel>()
            };
            //MeasurementModel mm = null;
            DateTime newestReadValue = readConfig.LatestValueRead;

            // we have data! --> parse the csv
            using (var reader = new StringReader(csvDataString))
            {
                var csv = new CsvReader(reader, new CsvConfiguration()
                {
                    HasHeaderRecord = settings.HasHeaders, Delimiter = settings.DelimeterChar, Quote = settings.QuotationChar
                });
                IFormatProvider doubleParser = System.Globalization.CultureInfo.InvariantCulture;
                while (csv.Read())
                {
                    MeasurementModel mm = new MeasurementModel()
                    {
                        Object = settings.MeasurementObject,
                        Tag    = settings.MeasurementTag
                    };
                    if (settings.HasHeaders)
                    {
                        mm.Timestamp = csv.GetField <DateTime>(settings.MeasurementTimeFieldHeader);
                    }
                    else
                    {
                        mm.Timestamp = csv.GetField <DateTime>(settings.MeasurementTimeFieldIndex);
                    }
                    if (mm.Timestamp.LocalDateTime >= readStartDate && mm.Timestamp.LocalDateTime <= readEndDate)
                    {
                        if (mm.Timestamp > newestReadValue)
                        {
                            newestReadValue = mm.Timestamp.DateTime;
                        }
                        // append only those measurements that are in valid time range
                        mm.Data = new List <DataModel>();
                        foreach (var item in settings.ItemMap)
                        {
                            var    scale = item.Scale;
                            double readValue;
                            string rawValue;
                            if (settings.HasHeaders)
                            {
                                rawValue = csv.GetField(item.Header);
                            }
                            else
                            {
                                rawValue = csv.GetField(item.Index);
                            }
                            readValue = double.Parse(rawValue.Replace(",", "."), doubleParser);
                            mm.Data.Add(new DataModel()
                            {
                                Tag   = item.SamiTag,
                                Value = null != scale ? scale.ScaleValue(readValue) : readValue
                            });
                        }

                        p.Measurements.Add(mm);
                    }
                }
            }

            readConfig.LatestValueRead = newestReadValue;
            var serialized = SerializeHelper.SerializeToStringWithDCS <ReadConfig>(readConfig);

            System.IO.File.WriteAllText(readConfigFile, serialized);


            // When your plugin has something to save raise ProcessCompleted event. The Name property can be used as ProcessCompletedEventArgs source parameter.
            // If at some point your plugin has nothing to save, then don't raise the event.
            if (null != p.Measurements && p.Measurements.Count > 0)
            {
                this.OnProcessCompleted(new ProcessCompletedEventArgs(this.Name, p));
            }
        }