Creating client tags in runtime

Am using a global template across many projects which needs to verify presence of client tags and create missing ones at runtime to avoid manual maintenance of projects.

I am having issues with propagating bindings for these newly created tags…if I change the tag after I have created one, it won’t update properly until I reload. Bindings that use the new tag do not propagate properly or at all

I know this stuff is way of the beaten track and may break on occasion with updates, but compared to rolling ones own module much easier.

I can create the tags easily enough.

eg ntag=ProjectTag() ntag.setName(tagName) if dtype=="DateTime": ntag.setAttribute(TagProp.FormatString, BasicTagValue("yyyy-MM-dd h:mm:ss aa")) ntag.setTypeAndValue(DataType.DateTime,BasicTagValue(value))

I’m not sure if doing a ntag.startBinding(VisionClientContext, TagPath) is all that is required.

I cannot test as I have no idea of how to get hold of the VisionClientContext object required to test.

Is there are any docs or anyone that point one in the right direction it would be greatly appreciated…wading through the API classes and limited SDK docs leave one clueless as to how it all fits together properly.

Would all be solved if system.tag.addTag() could be generalized to include client tags.

-------- For those that are interested in what it is for and why one want to do this ----

It is for a global template menu system - see image. The top and left nav are actually instances of the same template

All menu items are templates on a template canvas loaded dynamically (eg menus can change to meet context). The templates even configure window sizing and scroll bar behaviour. In this image case the date defaults to today and is used across many windows and projects, hence the need for a client specific tag, which can easily be bound by components on any page. The beauty of this approach is that you can standardize this kind of selection task without the need for any session management apart from that exposed by the client tags. The user of the selected date tag can remain blissfully unaware of the init code etc required to manage the date. (this actual date defaults to start of day) which makes it super easy to generate historical charts.


You might find my shared script from this thread helpful, even if you repurpose the techniques.

I ended up giving up on this one, was wasting too much time on it.

Resorted to manually creating tags as required in projects, bit annoying but one can live with it.

I would love to see better SDK docs so it isn’t always so much of a battle to work out how the functions are intended to work together…one always seems to get 90% there and then fall over at the last hurdle due to having missed something essential.

[quote=“gekkoman”]I would love to see better SDK docs so it isn’t always so much of a battle to work out how the functions are intended to work together…one always seems to get 90% there and then fall over at the last hurdle due to having missed something essential.[/quote]To be fair, the SDK isn’t intended to support general use of the underlying java objects from jython, perhaps with the exception of reading additional detail. You’re trying to modify the platform structure in unsupported ways – you can’t really expect IA to help you do that. The expectation of SDK users is that they have enough Java and/or general programming experience to need very little hand-holding.

Fair enough.

I figure that creating your own modules (I have made a few - mainly components) is largely unsupported as well, as it depends a lot on quality of your implementation.

I tend to try out things first in Jython as opposed to dealing with all the cruft around doing things as a Java module.

I also figure the forum is the right spot for this kind of question…IA gets to see the kind of things being asked, knowledge gets shared etc. If it gets answered fine, if not also fine.

IA is generally heading in the right direction for me…the recent addition of global templates, for example, has allowed me to drop a module level solution I had for a native ignition supported solution, which I believe to be the better option. I figure if I still have a few lingering lines of “naughtiness” then this still a better position than having to maintain a module.

If one looks more generally …the query is not so much about diving into Jython, but rather that the system.tag.addTag is not yet general in scope, I can see also why it wasn’t done up front. It is however the kind of thing that is likely to show up as product matures.

Hi gekkoman,

Perhaps you should use shared Python modules rather than client tags. Check out my article about that: Python Module Level Variables vs. Client Tags

Best,

1 Like

Nick,

That was helpful. Thanks!

I don’t disagree with Nick very often, but I will here. Client tags have one enormous advantage over python script module scoped variables: value change subscribers can freely come and go as windows are opened, cached, and closed, including in template holders, repeaters, and canvas objects. Ignition’s binding infrastructure makes all of this Just Work, with zero code maintenance effort on your part, regardless how often or rarely you are updating any given value.
If this applies to your application (and I bet it does), use a client tag, even if you have to shoe-horn your data representation into a dataset.
If you have a weird or python-constructed datatype that you need to persist in that form, by all means, use a module scoped variable. I have a number of deployments with such code. But I avoid using them without good cause.

1 Like

Back to gekkoman’s original question…

This creates a usable client tag, but fails to survive project save and load:[code]from com.inductiveautomation.ignition.common.sqltags import BasicTagValue
from com.inductiveautomation.factorypmi.application import FPMIApp
from com.inductiveautomation.ignition.common.sqltags.parser import TagPathParser
from com.inductiveautomation.factorypmi.application.sqltags.project import ProjectTag
from com.inductiveautomation.ignition.common.sqltags.model.types import DataType

tm = FPMIApp.getInstance().clientContext.tagManager
tp = TagPathParser.parse("[Client]")

nt1 = ProjectTag()
nt1.setName(“CreatedInt4”)
nt1.setDataType(DataType.Int4)
nt1.setValue(BasicTagValue(25))

node=tm.getTag(tp)
node.addChild(nt1)[/code]The following works and does survive designer save and reload:[code]from com.inductiveautomation.ignition.common.sqltags import BasicTagValue
from com.inductiveautomation.factorypmi.application import FPMIApp
from com.inductiveautomation.ignition.common.sqltags.parser import TagPathParser
from com.inductiveautomation.factorypmi.application.sqltags.project import ProjectTag
from com.inductiveautomation.ignition.common.sqltags.model.types import DataType
from com.inductiveautomation.ignition.common.sqltags.model.TagManagerBase import CollisionPolicy

tm = FPMIApp.getInstance().clientContext.tagManager
tp = TagPathParser.parse("[Client]")

nt2 = ProjectTag()
nt2.setName(“CreatedInt8”)
nt2.setDataType(DataType.Int8)
nt2.setValue(BasicTagValue(50))

tm.addTags(tp, [nt2], CollisionPolicy.Overwrite)[/code]What’s interesting is that combining the two methods causes both new tags to survive save/reload:[code]from com.inductiveautomation.ignition.common.sqltags import BasicTagValue
from com.inductiveautomation.factorypmi.application import FPMIApp
from com.inductiveautomation.ignition.common.sqltags.parser import TagPathParser
from com.inductiveautomation.factorypmi.application.sqltags.project import ProjectTag
from com.inductiveautomation.ignition.common.sqltags.model.types import DataType
from com.inductiveautomation.ignition.common.sqltags.model.TagManagerBase import CollisionPolicy

tm = FPMIApp.getInstance().clientContext.tagManager
tp = TagPathParser.parse("[Client]")

nt1 = ProjectTag()
nt1.setName(“CreatedInt4”)
nt1.setDataType(DataType.Int4)
nt1.setValue(BasicTagValue(25))

node=tm.getTag(tp)
node.addChild(nt1)

nt2 = ProjectTag()
nt2.setName(“CreatedInt8”)
nt2.setDataType(DataType.Int8)
nt2.setValue(BasicTagValue(50))

tm.addTags(tp, [nt2], CollisionPolicy.Overwrite)[/code]Enjoy!

2 Likes

Phil,

I agree that Client tags are much cleaner to use, especially if less savvy users are let loose to design pages for themselves. I feel this is the preferred way to do this in ignition.

I also do use python modules when appropriate. You can even do this at a python class level which is really powerful. There is no way you can do this with tags. eg being able to execute calls against shared class objects.

I typically try and use tags for normal user exposure, and modules for stuff that would mess up the user experience and or is not possible in tags.

Re my client tag issue my code already had the snippet

tm.addTags(tp,[ntag],tm.CollisionPolicy.Overwrite)

present, but I didn’t put it into the forum article. The code formed part of a much more general function which included, dynamic folder creation etc so I had distilled the gist to get the point across without the fluff

Tags surviving save/reload isn’t the problem… It is that you cannot update the tag reliably at run time. Many times if you change it in run time the tag does not reflect the change properly.

For the client tags created in code:

-In designer open up the tag browser to view the client tag. ( I am using a date in particular)
-Create a component and bind it to the tag. (eg calendar)
-Change value in component…quite regularly the tag value does not change to reflect the change in component.
-If you refresh and select the tag in the tag browser it will likely start working as expected.

There is a little bit of binding glue that is missing. It is my lack of knowledge of how the various ignition bits interact that is blocking my progress. I’m sure there is one more step involved that ensure changes propagate correctly via a binding all the time.

I’ve tried doing things like:

from com.inductiveautomation.factorypmi.application import FPMIApp app=FPMIApp.getInstance() ntag.startBinding(app.getAdapterContext(),tp)

but this gets mere nowhere and is likely wrong.

Tarek

Hi @pturmel,

It works in designer, but in client scope, it fails to create client tags. Any idea ?

No, never tried. I would expect there to be alligators. The techniques I've shown above are really intended to be tools to automate and/or generalize designer tasks, not a way to do dynamic designs at runtime.

it make sense. Client Tags creation had to be done in the designer before launching the vision client…