diff --git a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/DeviceGroup.kt b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/DeviceGroup.kt index f7bf494..b39d7b6 100644 --- a/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/DeviceGroup.kt +++ b/controls-constructor/src/commonMain/kotlin/space/kscience/controls/constructor/DeviceGroup.kt @@ -8,6 +8,7 @@ import space.kscience.controls.manager.DeviceManager 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 @@ -158,6 +159,12 @@ public fun DeviceManager.deviceGroup( return group } +public fun Context.deviceGroup( + name: String = "@group", + meta: Meta = Meta.EMPTY, + block: DeviceGroup.() -> Unit, +): DeviceGroup = request(DeviceManager).deviceGroup(name, meta, block) + private fun DeviceGroup.getOrCreateGroup(name: Name): DeviceGroup { return when (name.length) { 0 -> this diff --git a/controls-vision/build.gradle.kts b/controls-vision/build.gradle.kts index e1401d9..335bde2 100644 --- a/controls-vision/build.gradle.kts +++ b/controls-vision/build.gradle.kts @@ -12,6 +12,8 @@ val visionforgeVersion = "0.3.0-dev-10" kscience { jvm() js() + useKtor() + useContextReceivers() dependencies { api(projects.controlsCore) api(projects.controlsConstructor) @@ -21,6 +23,7 @@ kscience { jvmMain{ api("space.kscience:visionforge-server:$visionforgeVersion") + api("io.ktor:ktor-server-cio") } } diff --git a/controls-vision/src/jvmMain/kotlin/space/kscience/controls/vision/dashboard.kt b/controls-vision/src/jvmMain/kotlin/space/kscience/controls/vision/dashboard.kt new file mode 100644 index 0000000..2597e48 --- /dev/null +++ b/controls-vision/src/jvmMain/kotlin/space/kscience/controls/vision/dashboard.kt @@ -0,0 +1,61 @@ +package space.kscience.controls.vision + +import io.ktor.server.cio.CIO +import io.ktor.server.engine.ApplicationEngine +import io.ktor.server.engine.embeddedServer +import io.ktor.server.http.content.staticResources +import io.ktor.server.routing.Routing +import io.ktor.server.routing.routing +import kotlinx.html.TagConsumer +import space.kscience.dataforge.context.Context +import space.kscience.plotly.Plot +import space.kscience.plotly.PlotlyConfig +import space.kscience.visionforge.html.HtmlVisionFragment +import space.kscience.visionforge.html.VisionPage +import space.kscience.visionforge.html.VisionTagConsumer +import space.kscience.visionforge.plotly.plotly +import space.kscience.visionforge.server.VisionRoute +import space.kscience.visionforge.server.close +import space.kscience.visionforge.server.openInBrowser +import space.kscience.visionforge.server.visionPage +import space.kscience.visionforge.visionManager + +public fun Context.showDashboard( + port: Int = 7777, + routes: Routing.() -> Unit = {}, + configurationBuilder: VisionRoute.() -> Unit = {}, + visionFragment: HtmlVisionFragment, +): ApplicationEngine = embeddedServer(CIO, port = port) { + routing { + staticResources("", null, null) + routes() + } + + visionPage( + visionManager, + VisionPage.scriptHeader("js/constructor.js"), + configurationBuilder = configurationBuilder, + visionFragment = visionFragment + ) +}.also { + it.start(false) + it.openInBrowser() + + + println("Enter 'exit' to close server") + while (readlnOrNull() != "exit") { + // + } + + it.close() +} + +context(VisionTagConsumer<*>) +public fun TagConsumer<*>.plot( + config: PlotlyConfig = PlotlyConfig(), + block: Plot.() -> Unit, +) { + vision { + plotly(config, block) + } +} diff --git a/demo/constructor/build.gradle.kts b/demo/constructor/build.gradle.kts index 897b9af..daa4381 100644 --- a/demo/constructor/build.gradle.kts +++ b/demo/constructor/build.gradle.kts @@ -6,6 +6,7 @@ plugins { kscience { fullStack("js/constructor.js", jvmConfig = {withJava()}) useKtor() + useContextReceivers() dependencies { api(projects.controlsVision) } diff --git a/demo/constructor/src/jvmMain/kotlin/main.kt b/demo/constructor/src/jvmMain/kotlin/main.kt index 1df0f33..8fc1dac 100644 --- a/demo/constructor/src/jvmMain/kotlin/main.kt +++ b/demo/constructor/src/jvmMain/kotlin/main.kt @@ -1,9 +1,5 @@ package space.kscience.controls.demo.constructor -import io.ktor.server.cio.CIO -import io.ktor.server.engine.embeddedServer -import io.ktor.server.http.content.staticResources -import io.ktor.server.routing.routing import space.kscience.controls.api.get import space.kscience.controls.constructor.* import space.kscience.controls.manager.ClockManager @@ -12,18 +8,13 @@ import space.kscience.controls.manager.clock import space.kscience.controls.spec.doRecurring import space.kscience.controls.spec.name import space.kscience.controls.spec.write +import space.kscience.controls.vision.plot import space.kscience.controls.vision.plotDeviceProperty import space.kscience.controls.vision.plotNumberState +import space.kscience.controls.vision.showDashboard import space.kscience.dataforge.context.Context -import space.kscience.dataforge.context.request import space.kscience.plotly.models.ScatterMode -import space.kscience.visionforge.VisionManager -import space.kscience.visionforge.html.VisionPage import space.kscience.visionforge.plotly.PlotlyPlugin -import space.kscience.visionforge.plotly.plotly -import space.kscience.visionforge.server.close -import space.kscience.visionforge.server.openInBrowser -import space.kscience.visionforge.server.visionPage import kotlin.math.PI import kotlin.math.sin import kotlin.time.Duration.Companion.milliseconds @@ -38,9 +29,6 @@ public fun main() { plugin(ClockManager) } - val deviceManager = context.request(DeviceManager) - val visionManager = context.request(VisionManager) - val state = DoubleRangeState(0.0, -5.0..5.0) val pidParameters = PidParameters( @@ -50,7 +38,7 @@ public fun main() { timeStep = 0.005.seconds ) - val device = deviceManager.deviceGroup { + val device = context.deviceGroup { val drive = virtualDrive("drive", 0.005, state) val pid = pid("pid", drive, pidParameters) virtualLimitSwitch("start", state.atStartState) @@ -69,59 +57,37 @@ public fun main() { } } - val server = embeddedServer(CIO, port = 7777) { - routing { - staticResources("", null, null) - } - visionPage( - visionManager, - VisionPage.scriptHeader("js/constructor.js") - ) { - vision { - plotly { - plotNumberState(context, state) { - name = "real position" - } - plotDeviceProperty(device["pid"], Regulator.position.name) { - name = "read position" - } - - plotDeviceProperty(device["pid"], Regulator.target.name) { - name = "target" - } - } + context.showDashboard { + plot { + plotNumberState(context, state) { + name = "real position" + } + plotDeviceProperty(device["pid"], Regulator.position.name) { + name = "read position" } - vision { - plotly { + plotDeviceProperty(device["pid"], Regulator.target.name) { + name = "target" + } + } + + plot { // plotBooleanState(context, state.atStartState) { // name = "start" // } // plotBooleanState(context, state.atEndState) { // name = "end" // } - plotDeviceProperty(device["start"], LimitSwitch.locked.name) { - name = "start measured" - mode = ScatterMode.markers - } - plotDeviceProperty(device["end"], LimitSwitch.locked.name) { - name = "end measured" - mode = ScatterMode.markers - } - } + plotDeviceProperty(device["start"], LimitSwitch.locked.name) { + name = "start measured" + mode = ScatterMode.markers + } + plotDeviceProperty(device["end"], LimitSwitch.locked.name) { + name = "end measured" + mode = ScatterMode.markers } } - }.start(false) - - server.openInBrowser() - - - println("Enter 'exit' to close server") - while (readlnOrNull() != "exit") { - // } - - server.close() } \ No newline at end of file