This document explains how openhatd processes configuration files. It also covers the details about the common configuration sections of an openhatd main configuration file, and common settings of ports. Information about how advanced ports or plugins are configured is provided with their respective documentation.
Please also see general information about configuration files.
When opening a configuration file openhatd performs a case-sensitive text substitution of certain placeholders in the file. These placeholders have the form
$NAME with NAME being the parameter name. By convention these should be all uppercase. openhatd provides the following parameters:
- Environment variables (e. g.
- Command line parameters specified using the
- Internally provided parameters, these are:
OPENHAT_VERSION: The version of openhatd at compile time in format MAJOR.MINOR.PATCH
DATETIME: The startup timestamp in format %Y-%m-%d %H:%M:%S.%i
LOG_DATETIME: The startup timestamp in format %Y%m%d_%H%M%S, useful for creating log file names
CWD: The absolute path of the current working directory
- When including configuration files, all parameters that are specified with the include directive (see below).
Placeholders that have no corresponding parameter are not replaced. In log verbosity Debug and Extreme all access to configuration settings is logged. This allows for easy inspection of actual settings values at runtime.
Configuration files are included by specifying
Type = Include. An include node must contain the
Filename setting. Relative paths are assumed to be relative to the current configuration file. This can be overridden using the
RelativeTo setting (see "Relative paths" below).
An include node has an associated parameters node that is required to have the name
Key = Value pairs in this node are provided to the include file as parameters (see above). Example:
[Root] ... IncludeNode1 = 9999 [IncludeNode1] Type = Include Filename = MyInclude.ini [IncludeNode1.Parameters] MyParam1 = MyValue1 MyParam2 = MyValue2
MyInclude.ini, all occurrences of the string
$MyParam1 will be replaced by
An included configuration file must have its own
Root node which is evaluated just like the
Root node of the main configuration file. Included files can in turn include other files. If you include a file recursively openhatd will enter an infinite loop.
Include files are meant to avoid repeating common combinations of ports that differ only in IDs, labels and other minor parameters. One use case is to have a Select port together with an Exec port that triggers a shell script when the selection changes. If you need more than one combination like this it may make sense to outsource them to an include file. You can also employ another neat trick which involves making the include file executable (on Linux) and code the script to be executed at the beginning of the include file. This keeps code and configuration together. The following example accepts the parameters
$Command (note that
$COMMAND are shell script variables; these are not replaced unless they are present in the environment or the include file parameters, so take care how you name your parameters).
#!/bin/bash DEVICE=<device_ip> COMMAND=$2 if [ "$1" = "1" ] then # switch on arducom -d $DEVICE -c $COMMAND -p 00 elif [ "$1" = "2" ] then # switch off arducom -d $DEVICE -c $COMMAND -p 01 else echo "parameter value not supported: $1" fi exit # openhatd configuration part [Root] $Name_Select = 1 $Name_Exec = 2 [$Name_Select] Type = SelectPort Label = $Label Group = $Group OnChangeUser = $Name_Exec OnChangeInternal = $Name_Exec [$Name_Select.Items] Switch = 0 On = 1 Off = 2 [$Name_Exec] Type = Exec Program = select_remote_arducom.ini Parameters = $$Name_Select $Command ResetTime = 1000 Hidden = true
The purpose of this file is to provide a Select port plus an associated Exec port that is triggered when the selection is changed. The select port will execute the configuration file itself as a shell script. Because of the
exit command the openhatd configuration part will not be executed by the shell.
The shell script's parameters are the current value of the Select port and the value of the $Command parameter at include file load time. Now this involves a bit of trickery; note the
$$Name_Select part which will be resolved in two stages:
$Name will be replaced at include file load time; what remains is the ID of the Select port, for example
$Switch_Select. When the Exec port is about to execute the script it replaces this value with the current position of the referenced Select port and passes the parameter string to the script which receives this value as its first parameter,
Some nodes in openhatd require the specification of filenames, for example include files or dynamic plugin libraries. Absolute paths can be used in all cases but this is rarely a good choice. However, relative paths can be ambiguous: it is not always clear what they are relative to.
Most openhatd path specifications therefore support the
RelativeTo setting. If this setting is specified it must be either
CWD which means the current working directory, or
Config, which is the location of the current configuration file. A third setting,
Plugin, is used internally by plugins to specify locations relative to the current plugin shared library. The default value depends on the context.
The openhatd project folder structure is designed to be identical for development and production systems. This means that configuration files designed for testing during development can be used for production testing without changes. If you are building your own configurations you should have a look at these configuration files (they are located in the folder
testconfigs) to understand how relative paths should be used.
In many cases it is a good choice to keep additional resources (for example, a custom HTML GUI) relative to the main configuration file. Program components, such as plugins, should be located relative to the current working directory to conform to the project structure.
To specify a path relative to the current working directory the above include file example can be changed to:
[IncludeNode1] Type = Include Filename = MyInclude.ini RelativeTo = CWD
openhatd (and the OPDI libraries) use a special format for certain configuration values that is called the "configuration string format". This format can be described by:
Such a configuration string can contain an arbitrary number of
key=value pairs separated by a semicolon. Any semicolon, backslash or equals-sign in keys or values must be escaped by a backslash. For example, the value
x=y must be escaped to
The general section supports the following configuration settings:
SlaveName is the name of the openhatd server instance as displayed on a GUI.
The LogVerbosity specifies the logging detail and the amount of diagnostic output that openhatd will generate. It accepts one of the log level constants as its value. The default is
Specify a file name to be used to store the persistent configuration. Relative paths are assumed to be relative to the current working directory, unless the setting
RelativeTo specifies otherwise. The file must be writable by the user executing the openhatd process. Example:
PersistentConfig = persistent-config.txt
If this setting is specified a file is written every five seconds containing the process ID and current CPU metrics of the openhatd process. It can be used to monitor the correct operation of openhatd and is most useful with service management systems like e. g. upstart.
Relative paths are always assumed to be relative to the current working directory. It is recommended to use absolute paths, however, and to prefer ramdisks over Flash memory on systems like the Raspberry Pi to reduce SD card wear.
HeartbeatFile = /var/tmp/openhatd-heartbeat.txt
TargetFPS ("frames per second")
This optional setting specifies the maximum number of doWork loop iterations openhatd should perform per second. The default is 20 which yields a resolution of 50 milliseconds; enough for most processes. Increasing this number also increases CPU load and energy use. Change this setting only if you have very good reasons to do so.
The regulation mechanism is quite slow so it may take some time to reach the intended FPS with some degree of accuracy. Note that during an active OPDI connection there is no regulation taking place to increase responsiveness. This also means that during this time the process consumes 100% CPU time.
This setting (in milliseconds) specifies the timeout for OPDI messages until the connection is assumed to be lost. The default is 10000 (10 seconds). Normally a connected master will send at least a ping message every five seconds to keep the connection alive. The maximum value for this setting is 65535.
This setting (in milliseconds) specifies the time a connected OPDI master may be idle until the slave disconnects. The default is 180000 (180 seconds). The idle timeout is reset by user interactions only. Automatic refreshes do not cause the timer to be reset.
The device info is a configuration string that is sent to a GUI when connecting. How this string is interpreted depends on the GUI. Example:
DeviceInfo = startGroup=DialPorts
This device info string tells a GUI that the port group to start out with is the DialPorts group.
Ports can be hidden from GUIs if they are used for internal purposes only. If you want to find out more about the operation of hidden ports during a test you can globally disable port hiding by setting this value to false. You do not need to change the
Hidden settings of all ports individually:
AllowHidden = false
Operating systems with some decent sense of security will require root privileges to access certain protected resources, like memory-mapped GPIO, certain TCP port ranges and such. It is therefore necessary to at least start openhatd as root. After the preparation phase (and after all necessary resources have been allocated) it is unsafe to keep running as root user, though. To provide some protection against remote exploits you can specify the name of a user with lower privileges that openhatd will switch to before entering the running phase.
It is highly recommended to use this setting for production systems. On Linux systems it is advised to create a user
openhat and define
SwitchToUser = openhat
OPDI-based connections can optionally use an encryption method. This is especially useful if authentication is required to avoid transferring user name and password as clear text. Currently the only supported encryption method is AES with a 16 character key. Configure it like this:
[General] ... Encryption = AESEncryption [AESEncryption] Type = AES Key = 0123456789012345
OPDI-based connections can optionally require credentials (user name and password). They can be configured as follows:
[General] ... Authentication = LoginCredentials [LoginCredentials] Type = Login Username = Test Password = test
Note that the OPDI protocol specifies a hard-coded interval of one minute after requesting login credentials. If the data is not provided within this time the connection is closed.
This section is used to define OPDI connection settings. You need to at least specify the transport method.
Required. Currently, only
TCP is supported.
The listening port to use for TCP connections. The default value is 13110.
Common Port Settings
All ports have an internal ID which must be unique. Ports can be referenced by other ports using this ID. The ID is taken to be the node name that defines the port. Internally generated ports may have generated IDs.
IDs of ports can be referenced in different contexts, such as port lists (separated by space), expressions (separated by other tokens) etc.; also, the contexts may specify modifier characters that alter the meaning of port IDs. It is therefore strongly recommended to:
Use only alphanumeric characters and the underscore for port IDs and do not start them with a digit!
The convention for naming ports is upper camel case, for example:
DigitalPort1 WeatherRe_Port FluxCompensatorPressure
1LittlePort energy_cost_in_$ Fly^High
It is also recommended to keep port IDs as short as possible to avoid running into the hard-coded OPDI limits.
The following settings apply to all ports. Individual port implementations, however, may choose to deal with these settings differently, or not respect them at all. Consult their documentation for more details.
Hidden = true will hide the port from GUIs unless the setting
General.AllowHidden is set to
Use it for internal ports that you don't want the user to see.
Readonly = true will prevent a port's value to be changed by the user. It is still possible for the value to be changed by internal functions, though.
If the setting
General.PersistentConfig is defined to be the name of a valid writable file stting
Persistent = true enables a port to write its state to this file whenever it is changed. When reading the initial configuration the port will also take its state from this file rather than the configuration file.
How ports persist their state depends on their implementations. Port states are also persisted on shutdown before the openhatd process exits.
This setting defines the port's label on a GUI. It defaults to the port ID (which is the port's node name) if it is not specified.
The "directional capabilities" of a port. May be one of
Bidi. When a port is bidirectional its direction can be changed from the GUI. Is hardly used in openhatd because port directions are usually fixed within an automation model.
RefreshMode decides whether and when GUIs should be updated when values change. Refresh messages are sent to connected GUIs on a per-port basis. The GUIs then query the current state of the affected port.
The refresh mode can be
Periodic. If it is off, no refresh messages are sent. In automatic refresh mode a refresh message is sent when the port state changes or when the port signals an error. Periodic mode means that refresh messages are sent in millisecond intervals specified by the setting
RefreshTime (required). The default mode is
To avoid overloading GUIs with too many refresh messages they are sent once a second at maximum.
RefreshMode setting is
Periodic, this required setting specifies the refresh interval in milliseconds.
The unit specification tells GUIs how the port can be displayed. See Unit Specifications for more details.
Port tags are a list of tag names separated by space. Tags can be used to select sets of ports using port list specifications. Other than that, tags have no internal purpose, and they are not communicated to GUIs.
A good use case for this is a
log tag. A Logger port, for example, can then specify all ports to be logged using a single
Root section's values specify the order in which nodes are processed. This roughly corresponds with the internal ordering of ports, which can be relevant for the doWork loop. It also influences the ordering of ports on a GUI.
Sometimes it may be necessary to change the internal ordering of ports independent of the order of their creation. You can specify a port's property
OrderID to re-assign the order number. If the number specified here is higher than the internal order counter subsequently created ports will be auto-numbered with higher OrderIDs, which means they will appear after the port that has been assigned manually.