This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Alarm page demo using javascript and tag
#1
Hello!

I haven't found any slim alarm notification example so I created one (using forum magic search button and all kind of code examples). I bet there is quite many good programmers who maybe want to add some additional features. Would be nice to see these in this thread...

About page. It gonna check alarms by tags and shows in two separate table. One is active alarm table and another is event table. It's possible to delete all past events as well. 
Integration should take less than few minutes.
Alarm page date and time is actual alarm variable update time. Event date and time is time when system checked event variable (not actual alarm time).

Common functions:
Code:
function eventlog(text)
  local max = 30                             -- MAX NUMBER OF ENTRIES
  text = os.date('%d/%m/%Y %T ') .. text
  storage.exec('lpush', 'eventlog', text)
  storage.exec('ltrim', 'eventlog', 0, max - 1)
end

Resident script 3s:

1. Define group address base
2. Add tag-s what to check periodically
3. On first run change first three lines to true. Later change back to false
4. Activate script


Code:
create_eventlog_file = false                 --Execute on first run to create lp file
create_all_log_file = false                --Execute on first run to create lp file
create_group_addresses = false                --Execute on first run to create group addresses

group_address_base = '51/1/'                    --System generates two group addresses. Make sure that addresses are free (x/x/1 and x/x/2).
alarm_tags = {'SV1','SV2','SV3','EMAIL','HEATING'}        --These are alarm tags what is gonna checked constantly

-------------------------------------------------------
data1 = {
   type = 'event',
   name = 'ALARM PAGE - Update frontend',
   active = 1,
   params = group_address_base .. '1',
   subparams = 0,
   script = [[val = event.getvalue()
      if val then 
          grp.checkupdate("]] .. group_address_base .. [[1", 0)
        end]],
   category = '',
   description = 'Automatically generated',
}
data2 = {
   type = 'event',
   name = 'ALARM PAGE - Delete eventlog',
   active = 1,
   params = group_address_base .. '2',
   subparams = 0,
   script = [[val = event.getvalue()
      if val then
  storage.delete('eventlog')
  grp.update(']]..group_address_base .. [[2',0)
  grp.update(']]..group_address_base .. [[1',1)
end]],
   category = '',
   description = 'Automatically generated',
}

function create_scripts(data)
  exists = script.get(data.name)
  if not exists then
     db:insert('scripting', data)
     data.id = db:getlastautoid()
     script.save(data, true)
     script.reloadsingle(data)
  end
end

function createga(groupaddress,datatype2,name2)
  exist = grp.alias(groupaddress)
  if exist == nil then
    address = grp.create({
    datatype = datatype2,
    address = groupaddress,
    name = name2,
    comment = 'Automatically created object',
    units = '',
    tags = { },
    })
  end
end

if create_group_addresses then
    createga(group_address_base .. 1,dt.bool,'ALARM PAGE - Update frontend')
  createga(group_address_base .. 2,dt.bool,'ALARM PAGE - Delete eventlog')
  os.sleep(0.5)
  create_scripts(data1)
  create_scripts(data2)
end

function file_exists(name)
  local f = io.open(name, "r")
  return f ~= nil and io.close(f)
end

if create_eventlog_file then
    fil_name = '/www/user/eventlog.lp'
    if file_exists(fil_name) == false then
    dst = fil_name
    io.writefile(dst, [[<?
    require('apps')
    items = storage.exec('lrange', 'eventlog', 0, 999)
    text = table.concat(items, '\r\n')
    print(text)
    ?>]])
  end
end

if create_all_log_file then
    fil_name = '/www/user/all_alarms.lp'
    if file_exists(fil_name) == false then
    dst = fil_name
    io.writefile(dst, [[<?
    require('json')
    require('genohm-scada')
    mydata =storage.get('ALL_ALARMS')
    mydata = json.encode(mydata)
    print(mydata)
    ?>]])
    end
end

function check_events(tag, GA)
  index = 1
  all_alarms = {}
  update_table = false
  for it=1, #tag, 1 do
    old = {}
    old_val = storage.get(tag[it] .. '_sent')
    update_storage = false
    events = grp.tag(tag[it])
    for i=1, #events, 1 do
      if old_val == nil then                            --if no info - update it to latest info
        update_storage = true
        update_table = true
      end
      old[i] = {sent =events[i].value}
      all_alarms[index] = {status =events[i].value, description =events[i].name, date =os.date('%d/%m/%Y', events[i].updatetime), time =os.date(' %T ', events[i].updatetime), tag =events[i].tagcache }
      index = index + 1
      if events[i].value == true then
        if old_val ~= nil then
          if old_val[i].sent == false then
            eventlog('1 ' .. events[i].tagcache .. ' ' .. events[i].name) -- 1 means alarm
            update_storage = true
            update_table = true
          end
        end
      elseif events[i].value == false then
        if old_val ~= nil then
          if old_val[i].sent == true then
            eventlog('0 ' .. events[i].tagcache .. ' ' .. events[i].name ) -- 0 means ok
            update_storage = true
            update_table = true
          end
        end
      end
    end
    if update_storage then
      storage.set(tag[it] ..'_sent',old)
    end 
  end
  if update_table then
      storage.set('ALL_ALARMS',all_alarms)
    os.sleep(0.5)
    grp.update(group_address_base .. '1', 1)
  end
end

check_events(alarm_tags)

Custom Javascript:

1. Define your plan ID where alarm and event table gonna be placed
2. Edit updateTableGA address. 
Do that on both scripts...

Code:
//////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////ALARM PAGE - ALARM LOG/////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

$(function() {
  var planID = 7                                ////change this
  var updateTableGA = '51/1/1'                  ////change this
  $('body').on('showplan', function(event, id) {
      var planid = window.currentPlanId;

   
    grp.listen(updateTableGA, function(object) {
      if (object.value == true || planid == planID ){
        $(function() {
          const tableArray = [];
          var DataArray = []
          $.get( "/user/eventlog.lp", function( data ) {
            chartdata = data
          });
          setTimeout(() => {    //little delay because reading chart data file
            const lines = chartdata.split('\n');

            lines.forEach(line => {
              // Split the line by space
              const parts = line.split(' ');

              // Extract date, time, and description
              const date = parts[0];
              const time = parts[1];
              const status = parts[2];
              const tag = parts[3];
              const description = parts.slice(4).join(' '); // Join the remaining parts as description

              // Push the data to the table array
              if (date != ''){
                tableArray.push({ date, time, description,tag, status });
              }
            });

            for (var i = 0; i <= tableArray.length-1; i++) {
              DataArray[i] = { date: tableArray[i].date, time: tableArray[i].time, description: tableArray[i].description, status:tableArray[i].status, tag:tableArray[i].tag }
            }
            console.log(DataArray)

            // Function to generate the HTML structure for the table
            function generateTable(data, statusIconColor1, statusIconColor0) {
              var tableHtml =   '<table id="data-table" style="background-color: #212120;" >' +
                                '<thead >' +
                                    '<tr>' +
                                    '<th class="align-left text-col">DATE</th>' +
                                    '<th class="align-left text-col">TIME</th>' +
                                    '<th class="align-left text-col">DESCRIPTION</th>' +
                                    '<th class="align-center text-col">SYSTEM</th>' +
                                    '<th class="align-center text-col">STATUS</th>' +
                                    '</tr>' +
                                '</thead>' +
                                '<tbody >';




              data.forEach(function(item, index) {
                var statusIconColor = (item.status === "1") ? statusIconColor1 : statusIconColor0;
                var statusIconStyle = 'color:' + statusIconColor + '; text-align: center;';
  console.log(item)
                tableHtml += '<tr>' +
                  '<td class="align-left  text-col">' + item.date + '</td>' +
                  '<td class="align-left  text-col">' + item.time + '</td>' +
                  '<td class="align-left  text-col">' + item.description + '</td>' +
                  '<td class="align-center  text-col">' + item.tag + '</td>' +
                  '<td class="align-center"><span style="' + statusIconStyle + '">' + ((item.status === true) ? "⬤" : "⬤") + '</span></td>' +
                  '</tr>';
              });
              tableHtml += '</tbody></table>';

              // Create a style element and append it to the document head
              var styleElement = document.createElement('style');
              styleElement.innerHTML = '#data-table td.align-center {text-align: center;} #data-table td.align-left {text-align: left;}  #data-table th.align-center {text-align: center;}'+
                '.text-col { color: #E5E5E5 }';
              document.head.appendChild(styleElement);
              return tableHtml;
            }

                        $('#data-table').remove();
            html_code = generateTable(DataArray, '#FF0000', "#00ff00")
            var el = $('<div>' + html_code + '</div>').css({
                position: 'absolute',
                width: '750px',
                //height: '300px',
                left: '1050px',
                bottom: '100px',
                top: '250px',
                zIndex: 999,

            }).appendTo('#plan-'+planID);
          }, 500);

        })
      }
    })
  })
})

//////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////ALARM PAGE - ACTIVE ALARMS/////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////

$(function() {
  var planID = 7                               ///change this
  var updateTableGA = '51/1/1'                 ///change this
  $('body').on('showplan', function(event, id) {
    var planid = window.currentPlanId;

    grp.listen(updateTableGA, function(object) {
      if (object.value == true || planid == planID ){
        // Fetch alarm data
        $.get( "/user/all_alarms.lp", function( data ) {
          var chartdata = JSON.parse(data);

          // Generate table with alarm data after a delay
          setTimeout(function() {
            generateTable(chartdata);
          }, 500); // Adjust the delay time as needed
        });
      }
    });

    // Function to generate the HTML structure for the table
    function generateTable(data) {
      // Filter out data where value is false
      var filteredData = data.filter(function(item) {
        return item.status === true;
      });
    // Format date and time strings for proper parsing
      filteredData.forEach(function(item) {
        // Convert date from "DD/MM/YYYY" to "YYYY-MM-DD"
        var dateParts = item.date.split('/');
        item.date = dateParts[2] + '-' + dateParts[1] + '-' + dateParts[0];

        // Trim and remove leading whitespace from time
        item.time = item.time.trim();
      });
      // Sort filteredData by date and time in ascending order

      filteredData.sort(function(a, b) {
        var dateA = new Date(a.date + ' ' + a.time);
        var dateB = new Date(b.date + ' ' + b.time);
        return dateB - dateA; // Reverse order to sort newest first
      });

      var tableHtml =   '<table id="data-table2" style="background-color: #212120;" >' +
                        '<thead >' +
                            '<tr>' +
                              '<th class="align-left text-col">DATE</th>' +
                              '<th class="align-left text-col">TIME</th>' +
                              '<th class="align-left text-col">DESCRIPTION</th>' +
                                                     '<th class="align-center text-col">SYSTEM</th>' +
                              '<th class="align-center text-col">STATUS</th>' +
                            '</tr>' +
                        '</thead>' +
                        '<tbody >';

      filteredData.forEach(function(item) {
        console.log(item)
        var statusIconColor = (item.status === true) ? '#FF0000' : '#00ff00';
        var statusIconStyle = 'color:' + statusIconColor + '; text-align: center;';

        tableHtml += '<tr>' +
            '<td class="align-left text-col">' + item.date + '</td>' +
            '<td class="align-left text-col">' + item.time + '</td>' +
            '<td class="align-left text-col">' + item.description + '</td>' +
              '<td class="align-center text-col" >' + item.tag + '</td>' +
            '<td class="align-center"><span style="' + statusIconStyle + '">' + ((item.status === "1") ? "⬤" : "⬤") + '</span></td>' +
            '</tr>';
      });

      tableHtml += '</tbody></table>';

      // Remove existing table if it exists
      $('#data-table2').remove();

      // Create the table and append it to the same location
      var $table = $(tableHtml);
      $table.css({
        position: 'absolute',
        width: '790px',
        left: '105px',
        bottom: '100px',
        top: '640px',
        zIndex: 1
      });
      $('#plan-' + planID).append($table);

      // Create a style element and append it to the document head
      var styleElement = document.createElement('style');
      styleElement.innerHTML = '#data-table2 td.align-center {text-align: center;} #data-table2 td.align-left {text-align: left;}  #data-table2 th.align-center {text-align: center;}'+
        '.text-col { color: #E5E5E5; }'
      document.head.appendChild(styleElement);
    }
  });
});

Email notification part is running on another script right now but maybe I'm gonna integrate into this script in future.

Attached Files Thumbnail(s)
   
Reply


Forum Jump: