Skip to content

Latest commit

 

History

History
308 lines (225 loc) · 8.51 KB

File metadata and controls

308 lines (225 loc) · 8.51 KB

CODESYS API Implementation Guide

Introduction

This guide provides essential information for implementing the CODESYS REST API wrapper, based on an analysis of the available CODESYS scripting interfaces. It focuses on key components of the CODESYS API that will be required to implement the functionality described in the architecture document.

Key CODESYS API Components

Session and System Management

The primary entry point to the CODESYS API is through the ScriptSystem class:

import scriptengine
from scriptengine import ScriptSystem

# Initialize the system
system = ScriptSystem()

Key capabilities include:

  • System management: Managing CODESYS system settings
  • Device repository: Accessing available devices
  • Project management: Creating and opening projects

Project Operations

Project operations are handled through the ScriptProjects interface:

# Access projects interface
projects = system.projects

# Create a new project
new_project = projects.create()

# Open an existing project
project = projects.open("C:/path/to/project.project")

# Save a project
project.save()

POU Management

Program Organization Units (POUs) can be created and managed through the project's application interface:

# Access the application
application = project.active_application

# Create a POU
pou = application.pou_container.create_pou(
    name="MyPOU",
    type=scriptengine.PouType.FUNCTION_BLOCK,
    language=scriptengine.ImplementationLanguage.ST
)

# Set POU code
pou.set_implementation_code("IF input > 0 THEN\n    output := TRUE;\nEND_IF;")

Online Operations

Online operations allow interaction with connected devices:

# Access online interface
online = system.online

# Connect to a device
device = online.connect_to_device("192.168.1.100")

# Login to an application
online_app = device.login(application)

# Start/stop the application
online_app.start()
online_app.stop()

Implementing the REST API Wrapper

Session Management

For the /session/start endpoint, you'll need to:

  1. Initialize the ScriptSystem
  2. Keep this instance alive throughout the server's lifetime
  3. Handle any initialization errors

Example implementation:

def start_codesys_session():
    try:
        system = ScriptSystem()
        # Store the system instance in a global or session store
        return {"success": True, "message": "CODESYS session started"}
    except Exception as e:
        return {"success": False, "error": str(e)}

Project Operations

For project operations endpoints:

def create_project(params):
    try:
        # Access the global system instance
        system = get_system_instance()
        
        # Create a new project
        project = system.projects.create()
        
        # Save with the specified name
        if "path" in params:
            project.save_as(params["path"])
            
        return {
            "success": True, 
            "project_path": project.path,
            "is_dirty": project.dirty
        }
    except Exception as e:
        return {"success": False, "error": str(e)}

POU Management

For POU management endpoints:

def create_pou(params):
    try:
        # Access the global system instance
        system = get_system_instance()
        
        # Get active project
        project = system.projects.active
        if not project:
            return {"success": False, "error": "No active project"}
            
        # Get application
        application = project.active_application
        
        # Create POU
        pou = application.pou_container.create_pou(
            name=params["name"],
            type=get_pou_type(params["type"]),
            language=get_implementation_language(params["language"])
        )
        
        # Set implementation if provided
        if "code" in params:
            pou.set_implementation_code(params["code"])
            
        return {"success": True, "pou_name": pou.name}
    except Exception as e:
        return {"success": False, "error": str(e)}

Script Generation

For the script execution endpoint, you'll need to generate Python scripts that can be executed by the CODESYS scripting engine. Here's an approach:

  1. Create a template-based script generator
  2. Generate script files with proper error handling
  3. Execute the scripts and capture results
def generate_script(template, params):
    """Generate a script from a template with parameters."""
    script_content = template.format(**params)
    
    # Write to temporary file
    temp_file = create_temp_file(script_content)
    
    return temp_file

def execute_script(script_path):
    """Execute a script and return the results."""
    try:
        # Access the global system instance
        system = get_system_instance()
        
        # Execute script
        result = system.execute_script(script_path)
        
        return {"success": True, "result": result}
    except Exception as e:
        return {"success": False, "error": str(e)}

Exception Handling

CODESYS operations can raise various exceptions. Create a mapping of CODESYS exceptions to HTTP status codes:

EXCEPTION_TO_HTTP_STATUS = {
    "FileNotFoundException": 404,
    "AccessDeniedException": 403,
    "InvalidOperationException": 400,
    # Add more mappings as needed
}

def handle_codesys_exception(e):
    """Map CODESYS exceptions to appropriate HTTP responses."""
    exception_type = type(e).__name__
    status_code = EXCEPTION_TO_HTTP_STATUS.get(exception_type, 500)
    
    return {
        "success": False,
        "error": {
            "code": exception_type,
            "message": str(e)
        }
    }, status_code

Persistent Session Management

To maintain a persistent CODESYS session:

  1. Launch CODESYS in a separate process
  2. Use inter-process communication to send commands
  3. Monitor the process health
  4. Restart automatically if needed
def start_codesys_process():
    """Start CODESYS in a separate process."""
    try:
        # Use subprocess to start CODESYS
        process = subprocess.Popen(
            [CODESYS_PATH, "-script", PERSISTENT_SCRIPT_PATH],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
        )
        
        # Store process handle
        set_codesys_process(process)
        
        # Start monitoring thread
        start_monitoring_thread()
        
        return True
    except Exception as e:
        logger.error(f"Failed to start CODESYS: {e}")
        return False

Performance Considerations

  1. Script Caching: Cache frequently used scripts
  2. Connection Pooling: Reuse connections to CODESYS
  3. Result Caching: Cache results of expensive operations
  4. Asynchronous Operations: Use async for long-running tasks

Security Implementation

  1. API Key Validation:
def validate_api_key(request):
    """Validate the API key from the request."""
    api_key = request.headers.get("Authorization", "")
    
    if api_key.startswith("ApiKey "):
        api_key = api_key[7:]  # Remove "ApiKey " prefix
    else:
        return False
        
    # Check against stored API keys
    return api_key in get_valid_api_keys()
  1. Input Validation:
def validate_project_params(params):
    """Validate parameters for project operations."""
    required = ["path"]
    for field in required:
        if field not in params:
            return False, f"Missing required field: {field}"
            
    # Validate path format
    if not is_valid_path(params["path"]):
        return False, "Invalid project path format"
        
    return True, ""

Conclusion

Implementing a REST API wrapper for CODESYS requires careful management of the CODESYS scripting environment, proper error handling, and secure API design. By utilizing the available scripting interfaces and following the architecture outlined in the design document, a robust and maintainable solution can be created.

The key challenges will be:

  1. Maintaining a persistent CODESYS session
  2. Handling errors and exceptions gracefully
  3. Ensuring secure access to the API
  4. Managing performance for concurrent operations

With proper implementation of the components outlined in this guide, these challenges can be addressed effectively.