From 0fe0c1f1e17bbcdb0b7015bac9c1e2e16e6c1209 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 9 Mar 2018 10:09:55 +0300 Subject: [PATCH] Control update --- .../inr/numass/control/cryotemp/PKT8Device.kt | 6 +- .../inr/numass/control/StorageHelper.kt | 3 +- .../inr/numass/control/readvac/CM32Device.kt | 64 ++++----- .../control/readvac/MKSBaratronDevice.kt | 70 +++++----- .../numass/control/readvac/MKSVacDevice.kt | 94 ++++++-------- .../control/readvac/MeradatVacDevice.kt | 100 +++++++------- .../control/readvac/VacCollectorDevice.kt | 122 +++++++++--------- 7 files changed, 197 insertions(+), 262 deletions(-) diff --git a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt index dc4b20ae..a37e37d0 100644 --- a/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt +++ b/numass-control/cryotemp/src/main/kotlin/inr/numass/control/cryotemp/PKT8Device.kt @@ -223,7 +223,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, } - override fun startMeasurement(oldMeta: Meta, newMeta: Meta) { + fun setMeasurement(oldMeta: Meta, newMeta: Meta) { if (!oldMeta.isEmpty) { logger.warn("Trying to start measurement which is already started") } @@ -317,7 +317,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, // } // // @Throws(MeasurementException::class) -// override fun startMeasurement(): Measurement { +// override fun setMeasurement(): Measurement { // //clearing PKT queue // try { // send("p") @@ -327,7 +327,7 @@ class PKT8Device(context: Context, meta: Meta) : PortSensor(context, // // throw new MeasurementException(e); // } // -// return super.startMeasurement() +// return super.setMeasurement() // } diff --git a/numass-control/src/main/kotlin/inr/numass/control/StorageHelper.kt b/numass-control/src/main/kotlin/inr/numass/control/StorageHelper.kt index a50a79a6..f9d8e0df 100644 --- a/numass-control/src/main/kotlin/inr/numass/control/StorageHelper.kt +++ b/numass-control/src/main/kotlin/inr/numass/control/StorageHelper.kt @@ -1,6 +1,7 @@ package inr.numass.control import hep.dataforge.control.devices.AbstractDevice +import hep.dataforge.kodex.nullable import hep.dataforge.storage.api.TableLoader import hep.dataforge.storage.commons.StorageConnection import hep.dataforge.values.Values @@ -14,7 +15,7 @@ class StorageHelper(private val device: AbstractDevice, private val loaderFactor private val loaderMap = HashMap() fun push(point: Values) { - if (!device.hasState("storing") || device.getState("storing").booleanValue()) { + if (device.optBooleanState("storing").nullable == true) { device.forEachConnection("storage", StorageConnection::class.java) { connection -> try { val pl = loaderMap.computeIfAbsent(connection, loaderFactory) diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/CM32Device.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/CM32Device.kt index 65058d93..fff7176e 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/CM32Device.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/CM32Device.kt @@ -6,10 +6,7 @@ package inr.numass.control.readvac import hep.dataforge.context.Context -import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.PortSensor -import hep.dataforge.control.measurements.Measurement -import hep.dataforge.control.measurements.SimpleMeasurement import hep.dataforge.control.ports.ComPort import hep.dataforge.control.ports.GenericPortController import hep.dataforge.control.ports.Port @@ -31,51 +28,36 @@ class CM32Device(context: Context, meta: Meta) : PortSensor(context, met } else { PortFactory.build(meta) } - return GenericPortController(context, port){it.endsWith("T--\r")} + return GenericPortController(context, port) { it.endsWith("T--\r") } } - - override fun startMeasurement(oldMeta: Meta, newMeta: Meta) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) { + startMeasurement { + doMeasure() + } } - override fun createMeasurement(): Measurement = CMVacMeasurement() + private fun doMeasure(): Meta{ + val answer = sendAndWait("MES R PM 1\r\n") + + return if (answer.isEmpty()) { + updateLogicalState(PortSensor.CONNECTED_STATE, false) + produceError("No signal") + } else if (!answer.contains("PM1:mbar")) { + updateLogicalState(PortSensor.CONNECTED_STATE, false) + produceError("Wrong answer: $answer") + } else if (answer.substring(14, 17) == "OFF") { + updateLogicalState(PortSensor.CONNECTED_STATE, true) + produceError("Off") + } else { + updateLogicalState(PortSensor.CONNECTED_STATE, true) + produceResult(answer.substring(14, 17) + answer.substring(19, 23)) + } + } override fun getType(): String { - return getMeta().getString("type", "Leibold CM32") - } - - private inner class CMVacMeasurement : SimpleMeasurement() { - - @Synchronized - @Throws(Exception::class) - override fun doMeasure(): Double? { - - val answer = sendAndWait("MES R PM 1\r\n") - - if (answer.isEmpty()) { - this.updateMessage("No signal") - updateLogicalState(PortSensor.CONNECTED_STATE, false) - return null - } else if (!answer.contains("PM1:mbar")) { - this.updateMessage("Wrong answer: " + answer) - updateLogicalState(PortSensor.CONNECTED_STATE, false) - return null - } else if (answer.substring(14, 17) == "OFF") { - this.updateMessage("Off") - updateLogicalState(PortSensor.CONNECTED_STATE, true) - return null - } else { - this.updateMessage("OK") - updateLogicalState(PortSensor.CONNECTED_STATE, true) - return java.lang.Double.parseDouble(answer.substring(14, 17) + answer.substring(19, 23)) - } - } - - override fun getDevice(): Device = this@CM32Device - - + return meta.getString("type", "numass.vac.cm32") } } diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSBaratronDevice.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSBaratronDevice.kt index ad6ccb42..b708d9b8 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSBaratronDevice.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSBaratronDevice.kt @@ -6,14 +6,15 @@ package inr.numass.control.readvac import hep.dataforge.context.Context -import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.PortSensor -import hep.dataforge.control.measurements.Measurement -import hep.dataforge.control.measurements.SimpleMeasurement +import hep.dataforge.control.devices.intState +import hep.dataforge.control.ports.GenericPortController import hep.dataforge.control.ports.Port +import hep.dataforge.control.ports.PortFactory import hep.dataforge.description.ValueDef -import hep.dataforge.exceptions.ControlException import hep.dataforge.meta.Meta +import hep.dataforge.states.StateDef +import hep.dataforge.values.ValueType import inr.numass.control.DeviceView /** @@ -21,52 +22,41 @@ import inr.numass.control.DeviceView */ @ValueDef(name = "channel") @DeviceView(VacDisplay::class) +@StateDef(value = ValueDef(name = "channel", type = [ValueType.NUMBER], def = "2"), writable = true) class MKSBaratronDevice(context: Context, meta: Meta) : PortSensor(context, meta) { - private val channel: Int = getMeta().getInt("channel", 2) - - - override fun createMeasurement(): Measurement = BaratronMeasurement() + var channel by intState("channel") override fun getType(): String { - return getMeta().getString("type", "MKS baratron") + return meta.getString("type", "numass.vac.baratron") } - @Throws(ControlException::class) - override fun buildPort(portName: String): Port { - val handler = super.buildPort(portName) - handler.setDelimiter("\r") - return handler + override fun connect(meta: Meta): GenericPortController { + val port: Port = PortFactory.build(meta) + logger.info("Connecting to port {}", port.name) + return GenericPortController(context, port) { it.endsWith("\r") } } - private inner class BaratronMeasurement : SimpleMeasurement() { - - override fun getDevice(): Device { - return this@MKSBaratronDevice + override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) { + startMeasurement(newMeta) { + doMeasure() } + } - @Synchronized - @Throws(Exception::class) - override fun doMeasure(): Double? { - val answer = sendAndWait("AV" + channel + "\r") - if (answer == null || answer.isEmpty()) { - // invalidateState("connection"); - updateLogicalState(PortSensor.CONNECTED_STATE, false) - this.updateMessage("No connection") - return null - } else { - updateLogicalState(PortSensor.CONNECTED_STATE, true) - } - val res = java.lang.Double.parseDouble(answer) - if (res <= 0) { - this.updateMessage("Non positive") - // invalidateState("power"); - return null - } else { - this.updateMessage("OK") - return res - } + private fun doMeasure(): Meta { + val answer = sendAndWait("AV$channel\r") + if (answer.isEmpty()) { + // invalidateState("connection"); + updateLogicalState(PortSensor.CONNECTED_STATE, false) + return produceError("No connection") + } else { + updateLogicalState(PortSensor.CONNECTED_STATE, true) + } + val res = java.lang.Double.parseDouble(answer) + return if (res <= 0) { + produceError("Non positive") + } else { + produceResult(res) } - } } diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSVacDevice.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSVacDevice.kt index ebb3e197..1ac276cf 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSVacDevice.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MKSVacDevice.kt @@ -6,11 +6,11 @@ package inr.numass.control.readvac import hep.dataforge.context.Context -import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.PortSensor -import hep.dataforge.control.measurements.Measurement -import hep.dataforge.control.measurements.SimpleMeasurement +import hep.dataforge.control.devices.booleanState +import hep.dataforge.control.ports.GenericPortController import hep.dataforge.control.ports.Port +import hep.dataforge.control.ports.PortFactory import hep.dataforge.description.ValueDef import hep.dataforge.description.ValueDefs import hep.dataforge.exceptions.ControlException @@ -40,13 +40,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, m private val deviceAddress: String = meta.getString("address", "253") - -// val isPowerOnProperty = SimpleBooleanProperty() -// var isPowerOn by isPowerOnProperty - - -// val channelProperty = SimpleIntegerProperty(meta.getInt("channel", 5)) -// var channel by channelProperty + var power: Boolean by booleanState("power") @Throws(ControlException::class) @@ -61,15 +55,12 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, m } } - @Throws(ControlException::class) - override fun buildPort(portName: String): Port { - val handler = super.buildPort(portName) - handler.setDelimiter(";FF") - return handler + override fun connect(meta: Meta): GenericPortController { + val port: Port = PortFactory.build(meta) + logger.info("Connecting to port {}", port.name) + return GenericPortController(context, port) { it.endsWith(";FF") } } - override fun createMeasurement(): Measurement = MKSVacMeasurement() - @Throws(ControlException::class) override fun computeState(stateName: String): Any = when (stateName) { "power" -> talk("FP?") == "ON" @@ -79,7 +70,7 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, m @Throws(ControlException::class) override fun requestStateChange(stateName: String, value: Value) { when (stateName) { - "power" -> setPower(value.booleanValue()) + "power" -> setPowerOn(value.booleanValue()) else -> super.requestStateChange(stateName, value) } @@ -93,18 +84,8 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, m super.shutdown() } -// fun powerOnProperty(): BooleanProperty { -// try { -// return JavaBeanBooleanPropertyBuilder().bean(this) -// .name("powerOn").getter("isPowerOn").setter("setPower").build() -// } catch (ex: NoSuchMethodException) { -// throw Error(ex) -// } -// -// } - - private fun setPower(powerOn: Boolean) { - if (powerOn != getLogicalState("power").booleanValue()) { + private fun setPowerOn(powerOn: Boolean) { + if (powerOn != power) { if (powerOn) { // String ans = talkMKS(p1Port, "@253ENC!OFF;FF"); // if (!ans.equals("OFF")) { @@ -112,47 +93,44 @@ class MKSVacDevice(context: Context, meta: Meta) : PortSensor(context, m // } val ans = talk("FP!ON") if (ans == "ON") { - setLogicalState("power", true) + updateLogicalState("power", true) } else { - this.notifyError("Failed to set power state", null) + this.notifyError("Failed to set power state") } } else { val ans = talk("FP!OFF") if (ans == "OFF") { - setLogicalState("power", false) + updateLogicalState("power", false) } else { - this.notifyError("Failed to set power state", null) + this.notifyError("Failed to set power state") } } } } - override fun getType(): String = meta.getString("type", "MKS vacuumeter") + override fun getType(): String = meta.getString("type", "numass.vac.mks") - private inner class MKSVacMeasurement : SimpleMeasurement() { - - @Synchronized - @Throws(Exception::class) - override fun doMeasure(): Double? { - // if (getState("power").booleanValue()) { - val channel = meta.getInt("channel", 5) - val answer = talk("PR$channel?") - if (answer == null || answer.isEmpty()) { - updateLogicalState(PortSensor.CONNECTED_STATE, false) - this.updateMessage("No connection") - return null - } - val res = parseDouble(answer) - return if (res <= 0) { - this.updateMessage("No power") - updateLogicalState("power", false) - null - } else { - this.updateMessage("OK") - res - } + override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) { + startMeasurement(newMeta) { + doMeasure() } + } - override fun getDevice(): Device = this@MKSVacDevice + private fun doMeasure(): Meta { + // if (getState("power").booleanValue()) { + val channel = meta.getInt("channel", 5) + val answer = talk("PR$channel?") + if (answer == null || answer.isEmpty()) { + updateLogicalState(PortSensor.CONNECTED_STATE, false) + return produceError("No connection") + } + val res = parseDouble(answer) + return if (res <= 0) { + updateLogicalState("power", false) + produceError("No power") + } else { + this.updateMessage("OK") + produceResult(res) + } } } diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MeradatVacDevice.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MeradatVacDevice.kt index e6341011..90a54022 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MeradatVacDevice.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/MeradatVacDevice.kt @@ -6,14 +6,14 @@ package inr.numass.control.readvac import hep.dataforge.context.Context -import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.PortSensor -import hep.dataforge.control.measurements.Measurement -import hep.dataforge.control.measurements.SimpleMeasurement +import hep.dataforge.control.devices.intState +import hep.dataforge.control.ports.GenericPortController import hep.dataforge.control.ports.Port +import hep.dataforge.control.ports.PortFactory import hep.dataforge.description.ValueDef -import hep.dataforge.exceptions.ControlException import hep.dataforge.meta.Meta +import hep.dataforge.states.StateDef import hep.dataforge.values.ValueType.NUMBER import java.math.BigDecimal import java.math.BigInteger @@ -23,73 +23,63 @@ import java.util.regex.Pattern /** * @author Alexander Nozik */ -@ValueDef(name = "address", type = arrayOf(NUMBER), def = "1", info = "A modbus address") +@StateDef(value = ValueDef(name = "address", type = [NUMBER], def = "1", info = "A modbus address"), writable = true) class MeradatVacDevice(context: Context, meta: Meta) : PortSensor(context, meta) { - @Throws(ControlException::class) - override fun buildPort(portName: String): Port { - val newHandler = super.buildPort(portName) - newHandler.setDelimiter("\r\n") - return newHandler - } + var address by intState("address") - override fun createMeasurement(): Measurement = MeradatMeasurement() + override fun connect(meta: Meta): GenericPortController { + val port: Port = PortFactory.build(meta) + logger.info("Connecting to port {}", port.name) + + return GenericPortController(context, port) { it.endsWith("\r\n") } + } override fun getType(): String { - return getMeta().getString("type", "Vit vacuumeter") + return meta.getString("type", "numass.vac.vit") + } + + override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) { + startMeasurement(newMeta) { + doMeasure() + } } - private inner class MeradatMeasurement : SimpleMeasurement() { + private fun doMeasure(): Meta { + val requestBase: String = String.format(":%02d", address) + val dataStr = requestBase.substring(1) + REQUEST + val query = requestBase + REQUEST + calculateLRC(dataStr) + "\r\n" // ":010300000002FA\r\n"; + val response: Pattern = Pattern.compile(requestBase + "0304(\\w{4})(\\w{4})..\r\n") - private val query: String // ":010300000002FA\r\n"; - private val response: Pattern - private val base: String + val answer = sendAndWait(query) { phrase -> phrase.startsWith(requestBase) } - init { - base = String.format(":%02d", getMeta().getInt("address", 1)) - val dataStr = base.substring(1) + REQUEST - query = base + REQUEST + calculateLRC(dataStr) + "\r\n" - response = Pattern.compile(base + "0304(\\w{4})(\\w{4})..\r\n") - } + if (answer.isEmpty()) { + updateLogicalState(PortSensor.CONNECTED_STATE, false) + return produceError("No signal") + } else { + val match = response.matcher(answer) - @Synchronized - @Throws(Exception::class) - override fun doMeasure(): Double? { - - val answer = sendAndWait(query) { phrase -> phrase.startsWith(base) } - - if (answer.isEmpty()) { - this.updateMessage("No signal") - updateLogicalState(PortSensor.CONNECTED_STATE, false) - return null - } else { - val match = response.matcher(answer) - - if (match.matches()) { - val base = Integer.parseInt(match.group(1), 16).toDouble() / 10.0 - var exp = Integer.parseInt(match.group(2), 16) - if (exp > 32766) { - exp -= 65536 - } - var res = BigDecimal.valueOf(base * Math.pow(10.0, exp.toDouble())) - res = res.setScale(4, RoundingMode.CEILING) - this.updateMessage("OK") - updateLogicalState(PortSensor.CONNECTED_STATE, true) - return res.toDouble() - } else { - this.updateMessage("Wrong answer: " + answer) - updateLogicalState(PortSensor.CONNECTED_STATE, false) - return null + return if (match.matches()) { + val base = Integer.parseInt(match.group(1), 16).toDouble() / 10.0 + var exp = Integer.parseInt(match.group(2), 16) + if (exp > 32766) { + exp -= 65536 } + var res = BigDecimal.valueOf(base * Math.pow(10.0, exp.toDouble())) + res = res.setScale(4, RoundingMode.CEILING) + updateLogicalState(PortSensor.CONNECTED_STATE, true) + produceResult(res) + } else { + updateLogicalState(PortSensor.CONNECTED_STATE, false) + produceError("Wrong answer: $answer") } } - - override fun getDevice(): Device = this@MeradatVacDevice } + companion object { - private val REQUEST = "0300000002" + private const val REQUEST = "0300000002" fun calculateLRC(inputString: String): String { /* @@ -100,7 +90,7 @@ class MeradatVacDevice(context: Context, meta: Meta) : PortSensor(contex var value = Integer.toHexString(-checksum) value = value.substring(value.length - 2).toUpperCase() if (value.length < 2) { - value = "0" + value + value = "0$value" } return value diff --git a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDevice.kt b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDevice.kt index 09ab213f..6db8483d 100644 --- a/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDevice.kt +++ b/numass-control/vac/src/main/kotlin/inr/numass/control/readvac/VacCollectorDevice.kt @@ -12,9 +12,9 @@ import hep.dataforge.control.collectors.RegularPointCollector import hep.dataforge.control.connections.Roles import hep.dataforge.control.devices.Device import hep.dataforge.control.devices.DeviceHub +import hep.dataforge.control.devices.DeviceListener +import hep.dataforge.control.devices.PortSensor.Companion.CONNECTED_STATE import hep.dataforge.control.devices.Sensor -import hep.dataforge.control.measurements.AbstractMeasurement -import hep.dataforge.control.measurements.Measurement import hep.dataforge.description.ValueDef import hep.dataforge.exceptions.ControlException import hep.dataforge.meta.Meta @@ -31,13 +31,10 @@ import hep.dataforge.values.ValueType import hep.dataforge.values.Values import inr.numass.control.DeviceView import inr.numass.control.StorageHelper +import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.experimental.time.delay import java.time.Duration -import java.time.Instant import java.util.* -import java.util.concurrent.Executors -import java.util.concurrent.ScheduledExecutorService -import java.util.concurrent.ScheduledFuture -import java.util.concurrent.TimeUnit import java.util.stream.Stream /** @@ -50,8 +47,22 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection = @@ -66,8 +77,6 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection = VacuumMeasurement() override fun getType(): String = "numass.vac.collector" @@ -87,7 +96,7 @@ class VacCollectorDevice(context: Context, meta: Meta, val sensors: Collection() { - private val collector = RegularPointCollector(averagingDuration) { this.result(it) } - private var executor: ScheduledExecutorService? = null - private var currentTask: ScheduledFuture<*>? = null + private fun notifyResult(values: Values) { + notifyResult(produceResult(values.toMeta())) + helper.push(values) + } - override fun getDevice(): Device { - return this@VacCollectorDevice - } - - - override fun start() { - executor = Executors.newSingleThreadScheduledExecutor { r: Runnable -> Thread(r, "VacuumMeasurement thread") } - val delay = getMeta().getInt("delay", 5)!! * 1000 - currentTask = executor!!.scheduleWithFixedDelay({ - sensors.forEach { sensor -> - try { - val value: Any? - value = if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) { - sensor.read() - } else { - null - } - collector.put(sensor.name, value) - } catch (ex: Exception) { - collector.put(sensor.name, Value.NULL) - } - } - }, 0, delay.toLong(), TimeUnit.MILLISECONDS) - } - - - @Synchronized override fun result(result: Values, time: Instant) { - super.result(result, time) - helper.push(result) - } - - private fun terminator(): Values { - val p = ValueMap.Builder() - p.putValue("timestamp", DateTimeUtils.now()) - getDeviceNames().forEach { n -> p.putValue(n.toUnescaped(), null) } - return p.build() - } - - override fun stop(force: Boolean): Boolean { - val isRunning = currentTask != null - if (isRunning) { - logger.debug("Stopping vacuum collector measurement. Writing terminator point") - result(terminator()) - currentTask!!.cancel(force) - executor!!.shutdown() - currentTask = null - afterStop() + override fun onStateChange(stateName: String, oldState: Value?, newState: Value) { + if (stateName == MEASURING_STATE) { + if (!newState.booleanValue()) { + notifyResult(terminator()) } - return isRunning } } + + override fun setMeasurement(oldMeta: Meta?, newMeta: Meta) { + oldMeta?.let { + stopMeasurement() + } + + val interval = Duration.ofSeconds(meta.getInt("delay", 5).toLong()) + + job = launch { + while (true) { + notifyMeasurementState(MeasurementState.IN_PROGRESS) + sensors.forEach { sensor -> + if (sensor.optBooleanState(CONNECTED_STATE).orElse(false)) { + sensor.measure() + } + } + notifyMeasurementState(MeasurementState.WAITING) + delay(interval) + } + } + } + + private fun terminator(): Values { + val p = ValueMap.Builder() + deviceNames.forEach { n -> p.putValue(n.toUnescaped(), null) } + return p.build() + } + + }