# OPC-UA javadoc and general functionality

**URL:** <https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913>\
**Category:** Module Development\
**Tags:** ignition81\
**Created:** [November 15, 2023, 6:33am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913 "2023-11-15T06:33:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![James\_Robertson](https://avatars.discourse-cdn.com/v4/letter/j/858c86/32.png) [@James\_Robertson](https://forum.inductiveautomation.com/u/James_Robertson)\
**Post date:** [November 15, 2023, 6:33am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/1 "2023-11-15T06:33:02Z")

</div>

I am trying to create an OPC-UA device driver in 8.1 and am using the OPC-UA example from GitHub as the starting point.

I understand the general gist of the example, but am trying to figure out how to implement a device that subscribes to data changes in a controller. I can't figure out the correct way to push these changes back to ignition, or how to handle polls from ignition where there has been no data change. My device also doesn't support browsing, and I can't figure out from the example how to implement tags without populating the tag browser.

I've tried looking for the javadoc for the managed device. It appears that all of the opcua packages are missing from the ignition javadoc web pages. com.inductiveautomation.ignition.gateway.opcua.server.api.ManagedDevice

I'm also not sure the function of the following methods:

> ```
> public void onDataItemsCreated(List<DataItem> dataItems) {
> subscriptionModel.onDataItemsCreated(dataItems);
> }
> 
> public void onDataItemsModified(List<DataItem> dataItems) {
> subscriptionModel.onDataItemsModified(dataItems);
> }
> 
> public void onDataItemsDeleted(List<DataItem> dataItems) {
> subscriptionModel.onDataItemsDeleted(dataItems);
> }
> 
> public void onMonitoringModeChanged(List<MonitoredItem> monitoredItems) {
> subscriptionModel.onMonitoringModeChanged(monitoredItems);
> }
> 
> ```

---

<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 15, 2023, 12:56pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/2 "2023-11-15T12:56:22Z")

</div>

Ignition use the Milo open-source OPC UA protocol stack and SDK. Code here:

> **[GitHub - eclipse/milo: Eclipse Milo™ - an open source implementation of OPC...](https://github.com/eclipse/milo)**
>
> Eclipse Milo™ - an open source implementation of OPC UA (IEC 62541). - GitHub - eclipse/milo: Eclipse Milo™ - an open source implementation of OPC UA (IEC 62541).

(Ignition also employs the Milo project lead, @Kevin.Herron, fyi.)

I don't see any javadocs....

---

<div class="post-metadata">

**Author:** ![James\_Robertson](https://avatars.discourse-cdn.com/v4/letter/j/858c86/32.png) [@James\_Robertson](https://forum.inductiveautomation.com/u/James_Robertson)\
**Post date:** [November 16, 2023, 1:42am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/3 "2023-11-16T01:42:11Z")

</div>

Thanks for the info regarding milo.  
I've looked through the milo examples and I'm still a bit lost.  
I don't understand how the ManagedDevice lines up with milo or how I am supposed to receive notification of new tags with a new 'OPC Item Path'.

---

<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 16, 2023, 1:52am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/4 "2023-11-16T01:52:38Z")

</div>

Yeah, the core interfaces are not part of IA's public javadocs.

Fundamentally, a driver must implement this interface:

`com.inductiveautomation.ignition.gateway.opcua.server.api.Device`

which looks like this in IntelliJ:

`public interface Device : org.eclipse.milo.opcua.sdk.server.api.AddressSpace, org.eclipse.milo.opcua.sdk.server.Lifecycle`

Those two Milo interfaces are the meat of the requirement.

I myself am still puttering around with this, as all of my drivers predate Milo and still rely on the `Driver` compatibility shim.

You'll have to bug Kevin to cough up some javadocs.

---

<div class="post-metadata">

**Author:** ![James\_Robertson](https://avatars.discourse-cdn.com/v4/letter/j/858c86/32.png) [@James\_Robertson](https://forum.inductiveautomation.com/u/James_Robertson)\
**Post date:** [November 17, 2023, 1:24am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/5 "2023-11-17T01:24:39Z")

</div>

Thanks pturml

@Kevin.Herron any chance the opcua javadocs can be posted?

---

<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 17, 2023, 11:33pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/6 "2023-11-17T23:33:20Z")

</div>

I'll look into this on Monday. I know there are some docs written on the basic interfaces, but those interfaces are written in Kotlin, and so producing Javadocs for those interfaces/classes presented some issue for our build system that I don't think was ever resolved. Might not be able to produce any until I rewrite the interfaces back to Java in 8.3

---

<div class="post-metadata">

**Author:** ![James\_Robertson](https://avatars.discourse-cdn.com/v4/letter/j/858c86/32.png) [@James\_Robertson](https://forum.inductiveautomation.com/u/James_Robertson)\
**Post date:** [November 20, 2023, 1:30am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/7 "2023-11-20T01:30:46Z")

</div>

Thanks Kevin,

My main issue is how to access tags that have been defined by there 'OPC Item Path' as I can't browse my device.

I'm also not sure about subscribed vs polled. The example shows how to respond to a poll, but I can't see how to send data without the poll?

Cheers

---

<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 20, 2023, 3:24am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/8 "2023-11-20T03:24:04Z")

</div>

OPC Item Path is an OPC UA NodeId.

If you can't browse your device, and you don't know ahead of time or at configuration time what Nodes will exist, then the `ManagedDevice` abstraction won't be of any use to you and you'll just have to implement `Device` directly.

Your implementation doesn't have to implement browsing. By default, any NodeId with a String identifier starting with `[YourDeviceName]` will be passed to your Device implementation's Read, Write, Browse, or Monitored Item related calls.

> [@James\_Robertson](#):
>
> The example shows how to respond to a poll, but I can't see how to send data without the poll?

The example is implementing Subscription / Monitored Item behavior by simply calling the read method over and over. It's up to your implementation to do something smarter if it's available. You don't ever just arbitrarily send information to the client, though. The client creates Monitored Items, and you are responsible for updating that item at the requested Sampling Interval, based on your best efforts.

---

<div class="post-metadata">

**Author:** ![James\_Robertson](https://avatars.discourse-cdn.com/v4/letter/j/858c86/32.png) [@James\_Robertson](https://forum.inductiveautomation.com/u/James_Robertson)\
**Post date:** [November 21, 2023, 12:53am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/9 "2023-11-21T00:53:03Z")

</div>

Thanks for the hint, I found the read and write methods in the AttributeService interface.

Do you have Kotlin documentation for the opcua, that would be useful.

I understand the high level data flow, its the interface detail I'm not clear on. I might try the milo forums as well.

---

<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 21, 2023, 12:57am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/10 "2023-11-21T00:57:43Z")

</div>

> [@James\_Robertson](#):
>
> I understand the high level data flow, its the interface detail I'm not clear on. I might try the milo forums as well.

The honest reality is that between the current examples (Ignition SDK, Milo example server and demo server) and the available code (all Milo stuff is open source), it's sink or swim and you need to figure it out.

Most of the Device API is just a thin extension on top of Milo OPC UA stuff, except the basic things on `Device` that aren't inherited, or the registration of a `DeviceType`, etc...

---

<div class="post-metadata">

**Author:** ![andrew.budaiev](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/andrew.budaiev/32/72921_2.png) [@andrew.budaiev](https://forum.inductiveautomation.com/u/andrew.budaiev)\
**Post date:** [November 21, 2023, 1:46am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/11 "2023-11-21T01:46:40Z")

</div>

> [@Kevin.Herron](#):
>
> 'll look into this on Monday. I know there are some docs written on the basic interfaces, but those interfaces are written in Kotlin, and so producing Javadocs for those interfaces/classes presented some issue for our build system that I don't think was ever resolved. Might not be able to produce any until I rewrite the interfaces back to Java in 8.3

Hey Kevin,

If I understood correctly, you will be rewriting interfaces written in Kotlin back to Java. May I ask what's wrong with Kotlin?

---

<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 21, 2023, 1:54am UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/12 "2023-11-21T01:54:15Z")

</div>

> [@andrew.budaiev](#):
>
> May I ask what's wrong with Kotlin?

Nothing, but for some reason our build system, or the KDoc plugin, or some combination, won't produce/combine Javadocs for the stuff written in Kotlin. I don't remember the details any more because I don't work on the build.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [February 28, 2025, 9:55pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/13 "2025-02-28T21:55:03Z")

</div>

I have a driver where nodes are not known at startup, so I need to implement Device interface instead of extend a ManagedDevice.

Is it possible to create the UaNode from the onDataItemsCreated ?  
Is onDataItemsCreated called when Ignition tag opc item has not been created in the device ?

```python
public class TestDevice implements Device {
    @NotNull
    @Override
    public String getName() {
        return null;
    }

    @NotNull
    @Override
    public String getStatus() {
        return "Running";
    }

    @NotNull
    @Override
    public String getTypeId() {
        return null;
    }

    @Override
    public void startup() {
    }

    @Override
    public void shutdown() {

    }

    @Override
    public void read(ReadContext readContext, Double aDouble, TimestampsToReturn timestampsToReturn, List<ReadValueId> list) {

    }

    @Override
    public void write(WriteContext writeContext, List<WriteValue> list) {

    }

    @Override
    public void onDataItemsCreated(List<DataItem> list) {

    }

    @Override
    public void onDataItemsModified(List<DataItem> list) {

    }

    @Override
    public void onDataItemsDeleted(List<DataItem> list) {

    }

    @Override
    public void onMonitoringModeChanged(List<MonitoredItem> list) {

    }

    @Override
    public void browse(BrowseContext browseContext, ViewDescription viewDescription, NodeId nodeId) {

    }

    @Override
    public void getReferences(BrowseContext browseContext, ViewDescription viewDescription, NodeId nodeId) {

    }
}

```

---

<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:** [February 28, 2025, 10:07pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/14 "2025-02-28T22:07:00Z")

</div>

It won't be called unless your Device indicates that Node exists and is managed by your AddressSpace. It doesn't necessarily need a UaNode instance to exist, but when a client calls CreateMonitoredItems, you'll end up getting a call to `read` for some of the attributes needed when creating a MonitoredItem, and provided this call is successful and a MonitoredItem can be created, you'll get a subsequent call to `onDataItemsCreated`.

If you're building a driver where you don't know what exists ahead of time, then maybe consider just not creating any UaNode instances at all. It's possible to do everything dynamically. My Modbus Server Driver does this.

[https://github.com/kevinherron/modbus-server-driver/tree/master](https://github.com/kevinherron/modbus-server-driver/tree/master)

[https://github.com/kevinherron/modbus-server-driver/blob/b7ef35f0ce450861a505a1c3e3d5833e42917e60/msd-gateway/src/main/java/com/kevinherron/ignition/modbus/ModbusAddressSpace.java](https://github.com/kevinherron/modbus-server-driver/blob/master/msd-gateway/src/main/java/com/kevinherron/ignition/modbus/ModbusAddressSpace.java)

---

<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:** [February 28, 2025, 10:13pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/15 "2025-02-28T22:13:16Z")

</div>

> [@Kevin.Herron](#):
>
> to do everything dynamically

I wimped out on this one. Future improvements, perhaps. For the moment, I create nodes on demand--whether read/write/subscribe or browse.

---

<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:** [February 28, 2025, 10:17pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/16 "2025-02-28T22:17:25Z")

</div>

We use both approaches, depends on the driver.

For Modbus and Modbus-like drivers where you just address memory ranges it makes a lot of sense. For others where there's a well-defined model (Logix, 61850), or other reasons (DNP3, BACnet), we use UaNode instances.

That said - a future rewrite of the Logix driver would go fully dynamic.

Part of the reason the AddressSpace API looks like it does (instead of being perhaps easier to use) is to maintain the ability for an unlimited number of Nodes to exist without actually needing instances of them to exist in memory.

---

<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:** [February 28, 2025, 10:22pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/17 "2025-02-28T22:22:02Z")

</div>

My drivers are good candidates, then, since they all have a "model" of the target's configured or browsed address space. In other words, its all in memory that way **now**. Just need attribute handling for those.

After the v83 conversion hysteria settles, I'll revisit this.

---

<div class="post-metadata">

**Author:** ![mazeyrat](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mazeyrat/32/10955_2.png) [@mazeyrat](https://forum.inductiveautomation.com/u/mazeyrat)\
**Post date:** [March 27, 2025, 6:08pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/18 "2025-03-27T18:08:02Z")

</div>

I try to implement the Device and create nodes on demand following the SDK opc-ua-device example.

on startup, I suppose I need to create rootNode but I don't figure out how to find **getNodeContext()** substitue ?

```python
        UaFolderNode rootNode = new UaFolderNode(
                getNodeContext(),
                deviceContext.nodeId(getName()),
                deviceContext.qualifiedName(String.format("[%s]", getName())),
                new LocalizedText(String.format("[%s]", getName()))
        );

```

---

<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:** [March 27, 2025, 6:16pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/19 "2025-03-27T18:16:58Z")

</div>

I create my own, like so:

```python
    public static class GenericDeviceNodeContext implements UaNodeContext {
        public final DeviceContext deviceContext;
        public final UaNodeManager nodeManager;

        public GenericDeviceNodeContext(DeviceContext deviceContext) {
            this.deviceContext = deviceContext;
            this.nodeManager = new UaNodeManager();
        }

        @Override
        public OpcUaServer getServer() {
            return deviceContext.getServer();
        }

        @Override
        public UaNodeManager getNodeManager() {
            return nodeManager;
        }
    }

```

---

<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:** [March 27, 2025, 6:59pm UTC](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913/20 "2025-03-27T18:59:48Z")

</div>

Yep, that's all you really need. It's just not provided for you if you're not using a "Managed" thingy.

The one from ManagedAddressSpace is just this: [milo/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/ManagedAddressSpace.java at 92b3334764064d935373b7a4a7fd098ef72284b5 · eclipse-milo/milo · GitHub](https://github.com/eclipse-milo/milo/blob/92b3334764064d935373b7a4a7fd098ef72284b5/opc-ua-sdk/sdk-server/src/main/java/org/eclipse/milo/opcua/sdk/server/ManagedAddressSpace.java#L61-L72)

[Next page](https://forum.inductiveautomation.com/t/opc-ua-javadoc-and-general-functionality/81913.md?page=2)
