Migrate to DataForge 0.8.0
This commit is contained in:
parent
dbacdbc7cf
commit
2a700a5a2a
@ -5,8 +5,8 @@ plugins {
|
|||||||
id("space.kscience.gradle.project")
|
id("space.kscience.gradle.project")
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion: String by extra("0.7.1")
|
val dataforgeVersion: String by extra("0.8.0")
|
||||||
val visionforgeVersion by extra("0.3.1")
|
val visionforgeVersion by extra("0.4.0")
|
||||||
val ktorVersion: String by extra(space.kscience.gradle.KScienceVersions.ktorVersion)
|
val ktorVersion: String by extra(space.kscience.gradle.KScienceVersions.ktorVersion)
|
||||||
val rsocketVersion by extra("0.15.4")
|
val rsocketVersion by extra("0.15.4")
|
||||||
val xodusVersion by extra("2.0.1")
|
val xodusVersion by extra("2.0.1")
|
||||||
|
@ -5,7 +5,7 @@ import space.kscience.controls.api.PropertyDescriptor
|
|||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
|
@ -12,11 +12,7 @@ import space.kscience.controls.manager.install
|
|||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
import space.kscience.dataforge.meta.Laminate
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
|
||||||
import space.kscience.dataforge.meta.MutableMeta
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import space.kscience.dataforge.misc.DFExperimental
|
import space.kscience.dataforge.misc.DFExperimental
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
@ -10,7 +10,7 @@ import space.kscience.controls.spec.DevicePropertySpec
|
|||||||
import space.kscience.controls.spec.MutableDevicePropertySpec
|
import space.kscience.controls.spec.MutableDevicePropertySpec
|
||||||
import space.kscience.controls.spec.name
|
import space.kscience.controls.spec.name
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,9 +25,9 @@ public interface DeviceState<T> {
|
|||||||
public companion object
|
public companion object
|
||||||
}
|
}
|
||||||
|
|
||||||
public val <T> DeviceState<T>.metaFlow: Flow<Meta> get() = valueFlow.map(converter::objectToMeta)
|
public val <T> DeviceState<T>.metaFlow: Flow<Meta> get() = valueFlow.map(converter::convert)
|
||||||
|
|
||||||
public val <T> DeviceState<T>.valueAsMeta: Meta get() = converter.objectToMeta(value)
|
public val <T> DeviceState<T>.valueAsMeta: Meta get() = converter.convert(value)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,9 +38,9 @@ public interface MutableDeviceState<T> : DeviceState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var <T : Any> MutableDeviceState<T>.valueAsMeta: Meta
|
public var <T : Any> MutableDeviceState<T>.valueAsMeta: Meta
|
||||||
get() = converter.objectToMeta(value)
|
get() = converter.convert(value)
|
||||||
set(arg) {
|
set(arg) {
|
||||||
value = converter.metaToObject(arg)
|
value = converter.read(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +98,7 @@ private open class BoundDeviceState<T>(
|
|||||||
override val valueFlow: StateFlow<T> = device.messageFlow.filterIsInstance<PropertyChangedMessage>().filter {
|
override val valueFlow: StateFlow<T> = device.messageFlow.filterIsInstance<PropertyChangedMessage>().filter {
|
||||||
it.property == propertyName
|
it.property == propertyName
|
||||||
}.mapNotNull {
|
}.mapNotNull {
|
||||||
converter.metaToObject(it.value)
|
converter.read(it.value)
|
||||||
}.stateIn(device.context, SharingStarted.Eagerly, initialValue)
|
}.stateIn(device.context, SharingStarted.Eagerly, initialValue)
|
||||||
|
|
||||||
override val value: T get() = valueFlow.value
|
override val value: T get() = valueFlow.value
|
||||||
@ -111,7 +111,7 @@ public suspend fun <T> Device.propertyAsState(
|
|||||||
propertyName: String,
|
propertyName: String,
|
||||||
metaConverter: MetaConverter<T>,
|
metaConverter: MetaConverter<T>,
|
||||||
): DeviceState<T> {
|
): DeviceState<T> {
|
||||||
val initialValue = metaConverter.metaToObject(readProperty(propertyName)) ?: error("Conversion of property failed")
|
val initialValue = metaConverter.readOrNull(readProperty(propertyName)) ?: error("Conversion of property failed")
|
||||||
return BoundDeviceState(metaConverter, this, propertyName, initialValue)
|
return BoundDeviceState(metaConverter, this, propertyName, initialValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ private class MutableBoundDeviceState<T>(
|
|||||||
get() = valueFlow.value
|
get() = valueFlow.value
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
device.launch {
|
device.launch {
|
||||||
device.writeProperty(propertyName, converter.objectToMeta(newValue))
|
device.writeProperty(propertyName, converter.convert(newValue))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ public suspend fun <T> Device.mutablePropertyAsState(
|
|||||||
propertyName: String,
|
propertyName: String,
|
||||||
metaConverter: MetaConverter<T>,
|
metaConverter: MetaConverter<T>,
|
||||||
): MutableDeviceState<T> {
|
): MutableDeviceState<T> {
|
||||||
val initialValue = metaConverter.metaToObject(readProperty(propertyName)) ?: error("Conversion of property failed")
|
val initialValue = metaConverter.readOrNull(readProperty(propertyName)) ?: error("Conversion of property failed")
|
||||||
return mutablePropertyAsState(propertyName, metaConverter, initialValue)
|
return mutablePropertyAsState(propertyName, metaConverter, initialValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ import space.kscience.controls.manager.clock
|
|||||||
import space.kscience.controls.spec.*
|
import space.kscience.controls.spec.*
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.double
|
import space.kscience.dataforge.meta.double
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
|
@ -2,7 +2,7 @@ package space.kscience.controls.constructor
|
|||||||
|
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.controls.spec.*
|
import space.kscience.controls.spec.*
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,7 +2,7 @@ package space.kscience.controls.constructor
|
|||||||
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +139,7 @@ public interface CachingDevice : Device {
|
|||||||
/**
|
/**
|
||||||
* Get the logical state of property or suspend to read the physical value.
|
* Get the logical state of property or suspend to read the physical value.
|
||||||
*/
|
*/
|
||||||
public suspend fun Device.requestProperty(propertyName: String): Meta = if (this is CachingDevice) {
|
public suspend fun Device.getOrReadProperty(propertyName: String): Meta = if (this is CachingDevice) {
|
||||||
getProperty(propertyName) ?: readProperty(propertyName)
|
getProperty(propertyName) ?: readProperty(propertyName)
|
||||||
} else {
|
} else {
|
||||||
readProperty(propertyName)
|
readProperty(propertyName)
|
||||||
|
@ -16,7 +16,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
|||||||
is PropertyGetMessage -> {
|
is PropertyGetMessage -> {
|
||||||
PropertyChangedMessage(
|
PropertyChangedMessage(
|
||||||
property = request.property,
|
property = request.property,
|
||||||
value = requestProperty(request.property),
|
value = getOrReadProperty(request.property),
|
||||||
sourceDevice = deviceTarget,
|
sourceDevice = deviceTarget,
|
||||||
targetDevice = request.sourceDevice
|
targetDevice = request.sourceDevice
|
||||||
)
|
)
|
||||||
@ -26,7 +26,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
|||||||
writeProperty(request.property, request.value)
|
writeProperty(request.property, request.value)
|
||||||
PropertyChangedMessage(
|
PropertyChangedMessage(
|
||||||
property = request.property,
|
property = request.property,
|
||||||
value = requestProperty(request.property),
|
value = getOrReadProperty(request.property),
|
||||||
sourceDevice = deviceTarget,
|
sourceDevice = deviceTarget,
|
||||||
targetDevice = request.sourceDevice
|
targetDevice = request.sourceDevice
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@ import space.kscience.controls.api.DeviceMessage
|
|||||||
import space.kscience.controls.api.PropertyChangedMessage
|
import space.kscience.controls.api.PropertyChangedMessage
|
||||||
import space.kscience.controls.spec.DevicePropertySpec
|
import space.kscience.controls.spec.DevicePropertySpec
|
||||||
import space.kscience.controls.spec.name
|
import space.kscience.controls.spec.name
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for device property history.
|
* An interface for device property history.
|
||||||
@ -42,7 +42,7 @@ public class CollectedPropertyHistory<T>(
|
|||||||
private val store: SharedFlow<ValueWithTime<T>> = eventFlow
|
private val store: SharedFlow<ValueWithTime<T>> = eventFlow
|
||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == propertyName }
|
.filter { it.property == propertyName }
|
||||||
.map { ValueWithTime(converter.metaToObject(it.value), it.time) }
|
.map { ValueWithTime(converter.read(it.value), it.time) }
|
||||||
.shareIn(scope, started = SharingStarted.Eagerly, replay = maxSize)
|
.shareIn(scope, started = SharingStarted.Eagerly, replay = maxSize)
|
||||||
|
|
||||||
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
||||||
|
@ -5,10 +5,8 @@ import kotlinx.io.Sink
|
|||||||
import kotlinx.io.Source
|
import kotlinx.io.Source
|
||||||
import space.kscience.dataforge.io.IOFormat
|
import space.kscience.dataforge.io.IOFormat
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A value coupled to a time it was obtained at
|
* A value coupled to a time it was obtained at
|
||||||
@ -36,8 +34,6 @@ public data class ValueWithTime<T>(val value: T, val time: Instant) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ValueWithTimeIOFormat<T>(val valueFormat: IOFormat<T>) : IOFormat<ValueWithTime<T>> {
|
private class ValueWithTimeIOFormat<T>(val valueFormat: IOFormat<T>) : IOFormat<ValueWithTime<T>> {
|
||||||
override val type: KType get() = typeOf<ValueWithTime<T>>()
|
|
||||||
|
|
||||||
|
|
||||||
override fun readFrom(source: Source): ValueWithTime<T> {
|
override fun readFrom(source: Source): ValueWithTime<T> {
|
||||||
val timestamp = InstantIOFormat.readFrom(source)
|
val timestamp = InstantIOFormat.readFrom(source)
|
||||||
@ -56,18 +52,18 @@ private class ValueWithTimeMetaConverter<T>(
|
|||||||
val valueConverter: MetaConverter<T>,
|
val valueConverter: MetaConverter<T>,
|
||||||
) : MetaConverter<ValueWithTime<T>> {
|
) : MetaConverter<ValueWithTime<T>> {
|
||||||
|
|
||||||
override val type: KType = typeOf<ValueWithTime<T>>()
|
|
||||||
|
|
||||||
override fun metaToObjectOrNull(
|
override fun readOrNull(
|
||||||
meta: Meta,
|
source: Meta,
|
||||||
): ValueWithTime<T>? = valueConverter.metaToObject(meta[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let {
|
): ValueWithTime<T>? = valueConverter.read(source[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let {
|
||||||
ValueWithTime(it, meta[ValueWithTime.META_TIME_KEY]?.instant ?: Instant.DISTANT_PAST)
|
ValueWithTime(it, source[ValueWithTime.META_TIME_KEY]?.instant ?: Instant.DISTANT_PAST)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun objectToMeta(obj: ValueWithTime<T>): Meta = Meta {
|
override fun convert(obj: ValueWithTime<T>): Meta = Meta {
|
||||||
ValueWithTime.META_TIME_KEY put obj.time.toMeta()
|
ValueWithTime.META_TIME_KEY put obj.time.toMeta()
|
||||||
ValueWithTime.META_VALUE_KEY put valueConverter.objectToMeta(obj.value)
|
ValueWithTime.META_VALUE_KEY put valueConverter.convert(obj.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public fun <T : Any> MetaConverter<T>.withTime(): MetaConverter<ValueWithTime<T>> = ValueWithTimeMetaConverter(this)
|
public fun <T : Any> MetaConverter<T>.withTime(): MetaConverter<ValueWithTime<T>> = ValueWithTimeMetaConverter(this)
|
@ -21,7 +21,7 @@ import kotlin.coroutines.CoroutineContext
|
|||||||
*/
|
*/
|
||||||
@OptIn(InternalDeviceAPI::class)
|
@OptIn(InternalDeviceAPI::class)
|
||||||
private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(device: D, item: Meta) {
|
private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(device: D, item: Meta) {
|
||||||
write(device, converter.metaToObject(item) ?: error("Meta $item could not be read with $converter"))
|
write(device, converter.readOrNull(item) ?: error("Meta $item could not be read with $converter"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,16 +29,16 @@ private suspend fun <D : Device, T> MutableDevicePropertySpec<D, T>.writeMeta(de
|
|||||||
*/
|
*/
|
||||||
@OptIn(InternalDeviceAPI::class)
|
@OptIn(InternalDeviceAPI::class)
|
||||||
private suspend fun <D : Device, T> DevicePropertySpec<D, T>.readMeta(device: D): Meta? =
|
private suspend fun <D : Device, T> DevicePropertySpec<D, T>.readMeta(device: D): Meta? =
|
||||||
read(device)?.let(converter::objectToMeta)
|
read(device)?.let(converter::convert)
|
||||||
|
|
||||||
|
|
||||||
private suspend fun <D : Device, I, O> DeviceActionSpec<D, I, O>.executeWithMeta(
|
private suspend fun <D : Device, I, O> DeviceActionSpec<D, I, O>.executeWithMeta(
|
||||||
device: D,
|
device: D,
|
||||||
item: Meta,
|
item: Meta,
|
||||||
): Meta? {
|
): Meta? {
|
||||||
val arg: I = inputConverter.metaToObject(item) ?: error("Failed to convert $item with $inputConverter")
|
val arg: I = inputConverter.readOrNull(item) ?: error("Failed to convert $item with $inputConverter")
|
||||||
val res = execute(device, arg)
|
val res = execute(device, arg)
|
||||||
return res?.let { outputConverter.objectToMeta(res) }
|
return res?.let { outputConverter.convert(res) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ public abstract class DeviceBase<D : Device>(
|
|||||||
* Notify the device that a property with [spec] value is changed
|
* Notify the device that a property with [spec] value is changed
|
||||||
*/
|
*/
|
||||||
protected suspend fun <T> propertyChanged(spec: DevicePropertySpec<D, T>, value: T) {
|
protected suspend fun <T> propertyChanged(spec: DevicePropertySpec<D, T>, value: T) {
|
||||||
propertyChanged(spec.name, spec.converter.objectToMeta(value))
|
propertyChanged(spec.name, spec.converter.convert(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,7 @@ package space.kscience.controls.spec
|
|||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.controls.api.PropertyDescriptor
|
import space.kscience.controls.api.PropertyDescriptor
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
internal object DeviceMetaPropertySpec : DevicePropertySpec<Device, Meta> {
|
internal object DeviceMetaPropertySpec : DevicePropertySpec<Device, Meta> {
|
||||||
override val descriptor: PropertyDescriptor = PropertyDescriptor("@meta")
|
override val descriptor: PropertyDescriptor = PropertyDescriptor("@meta")
|
||||||
|
@ -5,7 +5,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.controls.api.*
|
import space.kscience.controls.api.*
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,23 +72,23 @@ public interface DeviceActionSpec<in D, I, O> {
|
|||||||
public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name
|
public val DeviceActionSpec<*, *, *>.name: String get() = descriptor.name
|
||||||
|
|
||||||
public suspend fun <T, D : Device> D.read(propertySpec: DevicePropertySpec<D, T>): T =
|
public suspend fun <T, D : Device> D.read(propertySpec: DevicePropertySpec<D, T>): T =
|
||||||
propertySpec.converter.metaToObject(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
|
propertySpec.converter.readOrNull(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read typed value and update/push event if needed.
|
* Read typed value and update/push event if needed.
|
||||||
* Return null if property read is not successful or property is undefined.
|
* Return null if property read is not successful or property is undefined.
|
||||||
*/
|
*/
|
||||||
public suspend fun <T, D : DeviceBase<D>> D.readOrNull(propertySpec: DevicePropertySpec<D, T>): T? =
|
public suspend fun <T, D : DeviceBase<D>> D.readOrNull(propertySpec: DevicePropertySpec<D, T>): T? =
|
||||||
readPropertyOrNull(propertySpec.name)?.let(propertySpec.converter::metaToObject)
|
readPropertyOrNull(propertySpec.name)?.let(propertySpec.converter::readOrNull)
|
||||||
|
|
||||||
public suspend fun <T, D : Device> D.request(propertySpec: DevicePropertySpec<D, T>): T =
|
public suspend fun <T, D : Device> D.getOrRead(propertySpec: DevicePropertySpec<D, T>): T =
|
||||||
propertySpec.converter.metaToObject(requestProperty(propertySpec.name))
|
propertySpec.converter.read(getOrReadProperty(propertySpec.name))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write typed property state and invalidate logical state
|
* Write typed property state and invalidate logical state
|
||||||
*/
|
*/
|
||||||
public suspend fun <T, D : Device> D.write(propertySpec: MutableDevicePropertySpec<D, T>, value: T) {
|
public suspend fun <T, D : Device> D.write(propertySpec: MutableDevicePropertySpec<D, T>, value: T) {
|
||||||
writeProperty(propertySpec.name, propertySpec.converter.objectToMeta(value))
|
writeProperty(propertySpec.name, propertySpec.converter.convert(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,7 +104,7 @@ public fun <T, D : Device> D.writeAsync(propertySpec: MutableDevicePropertySpec<
|
|||||||
public fun <D : Device, T> D.propertyFlow(spec: DevicePropertySpec<D, T>): Flow<T> = messageFlow
|
public fun <D : Device, T> D.propertyFlow(spec: DevicePropertySpec<D, T>): Flow<T> = messageFlow
|
||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.mapNotNull { spec.converter.metaToObject(it.value) }
|
.mapNotNull { spec.converter.read(it.value) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A type safe property change listener. Uses the device [CoroutineScope].
|
* A type safe property change listener. Uses the device [CoroutineScope].
|
||||||
@ -117,7 +117,7 @@ public fun <D : Device, T> D.onPropertyChange(
|
|||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.onEach { change ->
|
.onEach { change ->
|
||||||
val newValue = spec.converter.metaToObject(change.value)
|
val newValue = spec.converter.read(change.value)
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
change.callback(newValue)
|
change.callback(newValue)
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ public fun <D : Device, T> D.useProperty(
|
|||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.collect { change ->
|
.collect { change ->
|
||||||
val newValue = spec.converter.metaToObject(change.value)
|
val newValue = spec.converter.readOrNull(change.value)
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
callback(newValue)
|
callback(newValue)
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,16 @@ import space.kscience.controls.api.ActionDescriptor
|
|||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.controls.api.PropertyDescriptor
|
import space.kscience.controls.api.PropertyDescriptor
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
|
|
||||||
public object UnitMetaConverter : MetaConverter<Unit> {
|
public object UnitMetaConverter : MetaConverter<Unit> {
|
||||||
|
|
||||||
override val type: KType = typeOf<Unit>()
|
override fun readOrNull(source: Meta): Unit = Unit
|
||||||
|
|
||||||
override fun metaToObjectOrNull(meta: Meta): Unit = Unit
|
override fun convert(obj: Unit): Meta = Meta.EMPTY
|
||||||
|
|
||||||
override fun objectToMeta(obj: Unit): Meta = Meta.EMPTY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaConverter
|
public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaConverter
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package space.kscience.controls.spec
|
package space.kscience.controls.spec
|
||||||
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
@ -12,16 +9,14 @@ public fun Double.asMeta(): Meta = Meta(asValue())
|
|||||||
|
|
||||||
//TODO to be moved to DF
|
//TODO to be moved to DF
|
||||||
public object DurationConverter : MetaConverter<Duration> {
|
public object DurationConverter : MetaConverter<Duration> {
|
||||||
override val type: KType = typeOf<Duration>()
|
override fun readOrNull(source: Meta): Duration = source.value?.double?.toDuration(DurationUnit.SECONDS)
|
||||||
|
|
||||||
override fun metaToObjectOrNull(meta: Meta): Duration = meta.value?.double?.toDuration(DurationUnit.SECONDS)
|
|
||||||
?: run {
|
?: run {
|
||||||
val unit: DurationUnit = meta["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
|
val unit: DurationUnit = source["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
|
||||||
val value = meta[Meta.VALUE_KEY].double ?: error("No value present for Duration")
|
val value = source[Meta.VALUE_KEY].double ?: error("No value present for Duration")
|
||||||
return@run value.toDuration(unit)
|
return@run value.toDuration(unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun objectToMeta(obj: Duration): Meta = obj.toDouble(DurationUnit.SECONDS).asMeta()
|
override fun convert(obj: Duration): Meta = obj.toDouble(DurationUnit.SECONDS).asMeta()
|
||||||
}
|
}
|
||||||
|
|
||||||
public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter
|
public val MetaConverter.Companion.duration: MetaConverter<Duration> get() = DurationConverter
|
@ -4,8 +4,8 @@ import space.kscience.controls.api.Device
|
|||||||
import space.kscience.controls.api.PropertyDescriptor
|
import space.kscience.controls.api.PropertyDescriptor
|
||||||
import space.kscience.controls.api.metaDescriptor
|
import space.kscience.controls.api.metaDescriptor
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.ValueType
|
import space.kscience.dataforge.meta.ValueType
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
@ -53,8 +53,8 @@ public fun <T, D : DeviceBase<D>> DeviceSpec<D>.logicalProperty(
|
|||||||
converter,
|
converter,
|
||||||
descriptorBuilder,
|
descriptorBuilder,
|
||||||
name,
|
name,
|
||||||
read = { propertyName -> getProperty(propertyName)?.let(converter::metaToObject) },
|
read = { propertyName -> getProperty(propertyName)?.let(converter::readOrNull) },
|
||||||
write = { propertyName, value -> writeProperty(propertyName, converter.objectToMeta(value)) }
|
write = { propertyName, value -> writeProperty(propertyName, converter.convert(value)) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
import space.kscience.visionforge.html.runVisionClient
|
||||||
import space.kscience.visionforge.jupyter.VFNotebookClient
|
import space.kscience.visionforge.jupyter.VFNotebookClient
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.runVisionClient
|
|
||||||
|
|
||||||
public fun main(): Unit = runVisionClient {
|
public fun main(): Unit = runVisionClient {
|
||||||
// plugin(DeviceManager)
|
// plugin(DeviceManager)
|
||||||
|
@ -144,7 +144,7 @@ public fun <T> MagixEndpoint.controlsPropertyFlow(
|
|||||||
.filter { message ->
|
.filter { message ->
|
||||||
message.sourceDevice == deviceName && message.property == propertySpec.name
|
message.sourceDevice == deviceName && message.property == propertySpec.name
|
||||||
}.map {
|
}.map {
|
||||||
propertySpec.converter.metaToObject(it.value)
|
propertySpec.converter.read(it.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ public suspend fun <T> MagixEndpoint.sendControlsPropertyChange(
|
|||||||
) {
|
) {
|
||||||
val message = PropertySetMessage(
|
val message = PropertySetMessage(
|
||||||
property = propertySpec.name,
|
property = propertySpec.name,
|
||||||
value = propertySpec.converter.objectToMeta(value),
|
value = propertySpec.converter.convert(value),
|
||||||
targetDevice = deviceName
|
targetDevice = deviceName
|
||||||
)
|
)
|
||||||
send(DeviceManager.magixFormat, message, source = sourceEndpointName, target = targetEndpointName)
|
send(DeviceManager.magixFormat, message, source = sourceEndpointName, target = targetEndpointName)
|
||||||
@ -177,6 +177,6 @@ public fun <T> MagixEndpoint.controlsPropertyMessageFlow(
|
|||||||
.filter { message ->
|
.filter { message ->
|
||||||
message.sourceDevice == deviceName && message.property == propertySpec.name
|
message.sourceDevice == deviceName && message.property == propertySpec.name
|
||||||
}.map {
|
}.map {
|
||||||
it to propertySpec.converter.metaToObject(it.value)
|
it to propertySpec.converter.read(it.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import space.kscience.controls.api.PropertyChangedMessage
|
import space.kscience.controls.api.PropertyChangedMessage
|
||||||
import space.kscience.controls.api.requestProperty
|
import space.kscience.controls.api.getOrReadProperty
|
||||||
import space.kscience.controls.spec.DeviceActionSpec
|
import space.kscience.controls.spec.DeviceActionSpec
|
||||||
import space.kscience.controls.spec.DevicePropertySpec
|
import space.kscience.controls.spec.DevicePropertySpec
|
||||||
import space.kscience.controls.spec.MutableDevicePropertySpec
|
import space.kscience.controls.spec.MutableDevicePropertySpec
|
||||||
@ -17,14 +17,14 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
* An accessor that allows DeviceClient to connect to any property without type checks
|
* An accessor that allows DeviceClient to connect to any property without type checks
|
||||||
*/
|
*/
|
||||||
public suspend fun <T> DeviceClient.read(propertySpec: DevicePropertySpec<*, T>): T =
|
public suspend fun <T> DeviceClient.read(propertySpec: DevicePropertySpec<*, T>): T =
|
||||||
propertySpec.converter.metaToObject(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
|
propertySpec.converter.readOrNull(readProperty(propertySpec.name)) ?: error("Property read result is not valid")
|
||||||
|
|
||||||
|
|
||||||
public suspend fun <T> DeviceClient.request(propertySpec: DevicePropertySpec<*, T>): T =
|
public suspend fun <T> DeviceClient.request(propertySpec: DevicePropertySpec<*, T>): T =
|
||||||
propertySpec.converter.metaToObject(requestProperty(propertySpec.name))
|
propertySpec.converter.read(getOrReadProperty(propertySpec.name))
|
||||||
|
|
||||||
public suspend fun <T> DeviceClient.write(propertySpec: MutableDevicePropertySpec<*, T>, value: T) {
|
public suspend fun <T> DeviceClient.write(propertySpec: MutableDevicePropertySpec<*, T>, value: T) {
|
||||||
writeProperty(propertySpec.name, propertySpec.converter.objectToMeta(value))
|
writeProperty(propertySpec.name, propertySpec.converter.convert(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*, T>, value: T): Job = launch {
|
public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*, T>, value: T): Job = launch {
|
||||||
@ -34,7 +34,7 @@ public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*
|
|||||||
public fun <T> DeviceClient.propertyFlow(spec: DevicePropertySpec<*, T>): Flow<T> = messageFlow
|
public fun <T> DeviceClient.propertyFlow(spec: DevicePropertySpec<*, T>): Flow<T> = messageFlow
|
||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.mapNotNull { spec.converter.metaToObject(it.value) }
|
.mapNotNull { spec.converter.readOrNull(it.value) }
|
||||||
|
|
||||||
public fun <T> DeviceClient.onPropertyChange(
|
public fun <T> DeviceClient.onPropertyChange(
|
||||||
spec: DevicePropertySpec<*, T>,
|
spec: DevicePropertySpec<*, T>,
|
||||||
@ -44,7 +44,7 @@ public fun <T> DeviceClient.onPropertyChange(
|
|||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.onEach { change ->
|
.onEach { change ->
|
||||||
val newValue = spec.converter.metaToObject(change.value)
|
val newValue = spec.converter.readOrNull(change.value)
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
change.callback(newValue)
|
change.callback(newValue)
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ public fun <T> DeviceClient.useProperty(
|
|||||||
.filterIsInstance<PropertyChangedMessage>()
|
.filterIsInstance<PropertyChangedMessage>()
|
||||||
.filter { it.property == spec.name }
|
.filter { it.property == spec.name }
|
||||||
.collect { change ->
|
.collect { change ->
|
||||||
val newValue = spec.converter.metaToObject(change.value)
|
val newValue = spec.converter.readOrNull(change.value)
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
callback(newValue)
|
callback(newValue)
|
||||||
}
|
}
|
||||||
@ -68,12 +68,12 @@ public fun <T> DeviceClient.useProperty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun <I, O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, I, O>, input: I): O {
|
public suspend fun <I, O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, I, O>, input: I): O {
|
||||||
val inputMeta = actionSpec.inputConverter.objectToMeta(input)
|
val inputMeta = actionSpec.inputConverter.convert(input)
|
||||||
val res = execute(actionSpec.name, inputMeta)
|
val res = execute(actionSpec.name, inputMeta)
|
||||||
return actionSpec.outputConverter.metaToObject(res ?: Meta.EMPTY)
|
return actionSpec.outputConverter.read(res ?: Meta.EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend fun <O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, Unit, O>): O {
|
public suspend fun <O> DeviceClient.execute(actionSpec: DeviceActionSpec<*, Unit, O>): O {
|
||||||
val res = execute(actionSpec.name, Meta.EMPTY)
|
val res = execute(actionSpec.name, Meta.EMPTY)
|
||||||
return actionSpec.outputConverter.metaToObject(res ?: Meta.EMPTY)
|
return actionSpec.outputConverter.read(res ?: Meta.EMPTY)
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import space.kscience.controls.api.get
|
import space.kscience.controls.api.get
|
||||||
import space.kscience.controls.api.requestProperty
|
import space.kscience.controls.api.getOrReadProperty
|
||||||
import space.kscience.controls.manager.DeviceManager
|
import space.kscience.controls.manager.DeviceManager
|
||||||
import space.kscience.dataforge.context.error
|
import space.kscience.dataforge.context.error
|
||||||
import space.kscience.dataforge.context.logger
|
import space.kscience.dataforge.context.logger
|
||||||
@ -91,7 +91,7 @@ public fun DeviceManager.launchTangoMagix(
|
|||||||
val device = get(payload.device)
|
val device = get(payload.device)
|
||||||
when (payload.action) {
|
when (payload.action) {
|
||||||
TangoAction.read -> {
|
TangoAction.read -> {
|
||||||
val value = device.requestProperty(payload.name)
|
val value = device.getOrReadProperty(payload.name)
|
||||||
respond(request, payload) { requestPayload ->
|
respond(request, payload) { requestPayload ->
|
||||||
requestPayload.copy(
|
requestPayload.copy(
|
||||||
value = value,
|
value = value,
|
||||||
@ -104,7 +104,7 @@ public fun DeviceManager.launchTangoMagix(
|
|||||||
device.writeProperty(payload.name, value)
|
device.writeProperty(payload.name, value)
|
||||||
}
|
}
|
||||||
//wait for value to be written and return final state
|
//wait for value to be written and return final state
|
||||||
val value = device.requestProperty(payload.name)
|
val value = device.getOrReadProperty(payload.name)
|
||||||
respond(request, payload) { requestPayload ->
|
respond(request, payload) { requestPayload ->
|
||||||
requestPayload.copy(
|
requestPayload.copy(
|
||||||
value = value,
|
value = value,
|
||||||
|
@ -9,8 +9,8 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.*
|
|||||||
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn
|
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn
|
||||||
import space.kscience.controls.api.Device
|
import space.kscience.controls.api.Device
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.MetaSerializer
|
import space.kscience.dataforge.meta.MetaSerializer
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ public suspend inline fun <reified T: Any> OpcUaDevice.readOpcWithTime(
|
|||||||
else -> error("Incompatible OPC property value $content")
|
else -> error("Incompatible OPC property value $content")
|
||||||
}
|
}
|
||||||
|
|
||||||
val res: T = converter.metaToObject(meta)
|
val res: T = converter.read(meta)
|
||||||
return res to time
|
return res to time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ public suspend inline fun <reified T> OpcUaDevice.readOpc(
|
|||||||
else -> error("Incompatible OPC property value $content")
|
else -> error("Incompatible OPC property value $content")
|
||||||
}
|
}
|
||||||
|
|
||||||
return converter.metaToObject(meta) ?: error("Meta $meta could not be converted to ${T::class}")
|
return converter.readOrNull(meta) ?: error("Meta $meta could not be converted to ${T::class}")
|
||||||
}
|
}
|
||||||
|
|
||||||
public suspend inline fun <reified T> OpcUaDevice.writeOpc(
|
public suspend inline fun <reified T> OpcUaDevice.writeOpc(
|
||||||
@ -77,7 +77,7 @@ public suspend inline fun <reified T> OpcUaDevice.writeOpc(
|
|||||||
converter: MetaConverter<T>,
|
converter: MetaConverter<T>,
|
||||||
value: T
|
value: T
|
||||||
): StatusCode {
|
): StatusCode {
|
||||||
val meta = converter.objectToMeta(value)
|
val meta = converter.convert(value)
|
||||||
return client.writeValue(nodeId, DataValue(Variant(meta))).await()
|
return client.writeValue(nodeId, DataValue(Variant(meta))).await()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public class MiloConfiguration : Scheme() {
|
|||||||
|
|
||||||
public var endpointUrl: String by string { error("Endpoint url is not defined") }
|
public var endpointUrl: String by string { error("Endpoint url is not defined") }
|
||||||
|
|
||||||
public var username: MiloUsername? by specOrNull(MiloUsername)
|
public var username: MiloUsername? by schemeOrNull(MiloUsername)
|
||||||
|
|
||||||
public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None)
|
public var securityPolicy: SecurityPolicy by enum(SecurityPolicy.None)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test
|
|||||||
import space.kscience.controls.spec.DeviceSpec
|
import space.kscience.controls.spec.DeviceSpec
|
||||||
import space.kscience.controls.spec.doubleProperty
|
import space.kscience.controls.spec.doubleProperty
|
||||||
import space.kscience.controls.spec.read
|
import space.kscience.controls.spec.read
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import kotlin.test.Ignore
|
import kotlin.test.Ignore
|
||||||
|
|
||||||
class OpcUaClientTest {
|
class OpcUaClientTest {
|
||||||
|
@ -6,8 +6,6 @@ import jetbrains.exodus.entitystore.PersistentEntityStores
|
|||||||
import jetbrains.exodus.entitystore.StoreTransaction
|
import jetbrains.exodus.entitystore.StoreTransaction
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@ -72,13 +70,13 @@ public class XodusDeviceMessageStorage(
|
|||||||
DEVICE_MESSAGE_ENTITY_TYPE,
|
DEVICE_MESSAGE_ENTITY_TYPE,
|
||||||
DeviceMessage::time.name,
|
DeviceMessage::time.name,
|
||||||
true
|
true
|
||||||
).asFlow().map {
|
).map {
|
||||||
Json.decodeFromString(
|
Json.decodeFromString(
|
||||||
DeviceMessage.serializer(),
|
DeviceMessage.serializer(),
|
||||||
it.getBlobString("json") ?: error("No json content found")
|
it.getBlobString("json") ?: error("No json content found")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}.asFlow()
|
||||||
|
|
||||||
override fun read(
|
override fun read(
|
||||||
eventType: String,
|
eventType: String,
|
||||||
@ -90,7 +88,7 @@ public class XodusDeviceMessageStorage(
|
|||||||
DEVICE_MESSAGE_ENTITY_TYPE,
|
DEVICE_MESSAGE_ENTITY_TYPE,
|
||||||
"type",
|
"type",
|
||||||
eventType
|
eventType
|
||||||
).asFlow().filter {
|
).filter {
|
||||||
it.timeInRange(range) &&
|
it.timeInRange(range) &&
|
||||||
it.propertyMatchesName(DeviceMessage::sourceDevice.name, sourceDevice) &&
|
it.propertyMatchesName(DeviceMessage::sourceDevice.name, sourceDevice) &&
|
||||||
it.propertyMatchesName(DeviceMessage::targetDevice.name, targetDevice)
|
it.propertyMatchesName(DeviceMessage::targetDevice.name, targetDevice)
|
||||||
@ -100,7 +98,7 @@ public class XodusDeviceMessageStorage(
|
|||||||
it.getBlobString("json") ?: error("No json content found")
|
it.getBlobString("json") ?: error("No json content found")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}.asFlow()
|
||||||
|
|
||||||
override fun close() {
|
override fun close() {
|
||||||
entityStore.close()
|
entityStore.close()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import jetbrains.exodus.entitystore.PersistentEntityStores
|
import jetbrains.exodus.entitystore.PersistentEntityStores
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.junit.jupiter.api.AfterAll
|
||||||
@ -7,8 +8,8 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
|||||||
import org.junit.jupiter.api.BeforeAll
|
import org.junit.jupiter.api.BeforeAll
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import space.kscience.controls.api.PropertyChangedMessage
|
import space.kscience.controls.api.PropertyChangedMessage
|
||||||
|
import space.kscience.controls.storage.read
|
||||||
import space.kscience.controls.xodus.XodusDeviceMessageStorage
|
import space.kscience.controls.xodus.XodusDeviceMessageStorage
|
||||||
import space.kscience.controls.xodus.query
|
|
||||||
import space.kscience.controls.xodus.writeMessage
|
import space.kscience.controls.xodus.writeMessage
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
@ -67,7 +68,7 @@ internal class PropertyHistoryTest {
|
|||||||
XodusDeviceMessageStorage(entityStore).use { storage ->
|
XodusDeviceMessageStorage(entityStore).use { storage ->
|
||||||
assertEquals(
|
assertEquals(
|
||||||
propertyChangedMessages[0],
|
propertyChangedMessages[0],
|
||||||
storage.query<PropertyChangedMessage>(
|
storage.read<PropertyChangedMessage>(
|
||||||
sourceDevice = "virtual-car".asName()
|
sourceDevice = "virtual-car".asName()
|
||||||
).first { it.property == "speed" }
|
).first { it.property == "speed" }
|
||||||
)
|
)
|
||||||
|
@ -7,7 +7,7 @@ import kotlinx.datetime.Instant
|
|||||||
import space.kscience.controls.api.PropertyChangedMessage
|
import space.kscience.controls.api.PropertyChangedMessage
|
||||||
import space.kscience.controls.misc.PropertyHistory
|
import space.kscience.controls.misc.PropertyHistory
|
||||||
import space.kscience.controls.misc.ValueWithTime
|
import space.kscience.controls.misc.ValueWithTime
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
|
|
||||||
public fun <T> DeviceMessageStorage.propertyHistory(
|
public fun <T> DeviceMessageStorage.propertyHistory(
|
||||||
propertyName: String,
|
propertyName: String,
|
||||||
@ -16,5 +16,5 @@ public fun <T> DeviceMessageStorage.propertyHistory(
|
|||||||
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
||||||
read<PropertyChangedMessage>(from..until)
|
read<PropertyChangedMessage>(from..until)
|
||||||
.filter { it.property == propertyName }
|
.filter { it.property == propertyName }
|
||||||
.map { ValueWithTime(converter.metaToObject(it.value), it.time) }
|
.map { ValueWithTime(converter.read(it.value), it.time) }
|
||||||
}
|
}
|
@ -149,7 +149,7 @@ private fun <T> Trace.updateFromState(
|
|||||||
public fun <T> Plot.plotDeviceState(
|
public fun <T> Plot.plotDeviceState(
|
||||||
context: Context,
|
context: Context,
|
||||||
state: DeviceState<T>,
|
state: DeviceState<T>,
|
||||||
extractValue: T.() -> Value = { state.converter.objectToMeta(this).value ?: Null },
|
extractValue: T.() -> Value = { state.converter.convert(this).value ?: Null },
|
||||||
maxAge: Duration = defaultMaxAge,
|
maxAge: Duration = defaultMaxAge,
|
||||||
maxPoints: Int = defaultMaxPoints,
|
maxPoints: Int = defaultMaxPoints,
|
||||||
minPoints: Int = defaultMinPoints,
|
minPoints: Int = defaultMinPoints,
|
||||||
|
@ -7,10 +7,9 @@ import space.kscience.dataforge.context.PluginFactory
|
|||||||
import space.kscience.dataforge.context.PluginTag
|
import space.kscience.dataforge.context.PluginTag
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.ElementVisionRenderer
|
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionClient
|
|
||||||
import space.kscience.visionforge.VisionPlugin
|
import space.kscience.visionforge.VisionPlugin
|
||||||
|
import space.kscience.visionforge.html.ElementVisionRenderer
|
||||||
|
|
||||||
public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer {
|
public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
@ -21,7 +20,7 @@ public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package space.kscience.controls.vision
|
package space.kscience.controls.vision
|
||||||
|
|
||||||
|
import space.kscience.visionforge.html.runVisionClient
|
||||||
import space.kscience.visionforge.markup.MarkupPlugin
|
import space.kscience.visionforge.markup.MarkupPlugin
|
||||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||||
import space.kscience.visionforge.runVisionClient
|
|
||||||
|
|
||||||
public fun main(): Unit = runVisionClient {
|
public fun main(): Unit = runVisionClient {
|
||||||
plugin(PlotlyPlugin)
|
plugin(PlotlyPlugin)
|
||||||
|
@ -24,7 +24,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||||
implementation("no.tornado:tornadofx:1.7.20")
|
implementation("no.tornado:tornadofx:1.7.20")
|
||||||
implementation("space.kscience:plotlykt-server:0.6.1")
|
implementation("space.kscience:plotlykt-server:0.7.1")
|
||||||
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
// implementation("com.github.Ricky12Awesome:json-schema-serialization:0.6.6")
|
||||||
implementation(spclibs.logback.classic)
|
implementation(spclibs.logback.classic)
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,9 @@ import space.kscience.controls.spec.*
|
|||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.ValueType
|
import space.kscience.dataforge.meta.ValueType
|
||||||
import space.kscience.dataforge.meta.descriptors.value
|
import space.kscience.dataforge.meta.descriptors.value
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
@ -22,7 +22,7 @@ class MagixVirtualCar(context: Context, meta: Meta) : VirtualCar(context, meta)
|
|||||||
(payload as? PropertyChangedMessage)?.let { message ->
|
(payload as? PropertyChangedMessage)?.let { message ->
|
||||||
if (message.sourceDevice == Name.parse("virtual-car")) {
|
if (message.sourceDevice == Name.parse("virtual-car")) {
|
||||||
when (message.property) {
|
when (message.property) {
|
||||||
"acceleration" -> write(IVirtualCar.acceleration, Vector2D.metaToObject(message.value))
|
"acceleration" -> write(IVirtualCar.acceleration, Vector2D.read(message.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,34 +11,26 @@ import space.kscience.controls.spec.doRecurring
|
|||||||
import space.kscience.controls.spec.read
|
import space.kscience.controls.spec.read
|
||||||
import space.kscience.dataforge.context.Context
|
import space.kscience.dataforge.context.Context
|
||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.MetaRepr
|
|
||||||
import space.kscience.dataforge.meta.double
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
import kotlin.reflect.KType
|
|
||||||
import kotlin.reflect.typeOf
|
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
data class Vector2D(var x: Double = 0.0, var y: Double = 0.0) : MetaRepr {
|
data class Vector2D(var x: Double = 0.0, var y: Double = 0.0) : MetaRepr {
|
||||||
|
|
||||||
override fun toMeta(): Meta = objectToMeta(this)
|
override fun toMeta(): Meta = convert(this)
|
||||||
|
|
||||||
operator fun div(arg: Double): Vector2D = Vector2D(x / arg, y / arg)
|
operator fun div(arg: Double): Vector2D = Vector2D(x / arg, y / arg)
|
||||||
|
|
||||||
companion object CoordinatesMetaConverter : MetaConverter<Vector2D> {
|
companion object CoordinatesMetaConverter : MetaConverter<Vector2D> {
|
||||||
|
|
||||||
override val type: KType = typeOf<Vector2D>()
|
override fun readOrNull(source: Meta): Vector2D = Vector2D(
|
||||||
|
source["x"].double ?: 0.0,
|
||||||
override fun metaToObjectOrNull(meta: Meta): Vector2D = Vector2D(
|
source["y"].double ?: 0.0
|
||||||
meta["x"].double ?: 0.0,
|
|
||||||
meta["y"].double ?: 0.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun objectToMeta(obj: Vector2D): Meta = Meta {
|
override fun convert(obj: Vector2D): Meta = Meta {
|
||||||
"x" put obj.x
|
"x" put obj.x
|
||||||
"y" put obj.y
|
"y" put obj.y
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ import space.kscience.dataforge.context.Context
|
|||||||
import space.kscience.dataforge.context.Factory
|
import space.kscience.dataforge.context.Factory
|
||||||
import space.kscience.dataforge.context.request
|
import space.kscience.dataforge.context.request
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.meta.MetaConverter
|
||||||
import space.kscience.dataforge.meta.get
|
import space.kscience.dataforge.meta.get
|
||||||
import space.kscience.dataforge.meta.int
|
import space.kscience.dataforge.meta.int
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
|
|
||||||
|
|
||||||
//TODO this device is not tested
|
//TODO this device is not tested
|
||||||
@ -94,7 +94,7 @@ class MksPdr900Device(context: Context, meta: Meta) : DeviceBySpec<MksPdr900Devi
|
|||||||
val channel by logicalProperty(MetaConverter.int)
|
val channel by logicalProperty(MetaConverter.int)
|
||||||
|
|
||||||
val value by doubleProperty(read = {
|
val value by doubleProperty(read = {
|
||||||
readChannelData(request(channel) ?: DEFAULT_CHANNEL)
|
readChannelData(getOrRead(channel))
|
||||||
})
|
})
|
||||||
|
|
||||||
val error by logicalProperty(MetaConverter.string)
|
val error by logicalProperty(MetaConverter.string)
|
||||||
|
@ -16,11 +16,7 @@ import space.kscience.controls.api.PropertyDescriptor
|
|||||||
import space.kscience.controls.ports.*
|
import space.kscience.controls.ports.*
|
||||||
import space.kscience.controls.spec.*
|
import space.kscience.controls.spec.*
|
||||||
import space.kscience.dataforge.context.*
|
import space.kscience.dataforge.context.*
|
||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.meta.asValue
|
|
||||||
import space.kscience.dataforge.meta.double
|
|
||||||
import space.kscience.dataforge.meta.get
|
|
||||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
|
||||||
import space.kscience.dataforge.names.NameToken
|
import space.kscience.dataforge.names.NameToken
|
||||||
import kotlin.collections.component1
|
import kotlin.collections.component1
|
||||||
import kotlin.collections.component2
|
import kotlin.collections.component2
|
||||||
|
Loading…
Reference in New Issue
Block a user