# OPC-UA Driver or OPC-UA Device !?

**URL:** <https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214>\
**Category:** Module Development\
**Tags:** ignition81\
**Created:** [November 8, 2022, 2:19am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214 "2022-11-08T02:19:38Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Behzad.Ebrahimi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/behzad.ebrahimi/32/38108_2.png) [@Behzad.Ebrahimi](https://forum.inductiveautomation.com/u/Behzad.Ebrahimi)\
**Post date:** [November 8, 2022, 2:19am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/1 "2022-11-08T02:19:38Z")

</div>

After 20 years working in Industrial Automation and Monitoring, I met the powerful **Ignition** application.  
After I tried to get Gold Certification, I found one big problem with the Inductive company! It does not have enough resources to support its community. When I started developing a new module, I became more confident! I have two reasons; First, after 75 days of posting my GOLD 8.1 test file, I did not get any response! Second, incomplete SDK documentation!

Currently, I am very thankful for @Kevin.Herron and @pturmel 🙏 They are very active in this forum 💯

But what is my problem:  
I want to **create an OPC-UA Driver that allows reading data without predefined nodes**.

I completely studied: [Ignition SDK Programmers Guide](https://docs.inductiveautomation.com/display/SE/Ignition+SDK+Programmers+Guide). In the [Development Guide](https://docs.inductiveautomation.com/display/SE/Development+Guide) page, it says: _All OPC-UA drivers must, at a minimum, implement the **Driver** interface._ But in [OPC-UA device example in github](https://github.com/inductiveautomation/ignition-sdk-examples/tree/master/opc-ua-device), I could find any implementation of **Driver** interface. In that example, it implemented Managed **Device** and Abstract **Device** ModuleHook.

After confusion, I started to read most of the related posts in the [module-development](https://forum.inductiveautomation.com/c/module-development/7) and [3rd-party-modules](https://forum.inductiveautomation.com/c/3rd-party-modules/8) sections. I found the following posts useful:

- [opc-tag-registration-through-designer](https://forum.inductiveautomation.com/t/opc-tag-registration-through-designer/44729)

- [adding-tags-to-ignition-opc-ua-server-thru-designer](https://forum.inductiveautomation.com/t/adding-tags-to-ignition-opc-ua-server-thru-designer/10131/2)

- [system-opc-writevalue](https://forum.inductiveautomation.com/t/system-opc-writevalue/23513)

- [opc-ua-driver-allow-reading-without-predefined-nodes](https://forum.inductiveautomation.com/t/opc-ua-driver-allow-reading-without-predefined-nodes/53267)

Also, I got an outdated [ModbusDriverExample](https://github.com/inductiveautomation/ignition-sdk-examples/tree/ignition-7.7/ModbusDriverExample) that it is not compatible with Ignition 8.1.

So, could you **please** provide a very simple sample code that provides ability reading tags like the Modbus Driver pattern? e.g `“ns=1;s=[device]HRF1234”`. It will be great if you provide that sample code based on [OPC-UA device example in github](https://github.com/inductiveautomation/ignition-sdk-examples/tree/master/opc-ua-device).

---

<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:** [November 8, 2022, 12:57pm UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/2 "2022-11-08T12:57:44Z")

</div>

> [@Behzad.Ebrahimi](#):
>
> a very simple sample code

It's not simple.

Also, I haven't switched to the new Device model, so have no current advice. I'll be learning it before too long.

FWIW, I think your criticism of the SDK is unfair. That Ignition _ **HAS** _ an SDK at all puts them miles ahead of the competition. Ping me when Kepware offers an SDK for their platform.

---

<div class="post-metadata">

**Author:** ![Behzad.Ebrahimi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/behzad.ebrahimi/32/38108_2.png) [@Behzad.Ebrahimi](https://forum.inductiveautomation.com/u/Behzad.Ebrahimi)\
**Post date:** [November 9, 2022, 12:53am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/3 "2022-11-09T00:53:24Z")

</div>

Dear @pturmel, thank you for your prompt response.  
Still, I believe that **Ignition** is **powerful**. So I spend a lot of energy learning it.  
I apologize Ignition community for my criticism. (@Kevin.Herron, @pturmel)

---

<div class="post-metadata">

**Author:** ![Behzad.Ebrahimi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/behzad.ebrahimi/32/38108_2.png) [@Behzad.Ebrahimi](https://forum.inductiveautomation.com/u/Behzad.Ebrahimi)\
**Post date:** [November 9, 2022, 12:57am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/4 "2022-11-09T00:57:08Z")

</div>

Anybody can provide [Development Guide](https://docs.inductiveautomation.com/display/SE/Development+Guide) using the new `Device` model, please?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [November 9, 2022, 3:07am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/5 "2022-11-09T03:07:33Z")

</div>

The [opc-ua-device](https://github.com/inductiveautomation/ignition-sdk-examples/tree/master/opc-ua-device) example is the only sample code available.

You already saw [the post](https://forum.inductiveautomation.com/t/opc-ua-driver-allow-reading-without-predefined-nodes/53267/2) where I suggested how you might implement "dynamic" nodes, but I'll restate. Either:

1. implement the `Device` interface directly
2. override the `read`/`write`/etc... calls from `ManagedDevice`

in either case, the calls will be targeting nodes with string-based NodeIds prefixed with `[$DeviceName]`. The remainder of the NodeId is up to you to to interpret as meaningful or not. In `ManagedDevice` it simply decides a NodeId is valid based on whether an actual UaNode instance has been created and added to the node manager. If not, StatusCode Bad\_NodeIdUnknown is returned.

`ManagedDevice` is just an extremely simple abstract class that extends [ManagedAddressSpace](https://github.com/eclipse/milo/blob/master/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/api/ManagedAddressSpace.java), which might serve as an example of how to implement these calls.

---

<div class="post-metadata">

**Author:** ![Behzad.Ebrahimi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/behzad.ebrahimi/32/38108_2.png) [@Behzad.Ebrahimi](https://forum.inductiveautomation.com/u/Behzad.Ebrahimi)\
**Post date:** [November 10, 2022, 12:27am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/6 "2022-11-10T00:27:07Z")

</div>

I found other good posts that are related to this topic:

- [OPC-UA driver for Ignition 8: New “Device” interface?](https://forum.inductiveautomation.com/t/opc-ua-driver-for-ignition-8-new-device-interface/25046)

- [Ignition 8 SDK: OPC UA device](https://forum.inductiveautomation.com/t/ignition-8-sdk-opc-ua-device/28887)

---

<div class="post-metadata">

**Author:** ![Behzad.Ebrahimi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/behzad.ebrahimi/32/38108_2.png) [@Behzad.Ebrahimi](https://forum.inductiveautomation.com/u/Behzad.Ebrahimi)\
**Post date:** [November 17, 2022, 2:33am UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/7 "2022-11-17T02:33:09Z")

</div>

@Kevin.Herron I tried to edit [ExampleDevice.java](https://github.com/inductiveautomation/ignition-sdk-examples/blob/master/opc-ua-device/opc-ua-device-gateway/src/main/java/com/inductiveautomation/ignition/examples/tagdriver/ExampleDevice.java) as following code.  
Is it correct to use the passed nodeId by read() function to create a dynamic node?  
Please see my first output in the attached picture.  
After running my module, the CPU usage goes to %100 and the Ignition hangs after a while!

```auto
	private int nNodeCounter = 0;
	private int nSimCounter = 0;
	private UaFolderNode folderDynamicX = null;
	private void addMyNode(NodeId nodeId)
	{
		if(folderDynamicX == null)
		{
			String name = "DynamicX";
			folderDynamicX = new UaFolderNode(getNodeContext(), deviceContext.nodeId(name), deviceContext.qualifiedName(name), new LocalizedText(name));
			getNodeManager().addNode(folderDynamicX);
			rootNode.addOrganizes(folderDynamicX);
		}

		nNodeCounter++;
		if((nNodeCounter < (10)))
		{
			String strIden = nodeId.getIdentifier().toString();
			strIden = strIden.substring(strIden.indexOf(']')+1);
			String formattedName = strIden;

			UaVariableNode node = UaVariableNode.builder(getNodeContext())
					.setNodeId(nodeId)
					.setBrowseName(deviceContext.qualifiedName(formattedName))
					.setDisplayName(new LocalizedText(formattedName))
					.setDataType(BuiltinDataType.UInt16.getNodeId())
					.setTypeDefinition(Identifiers.BaseDataVariableType)
					.setAccessLevel(AccessLevel.READ_ONLY)
					.setUserAccessLevel(AccessLevel.READ_ONLY)
					.build();

			//node.setValue(new DataValue(new Variant(nNodeCounter)));
			node.setValue(new DataValue(new Variant(nSimCounter)));
			node.getFilterChain().addLast(AttributeFilters.getValue(getAttributeContext -> new DataValue(nSimCounter++)));

			getNodeManager().addNode(node);
			folderDynamicX.addOrganizes(node);
		}
	}

	@Override
	public void read(ReadContext context, Double maxAge, TimestampsToReturn timestamps, List<ReadValueId> readValueIds)
	{
		//super.read(context, maxAge, timestamps, readValueIds);
		List<DataValue> results = Lists.newArrayListWithCapacity(readValueIds.size());

		for(ReadValueId readValueId : readValueIds)
		{
			boolean bRepeat = false;
			do
			{
				UaServerNode node = getNodeManager().get(readValueId.getNodeId());

				if(node != null)
				{
					DataValue value = node.readAttribute(new AttributeContext(context), readValueId.getAttributeId(),
							timestamps, readValueId.getIndexRange(), readValueId.getDataEncoding());

					logger.debug("Read value {} from attribute {} of {}", value.getValue().getValue(),
							AttributeId.from(readValueId.getAttributeId()).map(Object::toString).orElse("unknown"), node.getNodeId());

					results.add(value);
				}
				else
				{
					if(!bRepeat)
					{
						bRepeat = true;
						addMyNode(readValueId.getNodeId());
					}
					else
					{
						results.add(new DataValue(new Variant(321)));
						//results.add(new DataValue(StatusCodes.Bad_NodeIdUnknown));
						break;
					}
				}
			}
			while(bRepeat);
		}

		context.success(results);
	}

```

 ![DynamicTag](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/1/915784b48328befbbf816d44b7303af70d00d67d.png)

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [November 24, 2022, 2:38pm UTC](https://forum.inductiveautomation.com/t/opc-ua-driver-or-opc-ua-device/66214/8 "2022-11-24T14:38:23Z")

</div>

Well, I suppose you _could_ do this, but generally the point of the dynamic addressing approach is to avoid creating instances of a Node at all, and to just derive whatever information is requested using the NodeId and AttributeId being read, written, or browsed.
