Tag indirection in OPC item path for Multiple PLC's

We have several machines that are identical and run off of one central gateway. The gateway has multiple PLC’s and we are trying to avoid making multiple ignition projects. Is there a way to use the same project on different clients and have tag indirection at the opc item path ?
For example, have a client tag that looks at the host name and determines the machine number. Then, that machine number can be used for indirection in the opc paths for the plc tags. like [Machine {1}][Diagnostics]/Is Connected

Having one project just makes it easier to troubleshoot or make edits.
Thanks !!

1 Like

You can’t use indirection at the OPC item level. However, you can certainly set up folder of Tags for each machine, using the same name for identical purposes in each folder. Then you can use Indirect tags in a single project where the folder name is substituted. This approach applies to multiple machines with identical PLCs, and to multiple processes within one PLC that have the same structure. Set up all the tags in folders with consistent naming patterns, then make one window for all folders with that pattern.

I guess I can make Folders for all six machines. That will certainly work. I thought there would be an easier way than having to create folders and drag tags for all six identical PLC’s. Thanks !!

You can, you have to make a UDT for the tags. Then, you can make instances of your devices just by changing a udt parameter. Have you completed that section on IU yet?


I have this exact scenario, but I will have up to 40 identical systems, each with its own PLC and HMI client. Most will be served up from one gateway. There may eventually be a couple gateways, but still the same concept.
I guess I don’t quite follow the part about “make one window for all folders with that pattern”. Wouldn’t I have to have indirect tags on every button, display, label, graphic, property binding, etc then change the indirect pointer tag by identifying the client on each station on startup? Seems pretty cumbersome. Is the UDT method perhaps a better route? I have used quite a few UDTs in previous projects, but not sure how I would implement it for this.
The project will have around 10 to 15 windows and at least a couple hundred tags or potentially thousands of tags depending on how PLC development goes. Thanks.

Make a UDT and instances for each device. Using parameters, you can make the UDT instances easy to configure (probably just one parameter to change per device), and you can make (and edit if they change during development) 400 as easily as 4 via scripting (system.tag.configure).

And yes, use indirect bindings on everything so the client has one value that indicates which device to connect to (something like rootTagPath) that is used in all the bindings. This is a common way to create templates; in your case you’re making the whole project work somewhat like a template.


Thanks witman. So i know that if you rename or delete a tag that is used in windows or scripts, it essentially breaks everywhere the tag is used and you have to fix. And there still is no global find (in 7.9.9 anyway). But can I add parts to a UDT without breaking parts that are already used? I suspect I will create a UDT for the machine, then create the first instance of that, then I will need to add to the UDT very many times before the project is complete. You never know every single tag (or UDT element) that might be needed when just starting a project. And I guess the Indirect on all objects would point to the correct instance of the UDT for a given machine, based on the client ID. I think I see the path forward. (more complex than I would like, but better than the alternative of maintaining 40 projects).

Yes, and–as you note–renaming would require updating the indirect bindings affected by the renaming. If you’re renaming what I call the rootTagPath (the part that is part of every indirect path), you can make this easy by putting it in one custom property on the window and then having every indirect binding reference it from there. Update that property and all other bindings are updated as they refer to it.

The above doesn’t help you if you’re renaming the stub that makes up the end of the path, but there’s another strategy which can simplify things in some cases. Create custom properties on the window for every tag used on the window. Put your indirect tag bindings on these properties, and then bind all components (and make script references) directly to these custom properties. This way all your indirect bindings are in one place; you can update one binding to fix all component bindings and scripts that would’ve been affected had you bound them all indirectly to the renamed tag.

I use the above strategies on nearly all templates–pass in a rootTagPath as a parameter, and then do all the indirect bindings on internal properties. It allows a lot of flexibility and makes maintenance easier in my experience.

Fortunately I don’t have to change the end of path. As I understand it, first I would create a UDT such as BoatTags and within that UDT is a parameter that would be Device which will represent my OPC Device on the Gateway, which will point to the specific PLC. Inside the UDT would be all OPC tags I might need, and even memory tags or expression tags. In the OPC tag setup inside the UDT, the Device parameter would be part of the OPC path statement, such as ns=1;s=[{Device}]Pump.fault. I would create a Client Tag (string type) and have startup script put the correct Device name in it based on HostName. Then I might create another Client Tag (string type) called rootTagPath and in my startup script I can use HostName to put a derived value in the Client Tag rootTagPath which is the instance name of the UDT. On each window, i can make a custom property also called rootTagPath and bind it to the [Client]rootTagPath tag. Then on each object on my windows I can use Indirect tag binding such as VIP/Boat{1}PumpSts where {1} refers to Root Container.rootTagPath. Seems doable.

Yes, that sounds about right. :+1:

1 Like

Related to this, can i have indirect paths in a client tag change script? I tried this in the TagPaths and it didn’t like it. PBX/Water/{[Client]rootTagPath}/Main_HMIContinueBtn where rootTagPath is my variable pointer.

Later, I figured out if I make an expression tag in Client tags with the expression tag(“PBX/Water/” + {[~]rootTagPath} + “/Main_HMIContinueBtn”) that I can then use that Client tag in the Tag Change TagPaths list. Seems kludgey, and I thought it should work. But in fact, the Client tag will NOT trigger the Tag Change Script. I tried with a regular memory tag and that triggers it, but the Client tag absolutely will not. It checks out as valid in the Tag Change script editor. It is like Client Tag Change script does not recognize Client Tags even though it let me put it in there and accepted it.

In the Client Event Tag Change script, yes, but not in the list of tags that trigger it. So you’d want to list all the PBX/Water/*/Main_HMIContinueBtn variations in the tags list and then check within the script that the changed tag matches the one you’re looking for. Something like this (untested):

rootTagPath = system.tag.read('[Client]rootTagPath').value
if event.getTagPath().toString() == 'PBX/Water/%s/Main_HMIContinueBtn' %rootTagPath:
	# Do something.

I considered that approach, but we have not yet created all the instances of the UDT that rootTagPath will represent. We will be deploying about 50 of these over the next couple years, but today I only know the name of units 1 and 2. I can go this way, but will have to add the new hard path for each variation in the tags list as each new unit is brought online and the new UDT instance is created. I was hoping that the only thing I have to do for each new unit is create the UDT instance.

The other option I considered is to do this script on the tag itself (Tag Event) in the UDT. Then the script is deployed automatically with each new instance of the UDT. I would prefer to use the script module over tag event.

This script needs to run if the “Continue” button is pressed on a physical push button station, or if “Continue” is pressed on an HMI window, so the Tags List of the Tag Change Script seemed like the right place to do that. One Script triggered from any given source.

This would accomplish you goal of only needing to create the UDT for each new instance. Consider creating the script in your script library and calling it from the tag event.

This has substantial negative consequences in v7.9.x. Specifically, editing the shared scripts causes scripting restarts on every project in the gateway, and causes every client (every project) to get an update notice. In v8.0, you can mitigate the impact by setting up a global scripting project that isn’t in the inheritance tree of your other projects.

Anyways, I agree with @ematschke that gateway tag change events (which can use project scripts) are a better choice. Having to manually maintain the list of tags to monitor is the only drawback.

I agree the gateway event script tag change events are generally a better option and are what I’d use; just have to remember to add the new tags to the list when UDT instances are added.

Customer is not ready to go to v8.0, so that is not an option for me right now. We are on 7.9.9
If using tag change script and changing the tags list when a new unit is brought online, won’t that also cause the same script restarts in each client? Also to be clear this is a Client Tag Change Script if that makes a difference.

The issue is saving changes to a script in the script library restarts scripting on every project in the gateway. If you put the whole script in the client event scripts tag change script (rather than calling a shared script from there), it doesn’t have this issue. You could also put the script in a project script (rather than globally shared script), and call that from the client event scripts tag change script.

I was thinking Project Script Library anyway. I will try the script in both places and see what works best when we start deploying multiple units. Thank you gentlemen.

Yes. I’m sorry, I read and responded pretty quick and some of what I wrote above wasn’t very clear. I believe any changes to client event scripts, project scripts library, or gateway event scripts defined in the project will result in a project update/restart for that project (but not all projects) when saved and published, while changes to global scripts restart scripting for all projects on the gateway.

Client tag events defined on the client tag will also update/restart the clients running the project they are defined in when saved and published. I don’t believe you can have UDT client tags.

Gateway tag events defined on the tag will not update/restart clients. Depending on what the script does, and whether more than one client will be pointing to the same UDT at a time, it may make sense to define the tag change event script in the UDT if you want to avoid client updates when you add a new UDT instance. One drawback to defining tag change scripts on the tag is that they’re not always easy to find (or at least they are easy to overlook).

On the other hand, if these additions aren’t frequent, maybe the client update/restart aren’t a big deal.

@pturmel, I hope I haven’t garbled anything above… please correct if so!

1 Like