commit #22
This commit is contained in:
parent
745a83d757
commit
379fc8eebb
7 changed files with 160 additions and 1 deletions
|
@ -15,6 +15,7 @@ allprojects {
|
||||||
kotlinOptions.jvmTarget = "19"
|
kotlinOptions.jvmTarget = "19"
|
||||||
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
|
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
|
||||||
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes"
|
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.ExperimentalUnsignedTypes"
|
||||||
|
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.time.ExperimentalTime"
|
||||||
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.contracts.ExperimentalContracts"
|
kotlinOptions.freeCompilerArgs += "-opt-in=kotlin.contracts.ExperimentalContracts"
|
||||||
kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
|
kotlinOptions.freeCompilerArgs += "-Xcontext-receivers"
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,4 +28,6 @@ object Washs {
|
||||||
val bar = StairvilleTlb(DmxAddress(121u))
|
val bar = StairvilleTlb(DmxAddress(121u))
|
||||||
val sideLight = StairvilleClb4(DmxAddress(126u))
|
val sideLight = StairvilleClb4(DmxAddress(126u))
|
||||||
|
|
||||||
val devices = persistentSetOf(*FrontLights.all.toTypedArray(), spotLeft, spotRight, *Tops.both.toTypedArray(), *Washs.both.toTypedArray(), bar)
|
val fogMachine = FogMachine(DmxAddress(200u)) // TODO: Adresse korrigieren
|
||||||
|
|
||||||
|
val devices = persistentSetOf(*FrontLights.all.toTypedArray(), spotLeft, spotRight, *Tops.both.toTypedArray(), *Washs.both.toTypedArray(), bar, fogMachine)
|
|
@ -0,0 +1,23 @@
|
||||||
|
package de.moritzruth.lampenfieber.device
|
||||||
|
|
||||||
|
import de.moritzruth.theaterdsl.device.Device
|
||||||
|
import de.moritzruth.theaterdsl.device.PercentageDV
|
||||||
|
import de.moritzruth.theaterdsl.dmx.DmxAddress
|
||||||
|
import de.moritzruth.theaterdsl.dmx.DmxDataWriter
|
||||||
|
import de.moritzruth.theaterdsl.dmx.DmxValue
|
||||||
|
import de.moritzruth.theaterdsl.value.percent
|
||||||
|
import kotlinx.collections.immutable.persistentSetOf
|
||||||
|
|
||||||
|
class FogMachine(override val firstChannel: DmxAddress) : Device {
|
||||||
|
override val numberOfChannels = 4u
|
||||||
|
|
||||||
|
override fun writeDmxData(writer: DmxDataWriter) {
|
||||||
|
writer.writePercentage(10.percent)
|
||||||
|
writer.writePercentage(power.getCurrentValue())
|
||||||
|
writer.writeRaw(DmxValue(0u)) // ignored
|
||||||
|
writer.writeRaw(DmxValue(0u)) // ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
val power = PercentageDV()
|
||||||
|
override val dvs = persistentSetOf(power)
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
package de.moritzruth.theaterdsl.show
|
package de.moritzruth.theaterdsl.show
|
||||||
|
|
||||||
|
import de.moritzruth.lampenfieber.device.fogMachine
|
||||||
import de.moritzruth.theaterdsl.device.Device
|
import de.moritzruth.theaterdsl.device.Device
|
||||||
import de.moritzruth.theaterdsl.device.DynamicValue
|
import de.moritzruth.theaterdsl.device.DynamicValue
|
||||||
import de.moritzruth.theaterdsl.dmx.EnttecOpenDmxUsb
|
import de.moritzruth.theaterdsl.dmx.EnttecOpenDmxUsb
|
||||||
import de.moritzruth.theaterdsl.dmx.PerDeviceDmxDataWriter
|
import de.moritzruth.theaterdsl.dmx.PerDeviceDmxDataWriter
|
||||||
import de.moritzruth.theaterdsl.util.InstantAsEpochMillisecondsSerializer
|
import de.moritzruth.theaterdsl.util.InstantAsEpochMillisecondsSerializer
|
||||||
import de.moritzruth.theaterdsl.util.mapState
|
import de.moritzruth.theaterdsl.util.mapState
|
||||||
|
import de.moritzruth.theaterdsl.value.Percentage
|
||||||
|
import de.moritzruth.theaterdsl.value.percent
|
||||||
import io.github.oshai.KLogger
|
import io.github.oshai.KLogger
|
||||||
import io.github.oshai.KotlinLogging
|
import io.github.oshai.KotlinLogging
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
@ -32,13 +35,21 @@ import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
import kotlin.time.TimeSource
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
|
|
||||||
|
data class FogState(val power: Percentage, val time: TimeSource.Monotonic.ValueTimeMark = TimeSource.Monotonic.markNow()) {
|
||||||
|
companion object {
|
||||||
|
fun off() = FogState(0.percent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ShowContext(
|
class ShowContext(
|
||||||
val devices: ImmutableSet<Device>,
|
val devices: ImmutableSet<Device>,
|
||||||
val show: Show,
|
val show: Show,
|
||||||
val logger: KLogger,
|
val logger: KLogger,
|
||||||
val stateFlow: MutableStateFlow<ShowState>,
|
val stateFlow: MutableStateFlow<ShowState>,
|
||||||
|
val fogState: MutableStateFlow<FogState>,
|
||||||
val outputDataFreeze: AtomicInteger
|
val outputDataFreeze: AtomicInteger
|
||||||
) {
|
) {
|
||||||
val stepFlow = stateFlow.mapState {
|
val stepFlow = stateFlow.mapState {
|
||||||
|
@ -92,11 +103,13 @@ suspend fun runShow(show: Show, devices: ImmutableSet<Device>) = coroutineScope
|
||||||
show,
|
show,
|
||||||
logger,
|
logger,
|
||||||
stateFlow,
|
stateFlow,
|
||||||
|
MutableStateFlow(FogState.off()),
|
||||||
AtomicInteger(0)
|
AtomicInteger(0)
|
||||||
)
|
)
|
||||||
|
|
||||||
startDataWriting(context)
|
startDataWriting(context)
|
||||||
startStepRunning(context)
|
startStepRunning(context)
|
||||||
|
startFogHandling(context)
|
||||||
startWebsocketServer(context)
|
startWebsocketServer(context)
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
|
@ -124,6 +137,15 @@ fun CoroutineScope.startDataWriting(context: ShowContext) = launch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CoroutineScope.startFogHandling(context: ShowContext) = launch {
|
||||||
|
context.fogState.collectLatest { state ->
|
||||||
|
fogMachine.power.static(state.power)
|
||||||
|
|
||||||
|
delay(1000)
|
||||||
|
fogMachine.power.off()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun CoroutineScope.startStepRunning(context: ShowContext) = launch {
|
fun CoroutineScope.startStepRunning(context: ShowContext) = launch {
|
||||||
var lastPosition = ShowPosition.START
|
var lastPosition = ShowPosition.START
|
||||||
var lastStepJob: Job? = null
|
var lastStepJob: Job? = null
|
||||||
|
@ -197,6 +219,12 @@ private fun CoroutineScope.startWebsocketServer(context: ShowContext) = launch(D
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post("/fog") {
|
||||||
|
val power = call.receive<Percentage>()
|
||||||
|
context.fogState.value = FogState(power)
|
||||||
|
call.respond(HttpStatusCode.NoContent)
|
||||||
|
}
|
||||||
|
|
||||||
get("/show") {
|
get("/show") {
|
||||||
call.respond(context.show.acts.toMutableList())
|
call.respond(context.show.acts.toMutableList())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package de.moritzruth.theaterdsl.value
|
package de.moritzruth.theaterdsl.value
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Percentage(val value: Double) : Comparable<Percentage> {
|
value class Percentage(val value: Double) : Comparable<Percentage> {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
21
ui/src/components/Button.vue
Normal file
21
ui/src/components/Button.vue
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="px-5 py-2 active:bg-green-800 transition duration-200 font-bold text-5"
|
||||||
|
:class="isActive ? 'bg-green-800' : 'bg-green-600'"
|
||||||
|
@click="e => emit('click', e)"
|
||||||
|
>
|
||||||
|
<slot/>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
isActive?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits(["click"])
|
||||||
|
</script>
|
81
ui/src/components/FogControl.vue
Normal file
81
ui/src/components/FogControl.vue
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span>Nebel: </span>
|
||||||
|
<Button
|
||||||
|
v-for="p in buttonPowers"
|
||||||
|
@mousedown="onButtonActive(p[0])"
|
||||||
|
@mouseup="onButtonInactive(p[0])"
|
||||||
|
:is-active="isActive && p[0] === power"
|
||||||
|
>
|
||||||
|
{{ p[0] * 100 }}%
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from "./Button.vue"
|
||||||
|
import { computed, ref, watch } from "vue"
|
||||||
|
import { onKeyDown, onKeyUp, useEventListener, useIntervalFn } from "@vueuse/core"
|
||||||
|
|
||||||
|
const activation = ref<"button" | "key" | null>(null)
|
||||||
|
const isActive = computed(() => activation.value !== null)
|
||||||
|
const power = ref(0)
|
||||||
|
|
||||||
|
function onButtonActive(p: number) {
|
||||||
|
activation.value = "button"
|
||||||
|
power.value = p
|
||||||
|
}
|
||||||
|
|
||||||
|
function onButtonInactive(p: number) {
|
||||||
|
if (activation.value === "button" && power.value === p) {
|
||||||
|
activation.value = null
|
||||||
|
power.value = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEventListener(document.body, "mouseup", () => {
|
||||||
|
if (activation.value === "button") activation.value = null
|
||||||
|
})
|
||||||
|
|
||||||
|
const buttonPowers: Array<[number, string]> = [[0.1, "7"], [0.25, "8"], [0.5, "9"], [1, "0"]]
|
||||||
|
|
||||||
|
for (const p of buttonPowers) {
|
||||||
|
onKeyDown(p[1], () => {
|
||||||
|
activation.value = "key"
|
||||||
|
power.value = p[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
onKeyUp(p[1], () => {
|
||||||
|
if (activation.value === "key" && power.value === p[0]) {
|
||||||
|
activation.value = null
|
||||||
|
power.value = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function send() {
|
||||||
|
fetch("/api/fog", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(power.value),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendTimer = useIntervalFn(send, 200, { immediate: false })
|
||||||
|
|
||||||
|
watch(power, () => {
|
||||||
|
if (activation.value === null) {
|
||||||
|
sendTimer.pause()
|
||||||
|
send()
|
||||||
|
} else {
|
||||||
|
send()
|
||||||
|
sendTimer.resume()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
Add table
Reference in a new issue