Skip to content

dcs.hal.plc

PLC hardware abstraction layer module.

This module provides a hardware abstraction class for reading and writing variables from and to Beckhoff TwinCAT PLC controllers using the pyads library.

AdsConnectionError

Bases: Exception

Exception raised when ADS connection to the PLC fails.

This exception is raised when the PLC connection cannot be established or when communication errors occur during variable read/write operations.

Attributes:

Name Type Description
message str

Explanation of the connection error.

LocalRepositoryEmptyError

Bases: Exception

Exception raised when the local variable repository is empty.

This exception is raised when attempting to perform operations that require configured variables, but no variables have been loaded into the PLC instance.

Attributes:

Name Type Description
message str

Explanation of the error.

PLC

Hardware abstraction class for reading and writing variables from and to PLC.

This class provides thread-safe communication with Beckhoff TwinCAT PLC controllers using the ADS (Automation Device Specification) protocol. It manages connection state, variable lists, and provides methods for reading and writing PLC variables.

Attributes:

Name Type Description
netid str

Network ID of the PLC controller (format: "x.x.x.x.x.x")

ip str

IP address of the PLC controller

plc_vars_input list

List of input variables that can be written to the PLC

plc_vars_output list

List of output variables that can be read from the PLC

connection Connection

ADS connection object to the PLC

lock_dict Lock

Thread lock for dictionary operations

lock_ads Lock

Thread lock for ADS communication operations

Example

plc = PLC(netid="192.168.1.100.1.1", ip="192.168.1.100") if plc.connect(): ... value = plc.get_variable("MAIN.bStartButton") ... plc.set_variable("MAIN.bLED", True) ... plc.close()

connection = field(default=None) class-attribute instance-attribute

ADS connection object to the PLC.

ip instance-attribute

IP address of the PLC controller.

lock_ads = field(factory=Lock) class-attribute instance-attribute

Thread lock for protecting ADS communication operations.

lock_dict = field(factory=Lock) class-attribute instance-attribute

Thread lock for protecting dictionary operations.

netid = field(validator=(validators.instance_of(str))) class-attribute instance-attribute

Network ID of the PLC controller in ADS format.

plc_vars_input = field(factory=list) class-attribute instance-attribute

List of input variables that can be written to the PLC.

plc_vars_output = field(factory=list) class-attribute instance-attribute

List of output variables that can be read from the PLC.

__attrs_post_init__()

Initialize the ADS connection object after instance creation.

This method is automatically called after the instance is created and sets up the pyads connection with the specified netid and PLC port.

check_variables_active()

Check which variables are currently active and available.

This method verifies the availability and status of all configured variables in the PLC. It can be used to validate configuration and ensure that all required variables are accessible.

Raises:

Type Description
NotImplementedError

This method is not yet implemented.

Note

This method is currently a placeholder and raises NotImplementedError. Full implementation would check variable accessibility and status.

close()

Close the connection to the PLC.

This method closes the active ADS connection to the PLC if it's currently open. It's important to call this method to properly release network resources when communication with the PLC is no longer needed.

Note

This method will print a confirmation message when the connection is closed.

connect()

Establish connection to the PLC.

This method attempts to open an ADS connection to the PLC and verifies the connection by reading device information. The connection attempt is thread-safe using the ADS lock.

Returns:

Name Type Description
bool bool

True if connection was successful, False otherwise.

Note

Connection status and any errors are printed to the console. Multiple calls to this method are safe - it will only open the connection if it's not already open.

Example

plc = PLC(netid="192.168.1.100.1.1", ip="192.168.1.100") if plc.connect(): ... print("Successfully connected to PLC") ... else: ... print("Failed to connect to PLC")

get_variable(variable_name)

Read a specific variable value from the PLC.

This method reads the current value of a single variable from the PLC. The variable must be present in either the input or output variable lists and must be marked as active.

Parameters:

Name Type Description Default
variable_name str

Name of the variable to read from the PLC. Must match the var_name_IN field of a configured variable.

required

Returns:

Name Type Description
Any Any

The current value of the variable as read from the PLC. The type depends on the variable's data type (BOOL, INT, REAL, etc.).

Raises:

Type Description
VariableNotFoundInRepositoryError

If the variable is not found in the configured variable lists or is marked as inactive.

Note

This method is thread-safe and searches through both input and output variable lists. The variable must be marked as active (active != "false").

Example

plc = PLC(netid="192.168.1.100.1.1", ip="192.168.1.100") plc.connect() temperature = plc.get_variable("MAIN.rCurrentTemperature") print(f"Current temperature: {temperature}°C")

read_variables()

Read all configured variables from the PLC and store them internally.

This method reads all variables from the configured output variable list and stores their values for later retrieval. The operation is thread-safe and requires an active PLC connection.

Raises:

Type Description
AdsConnectionError

If the PLC connection cannot be established.

NotImplementedError

This method is not yet fully implemented.

Note

This method is currently a placeholder and raises NotImplementedError. Full implementation would batch-read all configured variables for improved performance.

Example

plc.connect() plc.read_variables() # Reads all configured variables

set_plc_vars_input_list(plc_vars_input)

Load input variables list from the PLC configuration.

This method sets or extends the list of input variables that can be written to the PLC. Input variables are typically setpoints, commands, or configuration parameters sent from the control system to the PLC.

Parameters:

Name Type Description Default
plc_vars_input List[Any]

List of input variable objects containing variable definitions, names, data types, and other metadata.

required
Note

If the input list is empty, it will be replaced with the new list. If the input list already contains variables, the new variables will be appended to the existing list.

Example

vars = [{"name": "MAIN.rSetTemp", "type": "REAL"}, {"name": "MAIN.bStart", "type": "BOOL"}] plc.set_plc_vars_input_list(vars)

set_plc_vars_output_list(plc_vars_output)

Load output variables list from the PLC configuration.

This method sets or extends the list of output variables that can be read from the PLC. Output variables are typically sensor values, status information, or feedback data sent from the PLC to the control system.

Parameters:

Name Type Description Default
plc_vars_output List[Any]

List of output variable objects containing variable definitions, names, data types, and other metadata.

required
Note

If the output list is empty, it will be replaced with the new list. If the output list already contains variables, the new variables will be appended to the existing list.

Example

vars = [{"name": "MAIN.rCurrTemp", "type": "REAL"}, {"name": "MAIN.bRunning", "type": "BOOL"}] plc.set_plc_vars_output_list(vars)

set_variable(variable_name, value)

Write a specific variable value to the PLC.

This method writes a value to a single variable in the PLC. The variable must be present in the input variable list and must be marked as active.

Parameters:

Name Type Description Default
variable_name str

Name of the variable to write to the PLC. Must match the var_name field of a configured input variable.

required
value Any

The value to write to the variable. The type should match the variable's data type (BOOL, INT, REAL, etc.).

required

Returns:

Name Type Description
Any Any

The result of the write operation (typically None for successful writes).

Raises:

Type Description
VariableNotFoundInRepositoryError

If the variable is not found in the configured input variable list or is marked as inactive.

Note

This method is thread-safe and only searches through input variable lists since output variables are read-only from the control system perspective. The variable must be marked as active (active != "false").

Example

plc = PLC(netid="192.168.1.100.1.1", ip="192.168.1.100") plc.connect() plc.set_variable("MAIN.bStartProcess", True) plc.set_variable("MAIN.rSetTemperature", 25.5)

write_variables()

Write all modified variables to the PLC.

This method writes all variables that have been modified or queued for writing to the PLC. The operation is thread-safe and requires an active PLC connection.

Raises:

Type Description
AdsConnectionError

If the PLC connection cannot be established.

NotImplementedError

This method is not yet fully implemented.

Note

This method is currently a placeholder and raises NotImplementedError. Full implementation would batch-write all modified variables for improved performance.

Example

plc.connect() plc.write_variables() # Writes all modified variables

VariableNotFoundInRepositoryError

Bases: Exception

Exception raised when a requested variable is not found in the repository.

This exception is raised when attempting to read or write a variable that is not present in the configured variable lists, or when the variable is marked as inactive.

Attributes:

Name Type Description
message str

Explanation of the error including variable name and ID.