Commit 9abb2722 authored by Cyril Guilloud's avatar Cyril Guilloud Committed by Matias Guijarro
Browse files

__info__ for tango_attr_as_counter

parent c0fef6d4
......@@ -113,15 +113,14 @@ class Counter:
def get_metadata(self):
return {}
def __info__(self):
info_str = "Counter info:\n"
info_str += f" name = {self.name} \n"
def __info__(self, counter_type=None):
info_str = f"'{self.name}` counter info:\n"
info_str += f" counter type = {counter_type} \n" if counter_type else ""
info_str += f" fullname = {self.fullname} \n"
info_str += f" unit = {self.unit} \n"
info_str += f" shape = {self.shape} \n"
info_str += f" dtype = {self.dtype} \n"
info_str += f" fullname = {self.fullname} \n"
info_str += f" conversion_function = {self.conversion_function} \n"
info_str += f" _counter_controller = {self._counter_controller} \n"
return info_str
......@@ -182,11 +181,9 @@ class SamplingCounter(Counter):
def statistics(self):
return self._statistics
def __info__(self):
def __info__(self, counter_type="sampling"):
"""Standard method called by BLISS Shell info helper."""
info_str = "------ SamplingCounter ------\n"
info_str = super().__info__()
info_str += f"\nSamplingCounter info:\n"
info_str = super().__info__(counter_type=counter_type)
info_str += f" mode = {SamplingMode(self.mode).name} ({self.mode})\n"
return info_str
......@@ -199,10 +196,9 @@ class IntegratingCounter(Counter):
name, controller, conversion_function=conversion_function, unit=unit
)
def __info__(self):
def __info__(self, counter_type="integrating"):
"""Standard method called by BLISS Shell info helper."""
info_str = "------ IntegratingCounter ------\n"
info_str += super().__info__()
info_str = super().__info__(counter_type=counter_type)
return info_str
......@@ -315,13 +311,11 @@ class SoftCounter(SamplingCounter):
def __info__(self):
"""Standard method called by BLISS Shell info helper."""
info_str = "------ SoftCounter ------\n"
info_str = super().__info__()
info_str += f"\nSoftCounter info:\n"
info_str += f" ctrl_name = {self.ctrl_name}\n"
info_str = super().__info__(counter_type="software")
return info_str
class CalcCounter(Counter):
pass
def __info__(self):
return super().__info__(counter_type="calc")
......@@ -13,7 +13,6 @@ Tango attribute as a counter
TODO :
* alarm ?
* format ?
* writability ?
YAML_ configuration example:
......@@ -41,7 +40,7 @@ import weakref
from bliss.common.counter import SamplingCounter, SamplingMode
from bliss.common import tango
from bliss import global_map
from bliss.common.logtools import log_debug
from bliss.common.logtools import log_debug, log_error
from bliss.controllers.counter import SamplingCounterController
......@@ -91,6 +90,48 @@ def get_attr_config(tango_uri, attr_name):
return get_attr_config.config[attr_cfg_key]
"""
Example of get_attr_config(self.tango_uri, self.attribute)
AttributeInfoEx[
alarms = AttributeAlarmInfo(delta_t = 'Not specified', delta_val = 'Not specified',
extensions = [], max_alarm = 'Not specified',
max_warning = 'Not specified', min_alarm = 'Not specified',
min_warning = 'Not specified')
data_format = tango._tango.AttrDataFormat.SCALAR
data_type = tango._tango.CmdArgType.DevFloat
description = 'No description'
disp_level = tango._tango.DispLevel.OPERATOR
display_unit = 'No display unit'
enum_labels = []
events = AttributeEventInfo(arch_event = ArchiveEventInfo(archive_abs_change = 'Not specified',
archive_period = 'Not specified',
archive_rel_change = 'Not specified',
extensions = []),
ch_event = ChangeEventInfo(abs_change = 'Not specified',
extensions = [],
rel_change = 'Not specified'),
per_event = PeriodicEventInfo(extensions = [], period = '1000'))
extensions = []
format = '%6.2f'
label = 'hppstc1'
max_alarm = 'Not specified'
max_dim_x = 1
max_dim_y = 0
max_value = 'Not specified'
memorized = tango._tango.AttrMemorizedType.NOT_KNOWN
min_alarm = 'Not specified'
min_value = 'Not specified'
name = 'hppstc1'
root_attr_name = ''
standard_unit = 'No standard unit'
sys_extensions = []
unit = ''
writable = tango._tango.AttrWriteType.READ
writable_attr_name = 'None']
"""
class TangoCounterController(SamplingCounterController):
def __init__(self, tango_uri):
proxy = get_proxy(tango_uri)
......@@ -124,13 +165,13 @@ class TangoCounterController(SamplingCounterController):
class tango_attr_as_counter(SamplingCounter):
def __init__(self, name, config):
tango_uri = config.get_inherited("uri")
if tango_uri is None:
self.tango_uri = config.get_inherited("uri")
if self.tango_uri is None:
raise KeyError("uri")
self.attribute = config["attr_name"]
controller = _TangoCounterControllerDict.setdefault(
tango_uri, TangoCounterController(tango_uri)
self.tango_uri, TangoCounterController(self.tango_uri)
)
controller._counters[name] = self
......@@ -139,25 +180,26 @@ class tango_attr_as_counter(SamplingCounter):
controller, f" to read '{self.attribute}' tango attribute."
)
_tango_attr_config = get_attr_config(tango_uri, self.attribute)
_tango_attr_config = get_attr_config(self.tango_uri, self.attribute)
# UNIT
# Use 'unit' if present in YAML, otherwise, try to read the
# Tango configured unit.
yml_unit = config.get("unit")
tango_unit = _tango_attr_config.unit
if yml_unit is None:
if tango_unit != "":
unit = tango_unit
# Use 'unit' if present in YAML, otherwise, try to use the
# Tango configured 'unit'.
self.yml_unit = config.get("unit")
self.tango_unit = _tango_attr_config.unit
if self.yml_unit is None:
if self.tango_unit != "":
unit = self.tango_unit
else:
unit = None
else:
unit = yml_unit
unit = self.yml_unit
log_debug(
controller, f" * unit read from YAML config: '{yml_unit}'"
controller, f" * unit read from YAML config: '{self.yml_unit}'"
)
log_debug(
controller, f" * unit read from Tango config: '{tango_unit}'"
controller,
f" * unit read from Tango config: '{self.tango_unit}'",
)
log_debug(controller, f" * unit used: '{unit}'")
......@@ -174,11 +216,14 @@ class tango_attr_as_counter(SamplingCounter):
sampling_mode = config.get("mode", SamplingMode.MEAN)
# FORMAT
tango_format = _tango_attr_config.format
if tango_format:
self.format_string = tango_format
# Use 'format' if present in YAML, otherwise, try to use the
# Tango configured 'format'.
self.yml_format = config.get("format")
self.tango_format = _tango_attr_config.format
if self.yml_format:
self.format_string = self.yml_format
else:
self.format_string = ""
self.format_string = self.tango_format
# INIT
SamplingCounter.__init__(
......@@ -190,10 +235,37 @@ class tango_attr_as_counter(SamplingCounter):
unit=unit,
)
def __info__(self):
info_string = f"'{self.name}` Tango attribute counter info:\n"
info_string += f" device server = {self.tango_uri}\n"
info_string += f" Tango attribute = {self.attribute}\n"
# FORMAT
if self.yml_format is not None:
info_string += f' Beacon format = "{self.yml_format}"\n'
else:
if self.tango_format != "":
info_string += f' Tango format = "{self.tango_format}"\n'
else:
info_string += f" no format\n"
# UNIT
if self.yml_unit is not None:
info_string += f' Beacon unit = "{self.yml_unit}"\n'
else:
if self.tango_unit != "":
info_string += f' Tango unit = "{self.tango_unit}"\n'
else:
info_string += f" no unit\n"
return info_string
def convert_func(self, value):
attr_val = value * self.conversion_factor
return float(self.format_string % attr_val if self.format_string else attr_val)
formated_value = float(
self.format_string % attr_val if self.format_string else attr_val
)
return formated_value
TangoAttrCounter = tango_attr_as_counter
`tango_attr_as_counter` class allows to read, as a BLISS counter, an attribute
of a Tango Device Server.
`tango_attr_as_counter` class allows to read a Tango attribute in BLISS as a
counter.
## Configuration parameters
......@@ -28,6 +28,24 @@ BLISS:
attribute value) by which the raw read value is multiplied.
* `format` (string): string representing the display format to use.
### info
As `tango_attr_as_counter` class provide a `__info__()` method, some info about
the counter can be obtained just by typing the name of the counter:
```python
DEMO [1]: hppstc1
Out [1]: Tango Attribute Counter
Device Server: id42:20000/id42/wcid42hpps/tg
Tango Attribute: hppstc1
value: 23.5
no Tango unit
Beacon unit: gw
```
## Examples
Example to read *ring current* and *beam lifetime* from The Machine device
......@@ -78,9 +96,9 @@ DEMO [3]: t0=time.time();ct(0.0001, kohztc5, flowBase, flowM2, flowM1,
m0m2, pptc1);print("duration=", time.time()-t0)
get_proxy -- create dict
get_proxy -- create proxy for id21/wcid21m0/tg
get_proxy -- create proxy for id21/wcid21k/tg
get_proxy -- create proxy for id21/wcid21hpps/tg
get_proxy -- create proxy for id42/wcid42m0/tg
get_proxy -- create proxy for id42/wcid42k/tg
get_proxy -- create proxy for id42/wcid42hpps/tg
Tue Jul 23 15:56:13 2019
dt[s] = 0.0 ( 0.0/s)
......
......@@ -147,17 +147,14 @@ BLISS [4]: [a]
before returning.
Example of a typical implementation of `.__info__()` method (no more need of
exception management like previously):
```python
def __info__(self):
"""Standard method called by BLISS Shell info helper."""
info_str = ""
info_str += " bla bla\n"
return info_str
```
Example:
```python
def __info__(self):
info_str = "bla \n"
info_str += "bli \n"
return info_str
```
The equivalent of `repr(obj)` or `str(obj)` is also availabe in
`bliss.shell.standard` as `info(obj)` which can be used also outside the Bliss
......
......@@ -62,7 +62,7 @@ nav:
- Opiom: config_opiom.md
- PEPU: config_pepu.md
- TFG: config_tango_tfg.md
- Tango attribute counters: config_tac.md
- Tango attribute as counters: config_taac.md
- Nano-BPM: config_nano_bpm.md
- Shutters, FE and Valves: config_shutter.md
- Wagos:
......
# --encoding: utf-8--
import time
from tango.server import run
from tango.server import Device
from tango.server import attribute, command
......@@ -8,7 +7,7 @@ from tango import DevState
class Dummy(Device):
position = attribute(format="%3.2f")
position = attribute(format="%3.2f", unit="mm")
velocity = attribute(
fget="read_velocity", fset="write_velocity", access=AttrWriteType.READ_WRITE
)
......
......@@ -31,10 +31,9 @@
height_factor: 12.0
noise_factor: 1.01
-
name: tg_dummy_counter
name: taac_dummy_position
plugin: bliss
class: tango_attr_as_counter
uri: id00/tango/dummy
unit: mm
attr_name: position
......@@ -2,21 +2,22 @@
uri: id00/tango/dummy
plugin: bliss
counters:
- name: tac_undu_position
- name: taac_undu_position
attr_name: position
mode: MEAN
unit: mm
- name: tac_undu_acceleration
unit: km
format: "%5.3f"
- name: taac_undu_acceleration
attr_name: acceleration
mode: LAST
# no unit for test.
- name: tac_undu_velocity
# no format, no unit for test.
- name: taac_undu_velocity
attr_name: velocity
unit: mm
- name: wrong_counter
attr_name: wrong_attr
unit: mm
- name: tac_undu_cracoucas
- name: taac_undu_wrong_attr_name
attr_name: cracoucas
# wrong attr_name.
......
......@@ -469,58 +469,66 @@ def test_prepare_once_prepare_many(session):
def test_tango_attr_counter(beacon, dummy_tango_server, session):
counter = beacon.get("tg_dummy_counter")
counter.mode = "LAST"
counter = beacon.get("taac_dummy_position")
# `taac_dummy_position` is a tango_attr_as_counter which refers to
# "position" attribute of "id00/tango/dummy" test device.
counter = beacon.get("taac_dummy_position")
sc = ct(0.01, counter)
counter_value = sc.get_data()["tg_dummy_counter"][0]
counter_value = sc.get_data()["taac_dummy_position"][0]
assert counter_value == 1.41
assert counter.unit == "mm"
assert counter.format_string == "%3.2f"
assert counter.unit == "mm" # hard-coded in test config
assert counter.format_string == "%3.2f" # hard-coded in test config
assert counter.mode == SamplingMode.MEAN # default mode
with pytest.raises(tango.DevFailed):
wrong_counter = beacon.get("wrong_counter")
# get BLISS counters
tac_pos = beacon.get("tac_undu_position")
tac_vel = beacon.get("tac_undu_velocity")
# get BLISS tango_attr_as_counter counters
taac_pos = beacon.get("taac_undu_position")
taac_vel = beacon.get("taac_undu_velocity")
# Test overwriting properties in BEACON configuration.
assert taac_pos.format_string == "%5.3f"
assert taac_pos.unit == "km"
# test "no unit"
tac_acc = beacon.get("tac_undu_acceleration")
# Test no BEACON unit / no BEACON format
taac_acc = beacon.get("taac_undu_acceleration")
# test sampling mode
assert tac_pos.mode == SamplingMode.MEAN
assert tac_acc.mode == SamplingMode.LAST
# Sampling modes fixed in config.
assert taac_pos.mode == SamplingMode.MEAN
assert taac_acc.mode == SamplingMode.LAST
# test default sampling mode
assert tac_vel.mode == SamplingMode.MEAN
tac_pos.mode = "LAST"
tac_vel.mode = "LAST"
tac_acc.mode = "LAST"
# Default sampling mode is MEAN
assert taac_vel.mode == SamplingMode.MEAN
with pytest.raises(tango.DevFailed):
tac_cracoucas = beacon.get("tac_undu_cracoucas")
_ = beacon.get("taac_undu_wrong_attr_name")
# get UNDULATOR object
# Get directly BLISS UNDULATOR object (not via tango_attr_as_counter)
# to compare taac values to direct values.
u23a = beacon.get("u23a")
sc = ct(0.01, tac_pos, tac_vel, tac_acc)
pos = sc.get_data()["tac_undu_position"][0]
vel = sc.get_data()["tac_undu_velocity"][0]
acc = sc.get_data()["tac_undu_acceleration"][0]
sc = ct(0.01, taac_pos, taac_vel, taac_acc)
pos = sc.get_data()["taac_undu_position"][0]
vel = sc.get_data()["taac_undu_velocity"][0]
acc = sc.get_data()["taac_undu_acceleration"][0]
assert u23a.position == 1.4078913
assert pos == 1.41
# formating is applyed before averaging :(
pytest.approx(pos) == 1.408
assert u23a.velocity == vel
assert u23a.acceleration == acc
# Test missing uri
with pytest.raises(KeyError):
no_uri_counter = beacon.get("no_uri_counter")
_ = beacon.get("no_uri_counter")
def test_info_counters(beacon):
def test_info_counters(beacon, dummy_tango_server):
"""
execute .__info__() method of 3 types of counters.
"""
......@@ -535,6 +543,18 @@ def test_info_counters(beacon):
# SoftCounter
soft_cnt = SoftCounter(mot_robz, "position")
diode1.__info__()
diode2.__info__()
soft_cnt.__info__()
assert diode1.__info__().startswith(
f"'{diode1.name}` counter info:\n counter type = sampling"
)
assert diode2.__info__().startswith(
f"'{diode2.name}` counter info:\n counter type = integrating"
)
assert soft_cnt.__info__().startswith(
f"'{soft_cnt.name}` counter info:\n counter type = software"
)
counter = beacon.get("taac_dummy_position")
assert counter.__info__().startswith(
f"'{counter.name}` Tango attribute counter info:"
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment