Triggered data logging

I plan an application that would log data from several PLCs via links that have variable and potentially pretty small bandwidth. Therefore, I would like to control the tags that FSQL queries and makes active in my OPC server (KepDirect), in order to limit the traffic. I am thinking that I want to use something like trigger tags to do so.

First, let me make sure I understand what I am seeing.

  1. The OPC server is always in contact with the PLCs. When a client (FSQL) asks for data, tags are activated and the data is passed to the client. When the client no longer requests data, the tags become inactive (after a time).

  2. In order for triggers to work in FSQL, the tag group(s) must be started.
    When the group is started, whether or not it is triggered, the tags are active in the OPC server, traffic is running to the PLCs, and data is updated in FSQL.

  3. The trigger only effects whether the data is logged to the database.

If this is all true, I would like the trigger to effect not only the DB logging, but also to stop the OPC-PLC traffic when the group is not triggered. Maybe the trigger can control the start/stop status of the group, or etc.

Is there a way to do this? Thanks.

Hi-

First off, I moved this from the FPMI forum to this one, since it belongs here. Hope you find it here…

Anyhow, ok: this is a fairly interesting scenario, and to be honest, I’m not sure exactly how to answer quite yet. However, let me start by commenting on your observations/explaining how it works:

FactorySQL uses OPC subscriptions exclusively to access the data. What this means is that FactorySQL says “I want point X, and I’d like to know about changes every Y seconds”. Now FSQL just sits back and waits. While the tag is active, the OPC server will handle monitoring the value, and send it to FSQL every Y seconds, if a change has occured. If there isn’t a change, nothing happens.

There is an active/inactive bit on the subscription and item level. For the most part, FactorySQL doesn’t play around with this too much: when the groups are running (or you want live values in the frontend), both the subscriptions and items are active. When values aren’t required (group is stopped), the subscription is removed. There is, however, a period of time where the subscription is made inactive before being removed. This is to avoid the overhead of removing/adding items in quick succession when a group is reloaded (happens at various time, such as right before the qroup starts logging).

Now, beyond that your observations are dead on. Triggers use OPC values, and affect logging to the db. The OPC server is always trying to maintain the current values.

What you’re looking for certainly makes sense, but again, I’m not 100% sure this second of what solution is best. My very first inclination is to say that you shouldn’t worry about how FSQL requests the data, and you should work on optimizing communication in Kepware. If you’re running your FSQL group at 5 seconds, but due to bandwidth issues you can only read value changes every 30 seconds or so, that’s fine. FSQL will get the changes as the come in. If bandwidth is costly, and you don’t want the connection to be in constant use, there may be some way of connecting it and disconnecting it on a timer. When it’s not available, Kepware will report “BAD DATA” quality for the items. It wouldn’t surprise me if kepware actually had some way to accomidate an “update schedule”, but I really don’t know about this. At any rate, as a first step, you could set up your devices and just tell kepware to poll them very slowly.

I’ll continue to think about this, but I just wanted to give you my initial response, and see what you think of it. As it is, there is no way to control whether a tag is active/inactive or to control group execution.

Regards,

There is a bit more to the eventual plan than I mentioned. I would like to control OPC traffic so that OPC server only polls tags when a user is looking at the FPMI screen that displays those data.

In other words, I want frequent data (group) updates when the data are required, and no or infrequent data updates when they are not.

From your explanation, is it possible to programmatically (FPMI) control the start/stop status of the group, or the subscription bit?

Two other potential methods to do this - is either of these possible?

  1. The group data rate in FSQL could be controlled via trigger bit.

  2. My OPC server (KepDirect for PLCs) has a system bit to enable/disable Kep tag groups. I am able to “write value down” to that tag via FSQL. Can I write to that bit via FPMI?

Thanks.

I am indeed able to write to the OPC server enable/disable bit via FPMI, so I have a method to get this done.

Still, I would prefer to be able to control the FSQL group start/stop status. Any way to do this via FPMI or trigger bits in FSQL?

Ah, good find on the tag group enabled bit. I think that’s going to be your best bet. Using those tags and some well-planned scripting I think you could create a pretty slick system in PMI where only the groups needed for a specific window are active.

Now, as for FSQL: the short answer is that right now, you can’t control the logging. I’m still not sure you would want to if you could, though. There’s a fair amount of overhead in starting and stopping groups, so the response time is going to be slower than simply enable/disabling your tag groups. With that said, the idea of being able to control the subscription state or the update rate may not be a bad idea. It’s not possible right now, but it’s been discussed before (at least the update rate portion), so it might find its way in soon.

Still, there may be a fair amount of flexibility with what you have now. Since you have those bits to control tags, you can do stuff like:
-use them as triggers to only run groups when the tags are active
-write to them from a control group that is “smarter”- ie. looks a table of active windows & a schedule to decide if they should be active or not
-loops through and runs each one for a certain amount of time

…and so on. Are there any other ideas/requirements you had in mind that wouldn’t be covered by these cases? Let me know if you have any question about these ideas.

Regards,

This will keep me busy for a while. Thanks.

Here’s what I came up with to achieve this. It seems to work quite well, although it’s nothing like rigorously tested. And thanks to Nathan for all his help.

  1. Create a database table ‘Control’ containing two data for each OPC group that you intent to enable/disable.

-Boolean ‘WTxEnabled’ where x distinguishes the group[/list]
-Datetime ‘WTxDisableTime’[/list]

  1. Create a separate FSQL group containing, for each OPG group to enable/disable:

    • An OPC item referencing the ‘project.device._system._enabled’ bit from the OPC server
    • An action item containing SQL query of the form
      'SELECT if(CURRENT_TIMESTAMP < WTxDisableTime, 1, 0) FROM control'
      and storing the result in ‘WTxEnabled’
  2. Insert the same OPC item (referencing the ‘project.device._system._enabled’ bit) into each OPC group to be enabled/disabled, and trigger the group on this bit.

  3. Create a global script module ‘package.module.updateDisableTimer()’ to create a SQL query and run it.

    # Update the time when the current window data logging will be disabled def updateDisableTime(currWindow): import fpmi query = 'UPDATE Control SET ' + currWindow + 'DisableTime = DATE_ADD(CURRENT_TIMESTAMP, INTERVAL 10 MINUTE)' fpmi.db.runUpdateQuery(query)

  4. Create a global event timer script to periodically run the SQL query from item 4

    current_window = app.nav.getCurrentWindow() if current_window == "WT1": package.module.updateDisableTime(current_window) elif current_window == "WT2": package.module.updateDisableTime(current_window) elif current_window == "Start": package.module.updateDisableTime("WT1") package.module.updateDisableTime("WT2") etc

  5. Create an internalFrameActivate event action in each window to run the global script immediately when a window is opened

    app.SAL1.updateDisableTime("WTx")

Now, when a window is opened,
- the WTxDisableTime is updated to 10 minutes from now, via the internalFrameActivate event
- since WTxDisableTime > CURRENT_TIMESTAMP, the FSQL action item sets WTxEnabled to TRUE
- WTxWnabled enables the group in the OPC server, and also triggers the FSQL group to log data
- The global event timer script periodically moves the updates WTxDisableTimer to 10 minutes from now
Note that this update only happens for groups required by the current window

When the window is closed, after 10 minutes the OPC group is disabled and the FSQL logging ceases.

Note that this only works when, like my application, just one window is open at a time, since it references the ‘current_window’ variable from the app.nav module and only updates data from the group(s) referenced in the timer script by the current window.

Too much fun. Hope this helps someone else. And thanks again Nathan.

I suppose to expand it out you could turn current_window into current_windows (a list), and have global functions that maintain it:
WindowOpened(X) - Adds window to list if not already there
MaintainList() - Gets called periodically and uses fpmi.gui.getOpenedWindows() to get all of the currently open windows and checking that list against current_windows, removing the items that are no longer open.

Then you would call your update function for all of the windows in the current window list.

Anyhow, this sounds pretty neat. Glad you and nathan we able to get it up and going!

Later,

It works really well - it’s pretty clever. Note that he’s using the Navigation Script Module from the goodies page. Kudos to Kepware for the Disable register.