Dealing with non-existent tags in UDTs and Templates

Fairly new to Ignition (using 8.1.1) and I’m having some trouble finding a solution to this. I’m wondering if there is a proper way using Vision to create a UDT and a Template with tags that do not exist.

As an example, let’s say I have a UDT called “Tank” configured with OPC tags “LowLvl” and “HighLvl”. I would like to create an instance for Tank1, even though Tank1 only has a HighLvl tag in the PLC and no LowLvl. With this UDT, I’d like to associate it to a custom “Tank” template, which, like the UDT, will use HighLvl/LowLvl tags, despite the existence of the tag.

When trying this with the UDT, I get Error_Configuration on the non-existent tags as somewhat expected. Is it fine to leave it like this, or is it bad practice?

Can anything be done on the Template side to hide non-existent tags? It seems like this can be done by controlling the Visible property by the quality of the tag, but I’m having trouble figuring how to achieve this.

Thanks in advance!

I’ll leave the others to recommend best practice, but I will say that you should not leave an OPC tag enabled if you know it doesn’t exist because the Ignition OPC UA client will be continually trying to create a subscription for it if it’s enabled.

1 Like

I guess I’m wondering then if there is a way to bind the quality of the non-existent tag to the “enabled” property of each tag in the Tank UDT

Consider reversing those words: LevelLow and Level High. This will group your tags by device instead of by action which is usually less useful and intuitive.

In terms of how to do what you're asking, I'm still in two minds. I have been creating a rectangle off the side of my templates called BINDINGS which contain all of my tag bindings that might have validly bad quality. For each tag, I also have a corresponding 'has' property e.g. 'hasAgitator', 'hasTemperature' etc. which usea the expression: isGood({Root Container.BINDINGS.tag})
It's a bit ugly having the rectangle out of view, but that way it's not going to add a bad overlay to the component for the tags that are bad which would happen if you put these on the root, for example.

Alternatively, you can add the same two bindings onto the relevant groups that will be made invisible if bad. It depends if you need to use the quality in multiple locations or not

What I ended up doing for the UDT was just manually disabling the tags not used in the PLC so Ignition wouldn’t keep trying to poll them. In the template, I bound the expression tag({Tank.tankUDT::Meta.TagPath} + "/HighLS.Enabled") to the visibility property. I think this works well for my case but I like your idea of separate expression tags to avoid the overlay, will keep that one in mind

Given that you have some different tags between tanks, I would suggest that from a pure data modeling point of view that trying to shoehorn both tank types into the same type of UDT and template is not the best approach. If you have a TankA that is different from TankB then IMHO the most correct thing is to have a UDT for TankA and different a UDT for TankB, and thus completely avoid the issues you are dealing with.

Ignition supports UDT Inheritance which helps with the tag side, however I am not sure if there is an equivalent template inheritance functionality.

I see the merits in the approach from @nminchin, but it does open itself up to accidentally deploying the wrong functionality for a specific piece of equipment (however that should be dealt with during pre-deployment testing). You are also carrying around cruft for every piece of equipment that doesn’t make use of the the disabled functionality. You can argue that Server memory and CPU are cheaper than developer time, but I’m a purist and the idea of wasting computer resources offends me :laughing:

I’ll get off my soapbox now :roll_eyes:

1 Like

When this comes up, I like to point out that for any given project, developer time is a one-time cost, while server memory and CPU are on-going costs. And of course, other projects will squeeze server resources as time goes on. Best to aim for performance up front. IMNSHO.

I'm certainly not one to complain about soap boxes. :speak_no_evil:

I see what you’re saying - I think I may actually end up making separate UDTs as you suggest, even just because seeing “Bad_Disabled” in the Tag Editor when everything is good offends me.

That is a good point about efficiency from you both. I thought there may have been a proper/clean way to accomplish what I’m doing but I think in the end I will be best to go with 2 separate UDTs/Templates.

Consider not using UDT parameters in your templates. Just give a tag path string. Indirect bind individual elements as needed. You can then supply a tag path to any UDT instance that has the appropriately named elements, without regard to UDT inheritance. Or even supply a folder path that isn’t a UDT. “Duck typing” for templates, if you will. (Walks like a duck, talks like a duck, must be a duck.) And if you must, such a template can examine individual bindings’ quality to hide missing parts, much as your original UDT was attempting, but handled entirely on the visualization side.

Ignition UDTs are great for managing tags. UDT-typed properties are a nightmare.

2 Likes

I avoid using the tag() function now as I always hear @pturmel 's voice in my head telling me it’s bad for performance :disappointed: tbh though, I haven’t had any issues with using it in the past, but that doesn’t mean it wouldn’t start to cause issues the more components you add. Better to build optimisations in rather than have to refactor once the bottleneck hits :man_shrugging:

Edit: Oh, I didn’t realise he replied here as well, haha. I’m also a huge proponent of not using UDTType properties on templates, and as Phil said, pass in a tagpath instead To UDT or not to UDT. That is the question - #15 by nminchin

I have trained you well, young padawan!

All you need now is the grey beard. :grin:

I have the same issue here. I am trying to bind the enable property in a tag member of a UDT to an expression so it get enabled/disabled based on its existence but I cant do it. Have you figured out a way or did you just go with disabling manually?