Support Forums
Need some direction on creating a report

I need to create a report that will display the lowest value that a tag registered throughout an entire day, along with the time that occurred. On top of that I need to display this information for the entire month.

I really do not know how to approach this at the moment.

I thought about using the standard report type since I believe it dumps all the available data into the report, and then possibly using a macro within the excel spreadsheet to pick out the lowest value from each day, grabbing the date/time stamp as well. I am not entirely sure how to do this, I do know how to view the macro thanks to the Developers guide.

Then I need a single excel spreadsheet for each month displaying the lowest value and time from each day. So again maybe its possible to append the report that is ran each day into the previous days report. 1st of the month starts a new report. Possible, I don't know.

Is there a way to view the SRC files for the various report types available by default in VTSCADA?

Thanks!

I need to create a report that will display the lowest value that a tag registered throughout an entire day, along with the time that occurred. On top of that I need to display this information for the entire month. I really do not know how to approach this at the moment. I thought about using the standard report type since I believe it dumps all the available data into the report, and then possibly using a macro within the excel spreadsheet to pick out the lowest value from each day, grabbing the date/time stamp as well. I am not entirely sure how to do this, I do know how to view the macro thanks to the Developers guide. Then I need a single excel spreadsheet for each month displaying the lowest value and time from each day. So again maybe its possible to append the report that is ran each day into the previous days report. 1st of the month starts a new report. Possible, I don't know. Is there a way to view the SRC files for the various report types available by default in VTSCADA? Thanks!

So I've been playing with the creating my own report type following the instructions in help files "Common Features of a Report Module". I've edited the example to provide the lowest value over a 24 hour period. The time column shows 0 though. I also want to poll the time of the lowest value and display it in place of the current time column.

{============================ QuarterHour ================================}
{ This generates a snapshort report given the time interval               }
{=========================================================================}
(
  Reporter                { Object value for call-backs                   };
  Start                   { Starting time (local, not UTC!)               };
  End                     { Ending time                                   };
  Tags                    { List of tag names to report on                };
)

[
  Titles                  { Array of ODBC database field names            };
  Types                   { Array of ODBC column type names               };
  Data                    { Actual data for the body of the report        };
  Format                  { Array of format strings which will be used
                            in successive SWrites to write Data           };
  TitleStrm               { Stream to build title line in                 };
  i                       { Loop counter                                  };
  j                       { Loop counter                                  };
  NTags                   { Number of tags                                };
  NRows                   { Number of periods (rows) in the report        };
  TagData                 { Array of tag data                             };
  TZBias                  { Only Valid if Called from Report Page         };

  Constant NUMFMT = "%13.2f";
  Constant COLFMT = "%13s";

    { Set up this module to become a plug-in for the reports }
  [(POINTS)
    Shared Report;
  ]

  Constant TypeFilter = "Loggers"     { type of tags to use in the report };
  Constant ReportName = "DAILY MINIMUM VALUE PER DAY" { title for the report            };
  Constant TPP        = 86400             { 86400 sec = 1 day            };
  Constant Mode[0]       = 1               { Mode 1 == Minimum In Range };  
  Constant Mode[1]       = 5               { Mode 5 == Time of minimum in range };

]

Init [

  If 1 Loop;
  [
      { Initialize the arrays for the tags }
    TZBias  = \IsTimeZoneAware ? TimeZone(0) : Invalid;
    NTags   = ArraySize(Tags, 0);
    TagData = New(NTags);

      { Remaining arrays include Date and Time as well as NTags }
    Titles  = New(NTags + 2);
    Types   = New(NTags + 2);
    Data    = New(NTags + 2);
    Format  = New(NTags + 2);

     { Build the title lines }
    TitleStrm = BuffStream(0);
    SWrite(TitleStrm, "%s from %s %s to %s %s\r\n\r\n",
           ReportName { Title for the report },
           Date(Start / 86400, 4), Time(Start % 86400, 2),
           Date((End - TPP) / 86400, 4),
           Time((End - TPP) % 86400, 2));

     { Set the value, type and format of the first two title columns }
    Titles[0] = "Date";
    Titles[1] = "Time";
    Types [0] = "TEXT";
    Types [1] = "TEXT";
    Format[0] = "%-13s";
    Format[1] = "%-9s";

     { write the first 2 columns of the title line }
    SWrite(TitleStrm, Format[0], Titles[0]);
    SWrite(TitleStrm, Format[1], Titles[1]);

     { Reset the loop counter }
    i = 0;
     { For each selected tag... }
    WhileLoop(i < NTags;
       { Add the tag name to the title line }
      Titles[i + 2] = PickValid(Scope(\Code, Tags[i])\Name, "Unknown");
      Types [i + 2] = "TEXT";
      Format[i + 2] = COLFMT;
      SWrite(TitleStrm, COLFMT, Titles[i + 2]);

       { and, query data for the tag }
      \GetLog(&TagData[i],
              Scope(\Code, Tags[i]) { Point object value      },
              "Value"               { Read data               },
              Start                 { Start time              },
              End                   { End time                },
              TPP                   { Time per point          },
              Invalid               { No max number of points },
              Mode                  { Calculation mode        },
              Invalid               { N/A                     },
              Invalid               { Stale time              },
              TZBias                { Time Zone Bias          });
      i++;
    );

      { Add CR, LF to title line and reset the stream }
    SWrite(TitleStrm, "\r\n");
    Seek(TitleStrm, 0, 0);

      { Let the VTScada Reporter module set up the ODBC columns }
    Reporter\ODBCColumns(Titles, Types);
      { And, the title line }
    Reporter\TitleLine(TitleStrm);
  ]
]

Loop [
   { ensure that GetLog has finished }
  If AValid(TagData[0], NTags) == NTags;
  [
     { Calculate the correct number of rows to avoid off-by-one errors }
    NRows = Ceil((End - Start) / TPP);

     { Reset the row counter }
    j = 0;
     { Loop through retrieved data, creating each report row }
    WhileLoop(j < NRows;
       { First two columns of the row will be date and time }
      Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP }
      Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP }
       { Loop through TagData array to get the data }
      i = 0;
      WhileLoop(i < NTags;
         { Fill in data array     }
        Data[i + 2] = Valid(Cast(TagData[i][j], 3)) ?
                      TagData[i][j] : Invalid;
         { Fill in format array   }
        Format[i + 2] = NUMFMT;
         { Increment loop counter }
        i++;
      ); { End WhileLoop          }

       { Pass the report line to the VTScada Reporter module }
      Reporter\DataLine(Format, Data);
       { Increment the data time index        }
      j++;
    ); { End WhileLoop }
    Slay(Self, 0);
  ]
]

The instructions say that you can retrieve more than one mode in a single GetLog statement and to do that to pass an array of values in as the mode parameter. I got as far as making Mode an array.

So I&#039;ve been playing with the creating my own report type following the instructions in help files &quot;Common Features of a Report Module&quot;. I&#039;ve edited the example to provide the lowest value over a 24 hour period. The time column shows 0 though. I also want to poll the time of the lowest value and display it in place of the current time column. ```` {============================ QuarterHour ================================} { This generates a snapshort report given the time interval } {=========================================================================} ( Reporter { Object value for call-backs }; Start { Starting time (local, not UTC!) }; End { Ending time }; Tags { List of tag names to report on }; ) [ Titles { Array of ODBC database field names }; Types { Array of ODBC column type names }; Data { Actual data for the body of the report }; Format { Array of format strings which will be used in successive SWrites to write Data }; TitleStrm { Stream to build title line in }; i { Loop counter }; j { Loop counter }; NTags { Number of tags }; NRows { Number of periods (rows) in the report }; TagData { Array of tag data }; TZBias { Only Valid if Called from Report Page }; Constant NUMFMT = &quot;%13.2f&quot;; Constant COLFMT = &quot;%13s&quot;; { Set up this module to become a plug-in for the reports } [(POINTS) Shared Report; ] Constant TypeFilter = &quot;Loggers&quot; { type of tags to use in the report }; Constant ReportName = &quot;DAILY MINIMUM VALUE PER DAY&quot; { title for the report }; Constant TPP = 86400 { 86400 sec = 1 day }; Constant Mode[0] = 1 { Mode 1 == Minimum In Range }; Constant Mode[1] = 5 { Mode 5 == Time of minimum in range }; ] Init [ If 1 Loop; [ { Initialize the arrays for the tags } TZBias = \IsTimeZoneAware ? TimeZone(0) : Invalid; NTags = ArraySize(Tags, 0); TagData = New(NTags); { Remaining arrays include Date and Time as well as NTags } Titles = New(NTags + 2); Types = New(NTags + 2); Data = New(NTags + 2); Format = New(NTags + 2); { Build the title lines } TitleStrm = BuffStream(0); SWrite(TitleStrm, &quot;%s from %s %s to %s %s\r\n\r\n&quot;, ReportName { Title for the report }, Date(Start / 86400, 4), Time(Start % 86400, 2), Date((End - TPP) / 86400, 4), Time((End - TPP) % 86400, 2)); { Set the value, type and format of the first two title columns } Titles[0] = &quot;Date&quot;; Titles[1] = &quot;Time&quot;; Types [0] = &quot;TEXT&quot;; Types [1] = &quot;TEXT&quot;; Format[0] = &quot;%-13s&quot;; Format[1] = &quot;%-9s&quot;; { write the first 2 columns of the title line } SWrite(TitleStrm, Format[0], Titles[0]); SWrite(TitleStrm, Format[1], Titles[1]); { Reset the loop counter } i = 0; { For each selected tag... } WhileLoop(i &lt; NTags; { Add the tag name to the title line } Titles[i + 2] = PickValid(Scope(\Code, Tags[i])\Name, &quot;Unknown&quot;); Types [i + 2] = &quot;TEXT&quot;; Format[i + 2] = COLFMT; SWrite(TitleStrm, COLFMT, Titles[i + 2]); { and, query data for the tag } \GetLog(&amp;TagData[i], Scope(\Code, Tags[i]) { Point object value }, &quot;Value&quot; { Read data }, Start { Start time }, End { End time }, TPP { Time per point }, Invalid { No max number of points }, Mode { Calculation mode }, Invalid { N/A }, Invalid { Stale time }, TZBias { Time Zone Bias }); i++; ); { Add CR, LF to title line and reset the stream } SWrite(TitleStrm, &quot;\r\n&quot;); Seek(TitleStrm, 0, 0); { Let the VTScada Reporter module set up the ODBC columns } Reporter\ODBCColumns(Titles, Types); { And, the title line } Reporter\TitleLine(TitleStrm); ] ] Loop [ { ensure that GetLog has finished } If AValid(TagData[0], NTags) == NTags; [ { Calculate the correct number of rows to avoid off-by-one errors } NRows = Ceil((End - Start) / TPP); { Reset the row counter } j = 0; { Loop through retrieved data, creating each report row } WhileLoop(j &lt; NRows; { First two columns of the row will be date and time } Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP } Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP } { Loop through TagData array to get the data } i = 0; WhileLoop(i &lt; NTags; { Fill in data array } Data[i + 2] = Valid(Cast(TagData[i][j], 3)) ? TagData[i][j] : Invalid; { Fill in format array } Format[i + 2] = NUMFMT; { Increment loop counter } i++; ); { End WhileLoop } { Pass the report line to the VTScada Reporter module } Reporter\DataLine(Format, Data); { Increment the data time index } j++; ); { End WhileLoop } Slay(Self, 0); ] ] ```` The instructions say that you can retrieve more than one mode in a single GetLog statement and to do that to pass an array of values in as the mode parameter. I got as far as making Mode an array.
edited Dec 18 '19 at 12:59 pm

Hopefully someone will be able to help me with this.

I edited the example and figured out how to do the arrays for the mode. Everything complies and a report is created but the data fields are blank.

Here is the code

{============================ QuarterHour ================================}
{ This generates a snapshort report given the time interval               }
{=========================================================================}
(
  Reporter                { Object value for call-backs                   };
  Start                   { Starting time (local, not UTC!)               };
  End                     { Ending time                                   };
  Tags                    { List of tag names to report on                };
)

[
  Titles                  { Array of ODBC database field names            };
  Types                   { Array of ODBC column type names               };
  Fields                   { Array of fields for GetTagHistory             };
  Modes                   { Array of modes for GetTagHistory              };
  Data                    { Actual data for the body of the report        };
  Format                  { Array of format strings which will be used
                            in successive SWrites to write Data           };
  TitleStrm               { Stream to build title line in                 };
  i                       { Loop counter                                  };
  j                       { Loop counter                                  };
  NTags                   { Number of tags                                };
  NRows                   { Number of periods (rows) in the report        };
  TagData                 { Array of tag data                             };
  TZBias                  { Only Valid if Called from Report Page         };

  Constant NUMFMT = "%13.2f";
  Constant COLFMT = "%13s";

    { Set up this module to become a plug-in for the reports }
  [(POINTS)
    Shared Report;
  ]

  Constant TypeFilter = "Loggers"     { type of tags to use in the report };
  Constant ReportName = "DAILY MINIMUM VALUE" { title for the report            };
  Constant TPP        = 86400             { 86400 sec = 1 day            };

]

Init [

  If 1 Loop;
  [
      { Initialize the arrays for the tags }
    TZBias  = \IsTimeZoneAware ? TimeZone(0) : Invalid;

    { Declare the arrays and initialize the error }
    { and result values                           }
    Fields = New(2);
    Fields[0] = "Value";
    Fields[1] = "Value";

    { Declare what retrieval modes will be used }
    Modes = New(2);
    Modes[0] = 1 { Min         };
    Modes[1] = 5 { Time of Min };

    NTags   = ArraySize(Tags, 0);
    TagData = New(NTags);

      { Remaining arrays include Date and Time as well as NTags }
    Titles  = New(NTags + 3);
    Types   = New(NTags + 3);
    Data    = New(NTags + 3);
    Format  = New(NTags + 3);

     { Build the title lines }
    TitleStrm = BuffStream(0);
    SWrite(TitleStrm, "%s from %s %s to %s %s\r\n\r\n",
           ReportName { Title for the report },
           Date(Start / 86400, 4), Time(Start % 86400, 2),
           Date((End - TPP) / 86400, 4),
           Time((End - TPP) % 86400, 2));

     { Set the value, type and format of the first two title columns }
    Titles[0] = "Date";
    Titles[1] = "Time";
    Types [0] = "TEXT";
    Types [1] = "TEXT";
    Format[0] = "%-13s";
    Format[1] = "%-9s";

     { write the first 2 columns of the title line }
    SWrite(TitleStrm, Format[0], Titles[0]);
    SWrite(TitleStrm, Format[1], Titles[1]);

     { Reset the loop counter }
    i = 0;
     { For each selected tag... }
    WhileLoop(i < NTags;
       { Add the tag name to the title line }
      Titles[i + 2] = "Minimum Reading";
      Types [i + 2] = "TEXT";
      Format[i + 2] = COLFMT;
      Titles[i + 3] = "Time of Minimum";
      Types [i + 3] = "TEXT";
      Format[i + 3] = COLFMT;
      SWrite(TitleStrm, COLFMT, Titles[i + 3]);

       { and, query data for the tag }
      \GetLog(&TagData[i],
              Scope(\Code, Tags[i]) { Point object value      },
              Fields                { Read data               },
              Start                 { Start time              },
              End                   { End time                },
              TPP                   { Time per point          },
              Invalid               { No max number of points },
              Modes                 { Calculation mode        },
              Invalid               { N/A                     },
              Invalid               { Stale time              },
              TZBias                { Time Zone Bias          });
      i++;
    );

      { Add CR, LF to title line and reset the stream }
    SWrite(TitleStrm, "\r\n");
    Seek(TitleStrm, 0, 0);

      { Let the VTScada Reporter module set up the ODBC columns }
    Reporter\ODBCColumns(Titles, Types);
      { And, the title line }
    Reporter\TitleLine(TitleStrm);
  ]
]

Loop [
   { ensure that GetLog has finished }
  If AValid(TagData[0], NTags) == NTags;
  [
     { Calculate the correct number of rows to avoid off-by-one errors }
    NRows = Ceil((End - Start) / TPP);

     { Reset the row counter }
    j = 0;
     { Loop through retrieved data, creating each report row }
    WhileLoop(j < NRows;
       { First two columns of the row will be date and time }
      Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP }
      Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP }
       { Loop through TagData array to get the data }
      i = 0;
      WhileLoop(i < NTags;
         { Fill in data array     }
        Data[i + 2] = Valid(Cast(TagData[i][j], 3)) ?
                      TagData[i][j] : Invalid;
         { Fill in format array   }
        Format[i + 2] = NUMFMT;
         { Increment loop counter }
        i++;
      ); { End WhileLoop          }

       { Pass the report line to the VTScada Reporter module }
      Reporter\DataLine(Format, Data);
       { Increment the data time index        }
      j++;
    ); { End WhileLoop }
    Slay(Self, 0);
  ]
]
Hopefully someone will be able to help me with this. I edited the example and figured out how to do the arrays for the mode. Everything complies and a report is created but the data fields are blank. Here is the code ```` {============================ QuarterHour ================================} { This generates a snapshort report given the time interval } {=========================================================================} ( Reporter { Object value for call-backs }; Start { Starting time (local, not UTC!) }; End { Ending time }; Tags { List of tag names to report on }; ) [ Titles { Array of ODBC database field names }; Types { Array of ODBC column type names }; Fields { Array of fields for GetTagHistory }; Modes { Array of modes for GetTagHistory }; Data { Actual data for the body of the report }; Format { Array of format strings which will be used in successive SWrites to write Data }; TitleStrm { Stream to build title line in }; i { Loop counter }; j { Loop counter }; NTags { Number of tags }; NRows { Number of periods (rows) in the report }; TagData { Array of tag data }; TZBias { Only Valid if Called from Report Page }; Constant NUMFMT = &quot;%13.2f&quot;; Constant COLFMT = &quot;%13s&quot;; { Set up this module to become a plug-in for the reports } [(POINTS) Shared Report; ] Constant TypeFilter = &quot;Loggers&quot; { type of tags to use in the report }; Constant ReportName = &quot;DAILY MINIMUM VALUE&quot; { title for the report }; Constant TPP = 86400 { 86400 sec = 1 day }; ] Init [ If 1 Loop; [ { Initialize the arrays for the tags } TZBias = \IsTimeZoneAware ? TimeZone(0) : Invalid; { Declare the arrays and initialize the error } { and result values } Fields = New(2); Fields[0] = &quot;Value&quot;; Fields[1] = &quot;Value&quot;; { Declare what retrieval modes will be used } Modes = New(2); Modes[0] = 1 { Min }; Modes[1] = 5 { Time of Min }; NTags = ArraySize(Tags, 0); TagData = New(NTags); { Remaining arrays include Date and Time as well as NTags } Titles = New(NTags + 3); Types = New(NTags + 3); Data = New(NTags + 3); Format = New(NTags + 3); { Build the title lines } TitleStrm = BuffStream(0); SWrite(TitleStrm, &quot;%s from %s %s to %s %s\r\n\r\n&quot;, ReportName { Title for the report }, Date(Start / 86400, 4), Time(Start % 86400, 2), Date((End - TPP) / 86400, 4), Time((End - TPP) % 86400, 2)); { Set the value, type and format of the first two title columns } Titles[0] = &quot;Date&quot;; Titles[1] = &quot;Time&quot;; Types [0] = &quot;TEXT&quot;; Types [1] = &quot;TEXT&quot;; Format[0] = &quot;%-13s&quot;; Format[1] = &quot;%-9s&quot;; { write the first 2 columns of the title line } SWrite(TitleStrm, Format[0], Titles[0]); SWrite(TitleStrm, Format[1], Titles[1]); { Reset the loop counter } i = 0; { For each selected tag... } WhileLoop(i &lt; NTags; { Add the tag name to the title line } Titles[i + 2] = &quot;Minimum Reading&quot;; Types [i + 2] = &quot;TEXT&quot;; Format[i + 2] = COLFMT; Titles[i + 3] = &quot;Time of Minimum&quot;; Types [i + 3] = &quot;TEXT&quot;; Format[i + 3] = COLFMT; SWrite(TitleStrm, COLFMT, Titles[i + 3]); { and, query data for the tag } \GetLog(&amp;TagData[i], Scope(\Code, Tags[i]) { Point object value }, Fields { Read data }, Start { Start time }, End { End time }, TPP { Time per point }, Invalid { No max number of points }, Modes { Calculation mode }, Invalid { N/A }, Invalid { Stale time }, TZBias { Time Zone Bias }); i++; ); { Add CR, LF to title line and reset the stream } SWrite(TitleStrm, &quot;\r\n&quot;); Seek(TitleStrm, 0, 0); { Let the VTScada Reporter module set up the ODBC columns } Reporter\ODBCColumns(Titles, Types); { And, the title line } Reporter\TitleLine(TitleStrm); ] ] Loop [ { ensure that GetLog has finished } If AValid(TagData[0], NTags) == NTags; [ { Calculate the correct number of rows to avoid off-by-one errors } NRows = Ceil((End - Start) / TPP); { Reset the row counter } j = 0; { Loop through retrieved data, creating each report row } WhileLoop(j &lt; NRows; { First two columns of the row will be date and time } Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP } Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP } { Loop through TagData array to get the data } i = 0; WhileLoop(i &lt; NTags; { Fill in data array } Data[i + 2] = Valid(Cast(TagData[i][j], 3)) ? TagData[i][j] : Invalid; { Fill in format array } Format[i + 2] = NUMFMT; { Increment loop counter } i++; ); { End WhileLoop } { Pass the report line to the VTScada Reporter module } Reporter\DataLine(Format, Data); { Increment the data time index } j++; ); { End WhileLoop } Slay(Self, 0); ] ] ````
edited Dec 18 '19 at 4:25 pm

Well I eventually figured out how to make this work.

I had to use separate GetLog instructions to get both the lowest value and the time that the lowest value occurred. I just could not get it to work with using a single GetLog instruction and using arrays for the Mode and Name fields. Followed a few examples but could not get it to work. I could get it to poll for a single date, but would not work for a group of dates like an entire month.

This is the working code. You can select multiple tags and it will create additional columns showing the lowest value and the date-time the lowest value occurred.

{======================= Daily Minimum Snapshot ==========================}
{ This generates a snapshort report given the time interval               }
{=========================================================================}
(
  Reporter                { Object value for call-backs                   };
  Start                   { Starting time (local, not UTC!)               };
  End                     { Ending time                                   };
  Tags                    { List of tag names to report on                };
)

[
  Titles                  { Array of ODBC database field names            };
  Types                   { Array of ODBC column type names               };
  Data                    { Actual data for the body of the report        };
  Format                  { Array of format strings which will be used
                            in successive SWrites to write Data           };
  TitleStrm               { Stream to build title line in                 };
  i                       { Loop counter                                  };
  j                       { Loop counter                                  };
  NTags                   { Number of tags                                };
  NRows                   { Number of periods (rows) in the report        };
  TagData                 { Array of tag data                             };
  TagData2                { Array of tag data                             };
  LocalTime                { Result timestamp converted to local           };
  TZBias                  { Only Valid if Called from Report Page         };

  Constant NUMFMT = "%13.2f";
  Constant COLFMT = "%13s";

    { Set up this module to become a plug-in for the reports }
  [(POINTS)
    Shared Report;
  ]

  Constant TypeFilter = "Loggers"     { type of tags to use in the report };
  Constant ReportName = "Daily Minimum Snapshot" { title for the report            };
  Constant TPP        = 86400             { 900 sec = 15 minutes            };
  Constant Mode       = 1;               
  Constant Mode2      = 5;               
]

Init [

  If 1 Loop;
  [
      { Initialize the arrays for the tags }
    TZBias  = \IsTimeZoneAware ? TimeZone(0) : Invalid;
    NTags   = ArraySize(Tags, 0);
    TagData = New(NTags);
    TagData2 = New(NTags);

      { Remaining arrays include Date and Time as well as NTags }
    Titles  = New((NTags * 2) + 2);
    Types   = New((NTags * 2) + 2);
    Data    = New((NTags * 2) + 2);
    Format  = New((NTags * 2) + 2);

     { Build the title lines }
    TitleStrm = BuffStream(0);
    SWrite(TitleStrm, "%s from %s %s to %s %s\r\n\r\n",
           ReportName { Title for the report },
           Date(Start / 86400, "MMM d, yyyy"),
           Time(Start, "HH:mm:ss"),
           Date(End / 86400, "MMM d, yyyy"),
           Time(End , "HH:mm:ss"));

     { Set the value, type and format of the first two title columns }
    Titles[0] = "Date";
    Titles[1] = "Time";
    Types [0] = "TEXT";
    Types [1] = "TEXT";
    Format[0] = "%-13s";
    Format[1] = "%-9s";

     { write the first 2 columns of the title line }
    SWrite(TitleStrm, Format[0], Titles[0]);
    SWrite(TitleStrm, Format[1], Titles[1]);

     { Reset the loop counter }
    i = 0;
     { For each selected tag... }
    WhileLoop(i < NTags;    
    { Add the tag name to the title line }
      Titles[(i * 2) + 2] = PickValid(Scope(\Code, Tags[i])\Name, "Unknown");
      Types [(i * 2) + 2] = "TEXT";
      Format[(i * 2) + 2] = COLFMT;
      SWrite(TitleStrm, COLFMT, Titles[(i * 2) + 2]);
      Titles[(i * 2) + 3] = "Date - Time";
      Types [(i * 2) + 3] = "TEXT";
      Format[(i * 2) + 3] = COLFMT;
      SWrite(TitleStrm, COLFMT, Titles[(i * 2) + 2]);

       { and, query data for the tag }
      \GetLog(&TagData[i],
              Scope(\Code, Tags[i]) { Point object value      },
              "Value"               { Read data               },
              Start                 { Start time              },
              End                   { End time                },
              TPP                   { Time per point          },
              Invalid               { No max number of points },
              Mode                  { Calculation mode        },
              Invalid               { N/A                     },
              Invalid               { Stale time              },
              TZBias                { Time Zone Bias          });

      \GetLog(&TagData2[i],
              Scope(\Code, Tags[i]) { Point object value      },
              "Value"               { Read data               },
              Start                 { Start time              },
              End                   { End time                },
              TPP                   { Time per point          },
              Invalid               { No max number of points },
              Mode2                 { Calculation mode        },
              Invalid               { N/A                     },
              Invalid               { Stale time              },
              TZBias                { Time Zone Bias          });
      i++;
    );

      { Add CR, LF to title line and reset the stream }
    SWrite(TitleStrm, "\r\n");
    Seek(TitleStrm, 0, 0);

      { Let the VTScada Reporter module set up the ODBC columns }
    Reporter\ODBCColumns(Titles, Types);
      { And, the title line }
    Reporter\TitleLine(TitleStrm);
  ]
]

Loop [
   { ensure that GetLog has finished }
  If AValid(TagData[0], NTags) == NTags;
  [
     { Calculate the correct number of rows to avoid off-by-one errors }
    NRows = Ceil((End - Start) / TPP);

     { Reset the row counter }
    j = 0;
     { Loop through retrieved data, creating each report row }
    WhileLoop(j < NRows;
       { First two columns of the row will be date and time }
      Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP }
      Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP }
       { Loop through TagData array to get the data }
      i = 0;
      WhileLoop(i < NTags;

       { Fill in data array     }
      Data[(i * 2) + 2] = Valid(Cast(TagData[i][j], 3)) ?
                    TagData[i][j] : Invalid;
       { Fill in format array   }
      Format[(i * 2) + 2] = NUMFMT;      

       { Convert the UTC timestamp to local time }
      LocalTime = ConvertTimestamp(TagData2[i][j],Invalid,Invalid,0);
       { Format for human consumption }
      Data[(i * 2) + 3] = concat(Date(LocalTime / 86400, 4), " - ", Time(LocalTime % 86400, 2));

      { Increment loop counter }
        i++;
      ); { End WhileLoop          }

       { Pass the report line to the VTScada Reporter module }
      Reporter\DataLine(Format, Data);
       { Increment the data time index        }
      j++;
    ); { End WhileLoop }
    Slay(Self, 0);
  ]
]
Well I eventually figured out how to make this work. I had to use separate GetLog instructions to get both the lowest value and the time that the lowest value occurred. I just could not get it to work with using a single GetLog instruction and using arrays for the Mode and Name fields. Followed a few examples but could not get it to work. I could get it to poll for a single date, but would not work for a group of dates like an entire month. This is the working code. You can select multiple tags and it will create additional columns showing the lowest value and the date-time the lowest value occurred. ```` {======================= Daily Minimum Snapshot ==========================} { This generates a snapshort report given the time interval } {=========================================================================} ( Reporter { Object value for call-backs }; Start { Starting time (local, not UTC!) }; End { Ending time }; Tags { List of tag names to report on }; ) [ Titles { Array of ODBC database field names }; Types { Array of ODBC column type names }; Data { Actual data for the body of the report }; Format { Array of format strings which will be used in successive SWrites to write Data }; TitleStrm { Stream to build title line in }; i { Loop counter }; j { Loop counter }; NTags { Number of tags }; NRows { Number of periods (rows) in the report }; TagData { Array of tag data }; TagData2 { Array of tag data }; LocalTime { Result timestamp converted to local }; TZBias { Only Valid if Called from Report Page }; Constant NUMFMT = &quot;%13.2f&quot;; Constant COLFMT = &quot;%13s&quot;; { Set up this module to become a plug-in for the reports } [(POINTS) Shared Report; ] Constant TypeFilter = &quot;Loggers&quot; { type of tags to use in the report }; Constant ReportName = &quot;Daily Minimum Snapshot&quot; { title for the report }; Constant TPP = 86400 { 900 sec = 15 minutes }; Constant Mode = 1; Constant Mode2 = 5; ] Init [ If 1 Loop; [ { Initialize the arrays for the tags } TZBias = \IsTimeZoneAware ? TimeZone(0) : Invalid; NTags = ArraySize(Tags, 0); TagData = New(NTags); TagData2 = New(NTags); { Remaining arrays include Date and Time as well as NTags } Titles = New((NTags * 2) + 2); Types = New((NTags * 2) + 2); Data = New((NTags * 2) + 2); Format = New((NTags * 2) + 2); { Build the title lines } TitleStrm = BuffStream(0); SWrite(TitleStrm, &quot;%s from %s %s to %s %s\r\n\r\n&quot;, ReportName { Title for the report }, Date(Start / 86400, &quot;MMM d, yyyy&quot;), Time(Start, &quot;HH:mm:ss&quot;), Date(End / 86400, &quot;MMM d, yyyy&quot;), Time(End , &quot;HH:mm:ss&quot;)); { Set the value, type and format of the first two title columns } Titles[0] = &quot;Date&quot;; Titles[1] = &quot;Time&quot;; Types [0] = &quot;TEXT&quot;; Types [1] = &quot;TEXT&quot;; Format[0] = &quot;%-13s&quot;; Format[1] = &quot;%-9s&quot;; { write the first 2 columns of the title line } SWrite(TitleStrm, Format[0], Titles[0]); SWrite(TitleStrm, Format[1], Titles[1]); { Reset the loop counter } i = 0; { For each selected tag... } WhileLoop(i &lt; NTags; { Add the tag name to the title line } Titles[(i * 2) + 2] = PickValid(Scope(\Code, Tags[i])\Name, &quot;Unknown&quot;); Types [(i * 2) + 2] = &quot;TEXT&quot;; Format[(i * 2) + 2] = COLFMT; SWrite(TitleStrm, COLFMT, Titles[(i * 2) + 2]); Titles[(i * 2) + 3] = &quot;Date - Time&quot;; Types [(i * 2) + 3] = &quot;TEXT&quot;; Format[(i * 2) + 3] = COLFMT; SWrite(TitleStrm, COLFMT, Titles[(i * 2) + 2]); { and, query data for the tag } \GetLog(&amp;TagData[i], Scope(\Code, Tags[i]) { Point object value }, &quot;Value&quot; { Read data }, Start { Start time }, End { End time }, TPP { Time per point }, Invalid { No max number of points }, Mode { Calculation mode }, Invalid { N/A }, Invalid { Stale time }, TZBias { Time Zone Bias }); \GetLog(&amp;TagData2[i], Scope(\Code, Tags[i]) { Point object value }, &quot;Value&quot; { Read data }, Start { Start time }, End { End time }, TPP { Time per point }, Invalid { No max number of points }, Mode2 { Calculation mode }, Invalid { N/A }, Invalid { Stale time }, TZBias { Time Zone Bias }); i++; ); { Add CR, LF to title line and reset the stream } SWrite(TitleStrm, &quot;\r\n&quot;); Seek(TitleStrm, 0, 0); { Let the VTScada Reporter module set up the ODBC columns } Reporter\ODBCColumns(Titles, Types); { And, the title line } Reporter\TitleLine(TitleStrm); ] ] Loop [ { ensure that GetLog has finished } If AValid(TagData[0], NTags) == NTags; [ { Calculate the correct number of rows to avoid off-by-one errors } NRows = Ceil((End - Start) / TPP); { Reset the row counter } j = 0; { Loop through retrieved data, creating each report row } WhileLoop(j &lt; NRows; { First two columns of the row will be date and time } Data[0] = Date((Start + j * TPP) / 86400, 7); { Date at start of TPP } Data[1] = Time((Start + j * TPP) % 86400, 2); { Time at start of TPP } { Loop through TagData array to get the data } i = 0; WhileLoop(i &lt; NTags; { Fill in data array } Data[(i * 2) + 2] = Valid(Cast(TagData[i][j], 3)) ? TagData[i][j] : Invalid; { Fill in format array } Format[(i * 2) + 2] = NUMFMT; { Convert the UTC timestamp to local time } LocalTime = ConvertTimestamp(TagData2[i][j],Invalid,Invalid,0); { Format for human consumption } Data[(i * 2) + 3] = concat(Date(LocalTime / 86400, 4), &quot; - &quot;, Time(LocalTime % 86400, 2)); { Increment loop counter } i++; ); { End WhileLoop } { Pass the report line to the VTScada Reporter module } Reporter\DataLine(Format, Data); { Increment the data time index } j++; ); { End WhileLoop } Slay(Self, 0); ] ] ````

This is what the result looks like
5dfbaaa234d9f

This is what the result looks like ![5dfbaaa234d9f](serve/attachment&amp;path=5dfbaaa234d9f)
137
5
1
live preview
enter atleast 10 characters
WARNING: You mentioned %MENTIONS%, but they cannot see this message and will not be notified
Saving...
Saved
With selected deselect posts show selected posts
All posts under this topic will be deleted ?
Pending draft ... Click to resume editing
Discard draft