Skip to content

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:

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
  • 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.

Changing a configuration parameter