Introduction

The eta_utility.connectors module is meant to provide a standardized interface for multiple different protocols which are used in factory operations or for the optimization of factory operations. Two important protocols which we encounter regularly are Modbus TCP and OPC UA. In addition to this we have also created connectors for additional API which we work with.

The eta_utility connector format has the advantage that it can be used for many different kinds of protocols and APIs, with the limitation that some of them do not support all functions (for example, specific APIs/protocols may not provide write access). Each connection can contain multiple Nodes (see below). These are used as the default data points when reading data from the connection. Read data will be returned in a pandas.DataFrame with the node names as column names.

The connectors module also provides subscription handlers which take data read from connections in regular intervals and for example store it in files or in memory for later access. These subscription handlers can handle multiple different connections (with different protocols) at the same time.

The LiveConnect class is specifically designed to combine the functionality from the eta_x and connectors modules. It can establish connections and provides an interface equivalent to the classes in the simulators module. This allows easy substitution of simulation models with actual connections to real machines (or the other way). When trying to deploy a model into operation this substitution can be very useful.

The connectors are based on the concept of Nodes to which we establish connections. A Node object is a unique description of a specific data point and includes all information required to establish a connection and read data from the specified data point. Each data point has its own node, not just each device (or connection) that we are connecting to. Therefore, Nodes are the easiest way to instantiate connections, however they can be a bit unwieldy to work with when trying to read many different data points from the same device.

There are multiple ways to instantiate connections, depending on the use case:

  • When only a single connection is needed, the connection can be instantiated directly. This is possible with or without specifying nodes. Node objects do have to be created however, to be able to tell the connection where (which data points) to read data from or write data to.

  • If you already have the Node object(s) and want to create connection(s), you should use the from_node method of the BaseConnection class. It requires less duplicate information than direct instantiation. If a single node is passed, the method returns the connection for that node. When multiple connections to different devices are needed, it is usually easiest to create all of the Node objects first and pass them in a list. Then, from_node returns a dictionary of connections and automatically selects the correct nodes for each connection.

  • When a single connection is needed and access to the Node objects is not required, many (not all) connectors offer a from_ids classmethod which returns the Connection object and creates the Nodes only internally.

Nodes

Each Node object uniquely identifies a specific data point. All Node objects have some information in common. This information idenfies the device which the data point belongs to and can also contain information required for authentication with the device. Depending on the protocol the Node object contains additional information to correctly identify the data points.

The URL may contain the username and password (schema://username:password@hostname:port/path). This is handled automatically by the connectors and the username and password will be removed before creating a connection.

The Node class should always be used to instantiate nodes. The type of the node can be specified using the protocol parameter.

class eta_utility.connectors.Node(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

The node objects represents a single variable. Valid keyword arguments depend on the protocol.

The following classes are there to document the required parameters for each type of node.

Note

Always use the Node class to instantiate nodes! (not its subclasses)

class eta_utility.connectors.node.NodeLocal(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Local Node (no specific protocol), useful for example to manually provide data to subscription handlers.

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.

class eta_utility.connectors.node.NodeModbus(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Node for the Modbus protocol.

mb_slave: int | None

Modbus Slave ID

mb_register: str

Modbus Register name. One of input, discrete_input, coils and holding. Note that only coils and holding can be written to.

mb_channel: int

Modbus Channel (Address of the value)

mb_bit_length: int

Length of the value in bits (default 32). This determines, how much data is read from the server. The value must be a multiple of 16.

mb_byteorder: str

Byteorder of values returned by modbus

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.

class eta_utility.connectors.node.NodeOpcUa(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Node for the OPC UA protocol.

opc_id: str | None

Node ID of the OPC UA Node.

opc_path_str: str | None

Path to the OPC UA node.

opc_ns: int | None

Namespace of the OPC UA Node.

opc_id_type: str

Type of the OPC UA Node ID Specification.

opc_name: str

Name of the OPC UA Node.

opc_path: list[NodeOpcUa]

Path to the OPC UA node in list representation. Nodes in this list can be used to access any parent objects.

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.

class eta_utility.connectors.node.NodeEnEffCo(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Node for the EnEffCo API.

eneffco_code: str

EnEffCo datapoint code / ID.

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.

class eta_utility.connectors.node.NodeEntsoE(name: str, url: str, protocol: str, *args: Any, **kwargs: Any)[source]

Node for the EntsoE API (see ENTSO-E Transparency Platform API).

Available endpoint

Endpoint

Description

ActualGenerationPerType

Actual Generation Per Energy Type

Price

Price day ahead

Currently, there is only two endpoints available, due to the parameter managing required by the API documentation. The other possible endpoints are listed in

eta_utility.connectors.entso_e._ConnectionConfiguration._doc_types

Main bidding zone

Bidding Zone

Description

DEU-LUX

Deutschland-Luxemburg

The other possible bidding zones are listed in

eta_utility.connectors.entso_e._ConnectionConfiguration._bidding_zones

endpoint: str

REST endpoint.

bidding_zone: str

Bidding zone.

name: str

Name for the node.

url: str

URL of the connection.

url_parsed: ParseResult

Parse result object of the URL (in case more post-processing is required).

usr: str | None

Username for login to the connection (default: None).

pwd: str | None

Password for login to the connection (default: None).

interval: str | None

Interval

dtype: Callable | None

Data type of the node (for value conversion). Note that strings will be interpreted as utf-8 encoded. If you do not want this behaviour, use ‘bytes’.

Connection Instantiation

Connections can be instantiated using different methods as described above. The two most common methods are described here, they are instantiation of a connection from_ids and the instantiation of a single or multiple connection(s) using from_node.

Instantiation from_node in BaseConnection is useful if you already have created some node(s) and would like to create connection(s) from them. Each connection class also has its own _from_node method, since the necessary/accepted keywords might differ. To create connections, a password and a username are often required. For setting these the following prioritization applies:

  • If a password is given in the node, take it.

  • If there is no password there, take as “default” a password from the arguments.

  • If there is neither, the username and password are empty.

BaseConnection.from_node(node: Nodes, **kwargs: Any) BaseConnection | dict[str, Any]
Initialize the connection object from a node object. If multiple nodes are passed,

a list of connections is returned.

Parameters:
  • node – Node(s) to initialize from.

  • kwargs – Other arguments are ignored.

Returns:

BaseConnection object or dictionary of BaseConnections

The from_ids method is helpful if you do not require access to the nodes and just want to quickly create a single connection.

Note

This is not available for all connectors, since the concept of IDs does not apply universally. An example is shown here. Refer to the API documentation of the connector you would like to use to see if the method exists and which parameters are required.

EnEffCoConnection.from_ids(ids: Sequence[str], url: str, usr: str, pwd: str, api_token: str) EnEffCoConnection[source]

Initialize the connection object from an EnEffCo protocol through the node IDs

Parameters:
  • ids – Identification of the Node.

  • url – URL for EnEffco connection.

  • usr – Username for EnEffCo login.

  • pwd – Password for EnEffCo login.

  • api_token – Token for API authentication.

Returns:

EnEffCoConnection object.