On tag change, rising edge of "[default]Tray_Trimming_Cell/New_Fault_Trigger", I want to take the current date/time, store in 2 different formats, then write one set to 2 tags.
Then I have a dictionary of tag values and the other set of formatted date/time to send to database via a Named Query.
I know that my gateway event tag change script and named query are functional as I can toggle the 'New_Fault_Trigger' bit in the PLC and everything functions as intended, but when I have the designer closed, nothing seems to function; isn't this why we use the gateway script in the first place?
I'm sure that there's something very basic that I'm missing here but I could do with a push in the right direction.
Lastly, is this the 'cleanest' way of going about what I am trying to achieve or is there a more efficient route?
Why are you importing datetime? Use the native system.date functions
Why are you using sleep?
Unless you are working in 7.9, system.tag.read is obsolete. You need system.tag.readBlocking. You should make a single call of this function to your list of tag paths rather than several sequential calls
What's the reason for the fault time needing to be converted into two separate strings and then stored in tags? You would typically want to store this as a date time type and then apply formatting to the component where you are displaying the value
I used the sleep because values such as length, width... were referencing query tags: Trim_RFID is an OPC tag then product data would be returned into query tags. Also, the tag groups were leased as they shared a UDT with a 'Fault_Storage' array sent from a FIFO arrangement in the PLC. I have now given 'Fault_Last' its own driven tag group via 'New_Fault_Trigger', removed all query tags from the script and added SELECT subqueries in the Named Query.
Changed to readBlocking - I knew this but for some reason decided to un-know this!
Valid points.
# Read current value
currentvalue = event.getCurrentValue().getValue()
# Run script on falling edge of trigger
if currentvalue == False:
# Store DateTime
currentDateTime = system.date.now()
# Tag path prefix
tagPre = "[default]Tray_Trimming_Cell/Fault_Last/Fault_Last/"
# Define tag list for tag read
tagsSQL = [
tagPre + "RFID/Trim_RFID",
tagPre + "Fault_Name",
tagPre + "Downtime_Secs",
]
valuesSQL = [system.tag.readBlocking([tag])[0].value for tag in tagsSQL]
# Define parameter dictionary for Named Query
params = {
"DateTime": currentDateTime,
"RFID": valuesSQL[0],
"Fault": valuesSQL[1],
"DowntimeSecs": valuesSQL[2],
}
# Run the named query with the specified parameters
system.db.runNamedQuery("INSERT/Add Tray Trim Fault", params)
INSERT INTO TrayTrimFaultLog
(
DateTime,
RFID,
Fault,
DowntimeMins,
Description,
Family,
Length,
Width,
Carrier,
Feature1,
Feature2
)
VALUES
(
:DateTime,
:RFID,
:Fault,
:DowntimeSecs,
(SELECT Description FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Family FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Length FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Width FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Carrier FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Feature1 FROM RFIDTag WHERE RFIDTag = :RFID),
(SELECT Feature2 FROM RFIDTag WHERE RFIDTag = :RFID)
);
Thank you for your input, this is my first attempt at any data handling with ignition and I've already learned plenty from revising this... however, will this solve my initial problem? I'll test soon but I fear not, I have just applied better practice to my approach thanks to you.
There is a special newValue variable available in the gateway tag events.
Instead of doing the inequality check against False, the more “pythonic” way to write it would be:
if not newValue.value:
#do something
Jython will convert standard getters into named attributes, you should try to take advantage of these when you can as they are more performant.
For instance
event.getCurrentValue().getValue()
is less performant than
event.currentValue.value
Both will retrieve the same value
You have an extra trailing comma in both the tagsSQL declaration, and the params dictionary. Im not certain if the code would even compile like that.
The tagsSQL list declaration can be written like this:
tagsSQL = [tagPre + path for path in ("RFID/Trim_RFID", "Fault_Name", "Downtime_Secs")
Makes it a bit easier to add tags in the future.
The comprehension for values is backwards, you want to only call the read function a single time, yours will call it for each item in the list. The much more performant way to write this is:
It isn't explained by any of this, you're right, but I've just tested and I'm now logging to the database as expected with the designer closed and no other sessions showing active on the gateway status page.
I've completed logged out of the development environment on the VM and it is still functioning as intended.
I'll definitely take this advice onboard for future debugging.
1/3: So you're essentially eliminating the middleman and making the script more efficient, but still achieving the same outcome?
2. This makes sense. Was there any need for the == True in the first script or would 'if currentvalue:' have sufficed?
4. This did compile and run fine, but commas now deleted. Left over from removing the extra tags that are no longer required!
5. I clearly need to learn to use loops to eliminate repetition - can you tell that I'm quite new to this? Adapted.
6. So you can insert lists into the read function, handy. From your explanation and reading the code, I can completely see how this is more performant but I would have never imagined doing it this way.
I've learned a lot tonight and vastly improved my code in more ways than one. The real test is storing all this knowledge in my own database up top and then querying it whenever needed!
Not only can you, it is the intended way to call the function. They have included a special shadowed case so that calling the function with a single string will still function, but using a list is the best practice, and in this case significantly more performant.