OPC-UA example / module upgrade from Ignition-v7.5.x to Ignition-v8

We have a custom driver module based on a custom protocol that needs to be upgraded and since there have been a lot many changes to the sdk and Ignition platform from 7.5 to 8.0, we have a few questions/concerns that require some guidance:

  1. Based on this post on the forum: http://forum.inductiveautomation.com/t/opc-ua-driver-for-ignition-8-new-device-interface/25046 , referring to the change of “driver” api to the new “device” api (AbstractDriverModuleHook to AbstractDeviceModuleHook), Kevin Herron mentions of some breaking changes whenever eclipse/milo 0.5.0 releases. Also Kevin Herron added a commit that referenced this pull request yesterday : https://github.com/inductiveautomation/ignition-sdk-examples/pull/43
    We wanted to know how much does it impact ignition v8?
    Also we just came across the 8.1.0 version released today and have an overview.

  2. Should we continue with the upgrade on current stable version of ignition (8.0.16) or wait for the changes to be merged to a stable 8.1.x ?

  3. Is there a way we can get Ignition 8.1.x or 8.0.16 documentation?

  4. For how long will the xopc.driver api be supported?

The legacy Driver API has been deprecated but will not likely ever be removed.

You may find that your driver continues to work in Ignition 8 with minimal changes. I think it’s mostly dealing with the removal of “XOPC” OPC UA classes and their replacement with their Milo equivalents that is required when getting a Driver-API-based driver ready for 8.

If you’re going to rewrite against the Device API then waiting for 8.1 is your best bet. The release is imminent, the RC should be available today or tomorrow. The nightly already has the new Milo version integrated that was mentioned in the other post.

There are no 8.1 javadocs available yet, but the last published 8.0.x javadocs are available here: http://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.14/index.html

The examples repo and the forums are your best resources for module development other than that.

Thank you for your reply. I did start on the rewrite on the version 8, based on the OPC-UA example repo.

About the legacy driver API, I tried doing that in past weeks and it did not work for me. I also tried the Abstract Tag Driver example from git repo. Uploading that module on v8 threw errors for not finding the AbstractDriverModuleHook.

The AbstractTagDriver example wasn’t updated for 8.0/8.1. You could only have gotten that out of one of the old 7.x branches.

Yes, that is right. I think I understand things better now after working on the code changes for 8.1
Currently, I am stuck at an issue where, when I try to add a new device, the device is saved but the logs show the following error:

Device 'sample1' failed to start
at com.inductiveautomation.ignition.examples.tagdriver.ExampleDevice.onStartup(ExampleDevice.java:109)

The onStartup method is something I have as it is from the OPC-UA sdk example
Could you please suggest where should I check into?
Another point here is: I am not able to add a new MySQL database connection. The error here is:

Cannot create PoolableConnectionFactory (Access denied for user 'admin'@'localhost'

(using password: YES))

I have also tried with root and mysql users.
Currently the only valid database connection is SQLite.

Can you post the full error from the logs?

Here is the log from last upload of modl file:

INFO | jvm 1 | 2020/09/22 14:18:26 | I [o.a.w.r.PropertiesFactory ] [21:18:26]: Loading properties files from jar:file:/D:/Inductive/Inductive/Ignition-v8.1.0-SNAPSHOT/lib/core/gateway/wicket-core-6.1.1.jar!/org/apache/wicket/Application.properties with loader org.apache.wicket.resource.IsoPropertiesFilePropertiesLoader@2cd9b71f
INFO | jvm 1 | 2020/09/22 14:18:26 | I [o.a.w.r.PropertiesFactory ] [21:18:26]: Loading properties files from jar:file:/D:/Inductive/Inductive/Ignition-v8.1.0-SNAPSHOT/lib/core/gateway/wicket-extensions-6.1.1.jar!/org/apache/wicket/extensions/Initializer.properties with loader org.apache.wicket.resource.IsoPropertiesFilePropertiesLoader@2cd9b71f
INFO | jvm 1 | 2020/09/22 14:18:28 | I [P.InternalDatabase ] [21:18:28]: Creating auto-backup of internal database "config.idb"...
INFO | jvm 1 | 2020/09/22 14:18:28 | I [P.InternalDatabase ] [21:18:28]: Created auto-backup of internal database "config.idb" in 183 ms
INFO | jvm 1 | 2020/09/22 14:18:59 | I [C.BasicExecutionEngine ] [21:18:59]: Modifying an existing execution unit. [Owner=uadriverexample, Name=sample1]
INFO | jvm 1 | 2020/09/22 14:18:59 | E [c.i.i.g.o.s.DeviceManager ] [21:18:59]: Device 'sample1' failed to start
INFO | jvm 1 | 2020/09/22 14:18:59 | java.lang.IllegalStateException: cannot call startup when state=RUNNING
INFO | jvm 1 | 2020/09/22 14:18:59 | at org.eclipse.milo.opcua.sdk.server.AbstractLifecycle.startup(AbstractLifecycle.java:34)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.examples.tagdriver.ExampleDevice.onStartup(ExampleDevice.java:109)
INFO | jvm 1 | 2020/09/22 14:18:59 | at org.eclipse.milo.opcua.sdk.server.LifecycleManager$1.startup(LifecycleManager.java:95)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at org.eclipse.milo.opcua.sdk.server.LifecycleManager.onStartup(LifecycleManager.java:49)
INFO | jvm 1 | 2020/09/22 14:18:59 | at org.eclipse.milo.opcua.sdk.server.AbstractLifecycle.startup(AbstractLifecycle.java:32)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.api.ManagedDevice.startup(ManagedDevice.kt:27)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager$DeviceAddressSpace.startup(DeviceManager.kt:307)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager.createAndStartupDevice(DeviceManager.kt:186)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager.access$createAndStartupDevice(DeviceManager.kt:42)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager$DeviceSettingsRecordListener$recordUpdated$1.invokeSuspend(DeviceManager.kt:262)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
INFO | jvm 1 | 2020/09/22 14:18:59 | at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager$DeviceSettingsRecordListener.recordUpdated(DeviceManager.kt:259)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.opcua.server.DeviceManager$DeviceSettingsRecordListener.recordUpdated(DeviceManager.kt:249)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.localdb.PersistenceInterfaceImpl.notifyRecordUpdated(PersistenceInterfaceImpl.java:179)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundantPersistenceInterfaceImpl.doNotifyRecordUpdated(RedundantPersistenceInterfaceImpl.java:111)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundantPersistenceInterfaceImpl$RecordUpdateListener.recordUpdated(RedundantPersistenceInterfaceImpl.java:407)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundantPersistenceInterfaceImpl$RecordUpdateMessage.notify(RedundantPersistenceInterfaceImpl.java:457)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundantPersistenceInterfaceImpl$RecordUpdateListener.receiveCall(RedundantPersistenceInterfaceImpl.java:390)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.QueueableMessageReceiver.receiveCall(QueueableMessageReceiver.java:47)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl.dispatchMessage(RedundancyManagerImpl.java:933)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.gateway.redundancy.RedundancyManagerImpl$ExecuteTask.run(RedundancyManagerImpl.java:1008)
INFO | jvm 1 | 2020/09/22 14:18:59 | at com.inductiveautomation.ignition.common.execution.impl.BasicExecutionEngine$ThrowableCatchingRunnable.run(BasicExecutionEngine.java:518)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:18:59 | at java.base/java.lang.Thread.run(Unknown Source)
INFO | jvm 1 | 2020/09/22 14:20:28 | I [P.InternalDatabase ] [21:20:28]: Creating auto-backup of internal database "config.idb"...
INFO | jvm 1 | 2020/09/22 14:20:28 | I [P.InternalDatabase ] [21:20:28]: Created auto-backup of internal database "config.idb" in 245 ms
INFO | jvm 1 | 2020/09/22 14:26:40 | I [s.ProjectRunner ] [21:26:40]: Setting SQL Bridge project enabled state to 'DISABLED' project-name=samplequickstart, module-name=SQL Bridge

Ah, looks like the current example has 2 calls to subscriptionModel.startup(). Delete one of those. We’ll have to update the example.

Great! It works :slight_smile:
Thank you so much for this!

@Kevin.Herron,
Can you provide in the OPC-UA Device Example for 8.1, how to manage writable items ?

Updated: https://github.com/inductiveautomation/ignition-sdk-examples/commit/a6cbbfed9cc7b55cd2c175e3d6971d5650d34d9a

If a UaNode will be writable make sure the AccessLevel indicates that and then it will be writable. You can install an AttributeFilter to “intercept” the write and perhaps do something with the value. The example just logs it before passing it on to the next filter where it eventually will get set on the UaNode instance.

1 Like