Skip to content
Snippets Groups Projects
Commit a0f8faac authored by David Hammer's avatar David Hammer
Browse files

Merge branch 'fix/condition-watcher-states' into 'master'

Condition watcher: fix MONITORING state behavior

See merge request !148
parents 61f8ea94 ceb96320
No related branches found
No related tags found
1 merge request!148Condition watcher: fix MONITORING state behavior
......@@ -56,7 +56,8 @@ class ConditionBase(Device):
accessMode=AccessMode.READONLY,
)
conditionsMatch = String(displayType="State")
monitoringState = String(displayType="State", defaultValue="OFF")
conditionsMatchState = String(displayType="State", defaultValue="OFF")
@property
def keys_to_get(self):
......@@ -67,14 +68,25 @@ class ConditionBase(Device):
raise NotImplementedError("Subclass must implement!")
async def onInitialization(self):
self._state_signifier = StateSignifier()
self.state = State.INIT
self._state_signifier = StateSignifier(
[
State.OFF,
State.ON,
State.MONITORING,
State.CHANGING,
State.INIT,
State.ERROR,
]
)
self._update_state(State.INIT)
self._manager_dev = await connectDevice(self.managerDeviceId.value)
self._monitor = None
if self._manager_dev.classId.value == "CalibrationManager":
self._operation_mode = PipelineOperationMode.MANAGED
else:
self._operation_mode = PipelineOperationMode.STANDALONE
self.state = State.ON
self._update_state()
self.log_status("Ready!")
def _trigger_constant_loading(self):
if self._operation_mode is PipelineOperationMode.MANAGED:
......@@ -110,13 +122,28 @@ class ConditionBase(Device):
)
@Slot(
allowedStates=[State.ON, State.ERROR],
displayedName="Start monitoring",
allowedStates=[State.ON, State.ERROR, State.MONITORING],
displayedName="Toggle monitoring",
description="Will keep settings on manager in sync with control device(s) "
"automagically by monitoring for updates.",
)
async def startMonitoring(self):
self.state = State.CHANGING
async def toggleMonitoring(self):
if self._monitor is None:
self.log_status("Will start monitoring")
self.monitoringState = State.CHANGING.value
self._update_state()
await self._start_monitor()
self.monitoringState = State.MONITORING.value
self._update_state()
else:
self.log_status("Will stop monitoring")
self.monitoringState = State.CHANGING.value
self._update_state()
await self._stop_monitor()
self.monitoringState = State.OFF.value
self._update_state()
async def _start_monitor(self):
control_devs = {
control_id: await connectDevice(control_id)
for control_id in self.keys_to_get.keys()
......@@ -145,26 +172,19 @@ class ConditionBase(Device):
await self._check_or_update(
self.updateManagerOnMonitor.value, control_devs=control_devs
)
self._update_state()
# TODO: maybe debounce
if self.loadConstantsOnMonitor.value:
self._trigger_constant_loading()
self._monitor = background(aux)
self._control_devs = control_devs
self.state = self._state_signifier.returnMostSignificant(
[State.MONITORING, State[self.conditionsMatch]]
)
@Slot(
allowedStates=[State.MONITORING, State.ERROR],
displayedName="Stop monitoring",
)
async def stopMonitoring(self):
self.state = State.CHANGING
async def _stop_monitor(self):
self._monitor.cancel()
for dev in self._control_devs.values():
await disconnectDevice(dev)
self.state = State.ON
self._monitor = None
async def _check_or_update(self, update_manager, control_devs=None):
"""Will compare values of keys_to_get on control device(s) to actual values on
......@@ -192,6 +212,7 @@ class ConditionBase(Device):
)
row_state = State.ON
if not could_look_up:
# warning already issued in _look_up
happy = False
row_state = State.UNKNOWN
elif ideal_value != manager_value:
......@@ -204,11 +225,18 @@ class ConditionBase(Device):
)
except Exception as ex:
manager_value = f"Failed to set {ideal_value}: {ex}"
self.log_status(manager_value, log="WARN")
row_state = State.ERROR
else:
self.log_status(
f"Set {manager_key}={ideal_value} on manager"
)
manager_value = ideal_value
updated_manager = True
else:
self.log_status(
f"{manager_key} != {ideal_value}, is {manager_value}"
)
happy = False
row_state = State.ERROR
key_mapping.append(
......@@ -239,9 +267,10 @@ class ConditionBase(Device):
self.keyMapping = key_mapping
if happy:
self.conditionsMatch = State.ON.value
self.conditionsMatchState = State.ON.value
else:
self.conditionsMatch = State.ERROR.value
# in this case, have already warned
self.conditionsMatchState = State.ERROR.value
return updated_manager
......@@ -276,7 +305,7 @@ class ConditionBase(Device):
except Exception as ex:
warning = f"Failed to process control value {control_value}; {ex}"
ideal_value = warning
self.log.WARN(warning)
self.log_status(warning, log="WARN")
could_look_up = False
else:
ideal_value = "control key not found"
......@@ -298,11 +327,10 @@ class ConditionBase(Device):
"does not change anything on manager.",
)
async def checkConditions(self):
self.state = State.CHANGING
self.conditionsMatchState = State.CHANGING.value
self._update_state()
await self._check_or_update(False)
self.state = self._state_signifier.returnMostSignificant(
[State.ON, State[self.conditionsMatch]]
)
self._update_state()
@Slot(
allowedStates=[State.ON, State.ERROR],
......@@ -311,11 +339,10 @@ class ConditionBase(Device):
"also 'Start monitoring' for automatic version of this.",
)
async def updateConditions(self):
self.state = State.CHANGING
self.conditionsMatchState = State.CHANGING.value
self._update_state()
await self._check_or_update(True)
self.state = self._state_signifier.returnMostSignificant(
[State.ON, State[self.conditionsMatch]]
)
self._update_state()
availableScenes = VectorString(
displayedName="Available scenes",
......@@ -328,6 +355,22 @@ class ConditionBase(Device):
daqPolicy=DaqPolicy.OMIT,
)
doNotCompressEvents = Bool(
requiredAccessLevel=AccessLevel.GOD,
accessMode=AccessMode.READONLY,
defaultValue=True,
daqPolicy=DaqPolicy.OMIT,
)
def _update_state(self, main=State.ON):
self.state = self._state_signifier.returnMostSignificant(
(main, State[self.conditionsMatchState], State[self.monitoringState])
)
def log_status(self, msg, log="INFO"):
self.status = msg
getattr(self.log, log)(msg)
@slot
def requestScene(self, params):
return Hash(
......
......@@ -1220,41 +1220,73 @@ def condition_checker_overview(device_id, schema):
schema_hash = schema_to_hash(schema)
return VerticalLayout(
HorizontalLayout(
DisplayCommandModel(
keys=[f"{device_id}.checkConditions"],
width=7 * BASE_INC,
height=BASE_INC,
),
DisplayCommandModel(
keys=[f"{device_id}.updateConditions"],
width=7 * BASE_INC,
height=BASE_INC,
VerticalLayout(
DisplayLabelModel(
keys=[f"{device_id}.deviceId"],
width=14 * BASE_INC,
height=BASE_INC,
),
DisplayStateColorModel(
show_string=True,
keys=[f"{device_id}.state"],
width=7 * BASE_INC,
height=BASE_INC,
),
titled("Condition check")(boxed(HorizontalLayout))(
DisplayStateColorModel(
show_string=True,
keys=[f"{device_id}.conditionsMatchState"],
width=7 * BASE_INC,
height=BASE_INC,
),
VerticalLayout(
DisplayCommandModel(
keys=[f"{device_id}.checkConditions"],
width=7 * BASE_INC,
height=BASE_INC,
),
DisplayCommandModel(
keys=[f"{device_id}.updateConditions"],
width=7 * BASE_INC,
height=BASE_INC,
),
),
),
titled("Monitor conditions")(boxed(VerticalLayout))(
HorizontalLayout(
DisplayStateColorModel(
show_string=True,
keys=[f"{device_id}.monitoringState"],
width=7 * BASE_INC,
height=BASE_INC,
),
DisplayCommandModel(
keys=[f"{device_id}.toggleMonitoring"],
width=7 * BASE_INC,
height=BASE_INC,
),
),
EditableRow(
device_id, schema_hash, "updateManagerOnMonitor", 7, 1
),
EditableRow(
device_id, schema_hash, "loadConstantsOnMonitor", 7, 1
),
),
),
DisplayStateColorModel(
keys=[f"{device_id}.conditionsMatch"],
width=7 * BASE_INC,
height=BASE_INC,
DisplayTextLogModel(
keys=[f"{device_id}.status"],
width=14 * BASE_INC,
height=14 * BASE_INC,
),
),
HorizontalLayout(
DisplayCommandModel(
keys=[f"{device_id}.startMonitoring"],
width=7 * BASE_INC,
height=BASE_INC,
),
DisplayCommandModel(
keys=[f"{device_id}.stopMonitoring"],
width=7 * BASE_INC,
height=BASE_INC,
titled("Condition table")(boxed(VerticalLayout))(
TableElementModel(
keys=[f"{device_id}.keyMapping"],
width=30 * BASE_INC,
height=20 * BASE_INC,
),
),
EditableRow(device_id, schema_hash, "updateManagerOnMonitor", 13, 1),
EditableRow(device_id, schema_hash, "loadConstantsOnMonitor", 13, 1),
TableElementModel(
keys=[f"{device_id}.keyMapping"],
width=30 * BASE_INC,
height=20 * BASE_INC,
),
)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment