Configuration files¶
When a Beacon server starts, it loads all configuration files found under the root directory
specified with --db-path
on the beacon server command line.
Configuration files are plain text files in YAML format (.yml
) used to declare and describe the
various BLISS objects.
The idea is to have a centralized configuration database per beamline accessible from different computers (Beacon & BLISS sessions).
While loading the configuration, Beacon builds an internal representation of the objects defined in YAML files. The configuration files structure is flattened and exposed as a Python dictionary with key-value pairs. The keys being object names and values being the corresponding configuration information.
About YAML format
- It maps standard native types to Python equivalents (list, dictionary, numbers, strings…).
- It handles comments (contrary to JSON).
- It is optimized for human-readability (contrary to XML).
YAML items¶
A YAML item is a key-value pair, using key: value
syntax. A YAML mapping
is a set of YAML items:
YAML example with basic items
key_1: 1 # float value
key_2: ['a', 'b', 'c'] # list value
key_3: a string # string value
Info
An online YAML parser can help finding YAML syntax errors.
Object configuration¶
A new entry in the configuration is done by providing the - name: <obj_name>
YAML item.
However, for most of the BLISS objects, it is also necessary to provide the class: <obj_class>
and plugin: <plugin>
items.
Any other custom items, relevant in the object context, can be added to the configuration (channel, unit, …).
A single object YAML configuration
- name: foo # a configuration entry for an object named 'foo'
class: FooClass # the class for the 'foo' object
plugin: generic # the plugin used to instanciate the FooClass object
channel: 42 # a custom item interpreted by the FooClass
Multiple objects configurations can be defined in one file by using the YAML list notation -
:
Multiple objects YAML configuration
- name: foo # one object named 'foo'
class: FooClass
plugin: generic
channel: 42
- name: bar # another object named 'bar'
class: BarClass
plugin: default
unit: mm
Multiple objects configurations can be nested to reflect the hierarchy and dependences between objects.
For example, the axes managed by a motor controller are declared within the controller’s configuration, under the axes
key.
Nested objects YAML configuration
- name: dummy_motor_ctrl # one top-object (motor controller)
class: mockup
axes:
- name: robx # one sub-object (axis 'robx')
steps_per_unit: 10000
velocity: 100
acceleration: 300
unit: mm
- name: roby # one sub-object (axis 'roby')
steps_per_unit: 10000
velocity: 1000
acceleration: 100
unit: mm
Warning
- Notice the usage of
-
to declare an object (or sub-object) configuration entry - Notice that indentation matters (2 spaces as default)
- Notice that a sub-object configuration can be declared within a top-object configuration
Object reference¶
In the configuration of one object, it is possible to reference another object defined elsewhere in the configuration files.
Referencing is done by adding the $
character in front of the object name.
For example, $front_blade
points to the object named front_blade
.
YAML example using objects references
- name: gslits # a CalcController using referenced axes as inputs
class: slits
axes:
- name: $ssf # a reference to existing 'ssf' axis
tags: real front
- name: $ssb # a reference to existing 'ssb' axis
tags: real back
- name: sshg # the calculational axis created by this CalcController
tags: hgap
tolerance: 0.04
Info
Accessing an object reference triggers the instantiation of the pointed object.
For example, config.get_config('gslits')['axes'][0]['name']
will trigger instantiation of ssf
(if not already alive).
Tree structure¶
Directories¶
Beacon’s internal tree structure mirrors the file-system directories. Multiple files are just a convenient way of grouping related objects within a container, whereas directories play a role in the organization of the configuration database.
The following YAML configuration tree:
beamline_configuration/
└── directory_1
└── file_1.yml
Content of file_1.yml
- name: foo
class: FooClass
plugin: generic
channel: 42
- name: bar
class: BarClass
plugin: default
unit: mm
Access configuration in the shell
>>> from bliss.config.static import get_config
>>> config = get_config() # get the whole config
>>> config.pprint()
{ filename: None
directory_1:
[
{ filename: 'directory_1/file_1.yml'
name: foo
class: FooClass
plugin: generic
channel: 42
},
{ filename: 'directory_1/file_1.yml'
name: bar
class: BarClass
plugin: default
unit: mm
}
]
}
>>> config.names_list # get existing names from config
['foo', 'bar']
>>> config.get_config('foo') # get the config of the object named 'foo'
filename:<file_1.yml>,
plugin:'generic',
{'name': 'foo', 'class': 'FooClass', 'plugin': 'generic', 'channel': 42}
Info
Each YAML object configuration is attached to a parent node. In this case, the parent
node of the two objects defined in file_1.yml
is directory_1
.
YAML item inheritance¶
Inside a directory of the YAML configuration, a __init__.yml
file can be added.
beamline_configuration/
└── directory_1
└── __init__.yml
└── file_1.yml
└── file_2.yml
Example of a __init__.yml
file
familly: addams
plugin: generic
The YAML items declared in this file, can be accessed via the get_inherited()
method of any configuration object defined in a file of the same directory (or sub-directory).
This method will return the first occurrence found in the tree structure (local definition first).
Accessing inherited YAML items
>>> bar_cfg = config.get_config("bar")
>>> bar_cfg.get_inherited("familly") # 'familly' key found in '__init__.yml'
addams
>>> bar_cfg.get_inherited("plugin") # 'plugin' key found in 'bar' config first
default
Info
BLISS uses this mechanism internally for the plugin
key.
Therefore, if plugin
is specified in the __init__.yml
file,
it is not necessary to add it locally in an object configuration.
But if plugin
is also found locally, the local value has the priority.
root config file¶
Root __init__.yml
is located and can be used to setup “global” configuration info.
It can be used for example to:
- configure the data policy.
- define a global name like the instrument name
See here: to read Root __init__.yml
from a BLISS controller
Configuration behavior¶
Unlike in a SPEC session restart, where all the config was reloaded and parameters taken into account automatically, for performance considerations, in BLISS:
- the config is reloaded:
- on-demand:
config.reload()
- at the (re)start of a session
- on-demand:
- the parameters from config of an object are taken into account:
- at first start of a session
- on demand with
obj.apply_config()
- it is possible to mix both reload and apply with:
obj.apply_config(reload=True)
Changing a configuration parameter, example of the velocity of a BlissAxis.