Curiosity? Gateway Timer Event Scripts

Hey there community!

I was just curious at how many scripts Ignition can handle before "bogging" down the system. I have around 25 scripts. Only 18 are timer scripts that run every second. At what point is too much for the system? I use fixed delay and shared threading.

Just wondering what some of your projects look like and how many gateway scripts people are using for funsies! Are people up in the 200s??

Thanks for the boredom chat :slight_smile:

You can add some instrumentation to your scripts to see how long they are taking to execute (java.lang.System.nanoTime()). From that and knowing the number of cores in your system, you can extrapolate to an upper limit.

On a well provisioned server, with well architected scripts, you can comfortably have tens to hundreds of gateway event scripts. I wouldn't go beyond that, well before hitting technical restrictions, simply because it would be an absolute maintenance nightmare. Nothing in the project UI is designed around projects with that many resources, and working in them would be an absolute slog. I would also question the overall design of such an overstuffed project.

1 Like

(post deleted by author)

I think that the 'bogging' down would not be directly determined by the number of scripts, but by the processing that those scripts require and that is occurring in them, you can have just one that crashes your gateway or you can have hundreds with no significant effects during their execution.

You mention that you have 18 running at 1 second, do you really have to run all of those every 1 second, would the system really be affected if they run at 1.5s, 2s, etc..? The largest amount of resources that you can save and disperse will be better for your gateway.

On the other hand, only as a thought without foundation, thinking about having 200s of gateway scripts as timer scripts or similar sounds like it might not be the best approach, I don't know the context, but you could evaluate the option of using tag event scripts.

As a matter of interest, what are these actually doing? There may be a much more efficient way of doing this.

Thanks for the responses.

I am using a gateway timer script that runs every second as a counter mechanism for a boolean tag.

When the boolean value is true, then start counting up in seconds, like a RTO feature on the PLC side that holds how long the value has been true for total duration on. Yes, I know it would be easier to just do this in the PLC and I have before, but I wanted to see if I could do this only on the Ignition side without PLC involvement. I do not have the SQL module purchased for transaction group method. I do have tag historian but could not figure out how to use the query Tag Historian DurationOn feature over a period of time and write to new tag value to retain the count in seconds on per say.

I am totally open to new ideas and a better way to achieve this.

Single Gateway Tag Change Event script.

On boolean transition to high, write a timestamp to a tag, have another expression tag pointed at the timestamp tag and do date math to determine delta in seconds. Something like dateDiff(now(), {booleanOnTstamp}, 'seconds')

Only show the value from the expression tag if the boolean is on. Or you could add an if statement to the expression tag to show 0 when the boolean is off.

Each of your booleans would have an associated timestamp and time delta tag with it. Folder structure would work or you could make a UDT.

Edit: Whoops its an RTO not TON. See pturmel's response.

1 Like

As Ryan suggests, don't count in a timer event. The timing is not very precise.

To get retention of prior time, you need at least two timestamps to hold state, updated when the signal changes. A stop timestamp, and an adjusted start timestamp. The start timestamp needs to be adjusted backwards from now() by the amount accumulated before.

Drop these tags into a test folder to see how to set this up:

{
  "tags": [
    {
      "valueSource": "expr",
      "expression": "if(\n\t{[.]RTO_Reset},\n\t0.0,\n\t0.001 * dateDiff(\n\t\t{[.]RTO_StartTS},\n\t\tif(\n\t\t\t{[.]RTO_Signal},\n\t\t\tnow(250),\n\t\t\t{[.]RTO_StopTS}\n\t\t),\n\t\t\u0027ms\u0027\n\t)\n)",
      "dataType": "Float8",
      "name": "RTO_Accum",
      "formatString": "#,##0.000",
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "memory",
      "eventScripts": [
        {
          "eventid": "valueChanged",
          "script": "\tnowTS \u003d system.date.now()\n\tif currentValue.value:\n\t\t# Signal is true.  Write the current timestamp to both state tags.\n\t\tsystem.tag.writeBlocking([\u0027[.]RTO_StartTS\u0027, \u0027[.]RTO_StopTS\u0027], [nowTS, nowTS])\n"
        }
      ],
      "dataType": "Boolean",
      "name": "RTO_Reset",
      "value": false,
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "memory",
      "eventScripts": [
        {
          "eventid": "valueChanged",
          "script": "\tresetting, startTS, stopTS \u003d [qv.value for qv in system.tag.readBlocking([\u0027[.]RTO_Reset\u0027, \u0027[.]RTO_StartTS\u0027, \u0027[.]RTO_StopTS\u0027])]\n\tif not resetting:\n\t\tnowTS \u003d system.date.now()\n\t\tif currentValue.value:\n\t\t\t# Signal is true.  If stopTS is after startTS, the new startTS must\n\t\t\t# be moved back before nowTS by their delta.\n\t\t\tif stopTS.after(startTS):\n\t\t\t\tpriorMS \u003d stopTS.time - startTS.time\n\t\t\t\tsystem.tag.writeBlocking([\u0027[.]RTO_StartTS\u0027], [system.date.addMillis(nowTS, -priorMS)])\n\t\t\telse:\n\t\t\t\tsystem.tag.writeBlocking([\u0027[.]RTO_StartTS\u0027], [nowTS])\n\t\telse:\n\t\t\t# Signal is false.  Just write the current timestamp to stopTS\n\t\t\tsystem.tag.writeBlocking([\u0027[.]RTO_StopTS\u0027], [nowTS])\n"
        }
      ],
      "dataType": "Boolean",
      "name": "RTO_Signal",
      "value": false,
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "memory",
      "dataType": "DateTime",
      "name": "RTO_StartTS",
      "formatString": "yyyy-MM-dd h:mm:ss aa",
      "value": 1740157975856,
      "tagType": "AtomicTag"
    },
    {
      "valueSource": "memory",
      "dataType": "DateTime",
      "name": "RTO_StopTS",
      "formatString": "yyyy-MM-dd h:mm:ss aa",
      "value": 1740157975856,
      "tagType": "AtomicTag"
    }
  ]
}

In the accumulator expression tag, adjust the now(250) to the update pace you want.

Edit: If you do many of these, move the two scripts to functions in the Gateway Scripting Project's library, so the tag events can be one-liners.

1 Like

If seems like you should be able to create a runtime expression tag with an expression like this:

coalesce(
if({[.]running},{self}+1,{self})}
,0)

and have it increment when the tag group executes and the 'running' tag is true. But I don't know how to get it to work.

That's what I suspected and that's why I asked. As others explained it's not a Great PlanTM and the expression wouldn't run exactly on 1000 ms so there would be an error.

That would be a circular reference, and typically blows up on a null on gateway startup.

Thank you. I will work on this and see if I get it working. I have one time stamp tag already for the start time, but never thought about adding another one for stop time to capture that duration.