# Opc read values efficiency gains or better approaches

**URL:** <https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [July 3, 2025, 1:39am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081 "2025-07-03T01:39:26Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tanda](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tanda/32/19154_2.png) [@tanda](https://forum.inductiveautomation.com/u/tanda)\
**Post date:** [July 3, 2025, 1:39am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/1 "2025-07-03T01:39:26Z")

</div>

I am interacting with an Allen Bradley PLC to gather data from equipment it is controlling. The basic setup is the PLC gathers information from the process and alerts Ignition with a handshake tag. Ignition stores data in database and resets the handshake. Only five values are exchanged (three of them are strings that could be about 900 bytes long). The code below executing in a tag change scrip is my current approach. **I'm looking for advice on any efficiencies or completely different approaches**. The turn around on this handshake is a few seconds and it's really adding up in the process time. I've thought of splitting the db write off in a separate thread so I can get right back to the PLC. However, it seems that it's the OPC reads/writes that are dominating the time.

```python
def valueChanged(tag, tagPath, previousValue, currentValue, initialChange, missedEvents):
	
	# if the send tag change isn't from a restart and has just changed to true
	if((initialChange != True) and (currentValue.value == True)):
		# read the sent seqence number, increment it, return it and acknowledgement that we are in process
		sequenceResponse = system.opc.readValue("Ignition OPC UA Server", "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Cmd.SeqNum").value + 1
		taglist_1 = ["[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.Ready",
				   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.Done",
				   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.AckNum",
				   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.AckSend",
				   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.IP"]
		valuelist_1 = [False,False,sequenceResponse,True,True]
		system.opc.writeValues("Ignition OPC UA Server", taglist_1, valuelist_1)
		
		# capture the job number and weld data with direct opc reads from PLC
		taglist_2 = ["[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].JobNumber",
		   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].WeldSummary",
	 	   "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].VoltageWF",
	       "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].CurrentWF",
	       "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].WeldX",
	       "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldData[0].WeldY"]
		
		qualifiedList = system.opc.readValues("Ignition OPC UA Server",taglist_2)
		
		jobNumber = qualifiedList[0].getValue()
		weldSummary = qualifiedList[1].getValue()
		voltageWF = qualifiedList[2].getValue()
		currentWF = qualifiedList[3].getValue()
		weldX = qualifiedList[4].getValue()
		weldY = qualifiedList[5].getValue()
		
		# insert values into the weld database
		parameters = {"welderID":40,"jobNumber":str(jobNumber),"weldSummary":str(weldSummary),"voltageWF":str(voltageWF),"currentWF":str(currentWF),"weldX":float(weldX),"weldY":float(weldY)}
		system.db.runNamedQuery("SPM_LineControl","Insert_Weld_Raw",parameters)
			
		# signal that we are no longer in process, done and ready for next weld
		taglist_3 = ["[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.IP",
					 "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.Done",
					 "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.AckSend",
					 "[Z1000_PLC]Program:Supervisor_PalletData.p_WeldReq[0].Stat.Ready"]
		valuelist_3 = [False,True,False,True]
		system.opc.writeValues("Ignition OPC UA Server", taglist_3, valuelist_3)

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 3, 2025, 1:53am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/2 "2025-07-03T01:53:32Z")

</div>

That is a tag's `valueChange` event, which is not a safe place to use any `system.opc.*` functions--you risk locking up all tag event processing. Similarly, it isn't safe to do DB operations either, except for fire-and-forget inserts through the Store and Forward system. Finally, it is usually racy to use a single handshake tag--use two, one only written by the PLC, and an echo that is only written by Ignition.

The correct place for such busy and dangerous code is a project library script function called from a tag change event in a project's gateway events. (Not on the tag.)

Finally, you need to investigate how well your device is actually performing, comms-wise. While AB Logix PLCs tend to support way more comms than other brands, in my experience, it is rather easy to screw that up with poor architecture (in the PLC) and with certain kinds of newbie mistakes (drag-n-drop of all the PLC tags from OPC browser to Ignition Tag Browser being #1).

Do you even know if your PLC comms are overloaded? (Device diagnostics.)

Some reading (follow links, too):

> [@Ignition & Logix Best Practice Tips for better communications](https://forum.inductiveautomation.com/t/ignition-logix-best-practice-tips-for-better-communications/60386):
>
> Hi All, After a whole bunch of issues I have gone down the rabbit hole of what is wrong with our setup on site. I will preface this by saying I a relatively new to all of this.... so be gentle stuck_out_tongue Based on much reading(such wow) I believe I have a list of things our site could take away for a better system. Some of them are easy to implement, whilst some of them need... significant work to realize. Especially the AOI approach in point 5 expressionless Before going too far a…

---

<div class="post-metadata">

**Author:** ![tanda](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tanda/32/19154_2.png) [@tanda](https://forum.inductiveautomation.com/u/tanda)\
**Post date:** [July 3, 2025, 2:50am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/3 "2025-07-03T02:50:00Z")

</div>

Phil,

Thanks for the quick response and advice, as always. I will move the code to the project library and initiate it from a gateway tag change. Vendor is responsible for the PLC side but I'm headed off to read the thread that you linked and maybe we can shore this up. Hopefully I can find some efficiencies along the way as this interaction is bogging down the whole process.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 3, 2025, 3:10am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/4 "2025-07-03T03:10:06Z")

</div>

Reading a KB or two of mostly strings should take a dozen or so milliseconds, and following writes would be similarly quick. I suspect your difficulty with this task is because your comms are already badly overloaded.

---

<div class="post-metadata">

**Author:** ![Chris\_Bingham](https://avatars.discourse-cdn.com/v4/letter/c/e5b9ba/32.png) [@Chris\_Bingham](https://forum.inductiveautomation.com/u/Chris_Bingham)\
**Post date:** [July 3, 2025, 4:02am UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/5 "2025-07-03T04:02:19Z")

</div>

> [@tanda](#):
>
> or completely different approaches

Is interrogating the PLC an option?

I find it interesting that the PLC requires a handshake here at all…just to ensure that the recent data/job is stored to a DB? Any other reason?

---

<div class="post-metadata">

**Author:** ![tanda](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tanda/32/19154_2.png) [@tanda](https://forum.inductiveautomation.com/u/tanda)\
**Post date:** [July 3, 2025, 4:45pm UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/6 "2025-07-03T16:45:59Z")

</div>

PLC is talking to a welder to gather information that gets overridden with each weld. The handshake is to let Ignition know there is data to offload, before the next weld overrides it. The PLC could buffer this but going in we didn't anticipate the interaction taking very long.

---

<div class="post-metadata">

**Author:** ![tanda](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tanda/32/19154_2.png) [@tanda](https://forum.inductiveautomation.com/u/tanda)\
**Post date:** [July 10, 2025, 9:07pm UTC](https://forum.inductiveautomation.com/t/opc-read-values-efficiency-gains-or-better-approaches/108081/7 "2025-07-10T21:07:46Z")

</div>

Just a quick follow up to close out the thread for those who might find it in the future.

Yes, the PLC com was very overloaded. Moved the routines to the Project Library and called them from a gateway tag change script which was a necessary clean up. However, the big win was from increasing max concurrent connections and basically eliminating all of the tags (except those monitored by the tag change script) and scripting all of the remaining Ignition to Rockwell PLC interactions through system.opc.read/write calls in the Project Library scripts.
