- - - - - Delphi Tutorials TOC - - - - - -
Other material for programmers
A program to log and display data.
This has good information, and a search button at the bottom of the page.
Please don't dismiss it because it isn't full of graphics, scripts, cookies, etc!
Click here if you want to know more about the source and format of these pages
Delphi Data Logging
This tutorial was put in level 5 for a number of reasons.
-- It relates to a large program.
-- As delivered, it requires that you have a device to serve .xml pages (You don't need one- see below.)
-- As delivered, it requires that you add components to your Delphi compiler.
So much for the bad news! The good news is that the sourcecode is provided, and you can get lots of good stuff out of it, if you will pick through "the bones". It would also be possible for an intermediate programmer to re-write the program, fixing it to read data from another source. Alternatively, this program might be your way into the world of client / server programming.
In a nutshell: The program is an interface to a wonderful device called the Poseidon, from HW group. It is a box you plug into your LAN, or to the internet if you have a static IP address available (or you have signed up for the free DynamicDNS service.) Into that, you plug temperature or humidity sensors. (It will also accept 3 digital inputs, provide 2 digital outputs... but these are outside the scope of the program this tutorial is about.) The Poseidon has a web server in it. If you have put it at IP address 192.168.0.26, then if you point your browser at 192.168.0.26/temper.xml, the Poseidon will send your browser some "stuff" (more later), quite like html, with the readings currently reported from the sensors you have connected to the Poseidon. You can read my independent comments for more details of the Poseidon.
The program offers a number of operating modes, but typically, you would have it running reading the sensors repeatedly. You can choose how frequently it should make readings. When it is running in this mode, it creates a graph of the readings, and, optionally, records the readings to a datafile.
If you activate the "record datafile" option, a text file like....
...will be created. The long number ("2005...") is just the date and time. The sample was produced with a Poseidon with two temperature sensors. Up to 7 are easily accommodated by the program. It autosenses how many sensors are present.
You can opt for the data to go into "DD60data.txt" (overwriting, without warning, any earlier file of that name), or into files with names like "DD60200506181642.txt". (Oops! As I write that, I see that DD60d200506181642.txt would be better. You may or may not find that the version of the program you download includes that "d" to split the "DD60" (program's name) from the "2005...." (datestamp indicating when data capture began. Interpretation of datestamp explained below. yyymmddhhmm. File above recorded from 2005, June, 18th, 16:42)
Click here to download zip with exe and sourcecode.
The "whole program" boils down to just two routines: ReadTtures and PlotTtures.
ReadTtures "only" has to fill the memo called DocumentMemo with something like.....
If you want to work with the program, but have no Poseidon, just fix it so that ReadTtures puts something like the above in DocumentMemo each time it is called. If you need help with that, just contact me.
By the way- a little plea: Never abbreviate "temperature" to "temp", please? "Temp", with me, always registers as "temporary". "Tture" makes such a nice, unambiguous, abbreviation.
What you see is an example of XML ("Extensible Markup Language"). Like HTML, it relies on tags, in pairs, e.g. <Temper> and </Temper> surrounding the 76.1. The tags may be nested, as in the <Poseidon> and </Poseidon> "wrapping up" the whole document.
The reason XML is a Good Thing is that it makes finding "stuff" within text easy. We'll see more about that later.
A little aside....
To tell you the truth, the Poseidon actually returns something more like what follows, but what you see above is the parts we will use. Also note that the Poseidon actually starts with <Temper> (matched by a terminal ;</Temper>.) These instances of "temper" are not, specifically, as I understand it, marking temperature readings.
<TempRange>-10 .. -5</TempRange>
<TempRange>-10 .. 40</TempRange>
Just to explore an aside from the aside: Even cooler than the Poseidon's xml serving capabilities is it's life as an SNMP agent. All of the "stuff" reported in the XML above is held inside the Poseidon in an MIB, which is a bit like the Windows registry. With the right tools (adequate ones: free), you can access the stuff in the MIB, to read it, or, where appropriate, write new values. There's more on this in my independent comments on the Poseidon.... but you don't need to know anything about SNMP or MIBs for this tutorial, so, back to business....
Just before we leave "ReadTtures", for those who DO have a Poseidon, or other XML server, how does the program "ask", across the LAN or internet, for the server to send "temper.xml", and how does it handle receipt of the same? I don't know! But I know a way to get what I need! That side of things is handled within my program with code adapted from the examples provided with the Belgian François Piette's wonderful Internet Component Suite (ICS). Basically, I fed the URL of the device in, called the Post method of the THttpCli object, and, hey presto, my memo was filled! If you want to dig into this part of the program, look at the event handlers for HttpCli1.
To use the ICS, you have to install third party components in your Delphi. I have to admit: This is the first time I've done it. But I've had no regrets. I only had to install WSocket, WSocket, WSocket, and HTTPProt. The ICS comes with some wonderful demo programs. I had a little trouble using some of them with Delphi 2 because the demos used "MainForm" for references to, not too surprisingly, the main (and in every case I saw, only) form of the project. A little tweaking of the dpr file gets the demos to run okay. The components ran first time, have run every time for me. Full sourcecode is provided. I saw no signs of spyware, etc, etc. Advice: However much you may share my distrust of adding components, you really don't want to attempt any internet stuff without either an expensive, advanced, version of Delphi, or someone's components.
The PlotTtures procedure takes care of several things. It looks at the memo, and extracts the temperature readings.... there must be at least 1, I think, and it can read up to 7. You don't have to tell the program how many there will be... however many are present are used.
One little detail which might confuse you: The XML data begins with a "temper" tag. This one is ignored, because it does not mark a temperature sensor result. All other "temper" tags contain data from temperature sensors.
The graph will fill from left to right, as you would probably expect. What you might not expect is that when the latest datum is plotted near the right hand edge of the graph, a gap begins to grow at the left hand edge of the graph. When the latest datum has been plotted at the right and edge, the next datum is plotted at the left hand edge, and after that, the graph "grows" across, left to right, "pushing" the gap ahead of itself.
If you are working on this aspect of the program, you can simply (at design time) make the image which carries the graph much narrower than it will be later. This will get you to the wrap-around point more quickly.
The program, if I do say so myself, is well structured. Everything up to the point when the XML is in the memo was created by M. Piette and his team; they get that credit. I created UseInfoInTemperXML to find the temperature readings in the XML (which by that time is waiting for me in the memo), and fill the array siTS. (Unused array elements are filled with -999 to flag the fact that they are unused.) Functions like FindTemper and sLineForDatafile reduce the "clutter" in the heart of UseInfoInTemperXML. Everything "under" PlotTtures is of my devising. Using PlotPoint(iNextX,siTS[c1],c1) kept PlotTtures readable. At that level, all you need to know is that here is where we plot another point on the graph. It goes at iNextX horizontally, where it goes vertically depends on siTS[c1], and it is a reading from channel c1. All the messy stuff that translates from the raw value for the temperature to the coordinate needed for the Delphi plotting (Image1.Picture.Bitmap.canvas.pixels[X,Y]:=clColor;) are dealt with in PlotPoint. Clarity and portability are further enhanced by putting specifics of the conversion from the temperature to a Y value into the function ScaleY.
The above neatly demonstrates a skill which will help you get your programs to work reliably, and help you write them quickly: You should strive to be able to build things in a hierarchy. At any given level, you should be able to see "everything", at least to some degree. "Pack up" "things" in modules, and modules of modules, (and modules of modules of modules!) to whatever extent is necessary to achieve clarity.
Odds and Ends:
There are two little functions buried in the code which you might find of use...
... checks that sTmp holds something like 192.168.0.25
... Returns 20051105130203 if the system date / time is 1:02:03pm 5Nov, 2005. It always returns 4+2+2+2+2+2 digits. If you don't what the seconds part, you just use copy(Datestamp,1,12). While 20051105130203 isn't particularly human friendly,. it can be parsed easily by database or spreadsheet programs, and if you sort on it, you get the result you would want. Personally, I would usually opt for the Delphi TDateTime format. To quote from the Delphi helpfile: "The integral part of a TDateTime value is the number of days that have passed since 12/30/1899. The fractional part of a TDateTime value is the time of day. E.g.-1.25 represents 12/29/1899, 6:00 am." I have also used a format which combines human readability (up to a point!) with machine-friendliness: 05a02c1234 is (20)05, January, 2nd, 3:12:34(am). Always ddlddlddd, where "d" is a digit, "l" is a letter. But I digress!!
Ini file: At the risk of teaching granny to suck eggs, let me point out to you the stuff below "F := TIniFile.Create" in the form's OnCreate, and in the OnDestroy procedure. That's "all" it takes to set up an ini file to remember things between runnings of the program. Quite handy.
Well! That's it for another tutorial... I hope you found it useful... Remember there is a link for downloading it and it's the source near the top of the page.
Click here if you're feeling kind! (Promotes my site via "Top100Borland")
Ad from page's editor: Yes.. I do enjoy compiling these things for you...
hope they are helpful. However.. this doesn't pay my bills!!! If you
find this stuff useful, (and you run an MS-DOS or Windows PC) please visit my freeware and shareware page,
download something, and circulate it for me? Links on your page to
this page would also be appreciated!
Click here to visit editor's freeware, shareware page.
Link to Tutorials main page
Here is how you can contact this page's author, Tom Boyd.
Page WILL BE tested for compliance with INDUSTRY (not MS-only) standards, using the free, publicly accessible validator at validator.w3.org
If this page causes a script to run, why? Because of things like Google panels, and the code for the search button. Why do I mention scripts? Be sure you know all you need to about spyware.
....... P a g e . . . E n d s .....