I have recently changed from a single gateway geometry to a Frontend / Backend geometry, with all devices connected to the backend gateway and designers operating through the frontend gateway. This has come with some growing pains, and the current one for which I can not seem to find the answer is the following:
Previously, I was able to detect the presence of a PLC and its online status via the reference {[System]Gateway/Devices/<my_plc_here>/Status}. Now, I no longer seem to have any devices directly available in System/Gateway/Devices. Gateway Network shows the backend with only IsAvailable and LastComm (both of which are standardly formatted tags).
Is this information no longer available to me or is there perhaps a setting I need to change in order to enable this?
Is there a way to add a reference tag that represents a whole folder at once? I don't relish the idea of having to manually make reference tags to every single component representing this device.
I attempted to "Create Data Type From Selected" on Devices/MyDevice but it threw "Error retrieving tag information."
java.lang.NullPointerException
at com.inductiveautomation.ignition.client.sqltags.impl.SystemTagManager.lambda$readAsync$2(SystemTagManager.java:178)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.lambda$groupMapCollate$0(GroupMapCollate.java:25)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.lambda$groupMapCollateIndexed$5(GroupMapCollate.java:53)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.base/java.util.HashMap$EntrySpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
at com.inductiveautomation.ignition.common.util.Futures.sequence(Futures.java:29)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.groupMapCollateIndexed(GroupMapCollate.java:62)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.groupMapCollate(GroupMapCollate.java:28)
at com.inductiveautomation.ignition.client.sqltags.impl.SystemTagManager.readAsync(SystemTagManager.java:171)
at com.inductiveautomation.ignition.client.tags.impl.ClientTagManagerImpl.lambda$readAsync$0(ClientTagManagerImpl.java:212)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.lambda$groupMapCollate$0(GroupMapCollate.java:25)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.lambda$groupMapCollateIndexed$5(GroupMapCollate.java:53)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.base/java.util.HashMap$EntrySpliterator.forEachRemaining(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source)
at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
at com.inductiveautomation.ignition.common.util.Futures.sequence(Futures.java:29)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.groupMapCollateIndexed(GroupMapCollate.java:62)
at com.inductiveautomation.ignition.gateway.util.GroupMapCollate.groupMapCollate(GroupMapCollate.java:28)
at com.inductiveautomation.ignition.client.tags.impl.ClientTagManagerImpl.readAsync(ClientTagManagerImpl.java:210)
at com.inductiveautomation.ignition.common.tags.model.TagManager.readAsync(TagManager.java:62)
at com.inductiveautomation.ignition.designer.tags.editing.dialog.TagEditorDialog.getUdtRootPath(TagEditorDialog.java:620)
at com.inductiveautomation.ignition.designer.tags.editing.dialog.TagEditorDialog.createTag(TagEditorDialog.java:651)
at com.inductiveautomation.ignition.designer.tags.frame.actions.CreateUDTFromSelectionAction.actionPerformed(ModifyActions.kt:190)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at java.desktop/javax.swing.AbstractButton.doClick(Unknown Source)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(Unknown Source)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(Unknown Source)
at java.desktop/java.awt.Component.processMouseEvent(Unknown Source)
at java.desktop/javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.desktop/java.awt.Component.processEvent(Unknown Source)
at java.desktop/java.awt.Container.processEvent(Unknown Source)
at java.desktop/java.awt.Component.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.desktop/java.awt.Container.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Window.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.Component.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.desktop/java.awt.EventQueue$4.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
at java.desktop/java.awt.EventQueue$5.run(Unknown Source)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)
Ignition v8.1.26 (b2023032308)
Java: Azul Systems, Inc. 11.0.18
I have no idea if this will work, but what about a Document type tag with the source being [System]Devices.jsonValues? Or possibly jsonValues from each inner device folder.
It's a special 'meta' tag that works for regular UDT instances and folders, but I have no idea if it works in the system tag provider.
Guessing you're out of luck, somewhat, then. You could write a script that runs the system.tag.browse function, then system.tag.configure, to semi-automatically create all the reference tags you want.
Definitely if I spend the time to build out the entire device I will do that, for now I am just going to pass the small number of variables I am interested in.
It would be nice to be able to map a folder to a UDT or something like that
# This example will add a new OPC Tag. It can be further expanded to modify more
# properties on the Tag. Additionally, this example can be used to edit an existing Tag
# by setting the baseTagPath to a Tag that already exists, and by modifying the collision policy.
# The provider and folder the Tag will be placed at.
baseTagPath = "[default]MyFolder"
# Properties that will be configured on that Tag.
tagName = "myNewTag"
opcItemPath = "ns=1;s=[Simulator]_Meta:Sine/Sine0"
opcServer = "Ignition OPC-UA Server"
valueSource = "opc"
sampleMode = "TagGroup"
tagGroup = "Default"
# Configure the tag.
tag = {
"name": tagName,
"opcItemPath" : opcItemPath,
"opcServer": opcServer,
"valueSource": valueSource,
"sampleMode" : sampleMode,
"tagGroup" : tagGroup
}
# Set the collision policy to Abort. Thus, if a Tag already exists at the base path,
# we will not override the Tag. If you are overwriting an existing Tag, then set this to "o".
collisionPolicy = "a"
# Create the Tag.
system.tag.configure(baseTagPath, [tag], collisionPolicy)
the field "tagName" should just be "name" as confirmed by looking at the raw data for a tag. I tried to run it with "tagName" and it threw an error, but behaved immediately when that field was changed to "name".
I'm confused. The only use of tagName in that example is as the name of a variable. The actual key passed in to system.tag.configure is name, which is correct and lines up with what you said. The variable name won't affect the execution of the function, because it's not relevant to to the actual value passed in.
Oh! You got me on a bad edit of the example code -- you're totally right. I must have moved the values over as variable names and missed the slight difference in that one field. Whoops! That's embarrassing.
One other thing I have noticed is that at least in my system the default opcServer was "Ignition OPC UA Server" rather than "Ignition OPC-UA Server" (hyphen). I am 98% sure I did not change the name of the OPC UA server, and I generated the server originally on 8.1.17 (in the event that the default name has changed since then).
The name with the hyphen is from old systems (Ignition 7.9 or older), if I remember correctly. We dropped the hyphen to make it more correct in 8.0, but it's a perpetual source of little tidbits like the scripting example here.
Whenever I hit a mismatch in a test system, I just double up the OPC client connection to localhost, to have both names present. Probably not a good idea for production, but simpler than searching and replacing in various tag exports.