Migrate to DataForge 0.8.0

This commit is contained in:
Alexander Nozik 2024-03-04 15:24:27 +03:00
parent dbacdbc7cf
commit 2a700a5a2a
36 changed files with 103 additions and 134 deletions

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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
/**

View File

@ -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
/**

View File

@ -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)

View File

@ -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
)

View File

@ -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>> =

View File

@ -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)

View File

@ -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))
}
/**

View File

@ -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")

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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)) }
)

View File

@ -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)

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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()
}

View File

@ -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)

View File

@ -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 {

View File

@ -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()

View File

@ -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" }
)

View File

@ -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) }
}

View File

@ -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,

View File

@ -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")
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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

View File

@ -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))
}
}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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