Logging downtime

Hey everyone,

I've been stuck on a task for some time and can't seem to find any raised topics on this - if I've just missed them, I'm really sorry.
I want to log how long a machine is not operated during change-overs and we currently don't have any specific signals for the start and end of this process, so my solution is to measure the time between OEE drop below 20% and then jump back over 20%. I've created a transaction group and made an hour meter for this, but the problem is with logging it - I've set the table action to insert a row, but it keeps addidng every second. How could I log the settled value only?

Thanks in advance.

When, and where, do you want to log it ?

I want to log every time the counter stops and only then, for ex.: currently the machine has been stopped for 15453 seconds due to a cleaning procedure, currently it gives 15 thousand lines on every second, while I want only the 15k value logged - just to get how long the machine was down and at what time. Where - in a DB or another tag, I'm not sure - my end goal is to present the values on a table, to showcase how long changeovers take.

If you're using the historian, you could historize the tag you're using, and simply process the history when you want a report.

Otherwise, I'd create a boolean tag, let's call it notOperated that monitors your OEE and becomes True if OEE is under 20, something like this:
Then you can use this as a trigger, and its timestamp to calculate how long it stayed True.

That is almost precisely what I have done - I have created a tag, that is true when an alarm on OEE is active, I then created a transaction group to have an hour meter:

The problem with this is how it writes the meter to a DB:

It adds a new row every time a second is added. How can I log the end, settled value, when the machine turns on again?

Use a tag change script (I'd go for a gateway event, but a script directly on the tag would also work). You may or may not need a secondary tag to store timestamps, as I don't remember if the previousTimestamp is available in tag change scripts.

The problem is likely how you have the Transaction group configured.

What are you using as the trigger?

In the trigger tab I haven't set anything in particular if that is what you are asking

I just have a tag that becomes true when OEE is below 20, and that automatically becomes false when OEE is back over 20

You should set you transaction group up so that this tag is the Trigger.

Add it to the group as an Item if you haven't already, set the option to execute this group on a trigger, and then set the Trigger on Item to the item that is bound to this tag.


  • Only execute once while trigger is active
  • Prevent trigger caused by group start (unless you want that to happen)
  • Active on value change

You could also use the actual value as the trigger, but I find it is clearer to use a boolean tag as a trigger, especially since you already have one.

This should make it so that the transaction is only triggered when your trigger tag changes, then you can use SQL to calculate the difference between when the records were stored.

Right now the transaction is triggered when ever any tag in the group changes, resulting in a record for every second.

1 Like

Thank you for your detailed answer. However the part I am struggling with is precisely the one you skipped over :smiley: I am struggling with differentiating the values from SQL, as the transaction group stores the hour meter every second that it is active, and I only need the value when it becomes false again.

This should prevent your data to be logged every second. It would log it just once.

Oh, sorry, my bad for reading that wrong.
I tried making the trigger and I do manage to get a singular value, and I'm really sorry for bothering you guys so much, but I with the trigger I am stuck on the fact, that if I create the trigger to be activated when the value is true, it writes a singular first second, not the last, and if I make it write when the tag becomes false, it only writes zero (tried battling this with making the seconds retentive, bet then the trigger doesn't go off, because the value isn't zero)

I recommend you not use the hour meter. It is meant for use with repeated recordings.
Instead, use an "Any Change" trigger and just log the current value. You can extract the durations from the timestamps using SQL LEAD() or LAG(). Some examples:

And more here.


Would another option be to use the transaction group - Standard Group rather than the Historical Group.

I've done this when recording batch data to our database. It has the option to either update an existing database entry or create a new entry. In this case you would need another tag to differentiate one downtime event from the next.

Another option would be to think about logging in a different way. I capture downtime events by having a tag setup to monitor or calculate the status for a piece of equipment. When the downtimeEventActive tag turns on indicating a downtime event started the tag script copies the current time to a eventStartTime tag. When the tag turns off it copies the current time to a eventEndTime tag then subtracts the eventStartTime from the eventEndTime to get a total duration of the event. Finally, the script adds one to a transaction trigger that is setup to trigger a Transaction Group to store the desired tags to a database.



Is it okay, instead of using transaction group, if we enable the 'Tag history' on that tag whose downtime/uptime is to be monitored and then use SQL query to get the duration?

Querying tag history with your own SQL is very complicated. The tag historian's bindings and scriptable query tools do not have the equivalent of LEAD() and LAG(). A dedicated table for events, using either the SQL Bridge module (transaction groups) or scripted inserts, will be much easier to work with.

@Shaheryar_Ahmad Personally I would rather use tag history and then get the data back by scripting. As Phil suggested, use SQL queries for tag history data can get hairy, but using tag history and scripting is rather simple IMO.


Okay I have done the same, enabled tag history on a tag named 'OnState_Button' and then use a script on this tag (on value change) picture below.

Issue is, the system.tag.writeBlocking is not storing duration output value into the other tag.

When seeking help about something that doesn't work, it's usually a good idea to make it clear what behavior you're observing. Like, error messages, etc.

But don't use spaces in tags names. As a general rule, if it's not a valid python variable name, it's not a good idea to use it for a tag name.

1 Like

Don't run the query in the tag event script. Run it in a timer event with dedicated thread, to update your duration tag steadily even when the state tags aren't changing.