Send a message from a gateway script to the perspective sessions

I have a machine that gets queried via OPCUA at a fixed, regular rate (say 1 second).
This is done through a Gateway Event of my project.
Every now and then (say 10 minutes) the the machine returns new data (it's a 'slow' process).
When new data data are available, they get saved on the database by the gateway event script.

The problem

And here is the problem: after saving the data I want that the perspective session (or sessions) of the project get updated to show the new data.

I don't want to query continuously the database. Infact, if I want the refresh to be prompt, the query rate should be hi (say 1 second) but since there are no new events but every 10 minutes, doing so I would put an high pressure on the database for little result, that is inefficient and potentially problematic for the other applications running on the same database.

Possible solution based on messages

Usually, the solution to this kind of problem is to have some type of message to be sent from the source (Gateway Script) to the application that needs to know that there are updates (perspective sessions).
So, the first question is: does Ignition offer specific support for this scenario? If not, is there a best practice that states how to cope with this problem?
My self-thought solution involves using a memory tag as a signal method, this would be set by the gateway script and queried in someway by perspective sessions; but I would like to hear from you regarding my previous question.

A memory tag that you update just after the data is saved in the database is probably the simplest method. (I would use a datetime memory tag and write system.date.now() to it.) The consumers in the UI would use a tag binding on a session or view or component custom property, with a change event to perform the necessary UI operations to redisplay content (probably a .refreshBinding() method call where the named query resides to make it run again).

The only downside to the memory tag approach is that binding evaluation will likely double-execute the query on view startup.

A more complicated approach that avoids that problem would be to broadcast a message after saving in the database, and having message handlers cause the content redisplay. Take a close look at this topic, and the behavioral differences between system.util.sendMessage() and system.perspective.sendMessage() in regards to gateway scope broadcasts:

1 Like

I went searching the forums to see if what I just did was okay:

I needed all perspective sessions to update a page (if it's open of course) when an item is added to a database through a vision client.
So I sent a message to the gateway using system.util.sendMessage, caught that in the gateway events, then dispatched a message like this:

for session in system.perspective.getSessionInfo():
    system.perspective.sendMessage('handler', scope='session', id=session.id)

Any thoughts on this ?

You might want system.util.sendMessage(...., scope='S'), but I'm not sure.

I'd use a memory tag bound in the pages that matter--have the gateway message handler set it (latest timestamp, perhaps). Or the vision client can update it. Only pages that care will notice, and Ignition will distribute to anyone who cares. (Other Vision clients, too, if it matters, and viewers connected via remote tag providers.)

1 Like

I used system.util.sendMessage(..., scope='G'), assuming 'sessions' in this case would be vision clients... is there a way to send a message directly to perspective sessions from vision ?

I don't know. Try scope='S' from Vision.

But then, I'm not terribly invested, as I'd use a memory tag as the sentinel. :man_shrugging:

1 Like

The system.util.sendMessage function allows for sending to only Perspective Sessions with a scope arg value of "S".

That being said, it seems like notifying sessions of some change in data is less efficient than simply updating some tag with the information, and having all sessions bound against the tag.

If you're writing your data to a database table, you could use a Query Tag, but this refreshes/updates at some fixed rate. You could use a DataSet Memory tag, and write to the Tag after you've updated the database table based on a query of the table.

# event occurs (machine update)
tagPath = "[provider]SomePath"
system.db.runPrepUpdate(...)  # update DB
system.tag.writeBlocking([tagPath], [system.db.runPrepQuery(...)])  # write to tag

This eliminates the need to to actively notify potential interested parties (sessions) and instead allows them to simply be passive observers of some value.

1 Like