{"id":29303,"date":"2022-08-23T00:57:37","date_gmt":"2022-08-23T07:57:37","guid":{"rendered":"https:\/\/digilent.com\/blog\/?p=29303"},"modified":"2022-08-23T00:57:37","modified_gmt":"2022-08-23T07:57:37","slug":"reading-generated-data-in-a-real-time-distributed-system-part-4","status":"publish","type":"post","link":"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-4\/","title":{"rendered":"Reading Generated Data in a Real-Time Distributed System &#8211; Part 4"},"content":{"rendered":"<h2><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.digilent.com\/blog\/wp-content\/uploads\/2022\/08\/2022-ReadingGeneratedData-part4-580.png\" alt=\"\" width=\"580\" height=\"290\" class=\"aligncenter size-full wp-image-29327\" data-wp-pid=\"29327\" \/><\/h2>\n<h2>Distributing the Applications to View the Data Remotely<\/h2>\n<p><span>The goal of this article series is to demonstrate how to create a data acquisition system on one system, and view the collected data in near real time from another. This can be accomplished by the use of a database and two VB.NET applications.\u00a0\u00a0 In Part 1, we learned how to set up the database and make it accessible. In Part 2, we created a data acquisition application, reading from a\u00a0<\/span><span onmouseover=\"ikb_showGlossaryToopTip(20);\" class=\"glossaryToolTip\">USB-2408<\/span><span>, and write the data to our database. Part 3, an app to read that collected data from the database and display it.\u00a0<\/span><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-1\/\">Part 1 &#8211; Setting Up an MS Database<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-2\/\">Part 2 &#8211; Creating an Application to Collect and Pass Data<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-3\/\">Part 3 &#8211; Creating an Application to View Data<\/a><\/p>\n<p><a href=\"https:\/\/digilent.com\/blog\/reading-generated-data-in-a-real-time-distributed-system-part-5\/\">Part 5 &#8211; Using Additional Software Packages<\/a><\/p>\n<p style=\"font-weight: 400;\">Up until now, all three components have been on one computer. Here in Part 4, we will deploy this system onto three computers: one for the database, one to collect the data, and one to view the data. If you have only two computers, you can still make this work by putting the database and data collection program on the same system.<\/p>\n<p style=\"font-weight: 400;\">We will need to make a couple tweaks to our applications.\u00a0 Nothing major, just to make it easier to find the database. Since the apps are no longer on the same PC, we need a way to have the app find and remember where the database is located.\u00a0 Sure, you could hard code it, but what if you move the database or one or both apps to other locations? \u00a0Or, you need to add another computer as a data collection point or another person needs to see the collected data. Here\u2019s one way to solve the problem. We will add code to create a configuration file that is automatically loaded at start up. \u00a0If one is not available, click on a menu item so you can tell the program where the database is then store that location so the next time you run the program is will find it upon start up.<\/p>\n<h2>Editing the DataCollectionToDatabase App<\/h2>\n<p style=\"font-weight: 400;\">Starting with the app from part 2, open DataCollectionToDatabase, go to the Code view of Form1.vb, and scroll to the top. \u00a0Below<span>\u00a0<\/span>Dim<span>\u00a0<\/span>drCurrent<span>\u00a0<\/span>As<span>\u00a0<\/span>DataRow<span>\u00a0<\/span>add the following:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>DatabaseFileNameAndPath<span>\u00a0<\/span>As\u00a0String<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>Filename<span>\u00a0<\/span>As<span>\u00a0<\/span>String<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>SettingsFileOut<span>\u00a0<\/span>As<span>\u00a0<\/span>IO.StreamWriter<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>SettingsFileIn<span>\u00a0<\/span>As<span>\u00a0<\/span>IO.StreamReader<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">And, in the Form1_Load() event, below<span>\u00a0<\/span>CreateDataBase()<span>\u00a0<\/span>Add the following:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;Get file path to user&#8217;s&#8221;MyDocuments\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">DimpathstringAsString=My.Computer.FileSystem.SpecialDirectories.MyDocuments<\/p>\n<p style=\"font-weight: 400;\">pathstring = pathstring +&#8221;\\MeasurementComputing\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">System.IO.Directory.CreateDirectory(pathstring)<\/p>\n<p style=\"font-weight: 400;\">&#8216;Create a file.<\/p>\n<p style=\"font-weight: 400;\">Filename =&#8221;&#8221;<\/p>\n<p style=\"font-weight: 400;\">Filename = pathstring +&#8221;Database.CFG&#8221;<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the data from the file and parse it.<\/p>\n<p style=\"font-weight: 400;\">Try<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 SettingsFileIn =NewStreamReader(Filename)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 DatabaseFileNameAndPath = SettingsFileIn.ReadLine()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 SettingsFileIn.Close()<\/p>\n<p style=\"font-weight: 400;\">CatchexAsException<\/p>\n<p style=\"font-weight: 400;\">EndTry<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">What this does: \u00a0If there is a file named Database.CFG, located in your computer\u2019s MyDocuments\\Measurement Computing\\OledExample folder, use the path located in that file. If the file does not exist, do nothing.<\/p>\n<p style=\"font-weight: 400;\">From the Solution Explorer, right click on Form1.vb, and select \u201cView Designer.\u201d Double click on \u201cSelect Database\u201d menu item to open the SelectDatabaseToolStripMenuItem_Click() event, and add the following code:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">OpenFileDialog1.Filter =<span>\u00a0<\/span>&#8220;MSACCESS (*.mdb)|*.mdb|All Files (*.*)|*.*&#8221;<\/p>\n<p style=\"font-weight: 400;\">OpenFileDialog1.FileName = DatabaseFileNameAndPath<\/p>\n<p style=\"font-weight: 400;\">OpenFileDialog1.ShowDialog(Me)<\/p>\n<p style=\"font-weight: 400;\">DatabaseFileNameAndPath = OpenFileDialog1.FileName<\/p>\n<p style=\"font-weight: 400;\">If<span>\u00a0<\/span>DatabaseFileNameAndPath =<span>\u00a0<\/span>&#8220;&#8221;\u00a0Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 MsgBox(&#8220;No file selected or bad file name selected.&#8221;,\u00a0MsgBoxStyle.OkOnly,<span>\u00a0<\/span>&#8220;Bad file name&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0<span>\u00a0<\/span>Exit Sub<\/p>\n<p style=\"font-weight: 400;\">End<span>\u00a0<\/span>If<\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;Create a file path to user&#8217;s &#8220;MyDocuments\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>pathstring<span>\u00a0<\/span>As<span>\u00a0<\/span>String<span>\u00a0<\/span>=<span>\u00a0<\/span>My.Computer.FileSystem.SpecialDirectories.MyDocuments<\/p>\n<p style=\"font-weight: 400;\">Pathstring = pathstring +<span>\u00a0<\/span>&#8220;\\MeasurementComputing\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">System.IO.Directory.CreateDirectory(pathstring)<\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;Create the file.<\/p>\n<p style=\"font-weight: 400;\">Filename = pathstring +&#8221;Database.CFG&#8221;<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut =NewStreamWriter(Filename)<\/p>\n<\/blockquote>\n<p>&nbsp;<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">&#8216;Write the DATABASE filename and path to the .cfg file<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut.WriteLine(DatabaseFileNameAndPath)<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut.Close()<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">We are using 2 string variables here and they can be confusing:<\/p>\n<p style=\"font-weight: 400;\"><em>DatabaseFileNameAndPath\u00a0<\/em>is a string containing filename and path to the database itself,<\/p>\n<p style=\"font-weight: 400;\"><em>Filename<\/em><span>\u00a0<\/span>is a string containing the filename and path to DatabaseFilenameAndPath.<\/p>\n<p style=\"font-weight: 400;\">When this event is selected, the Open File dialog box appears with filters turned on to show just Microsoft Access files (with the extension of .mdb) or all files.\u00a0 The user navigates to the database, selects it, and clicks on<span>\u00a0<\/span><strong>OK<\/strong>.\u00a0 The path and file name are returned in the string DatabaseFilenameAndPath:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">DatabaseFileNameAndPath = OpenFileDialog1.FileName<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\"><span>We want to store that path and file name somewhere locally where the app can find it the next time the app starts (that\u2019s what we added at the end of the Form1_Load() event). As stated above, we want to put the string in a file Database.CFG, and place the file in MyDocuments\\MeasurementComputing\\OledbExample.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/14-VB-Environments-1-600x437.png\" alt=\"\" width=\"600\" height=\"437\" class=\"aligncenter size-medium wp-image-29309\" data-wp-pid=\"29309\" srcset=\"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/14-VB-Environments-1-600x437.png 600w, https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/14-VB-Environments-1.png 808w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<h2>Editing the DatabaseToDataDisplayApp<\/h2>\n<p style=\"font-weight: 400;\">Now that we have the first app modified, let\u2019s modify the monitoring application.\u00a0 These edits are similar to DataCollectionToDatabase, I\u2019ll just provide the edits.<\/p>\n<p style=\"font-weight: 400;\">Open the application. From the Solution Explorer, right click on Form1.vb, and select \u201cViewCode.\u201d<\/p>\n<p style=\"font-weight: 400;\">Scroll to the top. \u00a0Just below<span>\u00a0<\/span>Dim<span>\u00a0<\/span>sql<span>\u00a0<\/span>As\u00a0String<span>\u00a0<\/span>add the following:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>DatabaseFileNameAndPath<span>\u00a0<\/span>As\u00a0String<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>Filename<span>\u00a0<\/span>As<span>\u00a0<\/span>String<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>SettingsFileOut<span>\u00a0<\/span>As<span>\u00a0<\/span>IO.StreamWriter<\/p>\n<p style=\"font-weight: 400;\">Dim<span>\u00a0<\/span>SettingsFileIn<span>\u00a0<\/span>As<span>\u00a0<\/span>IO.StreamReader<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">In the Timer1_Tick() event, comment out this line:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">sConnectionString =<span>\u00a0<\/span>&#8220;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\Users\\Public\\Documents\\MCCGenericOdbc.mdb&#8221;\u00a0\u00a0<span>\u00a0<\/span>&#8216;for oleDB<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">\u00a0And add:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">sConnectionString =&#8221;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=&#8221;&amp; DatabaseFileNameAndPath<\/p>\n<p style=\"font-weight: 400;\">From the Solution Explorer, right click Form1.vb, select \u201cView Designer.\u201d \u00a0Double click on Form1 to open the Form1_Load() event, and add the following:<\/p>\n<p style=\"font-weight: 400;\">&#8216;Get file path to user&#8217;s&#8221;MyDocuments\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">DimpathstringAsString=My.Computer.FileSystem.SpecialDirectories.MyDocuments<\/p>\n<p style=\"font-weight: 400;\">pathstring = pathstring +&#8221;\\MeasurementComputing\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">System.IO.Directory.CreateDirectory(pathstring)<\/p>\n<p style=\"font-weight: 400;\">&#8216;Create a file.<\/p>\n<p style=\"font-weight: 400;\">Filename = pathstring +&#8221;Database.CFG&#8221;<\/p>\n<p style=\"font-weight: 400;\">&#8216;Read the data from the file and parse it.<\/p>\n<p style=\"font-weight: 400;\">Try<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 SettingsFileIn =NewStreamReader(Filename)<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 DatabaseFileNameAndPath = SettingsFileIn.ReadLine()<\/p>\n<p style=\"font-weight: 400;\">\u00a0 \u00a0 SettingsFileIn.Close()<\/p>\n<p style=\"font-weight: 400;\">CatchexAsException<\/p>\n<p style=\"font-weight: 400;\">EndTry<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Return to the Form1 Design view, double click on \u201cSelectdatabase\u201d menu item, and add the following to the generated event:<\/p>\n<blockquote>\n<p style=\"font-weight: 400;\">OpenFileDialog1.Filter =&#8221;MSACCESS (*.mdb)|*.mdb|All Files (*.*)|*.*&#8221;<\/p>\n<p style=\"font-weight: 400;\">OpenFileDialog1.FileName = DatabaseFileNameAndPath<\/p>\n<p style=\"font-weight: 400;\">OpenFileDialog1.ShowDialog(Me)<\/p>\n<p style=\"font-weight: 400;\">DatabaseFileNameAndPath = OpenFileDialog1.FileName<\/p>\n<p style=\"font-weight: 400;\">IfDatabaseFileNameAndPath =&#8221;&#8221;\u00a0Then<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0 MsgBox(&#8220;No file selected or bad file name selected.&#8221;,\u00a0MsgBoxStyle.OkOnly,&#8221;Bad file name&#8221;)<\/p>\n<p style=\"font-weight: 400;\">\u00a0\u00a0\u00a0Exit Sub<\/p>\n<p style=\"font-weight: 400;\">EndIf<\/p>\n<p style=\"font-weight: 400;\">&#8216;Create a file path to user&#8217;s &#8220;MyDocuments\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">DimpathstringAsString=My.Computer.FileSystem.SpecialDirectories.MyDocuments<\/p>\n<p style=\"font-weight: 400;\">pathstring = pathstring +&#8221;\\MeasurementComputing\\OledbExample\\&#8221;<\/p>\n<p style=\"font-weight: 400;\">System.IO.Directory.CreateDirectory(pathstring)<\/p>\n<p style=\"font-weight: 400;\">&#8216;create the file.<\/p>\n<p style=\"font-weight: 400;\">Filename = pathstring +&#8221;Database.CFG&#8221;<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut =NewStreamWriter(Filename)<\/p>\n<p style=\"font-weight: 400;\">&#8216;Write the DATABASE filename and path to the .cfg file<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut.WriteLine(DatabaseFileNameAndPath)<\/p>\n<p style=\"font-weight: 400;\">SettingsFileOut.Close()<\/p>\n<\/blockquote>\n<p style=\"font-weight: 400;\">Now, you can compile and create deployment projects for these applications so that they may be distributed.\u00a0 Place the database on a centrally accessible computer.\u00a0 If desired, you can do this distributed system on two computers by having both the DataCollectionToDatabase application and MccGenericOdbc.mdb on one computer, and the other computer running the DatabaseToDataDisplay app.<\/p>\n<p style=\"font-weight: 400;\">Make sure all computers are mapped to drives containing the database. <a href=\"https:\/\/files.digilent.com\/resources\/MCC\/resources\/DatacollectionToDatabase.zip\">Completed application can be found HERE<\/a>.<\/p>\n<div class='watch-action'><div class='watch-position align-left'><div class='action-like'><a class='lbg-style6 like-29303 jlk' data-task='like' data-post_id='29303' data-nonce='35f55bdfa6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Like' \/><span class='lc-29303 lc'>0<\/span><\/a><\/div><div class='action-unlike'><a class='unlbg-style6 unlike-29303 jlk' data-task='unlike' data-post_id='29303' data-nonce='35f55bdfa6' rel='nofollow'><img src='https:\/\/digilent.com\/blog\/wp-content\/plugins\/wti-like-post-pro\/images\/pixel.gif' title='Unlike' \/><span class='unlc-29303 unlc'>0<\/span><\/a><\/div><\/div> <div class='status-29303 status align-left'>Be the 1st to vote.<\/div><\/div><div class='wti-clear'><\/div>","protected":false},"excerpt":{"rendered":"<p>Distributing the Applications to View the Data Remotely The goal of this article series is to demonstrate how to create a data acquisition system on one system, and view the &hellip; <\/p>\n","protected":false},"author":59,"featured_media":29337,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[4325,4361,4327,1563],"tags":[4359,4358],"ppma_author":[4507],"class_list":["post-29303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-debug-validation-test","category-data-acquisition","category-projects","category-guide","tag-daq","tag-mcc"],"jetpack_featured_media_url":"https:\/\/digilent.com\/blog\/wp-content\/uploads\/2022\/08\/2022-ReadingGeneratedData2-part4-580.png","authors":[{"term_id":4507,"user_id":59,"is_guest":0,"slug":"jgreenberg","display_name":"Jeff Greenberg","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/4733b4dee4cf309719f59882b387a0c9fcd17b506ca0858a86a1ecd2c7ed324a?s=96&d=mm&r=g","1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":"","9":"","10":""}],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/29303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/users\/59"}],"replies":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/comments?post=29303"}],"version-history":[{"count":0,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/posts\/29303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media\/29337"}],"wp:attachment":[{"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/media?parent=29303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/categories?post=29303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/tags?post=29303"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/digilent.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=29303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}