Skip to content

Repository files navigation

Redis Driver Module for Ignition

A comprehensive Redis database integration module for Inductive Automation's Ignition platform, providing seamless Redis connectivity across Gateway, Designer, and Client scopes.

🚀 Features

Core Capabilities

  • Multi-Scope Support: Full Redis functionality in Gateway, Designer, and Vision Client scopes
  • Connection Management: Robust connection pooling with health monitoring and automatic retry logic
  • Designer Tools: Redis Browser, CLI, and Profiler for development and debugging
  • Expression Functions: Native Redis functions for use in property bindings and expression tags
  • Scripting Functions: Complete system.redis.* scripting API for all scopes
  • Web API: RESTful endpoints for external Redis operations
  • Real-time Monitoring: Live connection status and metrics tracking
  • Production Safety: Gateway comm mode protection prevents accidental cache modifications

Redis Operations

  • String Operations: GET, SET, SET NX, DELETE, EXISTS, KEYS with TTL support
  • Hash Operations: HGET, HSET, HGETALL
  • Sorted Set Operations: ZADD, ZREM, ZRANGE with score management
  • Type Preservation: Automatic serialization with native type preservation (Integer, Double, Boolean, Lists, Maps)
  • Batch Operations: Pipeline multiple operations for improved performance
  • Key Management: Pattern matching and bulk operations

Enterprise Features

  • Connection Pooling: Configurable Jedis connection pools with health checks
  • Retry Logic: Exponential backoff retry with configurable limits
  • Error Handling: Comprehensive error reporting with Python-compatible exceptions
  • Security: Role-based access control integration
  • Monitoring: Built-in connection health and performance metrics

📋 Requirements

  • Ignition: Version 8.1.44 or higher
  • Java: JDK 17+
  • Redis: Version 3.0+ (tested with Redis 6.x and 7.x)
  • Gradle: 8.7+ (included via wrapper)

🛠️ Building the Module

Quick Start

# Clone the repository
git clone <repository-url>
cd redis-driver

# Build the module
./gradlew build

# The module file will be created at:
# build/distributions/Redis-Driver.modl

Development Build

# Clean build with tests
./gradlew clean build

# Build and deploy to local gateway (configure hostGateway in gradle.properties)
./gradlew deployModl

Project Structure

redis-driver/
├── common/           # Shared interfaces and utilities
│   └── src/main/java/dev/bwdesigngroup/redis/common/
│       ├── api/                      # RPC interfaces and DTOs
│       │   ├── BatchOperation.java   # Batch operation data structure
│       │   └── RedisScriptInterface.java
│       ├── exception/                # Exception handling
│       │   ├── RedisException.java
│       │   └── RedisExceptionHandler.java
│       ├── scripting/                # Script module base classes
│       │   ├── AbstractRedisScriptModule.java
│       │   └── RedisRPCScriptModule.java
│       └── util/                     # Utilities and constants
│           ├── RedisConstants.java
│           ├── RedisResultWrapper.java
│           └── RedisUtils.java
├── gateway/          # Gateway scope implementation
│   └── src/main/java/dev/bwdesigngroup/redis/gateway/
│       ├── connection/               # Connection management
│       │   ├── RedisConnectionConfig.java
│       │   ├── RedisConnectionManager.java
│       │   └── RedisConnector.java
│       ├── persistence/              # Database records
│       │   └── RedisConnectionRecord.java
│       ├── scripting/                # Script implementations
│       │   ├── RedisGatewayScriptModule.java
│       │   └── expressions/          # Expression functions
│       │       ├── RedisExpressionFunction.java
│       │       └── RedisExpressionProvider.java
│       ├── service/                  # Business logic services
│       │   ├── RedisConnectionService.java
│       │   └── RedisOperationService.java
│       ├── web/                      # REST API routes
│       │   ├── BaseRouteHandler.java
│       │   ├── RedisApiRoutes.java
│       │   ├── RedisConnectionRoutes.java
│       │   ├── RedisExtensionPage.java
│       │   └── RedisStatusRoutes.java
│       ├── RedisDriverGatewayHook.java
│       └── RedisExtensionPointType.java
├── designer/         # Designer scope implementation
│   └── src/main/java/dev/bwdesigngroup/redis/designer/
│       └── RedisDriverDesignerHook.java
├── client/           # Vision Client scope implementation
│   └── src/main/java/dev/bwdesigngroup/redis/client/
│       └── RedisDriverClientHook.java
├── docs/             # Module documentation
├── scripts/          # Build and deployment scripts
└── build.gradle.kts  # Root build configuration

📦 Installation

  1. Build or Download: Build the module from source or download a release
  2. Install Module: In the Ignition Gateway, go to Config → Modules → Install or Upgrade a Module
  3. Upload File: Select the Redis-Driver.modl file
  4. Restart Gateway: The gateway will restart automatically to load the module

⚙️ Configuration

Creating Redis Connections

  1. Navigate to Config → Redis → Connections
  2. Click Create new Redis Connection...
  3. Configure connection settings:

Basic Settings

  • Connection Name: Unique identifier for the connection
  • Enabled: Enable/disable the connection
  • Host: Redis server hostname or IP address
  • Port: Redis server port (default: 6379)
  • Password: Redis AUTH password (optional)
  • Database: Redis database number (default: 0)

Pool Settings

  • Max Pool Size: Maximum connections in pool (default: 8)
  • Max Idle: Maximum idle connections (default: 8)
  • Min Idle: Minimum idle connections (default: 0)
  • Timeout: Connection timeout in milliseconds (default: 2000)

Example Configuration

Connection Name: ProductionCache
Host: redis.company.com
Port: 6379
Password: ************
Database: 0
Max Pool Size: 20
Max Idle: 10
Min Idle: 2
Timeout: 5000

🛠️ Designer Tools

The module provides three powerful tools accessible from the Designer's Tools menu:

Redis Browser

Access: Tools → Redis → Browser

A visual interface for exploring and managing Redis data:

  • Key Explorer: Browse keys with pattern filtering and pagination
  • Type Detection: Automatic detection and display of key types (string, hash, list, set, zset)
  • TTL Display: View time-to-live for keys with expiration
  • Value Editor: View and edit key values with type-specific editors
  • Auto-refresh: Optional auto-refresh for monitoring live data
  • Bulk Operations: Optimized for large datasets (10,000+ keys)
  • Production Safety: Destructive operations blocked in read-only mode

Performance: Uses Redis pipelining to load thousands of keys instantly (single bulk RPC call vs. thousands of individual calls).

Redis CLI

Access: Tools → Redis → CLI

An interactive command-line interface for Redis:

  • Direct Commands: Execute any Redis command directly
  • Command History: Navigate previous commands with up/down arrows
  • Syntax Support: Full Redis command syntax including multi-word commands
  • Response Display: Formatted responses with type information
  • Production Safety: Destructive commands (SET, DEL, FLUSHDB, etc.) blocked in read-only mode

Example Commands:

GET user:123
SET cache:temp "value" EX 60
HGETALL config:database
ZADD leaderboard 100 "player1"
KEYS session:*

Redis Profiler

Access: Tools → Redis → Profiler

Performance monitoring and metrics:

  • Connection Status: Live connection state for all configured connections
  • Pool Metrics: Active/idle connection counts and utilization
  • Health Monitoring: Last health check timestamps
  • Error Tracking: Connection errors and retry attempts
  • Diagnostics: Detailed connection information

Gateway Communication Mode Protection

All Designer tools respect the Gateway communication mode:

  • Read-Write Mode: Full access to all operations
  • Read-Only Mode: Blocks SET, DEL, HSET, ZADD, EXPIRE, FLUSHDB, and other destructive commands
  • Disconnected Mode: All operations blocked

This prevents accidental modifications to production caches when developers are connected in read-only mode. The Designer toolbar shows the current comm mode.

🎯 Usage Examples

Expression Functions

Use Redis data directly in property bindings and expression tags:

// Get a string value
redisGet('ProductionCache', 'machine:line1:status')

// Check if key exists with conditional logic
if(redisExists('SessionStore', 'user:' + {Session.userId}), 
   'Logged In', 
   'Guest')

// Get typed values with automatic conversion
redisGetInt('Counters', 'production:total') + 1
redisGetDouble('Metrics', 'efficiency:line1') * 100
redisGetBoolean('Flags', 'maintenance:enabled')

// Hash operations
redisHGet('Configuration', 'database', 'host')

// Utility functions
redisKeyCount('Cache', 'session:*')
redisConnectionTest('ProductionCache')

Scripting Functions

Access full Redis functionality in Gateway, Designer, and Client scripts:

Basic Operations

# Import not needed - system.redis is automatically available

# String operations with native type support
system.redis.set('ProductionCache', 'machine:line1:temp', 75.2)  # Stores as native Double
temperature = system.redis.get('ProductionCache', 'machine:line1:temp')  # Returns 75.2 as Double

# Set with TTL options
system.redis.set('Cache', 'temp:data', 'value', ttlSeconds=300)  # 5 minute TTL
system.redis.set('Cache', 'session', data, ttlMillis=3600000)    # 1 hour TTL
system.redis.set('Cache', 'event', info, expirationDate=futureDate)

# Delete operations
system.redis.delete('ProductionCache', 'old:key')
deleted_count = system.redis.delete('Cache', 'key1', 'key2', 'key3')  # Multiple keys

# Check existence
if system.redis.exists('SessionStore', 'user:12345'):
    print("User session active")

# Pattern matching
session_keys = system.redis.keys('SessionStore', 'user:*')
print("Active sessions:", len(session_keys))

Hash Operations

# Set single field
system.redis.hset('Configuration', 'database', 'host', 'db.company.com')

# Set multiple fields at once
system.redis.hset('Configuration', 'database', {
    'host': 'db.company.com',
    'port': 5432,
    'username': 'app_user',
    'ssl': True
})

# Get hash values
db_host = system.redis.hget('Configuration', 'database', 'host')
db_config = system.redis.hgetAll('Configuration', 'database')
print("Database config:", db_config)  # Returns dict with native types preserved

Type-Preserved Operations

# Native types are automatically preserved
system.redis.set('Counters', 'production:total', 12345)          # Stored as Integer
count = system.redis.get('Counters', 'production:total')         # Returns Integer 12345

system.redis.set('Metrics', 'efficiency', 85.7)                  # Stored as Double
efficiency = system.redis.get('Metrics', 'efficiency')           # Returns Double 85.7

system.redis.set('Flags', 'maintenance', True)                   # Stored as Boolean
maintenance_mode = system.redis.get('Flags', 'maintenance')      # Returns Boolean True

# Complex types (lists, dicts) are automatically serialized
machine_data = {
    'id': 'LINE-001',
    'status': 'running',
    'temperature': 72.5,
    'speed': 1200,
    'errors': [],
    'maintenance_due': False
}
system.redis.set('Machines', 'line1:data', machine_data)
retrieved_data = system.redis.get('Machines', 'line1:data')      # Returns dict with types preserved

Batch Operations

# Create batch operations for pipeline execution
op1 = system.redis.createBatchOperation('op1', 'set').key('machine:1:status').value('running')
op2 = system.redis.createBatchOperation('op2', 'set').key('machine:1:temp').value(72.5)
op3 = system.redis.createBatchOperation('op3', 'get').key('machine:1:speed')
op4 = system.redis.createBatchOperation('op4', 'hget').key('config').field('timeout')
op5 = system.redis.createBatchOperation('op5', 'exists').key('machine:1:error')

# Execute batch
results = system.redis.batch('ProductionCache', [op1, op2, op3, op4, op5])

# Access results by operation ID
print("Speed:", results['op3'])           # Retrieved value
print("Config timeout:", results['op4'])  # Hash field value
print("Has error:", results['op5'])       # Boolean exists result

Connection Management

# List available connections
connections = system.redis.getConnectionNames()
print("Available Redis connections:", connections)

# Test connection health
if system.redis.testConnection('ProductionCache'):
    print("Redis connection is healthy")
else:
    print("Redis connection failed")

# Get TTL information
ttl = system.redis.getTTL('Cache', 'session:12345')
if ttl == -1:
    print("Key has no expiration")
elif ttl == -2:
    print("Key does not exist")
else:
    print("Key expires in %d milliseconds" % ttl)

Advanced Usage

Error Handling

# All operations throw Python-compatible exceptions
try:
    value = system.redis.get('InvalidConnection', 'key')
except KeyError as e:
    print("Connection not found:", e)
except ValueError as e:
    print("Invalid parameter:", e)
except IOError as e:
    print("Connection error:", e)
except RuntimeError as e:
    print("Operation failed:", e)

Performance Optimization

# Use batch operations for multiple related operations
operations = []
for i in range(100):
    op = system.redis.createBatchOperation('op%s' % i, 'set')
    op.key('sensor:%s:value' % i).value(readSensorValue(i))
    operations.append(op)

# Single network round-trip for all operations
system.redis.batch('SensorCache', operations)

# vs multiple round-trips (slower)
for i in range(100):
    system.redis.set('SensorCache', 'sensor:%s:value' % i, readSensorValue(i))

🌐 Web API

The module provides REST endpoints for external integrations:

Authentication

All API endpoints require appropriate Ignition Gateway permissions:

  • Development Mode: Unrestricted access (set redis.dev.mode=true)
  • Production Mode: Requires Config section permissions

Endpoints

Basic Operations

# Set a value with optional TTL
POST /main/system/redis/api/set
Content-Type: application/json
{
  "connection": "ProductionCache",
  "key": "machine:1:status",
  "value": "running",
  "ttlSeconds": 300  # Optional
}

# Get a value (preserves original type)
GET /main/system/redis/api/get/ProductionCache/machine:1:status

# Delete a key
DELETE /main/system/redis/api/delete/ProductionCache/machine:1:status

# Check existence
GET /main/system/redis/api/exists/ProductionCache/machine:1:status

# Get keys with pattern
GET /main/system/redis/api/keys/ProductionCache?pattern=machine:*

Hash Operations

# Set hash field
POST /main/system/redis/api/hset
Content-Type: application/json
{
  "connection": "ProductionCache",
  "key": "machine:1",
  "field": "status",
  "value": "running"
}

# Get hash field
GET /main/system/redis/api/hget/ProductionCache/machine:1/status

# Get all hash fields
GET /main/system/redis/api/hgetall/ProductionCache/machine:1

Utility Operations

# Test connection
GET /main/system/redis/api/test/ProductionCache

# Get TTL for a key
GET /main/system/redis/api/ttl/ProductionCache/session:12345

# Get connection diagnostics
GET /main/system/redis/api/connections/ProductionCache/diagnostics

# List all connections with status
GET /main/system/redis/api/connections

📊 Monitoring and Diagnostics

Connection Status

Monitor connection health in the Gateway web interface:

  • Config → Redis → Connections: View all connections with status
  • Status → System → Redis: Real-time connection monitoring via REST API

Status Indicators

  • Connected: ✅ Connection active and healthy
  • Connecting: 🔄 Connection in progress
  • Failed: ❌ Connection failed (with error details)
  • Disabled: ⏸️ Connection disabled in configuration
  • Disconnected: ⚪ Connection not established

Connection Metrics

Each connection displays:

  • Active Connections: Currently in use
  • Idle Connections: Available in pool
  • Pool Utilization: Active+Idle/Max format
  • Retry Attempts: Failed connection retry count
  • Last Health Check: Timestamp of last verification

Diagnostics API

# Get detailed connection information
GET /main/system/redis/status/connections

# Response includes:
{
  "count": 2,
  "connections": [
    {
      "name": "ProductionCache",
      "host": "redis.company.com",
      "port": 6379,
      "database": 0,
      "enabled": true,
      "connectionState": "CONNECTED",
      "activeConnections": 3,
      "idleConnections": 5,
      "maxTotal": 20,
      "retryAttempts": 0,
      "lastHealthCheck": "2024-01-21T10:30:15Z"
    }
  ]
}

🛡️ Security Considerations

Network Security

  • Firewall Rules: Ensure Redis ports (default 6379) are properly secured
  • VPN/Private Networks: Use secure networks for Redis communication
  • SSL/TLS: Configure Redis with SSL for encrypted connections (requires Redis 6+)

Authentication

  • Redis AUTH: Always use password authentication in production
  • Database Isolation: Use separate Redis databases for different applications
  • Connection Limits: Configure appropriate pool sizes to prevent resource exhaustion

Ignition Integration

  • Role-Based Access: API endpoints respect Ignition's role-based security
  • Gateway Permissions: Requires Config section access for administrative operations
  • Script Restrictions: Client/Designer operations use secure RPC to Gateway

🔧 Troubleshooting

Common Issues

Connection Failures

Symptom: "Connection 'ProductionCache' not found or not available"
Solutions:
1. Verify connection exists in Gateway config
2. Check connection is enabled
3. Verify Redis server is running and accessible
4. Check network connectivity and firewall rules
5. Validate password if using AUTH

Pool Exhaustion

Symptom: "Could not get a resource from the pool"
Solutions:
1. Increase Max Pool Size in connection settings
2. Check for connection leaks in custom scripts
3. Monitor connection usage patterns
4. Consider connection timeout adjustments

Type Conversion Issues

Symptom: "Value 'xyz' at key 'abc' cannot be converted to Integer"
Solutions:
1. Verify the stored value type matches expected type
2. Use system.redis.get() for automatic type detection
3. Handle type conversion errors in scripts
4. Check data source for consistency

Debug Mode

Enable detailed logging by setting system property:

-Dredis.dev.mode=true

This enables:

  • Unrestricted API access (development only)
  • Detailed connection logging
  • Enhanced error messages

Log Analysis

Check Ignition Gateway logs for Redis-related entries:

Location: {ignition}/logs/wrapper.log
Filter: "Redis" or "dev.bwdesigngroup.redis"

🧪 Testing

Unit Tests

# Run all tests
./gradlew test

# Run specific test class
./gradlew test --tests "*RedisConnectionManagerTest"

# Generate test reports
./gradlew test jacocoTestReport

Integration Testing

# Requires running Redis instance
export REDIS_HOST=localhost
export REDIS_PORT=6379
./gradlew integrationTest

🔄 Version History

v0.0.13 (Current Development)

  • Performance: Bulk key operations using Redis pipelining for Designer Redis Browser
  • Performance: Reduced 2000+ RPC calls to single bulk operation when loading keys
  • Security: Gateway communication mode protection for destructive operations
  • Security: Prevents accidental production cache modifications in read-only mode
  • UX: Sorted set operations (zadd, zrem, zrange) with pipeline support
  • UX: SET NX (if-not-exists) support with ifNotExists parameter
  • Developer Tools: Redis Browser with type detection and TTL display
  • Developer Tools: Redis CLI panel with command history
  • Developer Tools: Redis Profiler for performance monitoring
  • Logging: Reduced verbosity of routine operations (moved to debug level)
  • Versioning: Automatic version detection from git tags

v0.0.12 and Earlier

  • Initial releases
  • Multi-scope Redis connectivity (Gateway, Designer, Client)
  • Expression and scripting functions with native type preservation
  • REST API endpoints
  • Connection pooling with automatic retry
  • Batch operations support
  • TTL/expiration support
  • Comprehensive error handling with Python-compatible exceptions
  • Hash operations (hget, hset, hgetAll)
  • Key management with pattern matching

🤝 Contributing

Development Setup

  1. Clone Repository: git clone <repository-url>
  2. Import IDE: Import as Gradle project in IntelliJ IDEA or Eclipse
  3. Configure Environment: Set up local Redis instance for testing
  4. Build Module: Run ./gradlew build to verify setup

Code Style

  • Java: Follow Google Java Style Guide
  • Package Structure: Maintain organized package hierarchy
  • Documentation: Comprehensive JavaDoc for public APIs
  • Testing: Minimum 80% code coverage for new features
  • Logging: Use SLF4J with appropriate log levels

Pull Request Process

  1. Feature Branch: Create feature branch from main
  2. Implementation: Implement feature with tests
  3. Documentation: Update README and JavaDoc as needed
  4. Testing: Verify all tests pass
  5. Pull Request: Submit PR with detailed description

📄 License

This project is licensed under the Apache License 2.0.

📞 Support

Documentation

Community

Commercial Support

For commercial support, training, or custom development:

About

Redis integration module for Inductive Automation Ignition. Provides system.redis.* scripting functions, expression functions, REST endpoints, and Designer tooling (browser, CLI, profiler) with connection pooling and health monitoring across Gateway, Designer, and Client scopes. Requires Ignition 8.1.44+.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages