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")
|
||||
}
|
||||
|
||||
val dataforgeVersion: String by extra("0.7.1")
|
||||
val visionforgeVersion by extra("0.3.1")
|
||||
val dataforgeVersion: String by extra("0.8.0")
|
||||
val visionforgeVersion by extra("0.4.0")
|
||||
val ktorVersion: String by extra(space.kscience.gradle.KScienceVersions.ktorVersion)
|
||||
val rsocketVersion by extra("0.15.4")
|
||||
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.Factory
|
||||
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.asName
|
||||
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.Factory
|
||||
import space.kscience.dataforge.context.request
|
||||
import space.kscience.dataforge.meta.Laminate
|
||||
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.meta.*
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.*
|
||||
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.name
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
@ -25,9 +25,9 @@ public interface DeviceState<T> {
|
||||
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
|
||||
get() = converter.objectToMeta(value)
|
||||
get() = converter.convert(value)
|
||||
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 {
|
||||
it.property == propertyName
|
||||
}.mapNotNull {
|
||||
converter.metaToObject(it.value)
|
||||
converter.read(it.value)
|
||||
}.stateIn(device.context, SharingStarted.Eagerly, initialValue)
|
||||
|
||||
override val value: T get() = valueFlow.value
|
||||
@ -111,7 +111,7 @@ public suspend fun <T> Device.propertyAsState(
|
||||
propertyName: String,
|
||||
metaConverter: MetaConverter<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)
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ private class MutableBoundDeviceState<T>(
|
||||
get() = valueFlow.value
|
||||
set(newValue) {
|
||||
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,
|
||||
metaConverter: MetaConverter<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)
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,9 @@ import space.kscience.controls.manager.clock
|
||||
import space.kscience.controls.spec.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Factory
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
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.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.DurationUnit
|
||||
|
@ -2,7 +2,7 @@ package space.kscience.controls.constructor
|
||||
|
||||
import space.kscience.controls.api.Device
|
||||
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.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.
|
||||
*/
|
||||
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)
|
||||
} else {
|
||||
readProperty(propertyName)
|
||||
|
@ -16,7 +16,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
||||
is PropertyGetMessage -> {
|
||||
PropertyChangedMessage(
|
||||
property = request.property,
|
||||
value = requestProperty(request.property),
|
||||
value = getOrReadProperty(request.property),
|
||||
sourceDevice = deviceTarget,
|
||||
targetDevice = request.sourceDevice
|
||||
)
|
||||
@ -26,7 +26,7 @@ public suspend fun Device.respondMessage(deviceTarget: Name, request: DeviceMess
|
||||
writeProperty(request.property, request.value)
|
||||
PropertyChangedMessage(
|
||||
property = request.property,
|
||||
value = requestProperty(request.property),
|
||||
value = getOrReadProperty(request.property),
|
||||
sourceDevice = deviceTarget,
|
||||
targetDevice = request.sourceDevice
|
||||
)
|
||||
|
@ -9,7 +9,7 @@ import space.kscience.controls.api.DeviceMessage
|
||||
import space.kscience.controls.api.PropertyChangedMessage
|
||||
import space.kscience.controls.spec.DevicePropertySpec
|
||||
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.
|
||||
@ -42,7 +42,7 @@ public class CollectedPropertyHistory<T>(
|
||||
private val store: SharedFlow<ValueWithTime<T>> = eventFlow
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.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)
|
||||
|
||||
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
||||
|
@ -5,10 +5,8 @@ import kotlinx.io.Sink
|
||||
import kotlinx.io.Source
|
||||
import space.kscience.dataforge.io.IOFormat
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
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
|
||||
@ -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>> {
|
||||
override val type: KType get() = typeOf<ValueWithTime<T>>()
|
||||
|
||||
|
||||
override fun readFrom(source: Source): ValueWithTime<T> {
|
||||
val timestamp = InstantIOFormat.readFrom(source)
|
||||
@ -56,18 +52,18 @@ private class ValueWithTimeMetaConverter<T>(
|
||||
val valueConverter: MetaConverter<T>,
|
||||
) : MetaConverter<ValueWithTime<T>> {
|
||||
|
||||
override val type: KType = typeOf<ValueWithTime<T>>()
|
||||
|
||||
override fun metaToObjectOrNull(
|
||||
meta: Meta,
|
||||
): ValueWithTime<T>? = valueConverter.metaToObject(meta[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let {
|
||||
ValueWithTime(it, meta[ValueWithTime.META_TIME_KEY]?.instant ?: Instant.DISTANT_PAST)
|
||||
override fun readOrNull(
|
||||
source: Meta,
|
||||
): ValueWithTime<T>? = valueConverter.read(source[ValueWithTime.META_VALUE_KEY] ?: Meta.EMPTY)?.let {
|
||||
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_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)
|
@ -21,7 +21,7 @@ import kotlin.coroutines.CoroutineContext
|
||||
*/
|
||||
@OptIn(InternalDeviceAPI::class)
|
||||
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)
|
||||
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(
|
||||
device: D,
|
||||
item: 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)
|
||||
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
|
||||
*/
|
||||
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.PropertyDescriptor
|
||||
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> {
|
||||
override val descriptor: PropertyDescriptor = PropertyDescriptor("@meta")
|
||||
|
@ -5,7 +5,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
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 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.
|
||||
* 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? =
|
||||
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 =
|
||||
propertySpec.converter.metaToObject(requestProperty(propertySpec.name))
|
||||
public suspend fun <T, D : Device> D.getOrRead(propertySpec: DevicePropertySpec<D, T>): T =
|
||||
propertySpec.converter.read(getOrReadProperty(propertySpec.name))
|
||||
|
||||
/**
|
||||
* Write typed property state and invalidate logical state
|
||||
*/
|
||||
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
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.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].
|
||||
@ -117,7 +117,7 @@ public fun <D : Device, T> D.onPropertyChange(
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.filter { it.property == spec.name }
|
||||
.onEach { change ->
|
||||
val newValue = spec.converter.metaToObject(change.value)
|
||||
val newValue = spec.converter.read(change.value)
|
||||
if (newValue != null) {
|
||||
change.callback(newValue)
|
||||
}
|
||||
@ -136,7 +136,7 @@ public fun <D : Device, T> D.useProperty(
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.filter { it.property == spec.name }
|
||||
.collect { change ->
|
||||
val newValue = spec.converter.metaToObject(change.value)
|
||||
val newValue = spec.converter.readOrNull(change.value)
|
||||
if (newValue != null) {
|
||||
callback(newValue)
|
||||
}
|
||||
|
@ -5,20 +5,16 @@ import space.kscience.controls.api.ActionDescriptor
|
||||
import space.kscience.controls.api.Device
|
||||
import space.kscience.controls.api.PropertyDescriptor
|
||||
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.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
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 objectToMeta(obj: Unit): Meta = Meta.EMPTY
|
||||
override fun convert(obj: Unit): Meta = Meta.EMPTY
|
||||
}
|
||||
|
||||
public val MetaConverter.Companion.unit: MetaConverter<Unit> get() = UnitMetaConverter
|
||||
|
@ -1,9 +1,6 @@
|
||||
package space.kscience.controls.spec
|
||||
|
||||
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.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
@ -12,16 +9,14 @@ public fun Double.asMeta(): Meta = Meta(asValue())
|
||||
|
||||
//TODO to be moved to DF
|
||||
public object DurationConverter : MetaConverter<Duration> {
|
||||
override val type: KType = typeOf<Duration>()
|
||||
|
||||
override fun metaToObjectOrNull(meta: Meta): Duration = meta.value?.double?.toDuration(DurationUnit.SECONDS)
|
||||
override fun readOrNull(source: Meta): Duration = source.value?.double?.toDuration(DurationUnit.SECONDS)
|
||||
?: run {
|
||||
val unit: DurationUnit = meta["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
|
||||
val value = meta[Meta.VALUE_KEY].double ?: error("No value present for Duration")
|
||||
val unit: DurationUnit = source["unit"].enum<DurationUnit>() ?: DurationUnit.SECONDS
|
||||
val value = source[Meta.VALUE_KEY].double ?: error("No value present for Duration")
|
||||
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
|
@ -4,8 +4,8 @@ import space.kscience.controls.api.Device
|
||||
import space.kscience.controls.api.PropertyDescriptor
|
||||
import space.kscience.controls.api.metaDescriptor
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import kotlin.properties.PropertyDelegateProvider
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
@ -53,8 +53,8 @@ public fun <T, D : DeviceBase<D>> DeviceSpec<D>.logicalProperty(
|
||||
converter,
|
||||
descriptorBuilder,
|
||||
name,
|
||||
read = { propertyName -> getProperty(propertyName)?.let(converter::metaToObject) },
|
||||
write = { propertyName, value -> writeProperty(propertyName, converter.objectToMeta(value)) }
|
||||
read = { propertyName -> getProperty(propertyName)?.let(converter::readOrNull) },
|
||||
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.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.runVisionClient
|
||||
|
||||
public fun main(): Unit = runVisionClient {
|
||||
// plugin(DeviceManager)
|
||||
|
@ -144,7 +144,7 @@ public fun <T> MagixEndpoint.controlsPropertyFlow(
|
||||
.filter { message ->
|
||||
message.sourceDevice == deviceName && message.property == propertySpec.name
|
||||
}.map {
|
||||
propertySpec.converter.metaToObject(it.value)
|
||||
propertySpec.converter.read(it.value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +157,7 @@ public suspend fun <T> MagixEndpoint.sendControlsPropertyChange(
|
||||
) {
|
||||
val message = PropertySetMessage(
|
||||
property = propertySpec.name,
|
||||
value = propertySpec.converter.objectToMeta(value),
|
||||
value = propertySpec.converter.convert(value),
|
||||
targetDevice = deviceName
|
||||
)
|
||||
send(DeviceManager.magixFormat, message, source = sourceEndpointName, target = targetEndpointName)
|
||||
@ -177,6 +177,6 @@ public fun <T> MagixEndpoint.controlsPropertyMessageFlow(
|
||||
.filter { message ->
|
||||
message.sourceDevice == deviceName && message.property == propertySpec.name
|
||||
}.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.launch
|
||||
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.DevicePropertySpec
|
||||
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
|
||||
*/
|
||||
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 =
|
||||
propertySpec.converter.metaToObject(requestProperty(propertySpec.name))
|
||||
propertySpec.converter.read(getOrReadProperty(propertySpec.name))
|
||||
|
||||
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 {
|
||||
@ -34,7 +34,7 @@ public fun <T> DeviceClient.writeAsync(propertySpec: MutableDevicePropertySpec<*
|
||||
public fun <T> DeviceClient.propertyFlow(spec: DevicePropertySpec<*, T>): Flow<T> = messageFlow
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.filter { it.property == spec.name }
|
||||
.mapNotNull { spec.converter.metaToObject(it.value) }
|
||||
.mapNotNull { spec.converter.readOrNull(it.value) }
|
||||
|
||||
public fun <T> DeviceClient.onPropertyChange(
|
||||
spec: DevicePropertySpec<*, T>,
|
||||
@ -44,7 +44,7 @@ public fun <T> DeviceClient.onPropertyChange(
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.filter { it.property == spec.name }
|
||||
.onEach { change ->
|
||||
val newValue = spec.converter.metaToObject(change.value)
|
||||
val newValue = spec.converter.readOrNull(change.value)
|
||||
if (newValue != null) {
|
||||
change.callback(newValue)
|
||||
}
|
||||
@ -60,7 +60,7 @@ public fun <T> DeviceClient.useProperty(
|
||||
.filterIsInstance<PropertyChangedMessage>()
|
||||
.filter { it.property == spec.name }
|
||||
.collect { change ->
|
||||
val newValue = spec.converter.metaToObject(change.value)
|
||||
val newValue = spec.converter.readOrNull(change.value)
|
||||
if (newValue != null) {
|
||||
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 {
|
||||
val inputMeta = actionSpec.inputConverter.objectToMeta(input)
|
||||
val inputMeta = actionSpec.inputConverter.convert(input)
|
||||
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 {
|
||||
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.serialization.Serializable
|
||||
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.dataforge.context.error
|
||||
import space.kscience.dataforge.context.logger
|
||||
@ -91,7 +91,7 @@ public fun DeviceManager.launchTangoMagix(
|
||||
val device = get(payload.device)
|
||||
when (payload.action) {
|
||||
TangoAction.read -> {
|
||||
val value = device.requestProperty(payload.name)
|
||||
val value = device.getOrReadProperty(payload.name)
|
||||
respond(request, payload) { requestPayload ->
|
||||
requestPayload.copy(
|
||||
value = value,
|
||||
@ -104,7 +104,7 @@ public fun DeviceManager.launchTangoMagix(
|
||||
device.writeProperty(payload.name, value)
|
||||
}
|
||||
//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 ->
|
||||
requestPayload.copy(
|
||||
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 space.kscience.controls.api.Device
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import space.kscience.dataforge.meta.MetaSerializer
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
@ -43,7 +43,7 @@ public suspend inline fun <reified T: Any> OpcUaDevice.readOpcWithTime(
|
||||
else -> error("Incompatible OPC property value $content")
|
||||
}
|
||||
|
||||
val res: T = converter.metaToObject(meta)
|
||||
val res: T = converter.read(meta)
|
||||
return res to time
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ public suspend inline fun <reified T> OpcUaDevice.readOpc(
|
||||
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(
|
||||
@ -77,7 +77,7 @@ public suspend inline fun <reified T> OpcUaDevice.writeOpc(
|
||||
converter: MetaConverter<T>,
|
||||
value: T
|
||||
): StatusCode {
|
||||
val meta = converter.objectToMeta(value)
|
||||
val meta = converter.convert(value)
|
||||
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 username: MiloUsername? by specOrNull(MiloUsername)
|
||||
public var username: MiloUsername? by schemeOrNull(MiloUsername)
|
||||
|
||||
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.doubleProperty
|
||||
import space.kscience.controls.spec.read
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import kotlin.test.Ignore
|
||||
|
||||
class OpcUaClientTest {
|
||||
|
@ -6,8 +6,6 @@ import jetbrains.exodus.entitystore.PersistentEntityStores
|
||||
import jetbrains.exodus.entitystore.StoreTransaction
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
@ -72,13 +70,13 @@ public class XodusDeviceMessageStorage(
|
||||
DEVICE_MESSAGE_ENTITY_TYPE,
|
||||
DeviceMessage::time.name,
|
||||
true
|
||||
).asFlow().map {
|
||||
).map {
|
||||
Json.decodeFromString(
|
||||
DeviceMessage.serializer(),
|
||||
it.getBlobString("json") ?: error("No json content found")
|
||||
)
|
||||
}
|
||||
}
|
||||
}.asFlow()
|
||||
|
||||
override fun read(
|
||||
eventType: String,
|
||||
@ -90,7 +88,7 @@ public class XodusDeviceMessageStorage(
|
||||
DEVICE_MESSAGE_ENTITY_TYPE,
|
||||
"type",
|
||||
eventType
|
||||
).asFlow().filter {
|
||||
).filter {
|
||||
it.timeInRange(range) &&
|
||||
it.propertyMatchesName(DeviceMessage::sourceDevice.name, sourceDevice) &&
|
||||
it.propertyMatchesName(DeviceMessage::targetDevice.name, targetDevice)
|
||||
@ -100,7 +98,7 @@ public class XodusDeviceMessageStorage(
|
||||
it.getBlobString("json") ?: error("No json content found")
|
||||
)
|
||||
}
|
||||
}
|
||||
}.asFlow()
|
||||
|
||||
override fun close() {
|
||||
entityStore.close()
|
||||
|
@ -1,5 +1,6 @@
|
||||
import jetbrains.exodus.entitystore.PersistentEntityStores
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.Instant
|
||||
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.Test
|
||||
import space.kscience.controls.api.PropertyChangedMessage
|
||||
import space.kscience.controls.storage.read
|
||||
import space.kscience.controls.xodus.XodusDeviceMessageStorage
|
||||
import space.kscience.controls.xodus.query
|
||||
import space.kscience.controls.xodus.writeMessage
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.Name
|
||||
@ -67,7 +68,7 @@ internal class PropertyHistoryTest {
|
||||
XodusDeviceMessageStorage(entityStore).use { storage ->
|
||||
assertEquals(
|
||||
propertyChangedMessages[0],
|
||||
storage.query<PropertyChangedMessage>(
|
||||
storage.read<PropertyChangedMessage>(
|
||||
sourceDevice = "virtual-car".asName()
|
||||
).first { it.property == "speed" }
|
||||
)
|
||||
|
@ -7,7 +7,7 @@ import kotlinx.datetime.Instant
|
||||
import space.kscience.controls.api.PropertyChangedMessage
|
||||
import space.kscience.controls.misc.PropertyHistory
|
||||
import space.kscience.controls.misc.ValueWithTime
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
|
||||
public fun <T> DeviceMessageStorage.propertyHistory(
|
||||
propertyName: String,
|
||||
@ -16,5 +16,5 @@ public fun <T> DeviceMessageStorage.propertyHistory(
|
||||
override fun flowHistory(from: Instant, until: Instant): Flow<ValueWithTime<T>> =
|
||||
read<PropertyChangedMessage>(from..until)
|
||||
.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(
|
||||
context: Context,
|
||||
state: DeviceState<T>,
|
||||
extractValue: T.() -> Value = { state.converter.objectToMeta(this).value ?: Null },
|
||||
extractValue: T.() -> Value = { state.converter.convert(this).value ?: Null },
|
||||
maxAge: Duration = defaultMaxAge,
|
||||
maxPoints: Int = defaultMaxPoints,
|
||||
minPoints: Int = defaultMinPoints,
|
||||
|
@ -7,10 +7,9 @@ import space.kscience.dataforge.context.PluginFactory
|
||||
import space.kscience.dataforge.context.PluginTag
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.names.Name
|
||||
import space.kscience.visionforge.ElementVisionRenderer
|
||||
import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionClient
|
||||
import space.kscience.visionforge.VisionPlugin
|
||||
import space.kscience.visionforge.html.ElementVisionRenderer
|
||||
|
||||
public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
@ -21,7 +20,7 @@ public actual class ControlVisionPlugin : VisionPlugin(), ElementVisionRenderer
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package space.kscience.controls.vision
|
||||
|
||||
import space.kscience.visionforge.html.runVisionClient
|
||||
import space.kscience.visionforge.markup.MarkupPlugin
|
||||
import space.kscience.visionforge.plotly.PlotlyPlugin
|
||||
import space.kscience.visionforge.runVisionClient
|
||||
|
||||
public fun main(): Unit = runVisionClient {
|
||||
plugin(PlotlyPlugin)
|
||||
|
@ -24,7 +24,7 @@ dependencies {
|
||||
|
||||
implementation("io.ktor:ktor-client-cio:$ktorVersion")
|
||||
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(spclibs.logback.classic)
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import space.kscience.controls.spec.*
|
||||
import space.kscience.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Factory
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.meta.descriptors.value
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
import java.time.Instant
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
@ -22,7 +22,7 @@ class MagixVirtualCar(context: Context, meta: Meta) : VirtualCar(context, meta)
|
||||
(payload as? PropertyChangedMessage)?.let { message ->
|
||||
if (message.sourceDevice == Name.parse("virtual-car")) {
|
||||
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.dataforge.context.Context
|
||||
import space.kscience.dataforge.context.Factory
|
||||
import space.kscience.dataforge.meta.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 space.kscience.dataforge.meta.*
|
||||
import kotlin.math.pow
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
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)
|
||||
|
||||
companion object CoordinatesMetaConverter : MetaConverter<Vector2D> {
|
||||
|
||||
override val type: KType = typeOf<Vector2D>()
|
||||
|
||||
override fun metaToObjectOrNull(meta: Meta): Vector2D = Vector2D(
|
||||
meta["x"].double ?: 0.0,
|
||||
meta["y"].double ?: 0.0
|
||||
override fun readOrNull(source: Meta): Vector2D = Vector2D(
|
||||
source["x"].double ?: 0.0,
|
||||
source["y"].double ?: 0.0
|
||||
)
|
||||
|
||||
override fun objectToMeta(obj: Vector2D): Meta = Meta {
|
||||
override fun convert(obj: Vector2D): Meta = Meta {
|
||||
"x" put obj.x
|
||||
"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.request
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.MetaConverter
|
||||
import space.kscience.dataforge.meta.get
|
||||
import space.kscience.dataforge.meta.int
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
|
||||
|
||||
//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 value by doubleProperty(read = {
|
||||
readChannelData(request(channel) ?: DEFAULT_CHANNEL)
|
||||
readChannelData(getOrRead(channel))
|
||||
})
|
||||
|
||||
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.spec.*
|
||||
import space.kscience.dataforge.context.*
|
||||
import space.kscience.dataforge.meta.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.meta.*
|
||||
import space.kscience.dataforge.names.NameToken
|
||||
import kotlin.collections.component1
|
||||
import kotlin.collections.component2
|
||||
|
Loading…
Reference in New Issue
Block a user