### Synchronize PLC Memory and Data Path Reads Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Example demonstrating how to synchronize values read from PLC memory via address and via data path, accounting for data type sizes. ```python for mem_address in [0, 1, 2, 4, 8, 12, 68, 69, 151, 300, 368]: v1 = lsv2.read_plc_memory(mem_address, pyLSV2.MemoryType.DWORD, 1)[0] v2 = lsv2.read_data_path("/PLC/memory/D/%d" % (mem_address * 4)) assert v1 == v2 ``` -------------------------------- ### Get and Set Machine Parameters with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Reads or writes named machine parameters. Reading requires 'INSPECT' login, while writing requires 'PLCDEBUG'. Parameter naming conventions differ between older iTNC (numeric strings) and newer TNC controls (dot-path strings). Writes are temporary by default and lost on reboot unless 'safe_to_disk' is set to True. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Read a machine parameter (old iTNC style) if con.versions.is_itnc(): lang = con.get_machine_parameter("7230.0") else: lang = con.get_machine_parameter("CfgDisplayLanguage.ncLanguage") print("NC language setting:", lang) # Write a machine parameter (temporary, lost on reboot) ok = con.set_machine_parameter( name="CfgDisplayLanguage.ncLanguage", value="en", safe_to_disk=False, # False = RAM only, True = persist to disk ) print("Set parameter:", ok) ``` -------------------------------- ### LSV2.read_plc_memory — Read PLC Memory Source: https://context7.com/drunsinn/pylsv2/llms.txt Reads one or more values from PLC memory by type and starting index. Requires `PLCDEBUG` login. Supports various memory types including `MARKER`, `INPUT`, `OUTPUT`, `COUNTER`, `TIMER`, `BYTE`, `WORD`, `DWORD`, `STRING`, `INPUT_WORD`, `OUTPUT_WORD`, `INPUT_DWORD`, `OUTPUT_DWORD`. ```APIDOC ## LSV2.read_plc_memory ### Description Reads one or more values from PLC memory by type and starting index. ### Parameters - **start_index** (int) - The starting index in PLC memory. - **memory_type** (MemoryType) - The type of memory to read (e.g., MARKER, WORD, STRING). - **count** (int) - The number of values to read. ### Example ```python import pyLSV2 from pyLSV2 import MemoryType with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Read 5 markers starting at index 0 markers = con.read_plc_memory(0, MemoryType.MARKER, 5) print("Markers 0-4:", markers) # Read 3 words starting at index 10 words = con.read_plc_memory(10, MemoryType.WORD, 3) print("Words 10-12:", words) ``` ``` -------------------------------- ### Create, Delete, and Copy Filesystem Objects Source: https://context7.com/drunsinn/pylsv2/llms.txt Demonstrates creating nested directories, deleting files and empty directories, and copying files on the control. `make_directory()` creates intermediate parents automatically. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Create a nested directory structure ok = con.make_directory("TNC:/nc_prog/project/subdir") print("mkdir:", ok) # Delete a specific file ok = con.delete_file("TNC:/nc_prog/old_part.h") print("delete file:", ok) # Delete an empty directory ok = con.delete_empty_directory("TNC:/nc_prog/project/subdir") print("rmdir:", ok) # Copy a file within the control ok = con.copy_remote_file("TNC:/nc_prog/part1.h", "TNC:/nc_prog/backup/part1.h") print("copy:", ok) # Move/rename a file on the control ok = con.move_file("TNC:/nc_prog/part1.h", "TNC:/nc_prog/archive/part1.h") print("move:", ok) ``` -------------------------------- ### Read PLC Memory by Address Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Reads a specified number of PLC memory bits starting from a given address. Requires specifying the memory type and count. ```python con.read_plc_memory(32, pyLSV2.MemoryType.MARKER, 15) ``` -------------------------------- ### Read PLC Memory with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Reads values from PLC memory using different memory types and starting indices. Supports various data types including MARKER, WORD, DWORD, and STRING. Alternatively, native addressing like 'W1090' or 'M0' can be used. ```python import pyLSV2 from pyLSV2 import MemoryType with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Read 5 markers starting at index 0 markers = con.read_plc_memory(0, MemoryType.MARKER, 5) print("Markers 0-4:", markers) # [True, False, False, True, False] # Read 3 words starting at index 10 words = con.read_plc_memory(10, MemoryType.WORD, 3) print("Words 10-12:", words) # [1024, -5, 0] # Read first double-word dword = con.read_plc_memory(0, MemoryType.DWORD, 1) print("DWord 0:", dword) # Read PLC string at index 0 strings = con.read_plc_memory(0, MemoryType.STRING, 1) print("String 0:", strings) # Alternatively, use native addressing (M0, W1090, S20, etc.) val = con.read_plc_address("W1090") print("Word at W1090:", val) val = con.read_plc_address("M0") print("Marker M0:", val) ``` -------------------------------- ### Create Log File Sequence Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md This sequence demonstrates the process of creating a log file. It involves sending C_CC with specific parameters for filename and timestamp, followed by T_OK acknowledgment. A subsequent M_CC telegram signals successful creation. ```default >....R_ST <....S_ST............ >....C_ST............ <....T_OK >...%C_CC..operation.log;12.09.2020;00:00:00;. <....T_OK <....M_CC...d 0x00 0x1b 0x00 0x64 >....C_ST............ <....T_OK >....R_FLTNC:\operation.log. <....S_FLOperation Logbook Version 1.0.Sy.. ``` -------------------------------- ### Real-time Data Recording with LSV2 Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md This snippet demonstrates how to read available signals, select specific ones, and then record real-time data over a specified duration and interval. It also shows how to process the received data, applying offsets and factors. ```python availible_signals = con.read_scope_channels() selected_signals = list() selected_signals.append(availible_signals[0]) selected_signals.append(availible_signals[1]) for package in con.real_time_readings(selected_signals, duration=10, interval=6000): signal_readings = package.get_data() for signal in signal_readings: for data_value in signal.data: value = (data_value * signal.factor) + signal.offset ``` -------------------------------- ### LSV2.execution_state, LSV2.program_status, LSV2.program_stack Source: https://context7.com/drunsinn/pylsv2/llms.txt Query the current execution mode and active NC program. Requires `DNC` login. ```APIDOC ## LSV2.execution_state / LSV2.program_status / LSV2.program_stack — Runtime State Query the current execution mode and active NC program. Requires `DNC` login (enabled when `safe_mode=False`). ### Method ```python con.execution_state() -> ExecState con.program_status() -> PgmState con.program_stack() -> ProgramStack | None ``` ### Returns #### execution_state - **return value** (ExecState enum) - The current execution mode. Possible values include: MANUAL, MDI, PASS_REFERENCES, SINGLE_STEP, AUTOMATIC, UNDEFINED. #### program_status - **return value** (PgmState enum) - The status of the active NC program. Possible values include: STARTED, STOPPED, FINISHED, CANCELLED, INTERRUPTED, ERROR, IDLE. #### program_stack - **return value** (ProgramStack | None) - Information about the active program stack, including the main program, current program, and current line number. Returns None if no program is active or an error occurs. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Execution mode state = con.execution_state() print("Exec state:", state, pyLSV2.get_execution_status_text(state)) # Active program status pgm = con.program_status() print("Program state:", pgm, pyLSV2.get_program_status_text(pgm)) # Active program stack (main + currently called subprogram + line number) stack = con.program_stack() if stack is not None: print("Main program:", stack.main) print("Current program:", stack.current) print("Current line:", stack.line_no) ``` ``` -------------------------------- ### LSV2.make_directory, LSV2.delete_file, LSV2.delete_empty_directory Source: https://context7.com/drunsinn/pylsv2/llms.txt Functions for creating and deleting filesystem objects on the control. `make_directory()` supports creating intermediate parent directories automatically. ```APIDOC ## LSV2.make_directory / LSV2.delete_file / LSV2.delete_empty_directory — Filesystem Manipulation Create and delete filesystem objects on the control. `make_directory()` creates intermediate parents automatically. ### Method ```python con.make_directory(path: str) -> bool con.delete_file(path: str) -> bool con.delete_empty_directory(path: str) -> bool ``` ### Parameters #### make_directory - **path** (str) - Required - The full path to the directory to create. #### delete_file - **path** (str) - Required - The full path to the file to delete. #### delete_empty_directory - **path** (str) - Required - The full path to the empty directory to delete. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Create a nested directory structure ok = con.make_directory("TNC:/nc_prog/project/subdir") print("mkdir:", ok) # Delete a specific file ok = con.delete_file("TNC:/nc_prog/old_part.h") print("delete file:", ok) # Delete an empty directory ok = con.delete_empty_directory("TNC:/nc_prog/project/subdir") print("rmdir:", ok) ``` ### Response - **return value** (bool) - True if the operation was successful, False otherwise. ``` -------------------------------- ### LSV2.file_info / LSV2.directory_info Source: https://context7.com/drunsinn/pylsv2/llms.txt `file_info()` returns a `FileEntry` for a specific file (or `None` if absent). `directory_info()` returns a `DirectoryEntry` describing the current or named directory including free space. ```APIDOC ## LSV2.file_info / LSV2.directory_info — Inspect Remote Filesystem ### Description `file_info()` returns a `FileEntry` for a specific file (or `None` if absent). `directory_info()` returns a `DirectoryEntry` describing the current or named directory including free space. ### Parameters - **LSV2.file_info**: - **path** (str) - Required - The path to the file to get information about. - **LSV2.directory_info**: - **path** (str) - Optional - The path to the directory to get information about. Defaults to the current directory. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Check a specific file fi = con.file_info("TNC:/nc_prog/part1.h") if fi is not None: print("Name:", fi.name) print("Size:", fi.size, "bytes") print("Modified:", fi.timestamp) print("Protected:", fi.is_protected) print("Is dir:", fi.is_directory) else: print("File does not exist") # Current directory info di = con.directory_info() print("Current path:", di.path) print("Free space:", di.free_size, "bytes") # Info for a specific directory di2 = con.directory_info("TNC:/nc_prog") print("nc_prog free space:", di2.free_size) ``` ### Response - **FileEntry** (object, returned by `file_info`): - **name** (str) - The name of the file. - **size** (int) - The size of the file in bytes. - **timestamp** (str) - The last modified timestamp of the file. - **is_protected** (bool) - True if the file is protected, False otherwise. - **is_directory** (bool) - True if the entry is a directory, False otherwise. - **DirectoryEntry** (object, returned by `directory_info`): - **path** (str) - The path of the directory. - **free_size** (int) - The amount of free space in the directory in bytes. ``` -------------------------------- ### LSV2.grab_screen_dump — Capture Control Screen Source: https://context7.com/drunsinn/pylsv2/llms.txt Takes a screenshot of the current control display and saves it as a BMP file locally. Requires `FILETRANSFER` login. Creates a temporary file on `TNC:` and deletes it after download. ```APIDOC ## LSV2.grab_screen_dump ### Description Captures a screenshot of the control display and saves it as a BMP file locally. ### Parameters - **image_path** (pathlib.Path) - The local path where the BMP image will be saved. ### Example ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: image_path = pathlib.Path("/tmp/cnc_screen.bmp") ok = con.grab_screen_dump(image_path) if ok: print("Screen saved to", image_path) else: print("Screen capture failed:", con.last_error) ``` ``` -------------------------------- ### Connect to LSV2 Control (With Context Manager) Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Connect to an LSV2 control using a context manager, which automatically handles connection and disconnection. ```python import pyLSV2 with pyLSV2.LSV2("192.168.56.101") as con: ... con.connect() ... print(con.versions.control) ``` -------------------------------- ### Connect to LSV2 Control (No Context Manager) Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Basic connection and disconnection from an LSV2 control without using a context manager. Ensure to manually disconnect. ```python import pyLSV2 con = pyLSV2.LSV2("192.168.56.101") con.connect() print(con.versions.control) con.disconnect() ``` -------------------------------- ### Read Directory Content (R_DI with 0x01) Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md The R_DI command with an additional parameter of 0x01 requests all directory entries to be sent at once, rather than in separate packets. The exact structure of the directory information, including four-byte keys, is still under investigation. ```default > R_DI 0x01 ``` -------------------------------- ### LSV2.recive_file Source: https://context7.com/drunsinn/pylsv2/llms.txt Downloads a file from the control to a local path. Transfer mode is auto-detected from the extension unless `binary_mode` is set. ```APIDOC ## LSV2.recive_file — Download a File from the Control ### Description Downloads a file from the control to a local path. Transfer mode is auto-detected from the extension unless `binary_mode` is set. ### Parameters - **remote_path** (str) - Required - The path to the file on the control to download. - **local_path** (str or pathlib.Path) - Required - The destination path on the local system. - **override_file** (bool) - Optional - If True, overwrites the local file if it already exists. Defaults to False. - **binary_mode** (bool) - Optional - Explicitly set transfer mode to binary. If not set, it's auto-detected. ### Request Example ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Download an NC program ok = con.recive_file( remote_path="TNC:/nc_prog/part1.h", local_path="/tmp/part1.h", override_file=True, ) print("Download OK:", ok) # Download a binary tool-table backup ok = con.recive_file( remote_path="TNC:/table/tool.t", local_path=pathlib.Path("/backup/tool.t"), override_file=True, binary_mode=False, # tool tables are text ) if not ok: print("Last error:", con.last_error) ``` ### Response - **ok** (bool) - True if the file was downloaded successfully, False otherwise. ``` -------------------------------- ### LSV2.directory_content / LSV2.drive_info Source: https://context7.com/drunsinn/pylsv2/llms.txt `directory_content()` lists `FileEntry` objects in the current working directory. `drive_info()` lists available drives (`TNC:`, `PLC:`, `LOG:`, `SYS:`). ```APIDOC ## LSV2.directory_content / LSV2.drive_info — Browse the Filesystem ### Description `directory_content()` lists `FileEntry` objects in the current working directory. `drive_info()` lists available drives (`TNC:`, `PLC:`, `LOG:`, `SYS:`). ### Parameters - **LSV2.directory_content**: - No parameters required. Lists contents of the current working directory. - **LSV2.drive_info**: - No parameters required. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # List drives for drive in con.drive_info(): print("Drive:", drive.name, "Size:", drive.size) # Change directory and list contents con.change_directory("TNC:/nc_prog") for entry in con.directory_content(): if entry.is_directory: print("[DIR]", entry.name) elif not entry.is_drive: print("[FILE]", entry.name, entry.size, "bytes", entry.timestamp) ``` ### Response - **drive_info()** returns a list of `DriveEntry` objects: - **DriveEntry**: - **name** (str) - The name of the drive (e.g., "TNC:"). - **size** (int) - The total size of the drive in bytes. - **directory_content()** returns a list of `FileEntry` objects (similar to `file_info` response, but for directory contents): - **FileEntry**: - **name** (str) - The name of the file or directory. - **size** (int) - The size of the file in bytes (0 for directories). - **timestamp** (str) - The last modified timestamp. - **is_directory** (bool) - True if the entry is a directory. - **is_drive** (bool) - True if the entry represents a drive. ``` -------------------------------- ### Capture Control Screen Dump with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Captures a screenshot of the control display and saves it as a BMP file locally. Requires 'FILETRANSFER' login. A temporary file is created on the control and deleted after download. Check the return value for success and use 'con.last_error' for troubleshooting. ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: image_path = pathlib.Path("/tmp/cnc_screen.bmp") ok = con.grab_screen_dump(image_path) if ok: print("Screen saved to", image_path) print("File size:", image_path.stat().st_size, "bytes") else: print("Screen capture failed:", con.last_error) ``` -------------------------------- ### Manage LSV2 Access Levels Source: https://context7.com/drunsinn/pylsv2/llms.txt Log in to gain elevated access roles (e.g., DNC, PLCDEBUG) and log out to drop them. In safe mode, only INSPECT, FILETRANSFER, and MONITOR are allowed. Disabling safe mode is required for other roles. ```python import pyLSV2 from pyLSV2 import Login con = pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) con.connect() # Login with a role that requires a password ok = con.login(login=Login.PLCDEBUG, password="secret") print("PLCDEBUG login:", ok) # True / False # DNC login (no password required) ok = con.login(login=Login.DNC) print("DNC login:", ok) # Drop a specific login con.logout(login=Login.DNC) # Drop ALL active logins (also called automatically by disconnect()) con.logout(login=None) con.disconnect() ``` -------------------------------- ### Read File Information (R_FI) Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md Use the R_FI command followed by a file path to retrieve file metadata such as size, modification date, and filename. The response may include additional bytes for attributes or access rights. ```default > R_FI ``` -------------------------------- ### LSV2 Connection and Disconnection Source: https://context7.com/drunsinn/pylsv2/llms.txt Demonstrates how to establish and terminate a connection to a CNC control using the LSV2 class, both as a context manager and with manual connect/disconnect calls. It also shows how to enable compatibility mode for older controls. ```APIDOC ## LSV2 Class Usage ### Description The `LSV2` class manages the full lifecycle of a CNC connection. It can be used as a context manager for automatic cleanup or by manually calling `connect()` and `disconnect()`. ### Parameters - **hostname/IP** (string) - Required - The hostname or IP address of the CNC control. - **port** (int) - Optional - The TCP port for the connection (default: 19000). - **timeout** (int) - Optional - The connection timeout in seconds. - **safe_mode** (bool) - Optional - Enables or disables safe mode (default: True). - **compatibility_mode** (bool) - Optional - Enables compatibility mode for older controls (default: False). ### Usage Examples #### Context Manager (Recommended) ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, timeout=10) as con: print(con.versions.control) print(con.versions.nc_sw) print(con.parameters.lsv2_version) ``` #### Manual Connect/Disconnect ```python import pyLSV2 con = pyLSV2.LSV2("192.168.1.10", port=19000, timeout=10, safe_mode=False) con.connect() try: print(con.versions.control) finally: con.disconnect() ``` #### Compatibility Mode ```python import pyLSV2 con = pyLSV2.LSV2("192.168.1.10", compatibility_mode=True) con.connect() print(con.versions.is_itnc()) # True for iTNC530 print(con.versions.is_tnc()) # True for TNC320/620/640 print(con.versions.is_tnc7()) # True for TNC7 con.disconnect() ``` ``` -------------------------------- ### Download File from Control with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Downloads a file from the control to a local path. Transfer mode is auto-detected from the extension unless `binary_mode` is explicitly set. Use `override_file=True` to replace existing local files. ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Download an NC program ok = con.recive_file( remote_path="TNC:/nc_prog/part1.h", local_path="/tmp/part1.h", override_file=True, ) print("Download OK:", ok) # Download a binary tool-table backup ok = con.recive_file( remote_path="TNC:/table/tool.t", local_path=pathlib.Path("/backup/tool.t"), override_file=True, binary_mode=False, # tool tables are text ) if not ok: print("Last error:", con.last_error) ``` -------------------------------- ### Browse Remote Filesystem with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Lists available drives and the contents of a specified directory. `drive_info()` returns a list of available drives, and `directory_content()` lists `FileEntry` objects within a directory. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # List drives for drive in con.drive_info(): print("Drive:", drive.name, "Size:", drive.size) # Change directory and list contents con.change_directory("TNC:/nc_prog") for entry in con.directory_content(): if entry.is_directory: print("[DIR]", entry.name) elif not entry.is_drive: print("[FILE]", entry.name, entry.size, "bytes", entry.timestamp) ``` -------------------------------- ### LSV2.send_file Source: https://context7.com/drunsinn/pylsv2/llms.txt Uploads a local file to a path on the control. Automatically selects binary vs. text transfer mode based on file extension unless `binary_mode` is explicitly set. Parent directories are created if needed. ```APIDOC ## LSV2.send_file — Upload a File to the Control ### Description Uploads a local file to a path on the control. Automatically selects binary vs. text transfer mode based on file extension unless `binary_mode` is explicitly set. Parent directories are created if needed. ### Parameters - **local_path** (str or pathlib.Path) - Required - The path to the local file to upload. - **remote_path** (str) - Required - The destination path on the control. - **override_file** (bool) - Optional - If True, replaces the file if it already exists. Defaults to False. - **binary_mode** (bool) - Optional - Explicitly set transfer mode to binary. If not set, it's auto-detected. ### Request Example ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Upload an NC program to the TNC drive success = con.send_file( local_path="C:/programs/part1.h", remote_path="TNC:/nc_prog/part1.h", override_file=True, # replace if exists ) print("Upload OK:", success) # Upload a binary file (BMP) with explicit binary mode success = con.send_file( local_path=pathlib.Path("/tmp/logo.bmp"), remote_path="TNC:/pictures/", # trailing slash → keep original name override_file=False, binary_mode=True, ) if not success: print("Error:", con.last_error) ``` ### Response - **success** (bool) - True if the file was uploaded successfully, False otherwise. ``` -------------------------------- ### LSV2.login / LSV2.logout - Manage Access Levels Source: https://context7.com/drunsinn/pylsv2/llms.txt Explains how to manage access levels to the CNC control using the `login()` and `logout()` methods. It details the available login roles and how to handle password-protected logins. ```APIDOC ## LSV2.login / LSV2.logout ### Description `login()` requests an elevated access role, while `logout()` drops one or all roles. In safe mode, only `INSPECT`, `FILETRANSFER`, and `MONITOR` are allowed. Disabling safe mode grants access to `DNC`, `PLCDEBUG`, `SCOPE`, `DATA`, etc. ### Methods - **login(login, password=None)**: Requests a login with the specified role. Returns `True` on success, `False` otherwise. - **logout(login=None)**: Drops the specified login role. If `login` is `None`, all active logins are dropped. ### Login Roles (`pyLSV2.Login` enum) - `INSPECT` - `FILETRANSFER` - `MONITOR` - `DNC` - `PLCDEBUG` - `SCOPE` - `DATA` ### Parameters - **login** (`pyLSV2.Login` or `None`) - The login role to request or drop. - **password** (string) - Optional - The password for password-protected logins. ### Usage Example ```python import pyLSV2 from pyLSV2 import Login con = pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) con.connect() # Login with a role requiring a password ok = con.login(login=Login.PLCDEBUG, password="secret") print("PLCDEBUG login:", ok) # DNC login (no password required) ok = con.login(login=Login.DNC) print("DNC login:", ok) # Drop a specific login con.logout(login=Login.DNC) # Drop ALL active logins con.logout(login=None) con.disconnect() ``` ``` -------------------------------- ### LSV2.override_state Source: https://context7.com/drunsinn/pylsv2/llms.txt Reads the current feed, rapid, and spindle override percentages. Requires `DNC` login. ```APIDOC ## LSV2.override_state — Read Override Values Returns an `OverrideState` with feed, rapid, and spindle override percentages. Requires `DNC` login. ### Method ```python con.override_state() -> OverrideState | None ``` ### Returns - **return value** (OverrideState | None) - An object containing the current override values for feed, rapid, and spindle. Returns None if the values cannot be read. - **feed** (float) - Feed override percentage. - **rapid** (float) - Rapid override percentage. - **spindle** (float) - Spindle override percentage. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: ovr = con.override_state() if ovr is not None: print(f"Feed override: {ovr.feed:.1f}%") print(f"Rapid override: {ovr.rapid:.1f}%") print(f"Spindle override: {ovr.spindle:.1f}%") print(str(ovr)) ``` ### Example Output ``` Feed override: 100.0% Rapid override: 100.0% Spindle override: 100.0% F:100.0% FMAX:100.0% S:100.0% ``` ``` -------------------------------- ### Read Override Values Source: https://context7.com/drunsinn/pylsv2/llms.txt Retrieves the current feed, rapid, and spindle override percentages. Requires `DNC` login. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: ovr = con.override_state() if ovr is not None: print(f"Feed override: {ovr.feed:.1f}%") print(f"Rapid override: {ovr.rapid:.1f}%") print(f"Spindle override: {ovr.spindle:.1f}%") # str() representation: "F:100.0% FMAX:100.0% S:100.0%" print(str(ovr)) ``` -------------------------------- ### File Transfer Binary Mode Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md To enable binary mode for file transfers, append 0x01 after the filename. This mode is recommended for certain file types as indicated in TNCremo. ```default To enable binary mode, add 0x01 after the filename. ``` -------------------------------- ### Read Current Spindle Tool Information Source: https://context7.com/drunsinn/pylsv2/llms.txt Fetches detailed information about the currently active tool in the spindle, including its number, name, dimensions, and associated axis. Requires `DNC` login. Not supported on all control types. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: tool = con.spindle_tool_status() if tool is not None: print(f"Tool number: {tool.number}.{tool.index}") print(f"Tool name: {tool.name}") print(f"Length: {tool.length} mm") print(f"Radius: {tool.radius} mm") print(f"Axis: {tool.axis}") else: print("Tool info not supported for this control") ``` -------------------------------- ### Upload File to Control with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Uploads a local file to a specified path on the control. Parent directories are created if they don't exist. Override existing files with `override_file=True`. ```python import pathlib import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Upload an NC program to the TNC drive success = con.send_file( local_path="C:/programs/part1.h", remote_path="TNC:/nc_prog/part1.h", override_file=True, # replace if exists ) print("Upload OK:", success) # Upload a binary file (BMP) with explicit binary mode success = con.send_file( local_path=pathlib.Path("/tmp/logo.bmp"), remote_path="TNC:/pictures/", # trailing slash → keep original name override_file=False, binary_mode=True, ) if not success: print("Error:", con.last_error) ``` -------------------------------- ### Parse Table Files with tab2csv.py Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Demonstrates how to use the tab2csv.py script to parse table files. It can be used as a command-line tool to convert table files to CSV format. Options include specifying a decimal character, enabling debug or verbose logging. ```bash usage: tab2csv.py [-h] [--decimal_char DECIMAL_CHAR] [-d | -v] source command line script parsing table files positional arguments: source table file to parse options: -h, --help show this help message and exit --decimal_char DECIMAL_CHAR override local decimal char -d, --debug enable log level DEBUG -v, --verbose enable log level INFO ``` -------------------------------- ### Read Machine State (R_RI) - Program Status Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md When logged in with DNC, use R_RI with the value 0x001A (26) to read the current program status. DNC login requires a specific option to be enabled on the control. ```default > R_RI 0x001A (26) -> you can read the current program status ``` -------------------------------- ### Query Runtime State and Program Status Source: https://context7.com/drunsinn/pylsv2/llms.txt Retrieves the current execution mode, active NC program status, and program stack information. Requires `DNC` login (enabled when `safe_mode=False`). ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Execution mode state = con.execution_state() # Returns ExecState enum: MANUAL, MDI, PASS_REFERENCES, SINGLE_STEP, AUTOMATIC, UNDEFINED print("Exec state:", state, pyLSV2.get_execution_status_text(state)) # Active program status pgm = con.program_status() # Returns PgmState enum: STARTED, STOPPED, FINISHED, CANCELLED, INTERRUPTED, ERROR, IDLE, ... print("Program state:", pgm, pyLSV2.get_program_status_text(pgm)) # Active program stack (main + currently called subprogram + line number) stack = con.program_stack() if stack is not None: print("Main program:", stack.main) print("Current program:", stack.current) print("Current line:", stack.line_no) ``` -------------------------------- ### Handle pyLSV2 Exceptions and Non-Fatal Errors Source: https://context7.com/drunsinn/pylsv2/llms.txt Demonstrates how to handle both fatal exceptions (LSV2ProtocolException, LSV2StateException, LSV2InputException) and non-fatal failures (like file not found) using con.last_error. Ensure to disconnect the connection in a finally block. ```python import pyLSV2 from pyLSV2 import ( LSV2StateException, LSV2DataException, LSV2InputException, LSV2ProtocolException, LSV2StatusCode, ) con = pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) try: con.connect() # Non-fatal: returns False, check last_error ok = con.delete_file("TNC:/missing_file.h") if not ok: err = con.last_error if err.e_code == LSV2StatusCode.T_ER_NO_FILE: print("File did not exist, nothing to delete") else: print("Delete error:", err) # Fatal: raises on protocol / data issues try: values = con.read_plc_memory(0, pyLSV2.MemoryType.WORD, 99999) except LSV2InputException as e: print("Too many elements requested:", e) except LSV2ProtocolException as e: print("Protocol error:", e) except LSV2StateException as e: print("State error:", e) finally: con.disconnect() ``` -------------------------------- ### Check Python Version with vermin Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Command to check the minimum required Python version for the project using the vermin tool. This helps ensure compatibility with different Python environments. ```bash vermin --no-parse-comments . ``` -------------------------------- ### Run pyLSV2 Tests Source: https://github.com/drunsinn/pylsv2/blob/master/README.md Command to execute pyLSV2 tests. Requires a machine or programming station to be on with the PLC program running. The IP address and timeout for the connection are set as command-line parameters. ```bash pytest --address=192.168.56.103 --timeout=5 ``` -------------------------------- ### LSV2.spindle_tool_status Source: https://context7.com/drunsinn/pylsv2/llms.txt Retrieves information about the currently active tool in the spindle. Requires `DNC` login. May not be supported on all control types. ```APIDOC ## LSV2.spindle_tool_status — Read Current Spindle Tool Returns a `ToolInformation` data class with tool number, index, axis, length, radius, and name. Requires `DNC` login. Not supported on all control types. ### Method ```python con.spindle_tool_status() -> ToolInformation | None ``` ### Returns - **return value** (ToolInformation | None) - An object containing detailed information about the current tool. Returns None if tool information is not supported or cannot be retrieved. - **number** (int) - The tool number. - **index** (int) - The tool index. - **axis** (str) - The axis associated with the tool. - **length** (float) - The length of the tool in millimeters. - **radius** (float) - The radius of the tool in millimeters. - **name** (str) - The name of the tool. ### Request Example ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: tool = con.spindle_tool_status() if tool is not None: print(f"Tool number: {tool.number}.{tool.index}") print(f"Tool name: {tool.name}") print(f"Length: {tool.length} mm") print(f"Radius: {tool.radius} mm") print(f"Axis: {tool.axis}") else: print("Tool info not supported for this control") ``` ``` -------------------------------- ### Read Machine State (R_RI) - Current Program Name Source: https://github.com/drunsinn/pylsv2/blob/master/docs/protocol.md When logged in with DN, use R_RI with the value 0x0018 (24) to read the name of the currently executing program. ```default > R_RI 0x0018 (24) -> you can read the name of the current program in execution. ``` -------------------------------- ### Remote Keyboard Emulation with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Emulates remote keyboard input by locking the control keyboard, sending key codes, and then unlocking. Requires 'MONITOR' login. Use 'KeyCode' or 'OldKeyCode' enums. Not supported on TNC7. Ensure the keyboard is locked before sending keys and unlocked afterwards. ```python import pyLSV2 from pyLSV2 import KeyCode with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: # Always lock keyboard before sending keys, unlock afterwards con.set_keyboard_access(False) # lock keyboard con.send_key_code(KeyCode.MODE_MANUAL) # switch to manual mode # Other useful keys: # KeyCode.MODE_PGM_EDIT – program edit mode # KeyCode.MODE_AUTOMATIC – automatic execution mode # KeyCode.MODE_SINGLE_STEP – single-step mode # KeyCode.CE – clear error # KeyCode.ENT – enter/confirm # KeyCode.BOTTOM_SK0 ... BOTTOM_SK9 – soft keys con.set_keyboard_access(True) # unlock keyboard ``` -------------------------------- ### List Files Recursively with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Returns a list of file path strings found under a given remote directory. Supports recursive listing (`descend=True`) and optional regex pattern filtering. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # All files under TNC: drive all_files = con.get_file_list(path="TNC:", descend=True) print("Total files:", len(all_files)) # Only Klartext (.h) NC programs h_files = con.get_file_list( path="TNC:/nc_prog", descend=True, pattern=r"[\$A-Za-z0-9_-]*\.[hH]$", ) for f in h_files: print(f) # e.g. "TNC:\nc_prog\part1.H" # "TNC:\nc_prog\fixtures\clamp.H" # Only ISO (.i) programs, non-recursive i_files = con.get_file_list(path="TNC:/nc_prog", descend=False, pattern=r".*\.[iI]$") print("ISO programs:", len(i_files)) ``` -------------------------------- ### Read Scope Signals and Real-time Readings from iTNC530 Source: https://context7.com/drunsinn/pylsv2/llms.txt Retrieves oscilloscope signal descriptions and streams real-time signal data from iTNC530 controls. Requires SCOPE login and iTNC530. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000, safe_mode=False) as con: if not con.versions.is_itnc(): print("Scope only works on iTNC530") else: # List available signals all_signals = con.read_scope_signals() sig_dict = {f"{s.channel_name} - {s.signal_name}": s for s in all_signals} # Select axis position signals selected = [ sig_dict["s ist - X"], sig_dict["s ist - Y"], sig_dict["s ist - Z"], ] # Stream readings for 2 seconds at 3000 µs interval count = 0 for package in con.real_time_readings(selected, duration=2, interval=3000): data = package.get_data() x = data[0].data[0] * data[0].factor + data[0].offset y = data[1].data[0] * data[1].factor + data[1].offset z = data[2].data[0] * data[2].factor + data[2].offset print(f" X={x:.3f} Y={y:.3f} Z={z:.3f}") count += 1 print(f"Total readings: {count}") ``` -------------------------------- ### Inspect Remote File Information with pyLSV2 Source: https://context7.com/drunsinn/pylsv2/llms.txt Retrieves information about a specific file or directory on the remote control. `file_info()` returns a `FileEntry` object, while `directory_info()` provides details about a directory, including free space. ```python import pyLSV2 with pyLSV2.LSV2("192.168.1.10", port=19000) as con: # Check a specific file fi = con.file_info("TNC:/nc_prog/part1.h") if fi is not None: print("Name:", fi.name) print("Size:", fi.size, "bytes") print("Modified:", fi.timestamp) print("Protected:", fi.is_protected) print("Is dir:", fi.is_directory) else: print("File does not exist") # Current directory info di = con.directory_info() print("Current path:", di.path) print("Free space:", di.free_size, "bytes") # Info for a specific directory di2 = con.directory_info("TNC:/nc_prog") print("nc_prog free space:", di2.free_size) ```