opcua-smart advantages:
- Modular C Extension Structure: Splits code into separate directories (client/, server/, helpers/)
- Shared Helper Functions: Reusable functions in finders.c and values.c
- Separate Header Files: Clean separation of interface (.h) and implementation (.c)
opcua-client current state:
- Single monolithic C file (opcua_client.c) with all functionality
Current Issue: Repetitive type conversion code scattered throughout read/write functions
Suggestion: Extract value conversion to helper functions (like opcua-smart's values.c)
- Create extract_value() function that returns [value, type_symbol]
- Create value_to_variant() function that converts Ruby values to UA_Variant
- Support automatic type detection from Ruby values
- Return type metadata along with values (useful for debugging)
Benefits:
- Reduce code duplication significantly
- Support automatic type detection from Ruby values
- Return type metadata along with values
- Enable easier addition of new types
Example from opcua-smart: VALUE extract_value(UA_Variant value) { VALUE ret = rb_ary_new2(2); rb_ary_store(ret,0,Qnil); // actual value rb_ary_store(ret,1,Qnil); // type symbol // ... conversion logic return ret; }
Current Issue: Separate methods for each type (read_int32, read_float, etc.)
Suggestion: Add generic get() method (like opcua-smart) that:
- Accepts namespace and node identifier (numeric or string)
- Returns a node object with .value accessor
- Automatically detects and converts types
- Supports both get(ns, id) and get(id) with default namespace
Benefits:
- Simpler API for users who don't know the exact type
- Fewer method calls to remember
- More flexible - works with any type
- Keep existing type-specific methods for performance-critical code
Current Issue: Returns raw values; no node abstraction
Suggestion: Introduce Node classes (like opcua-smart's cVarNode, cMethodNode)
- Client#get() returns a Node object
- Node has .value and .value= methods
- Node has .id() and .to_s() methods for inspection
- Different node classes for variables, methods, objects
Benefits:
- Object-oriented API - more Ruby-like
- Lazy evaluation - read value only when accessed
- Metadata access - inspect node properties
- Method invocation - call OPC UA methods naturally
Current Issue: Requires separate connect and authentication calls
Suggestion: Parse URL in initialize() to extract credentials (like opcua-smart)
Example:
def initialize(url, user=nil, pass=nil) if url =~ /(^[^:]+)://([^:]+):([^@]+)@(.*)$/ initialize_base("#{$1}://#{$4}", $2, $3) else initialize_base(url, user, pass) end end
Benefits:
- Single-line connection with authentication
- Standard URL format familiar to developers
- Backward compatible - still accepts separate user/pass
Current Issue: Requires separate namespace and identifier parameters
Suggestion: Add support for OPC UA standard node ID strings (like opcua-smart)
Example:
client.get(5, "temperature") # Current style client.get("ns=5;s=temperature") # OPC UA standard format client.get("ns=5;i=1234") # Numeric identifier
Benefits:
- Standard OPC UA format - copy-paste from other tools
- Simpler for string identifiers - one parameter instead of two
- Backward compatible - keep existing API
Current Issue: Must always specify namespace index
Suggestion: Add default_ns property (like opcua-smart)
Example: client.default_ns = 5 client.get("temperature") # Uses namespace 5
Benefits:
- Less repetition when working with single namespace
- Cleaner code for common use cases
- Still allows override when needed
Current Issue: Basic subscription support
Suggestion: Improve subscription API (inspired by opcua-smart)
- Add subscription_interval property
- Add check_subscription() method for manual iteration
- Support on_change blocks with timestamp and type metadata
- Return [value, timestamp, type] to callbacks
Current Status: ALREADY FIXED!
Note: opcua-client now uses TypedData_Get_Struct correctly opcua-smart still uses older Data_Get_Struct - opcua-client is ahead here!
Current Issue: No helper functions for browsing node references
Suggestion: Add helper functions (like opcua-smart's finders.c)
- client_node_get_reference_by_name() - find child by name
- client_node_get_reference_by_type() - find reference by type
- client_node_list_references() - list all references
Benefits:
- Node discovery - explore server structure
- Relationship traversal - follow references
- Reusable code - DRY principle
Current Issue: Arrays supported but no multi-dimensional array support
Suggestion: Add array dimension handling (like opcua-smart)
- Read/write arrayDimensions attribute
- Support multi-dimensional arrays
- Set valueRank when writing arrays
Benefits:
- Full OPC UA compliance - support all array types
- Matrix data - 2D/3D arrays for scientific applications
Current Issue: Only one method name per operation
Suggestion: Add Ruby-style aliases
Example: rb_define_method(cClient, "read_bool", rb_readBooleanValue, 2); rb_define_method(cClient, "read_boolean", rb_readBooleanValue, 2); // alias
Benefits:
- Flexibility - users choose preferred style
- Compatibility - match other OPC UA libraries
Suggestion: Refactor into multiple files
- opcua_client.c - main client code
- opcua_values.c - value conversion helpers
- opcua_finders.c - node browsing helpers
- opcua_types.c - type definitions and constants
Benefits:
- Maintainability - easier to find and modify code
- Testability - test helpers independently
- Reusability - share code between client/server if needed
Current Issue: No DateTime type support
Suggestion: Add DateTime type (like opcua-smart)
Example: UA_DateTime tmp = UA_DateTime_fromUnixTime(rb_time_timeval(value).tv_sec);
Benefits:
- Timestamp values - essential for industrial data
- Time-series data - historical data access
- Value conversion helpers (#1) - Reduces code duplication significantly
- Generic get() method (#2) - Simplifies API dramatically
- Node ID string parsing (#5) - Standard OPC UA format
- Default namespace (#6) - Cleaner code for common cases
- Node objects (#3) - More Ruby-like API
- URL parsing (#4) - Convenience feature
- Type constants (#8) - Better documentation
- Error messages (#9) - Better debugging
- Subscription management (#7) - Advanced features
- Helper functions (#11) - For advanced browsing
- Array dimensions (#12) - For scientific applications
- DateTime support (#15) - For time-series data
- Alias methods (#13) - Convenience
- Code restructuring (#14) - Long-term maintainability
The opcua-smart repository demonstrates several excellent patterns:
- Cleaner abstraction with node objects
- Better code organization with helper functions
- More flexible API with generic methods and string parsing
- Ruby-friendly conventions with default values and aliases
However, opcua-client has some advantages:
- More complete type support (Int64, UInt64, SByte, etc.)
- Better array support (comprehensive read/write for all types)
- Modern Ruby C API (TypedData_Get_Struct)
Combine the strengths of both:
- Keep opcua-client's comprehensive type and array support
- Add opcua-smart's cleaner API and helper functions
- Maintain backward compatibility while adding new features
When implementing these suggestions:
- Start with high-priority items that provide most value
- Maintain backward compatibility - don't break existing code
- Add new features alongside existing methods
- Write tests for each new feature
- Update documentation as features are added
- Consider creating a migration guide for users
- opcua-smart repository: https://github.com/etm/opcua-smart
- open62541 documentation: https://www.open62541.org/
- OPC UA specification: https://opcfoundation.org/developer-tools/specifications-unified-architecture
End of suggestions.