Quick fix for OPC us server
This commit is contained in:
parent
aa52b4b927
commit
7579ddfad4
@ -56,6 +56,7 @@ internal class MetaEnumCodec : OpcUaBinaryDataTypeCodec<Number> {
|
||||
|
||||
internal fun opcToMeta(value: Any?): Meta = when (value) {
|
||||
null -> Meta(Null)
|
||||
is Variant -> opcToMeta(value.value)
|
||||
is Meta -> value
|
||||
is Value -> Meta(value)
|
||||
is Number -> when (value) {
|
||||
@ -79,12 +80,17 @@ internal fun opcToMeta(value: Any?): Meta = when (value) {
|
||||
"text" put value.text?.asValue()
|
||||
}
|
||||
is DataValue -> Meta {
|
||||
"value" put opcToMeta(value.value) // need SerializationContext to do that properly
|
||||
value.statusCode?.value?.let { "status" put Meta(it.asValue()) }
|
||||
value.sourceTime?.javaInstant?.let { "sourceTime" put it.toKotlinInstant().toMeta() }
|
||||
value.sourcePicoseconds?.let { "sourcePicoseconds" put Meta(it.asValue()) }
|
||||
value.serverTime?.javaInstant?.let { "serverTime" put it.toKotlinInstant().toMeta() }
|
||||
value.serverPicoseconds?.let { "serverPicoseconds" put Meta(it.asValue()) }
|
||||
val variant= opcToMeta(value.value)
|
||||
update(variant)// need SerializationContext to do that properly
|
||||
//TODO remove after DF 0.7.2
|
||||
this.value = variant.value
|
||||
"@opc" put {
|
||||
value.statusCode?.value?.let { "status" put Meta(it.asValue()) }
|
||||
value.sourceTime?.javaInstant?.let { "sourceTime" put it.toKotlinInstant().toMeta() }
|
||||
value.sourcePicoseconds?.let { "sourcePicoseconds" put Meta(it.asValue()) }
|
||||
value.serverTime?.javaInstant?.let { "serverTime" put it.toKotlinInstant().toMeta() }
|
||||
value.serverPicoseconds?.let { "serverPicoseconds" put Meta(it.asValue()) }
|
||||
}
|
||||
}
|
||||
is ByteString -> Meta(value.bytesOrEmpty().asValue())
|
||||
is XmlElement -> Meta(value.fragment?.asValue() ?: Null)
|
||||
|
@ -2,7 +2,6 @@ package space.kscience.controls.opcua.server
|
||||
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.toJavaInstant
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.eclipse.milo.opcua.sdk.core.AccessLevel
|
||||
import org.eclipse.milo.opcua.sdk.core.Reference
|
||||
import org.eclipse.milo.opcua.sdk.server.Lifecycle
|
||||
@ -21,14 +20,15 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.DateTime
|
||||
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText
|
||||
import space.kscience.controls.api.*
|
||||
import space.kscience.controls.manager.DeviceManager
|
||||
import space.kscience.controls.opcua.client.opcToMeta
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaSerializer
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.dataforge.names.plus
|
||||
|
||||
|
||||
public operator fun CachingDevice.get(propertyDescriptor: PropertyDescriptor): Meta? = getProperty(propertyDescriptor.name)
|
||||
public operator fun CachingDevice.get(propertyDescriptor: PropertyDescriptor): Meta? =
|
||||
getProperty(propertyDescriptor.name)
|
||||
|
||||
public suspend fun Device.read(propertyDescriptor: PropertyDescriptor): Meta = readProperty(propertyDescriptor.name)
|
||||
|
||||
@ -38,29 +38,11 @@ https://github.com/eclipse/milo/blob/master/milo-examples/server-examples/src/ma
|
||||
|
||||
public class DeviceNameSpace(
|
||||
server: OpcUaServer,
|
||||
public val deviceManager: DeviceManager
|
||||
public val deviceManager: DeviceManager,
|
||||
) : ManagedNamespaceWithLifecycle(server, NAMESPACE_URI) {
|
||||
|
||||
private val subscription = SubscriptionModel(server, this)
|
||||
|
||||
init {
|
||||
lifecycleManager.addLifecycle(subscription)
|
||||
|
||||
lifecycleManager.addStartupTask {
|
||||
nodeContext.registerHub(deviceManager, Name.EMPTY)
|
||||
}
|
||||
|
||||
lifecycleManager.addLifecycle(object : Lifecycle {
|
||||
override fun startup() {
|
||||
server.addressSpaceManager.register(this@DeviceNameSpace)
|
||||
}
|
||||
|
||||
override fun shutdown() {
|
||||
server.addressSpaceManager.unregister(this@DeviceNameSpace)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun UaFolderNode.registerDeviceNodes(deviceName: Name, device: Device) {
|
||||
val nodes = device.propertyDescriptors.associate { descriptor ->
|
||||
val propertyName = descriptor.name
|
||||
@ -74,14 +56,17 @@ public class DeviceNameSpace(
|
||||
setAccessLevel(AccessLevel.READ_WRITE)
|
||||
setUserAccessLevel(AccessLevel.READ_WRITE)
|
||||
}
|
||||
|
||||
descriptor.mutable -> {
|
||||
setAccessLevel(AccessLevel.WRITE_ONLY)
|
||||
setUserAccessLevel(AccessLevel.WRITE_ONLY)
|
||||
}
|
||||
|
||||
descriptor.readable -> {
|
||||
setAccessLevel(AccessLevel.READ_ONLY)
|
||||
setUserAccessLevel(AccessLevel.READ_ONLY)
|
||||
}
|
||||
|
||||
else -> {
|
||||
setAccessLevel(AccessLevel.NONE)
|
||||
setUserAccessLevel(AccessLevel.NONE)
|
||||
@ -104,26 +89,23 @@ public class DeviceNameSpace(
|
||||
}.build()
|
||||
|
||||
// Update initial value, but only if it is cached
|
||||
if(device is CachingDevice) {
|
||||
if (device is CachingDevice) {
|
||||
device[descriptor]?.toOpc(sourceTime = null, serverTime = null)?.let {
|
||||
node.value = it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to node value changes
|
||||
*/
|
||||
node.addAttributeObserver { _: UaNode, attributeId: AttributeId, value: Any ->
|
||||
if (attributeId == AttributeId.Value) {
|
||||
val meta: Meta = when (value) {
|
||||
is Meta -> value
|
||||
is Boolean -> Meta(value)
|
||||
is Number -> Meta(value)
|
||||
is String -> Json.decodeFromString(MetaSerializer, value)
|
||||
else -> return@addAttributeObserver //TODO("other types not implemented")
|
||||
}
|
||||
deviceManager.context.launch {
|
||||
device.writeProperty(propertyName, meta)
|
||||
if (descriptor.mutable) {
|
||||
|
||||
/**
|
||||
* Subscribe to node value changes
|
||||
*/
|
||||
node.addAttributeObserver { _: UaNode, attributeId: AttributeId, value: Any? ->
|
||||
if (attributeId == AttributeId.Value) {
|
||||
val meta: Meta = opcToMeta(value)
|
||||
deviceManager.context.launch {
|
||||
device.writeProperty(propertyName, meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +119,10 @@ public class DeviceNameSpace(
|
||||
device.onPropertyChange {
|
||||
nodes[property]?.let { node ->
|
||||
val sourceTime = time?.let { DateTime(it.toJavaInstant()) }
|
||||
node.value = value.toOpc(sourceTime = sourceTime)
|
||||
val newValue = value.toOpc(sourceTime = sourceTime)
|
||||
if (node.value.value != newValue.value) {
|
||||
node.value = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
//recursively add sub-devices
|
||||
@ -168,6 +153,24 @@ public class DeviceNameSpace(
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
lifecycleManager.addLifecycle(subscription)
|
||||
|
||||
lifecycleManager.addStartupTask {
|
||||
nodeContext.registerHub(deviceManager, Name.EMPTY)
|
||||
}
|
||||
|
||||
lifecycleManager.addLifecycle(object : Lifecycle {
|
||||
override fun startup() {
|
||||
server.addressSpaceManager.register(this@DeviceNameSpace)
|
||||
}
|
||||
|
||||
override fun shutdown() {
|
||||
server.addressSpaceManager.unregister(this@DeviceNameSpace)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onDataItemsCreated(dataItems: List<DataItem?>?) {
|
||||
subscription.onDataItemsCreated(dataItems)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user