Skip to content

Latest commit

 

History

History
609 lines (472 loc) · 14.5 KB

File metadata and controls

609 lines (472 loc) · 14.5 KB

REST API Reference

Overview

The OpenPLC Runtime v4 provides an internal REST API over HTTPS used by the OpenPLC Editor desktop application. The API is not intended for direct end-user interaction but can be used for advanced integration or diagnostics.

All endpoints are accessible at https://<host>:8443/api/<endpoint>.

Base URL

https://localhost:8443/api

Authentication

The runtime uses JWT-based authentication:

  1. First User Creation: POST /api/create-user (no authentication required for the first user)
  2. Login: POST /api/login returns a JWT access token
  3. Authenticated Requests: All other endpoints require Authorization: Bearer <token> header

Note: The OpenPLC Editor handles authentication automatically. Advanced integrators must implement the authentication flow manually.

Common Response Format

All API responses are JSON objects. Successful responses typically include a status field, while errors include descriptive error messages.

Authentication Endpoints

Create User

Create a new user account. The first user can be created without authentication. Subsequent users require JWT authentication.

Request:

POST /api/create-user
Content-Type: application/json

{
  "username": "admin",
  "password": "your_password",
  "role": "admin"
}

Response (Success):

{
  "msg": "User created",
  "id": 1
}

Response (Error):

{
  "msg": "Username already exists"
}

Status Codes:

  • 201 Created - User created successfully
  • 400 Bad Request - Missing username or password
  • 401 Unauthorized - User already exists and no valid JWT provided
  • 409 Conflict - Username already exists

Login

Authenticate and receive a JWT access token.

Request:

POST /api/login
Content-Type: application/json

{
  "username": "admin",
  "password": "your_password"
}

Response (Success):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (Error):

"Wrong username or password"

Status Codes:

  • 200 OK - Login successful
  • 401 Unauthorized - Invalid credentials
  • 500 Internal Server Error - Database error

Notes:

  • The access token should be included in the Authorization: Bearer <token> header for all subsequent requests
  • Tokens expire after a configured duration (default: 24 hours)

PLC Control Endpoints

All PLC control endpoints require JWT authentication.

Start PLC

Start the PLC program execution.

Request:

GET /api/start-plc
Authorization: Bearer <token>

Response:

{
  "status": "PLC started successfully"
}

Possible Status Values:

  • "PLC started successfully" - PLC transitioned to RUNNING state
  • "PLC is already running" - PLC was already in RUNNING state
  • "No PLC program loaded" - No compiled program available
  • "No response from runtime" - Runtime process not responding

Stop PLC

Stop the PLC program execution.

Request:

GET /api/stop-plc
Authorization: Bearer <token>

Response:

{
  "status": "PLC stopped successfully"
}

Possible Status Values:

  • "PLC stopped successfully" - PLC transitioned to STOPPED state
  • "PLC is already stopped" - PLC was already in STOPPED state
  • "No response from runtime" - Runtime process not responding

Get PLC Status

Query the current PLC state.

Request:

GET /api/status
Authorization: Bearer <token>

Response:

{
  "status": "RUNNING"
}

Possible Status Values:

  • "EMPTY" - No PLC program loaded
  • "INIT" - Program loaded, initializing
  • "RUNNING" - Actively executing scan cycles
  • "STOPPED" - Program loaded but not executing
  • "ERROR" - Recoverable error state
  • "No response from runtime" - Runtime process not responding

Ping Runtime

Check if the runtime process is responsive.

Request:

GET /api/ping
Authorization: Bearer <token>

Response:

{
  "status": "pong"
}

Possible Status Values:

  • "pong" - Runtime is responsive
  • null - Runtime not responding

Program Management Endpoints

Upload PLC Program

Upload a ZIP file containing the PLC program source files generated by OpenPLC Editor v4.

Request:

POST /api/upload-file
Authorization: Bearer <token>
Content-Type: multipart/form-data

file: <ZIP file>

Success Response:

{
  "UploadFileFail": "",
  "CompilationStatus": "COMPILING"
}

Error Response:

{
  "UploadFileFail": "Error message",
  "CompilationStatus": "FAILED"
}

Compilation Status Values:

  • "IDLE" - No build in progress
  • "UNZIPPING" - Extracting ZIP file
  • "COMPILING" - Running compilation scripts
  • "SUCCESS" - Build completed successfully
  • "FAILED" - Build failed

Error Conditions:

  • No file in request
  • File too large (>10 MB per file, >50 MB total)
  • ZIP validation failed (path traversal, compression ratio, disallowed extensions)
  • Another compilation in progress
  • File system error

Notes:

  • Compilation runs asynchronously in a background thread
  • Use the /api/compilation-status endpoint to monitor progress
  • The PLC is automatically stopped during compilation
  • The OpenPLC Editor compiles the program locally (JSON → XML → ST → C) and uploads the source files as a ZIP

Get Compilation Status

Query the status of the most recent compilation.

Request:

GET /api/compilation-status
Authorization: Bearer <token>

Response:

{
  "status": "SUCCESS",
  "logs": [
    "[INFO] Starting compilation",
    "[INFO] Compiling Config0.c...",
    "[INFO] Compiling Res0.c...",
    "[INFO] Compiling debug.c...",
    "[INFO] Compiling glueVars.c...",
    "[INFO] Compiling c_blocks_code.cpp...",
    "[INFO] Compiling shared library...",
    "[INFO] Build finished successfully"
  ],
  "exit_code": 0
}

Response Fields:

  • status - Current build status (IDLE, UNZIPPING, COMPILING, SUCCESS, FAILED)
  • logs - Array of log messages from the build process
  • exit_code - Exit code of the compilation script (0 = success, non-zero = error, null = in progress)

Notes:

  • The OpenPLC Editor polls this endpoint to monitor compilation progress
  • Logs are accumulated during compilation
  • Error messages are prefixed with [ERROR]
  • Exit code is null until compilation completes

Get Runtime Logs

Retrieve logs from the PLC runtime process.

Request:

GET /api/runtime-logs
GET /api/runtime-logs?id=<min_id>
GET /api/runtime-logs?level=<log_level>
Authorization: Bearer <token>

Query Parameters:

  • id (optional) - Minimum log ID to retrieve (for pagination)
  • level (optional) - Filter by log level (DEBUG, INFO, WARNING, ERROR)

Response:

{
  "runtime-logs": [
    {
      "id": 1,
      "timestamp": "2024-01-01T12:00:00.000Z",
      "level": "INFO",
      "message": "PLC started successfully"
    },
    {
      "id": 2,
      "timestamp": "2024-01-01T12:00:05.000Z",
      "level": "DEBUG",
      "message": "Scan Count: 100"
    }
  ]
}

Log Levels:

  • DEBUG - Detailed diagnostic information
  • INFO - General informational messages
  • WARNING - Warning messages
  • ERROR - Error messages

Error Handling

HTTP Status Codes

  • 200 OK - Request successful
  • 201 Created - Resource created successfully
  • 400 Bad Request - Invalid request parameters
  • 401 Unauthorized - Authentication required or invalid token
  • 409 Conflict - Resource conflict (e.g., username already exists)
  • 500 Internal Server Error - Server error

Error Response Format

{
  "error": "Error message description"
}

Or for some endpoints:

{
  "msg": "Error message description"
}

Usage Examples

Complete Authentication Flow

cURL Examples:

# Step 1: Create first user
curl -k -X POST https://localhost:8443/api/create-user \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123","role":"admin"}'

# Step 2: Login and get JWT token
TOKEN=$(curl -k -X POST https://localhost:8443/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}' \
  | jq -r '.access_token')

echo "Token: $TOKEN"

# Step 3: Use token for authenticated requests

# Get PLC status
curl -k https://localhost:8443/api/status \
  -H "Authorization: Bearer $TOKEN"

# Start PLC
curl -k https://localhost:8443/api/start-plc \
  -H "Authorization: Bearer $TOKEN"

# Stop PLC
curl -k https://localhost:8443/api/stop-plc \
  -H "Authorization: Bearer $TOKEN"

# Upload program
curl -k -X POST https://localhost:8443/api/upload-file \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@program.zip"

# Get compilation status
curl -k https://localhost:8443/api/compilation-status \
  -H "Authorization: Bearer $TOKEN"

# Get runtime logs
curl -k https://localhost:8443/api/runtime-logs \
  -H "Authorization: Bearer $TOKEN"

# Ping runtime
curl -k https://localhost:8443/api/ping \
  -H "Authorization: Bearer $TOKEN"

Note: The -k flag bypasses certificate verification for self-signed certificates.

Python Example:

import requests
import urllib3
import time

# Disable SSL warnings for self-signed certificates
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

base_url = "https://localhost:8443/api"

# Step 1: Create first user (no auth required)
response = requests.post(
    f"{base_url}/create-user",
    json={"username": "admin", "password": "admin123", "role": "admin"},
    verify=False
)
print(f"User creation: {response.json()}")

# Step 2: Login to get JWT token
response = requests.post(
    f"{base_url}/login",
    json={"username": "admin", "password": "admin123"},
    verify=False
)
token = response.json()["access_token"]
print(f"Received token: {token[:50]}...")

# Step 3: Use token for authenticated requests
headers = {"Authorization": f"Bearer {token}"}

# Get PLC status
response = requests.get(f"{base_url}/status", headers=headers, verify=False)
print(f"PLC Status: {response.json()}")

# Start PLC
response = requests.get(f"{base_url}/start-plc", headers=headers, verify=False)
print(f"Start PLC: {response.json()}")

# Upload program
with open("program.zip", "rb") as f:
    files = {"file": f}
    response = requests.post(
        f"{base_url}/upload-file",
        files=files,
        headers=headers,
        verify=False
    )
    print(f"Upload: {response.json()}")

# Monitor compilation
while True:
    response = requests.get(
        f"{base_url}/compilation-status",
        headers=headers,
        verify=False
    )
    status = response.json()
    print(f"Compilation Status: {status['status']}")

    if status["status"] in ["SUCCESS", "FAILED"]:
        print("Compilation Logs:")
        for log in status["logs"]:
            print(f"  {log}")
        break

    time.sleep(1)

JavaScript/Node.js Example:

const https = require('https');
const fetch = require('node-fetch');
const FormData = require('form-data');
const fs = require('fs');

// Disable SSL verification for self-signed certificates
const agent = new https.Agent({ rejectUnauthorized: false });
const baseUrl = "https://localhost:8443/api";

async function main() {
  // Step 1: Create first user
  let response = await fetch(`${baseUrl}/create-user`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      username: 'admin',
      password: 'admin123',
      role: 'admin'
    }),
    agent
  });
  console.log('User creation:', await response.json());

  // Step 2: Login to get JWT token
  response = await fetch(`${baseUrl}/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      username: 'admin',
      password: 'admin123'
    }),
    agent
  });
  const { access_token } = await response.json();
  console.log('Received token:', access_token.substring(0, 50) + '...');

  // Step 3: Use token for authenticated requests
  const headers = { 'Authorization': `Bearer ${access_token}` };

  // Get PLC status
  response = await fetch(`${baseUrl}/status`, { headers, agent });
  console.log('PLC Status:', await response.json());

  // Start PLC
  response = await fetch(`${baseUrl}/start-plc`, { headers, agent });
  console.log('Start PLC:', await response.json());

  // Upload program
  const formData = new FormData();
  formData.append('file', fs.createReadStream('program.zip'));

  response = await fetch(`${baseUrl}/upload-file`, {
    method: 'POST',
    headers: { ...headers },
    body: formData,
    agent
  });
  console.log('Upload:', await response.json());

  // Monitor compilation
  while (true) {
    response = await fetch(`${baseUrl}/compilation-status`, { headers, agent });
    const status = await response.json();
    console.log('Compilation Status:', status.status);

    if (status.status === 'SUCCESS' || status.status === 'FAILED') {
      console.log('Compilation Logs:');
      status.logs.forEach(log => console.log('  ' + log));
      break;
    }

    await new Promise(resolve => setTimeout(resolve, 1000));
  }
}

main();

Rate Limiting

Currently, there are no rate limits enforced. However, be mindful of:

  • Only one compilation can run at a time
  • Frequent start/stop commands may cause state transition issues
  • Log queries can be resource-intensive with large log volumes

Security Considerations

  1. HTTPS Only: All communication must use HTTPS (port 8443)
  2. JWT Authentication: All endpoints except first user creation and login require JWT authentication
  3. Self-Signed Certificates: Default installation uses self-signed certificates (OpenPLC Editor handles this automatically)
  4. File Upload Validation: ZIP files undergo comprehensive security checks before extraction
  5. Size Limits: Files are limited to prevent resource exhaustion (10 MB per file, 50 MB total)
  6. Path Validation: All file paths are validated to prevent traversal attacks
  7. Password Security: Passwords are hashed with PBKDF2-SHA256 (600,000 iterations), salt, and pepper

WebSocket Debug Interface

For real-time debugging and variable inspection, the OpenPLC Editor uses a WebSocket interface at https://<host>:8443/api/debug. See Debug Protocol for details.

Related Documentation