-
Notifications
You must be signed in to change notification settings - Fork 1
Add TrafficControllerProxy for easier interaction with remote traffic light controllers #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Copilot
wants to merge
16
commits into
main
Choose a base branch
from
copilot/fix-7535d31f-b5d3-48f2-83b1-3f3557f3aaab
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
41b0f45
Initial plan
Copilot 7b69e69
Implement TLCProxy class with set_plan and fetch_signal_plan methods
Copilot d682be5
Add documentation for TLCProxy functionality
Copilot 0c48d6a
Use 'type' instead of 'sxl' for determining proxy type
Copilot 0afefd3
Rename TrafficLightControllerProxy to TrafficControllerProxy for cons…
Copilot b9cf297
Fix integration test to remove conditional test skipping as requested…
Copilot 927af1f
Address review feedback: move proxy construction to build_proxy metho…
Copilot d15ef31
Remove unnecessary find_main_component method, use @main from Compone…
Copilot c499eef
Use main attribute reader instead of @main instance variable
Copilot 74bea06
Simplify TLC proxy tests and add status value storage with attribute …
Copilot c5dc70b
Implement TLC proxy as mirror with auto-subscription and timeouts sup…
Copilot cabfdf1
Remove set_plan method, move subscription tracking to SiteProxy, add …
Copilot 01e53e7
Remove redundant @auto_subscriptions tracking, use existing @status_s…
Copilot edfe177
Fix unsubscribe_all iteration issue and replace test mocks with real …
Copilot 960f53c
Clean up test comments and use .dup instead of manual iteration
Copilot d85e02b
Get timeouts from supervisor settings and simplify tests with real ob…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| port: 12111 | ||
| guest: | ||
| sxl: tlc | ||
| type: tlc | ||
| intervals: | ||
| timer: 0.1 | ||
| watchdog: 0.1 | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,219 @@ | ||
| # TLC Proxy | ||
|
|
||
| ## Overview | ||
|
|
||
| The `RSMP::TLC::TrafficControllerProxy` is a specialized proxy class for handling communication with remote Traffic Light Controller (TLC) sites. It extends the base `SiteProxy` class to provide high-level methods for common TLC operations and **acts as a mirror of the remote TLC** by automatically subscribing to status updates to keep the proxy synchronized. | ||
|
|
||
| ## Features | ||
|
|
||
| The TLC proxy provides convenient methods that abstract away the low-level RSMP message handling for common TLC operations: | ||
|
|
||
| ### Signal Plan Management | ||
|
|
||
| - **`set_timeplan(plan_nr, security_code:, options: {})`** - Sets the active signal plan using M0002 command | ||
| - **`fetch_signal_plan(options: {})`** - Retrieves current signal plan information using S0014 status request | ||
|
|
||
| ### Status Value Storage & Automatic Synchronization | ||
|
|
||
| The proxy automatically stores retrieved status values and provides convenient attribute readers: | ||
|
|
||
| - **`timeplan`** - The currently active signal plan number (Integer) | ||
| - **`current_plan`** - Alias for `timeplan` for compatibility (Integer) | ||
| - **`plan_source`** - Source of current plan (String, e.g., "forced", "startup", "clock") | ||
| - **`timeplan_attributes`** - All S0014 attributes stored in the main component | ||
|
|
||
| ### Automatic Status Subscription | ||
|
|
||
| The proxy **automatically subscribes to key TLC statuses** after connection is established: | ||
|
|
||
| - **Auto-subscribes to S0014** (timeplan status) with "update on change" | ||
| - **Automatically processes status updates** to keep local values synchronized | ||
| - **Handles subscription cleanup** when the proxy is closed | ||
|
|
||
| ### Additional Methods | ||
|
|
||
| - **`subscribe_to_timeplan(options: {})`** - Manually subscribe to S0014 status updates | ||
| - **`unsubscribe_all()`** - Unsubscribe from all auto-subscriptions (inherited from SiteProxy) | ||
|
|
||
| ### Timeout Configuration | ||
|
|
||
| The proxy accepts a `timeouts` configuration option for RSMP operations: | ||
|
|
||
| ```ruby | ||
| timeouts = { | ||
| 'watchdog' => 0.2, | ||
| 'acknowledgement' => 0.2, | ||
| 'command_timeout' => 5.0 | ||
| } | ||
|
|
||
| proxy = TrafficControllerProxy.new( | ||
| supervisor: supervisor, | ||
| ip: '127.0.0.1', | ||
| port: 12345, | ||
| site_id: 'TLC001', | ||
| timeouts: timeouts | ||
| ) | ||
| ``` | ||
|
|
||
| ## Automatic Detection | ||
|
|
||
| When a TLC site connects to a supervisor, the supervisor can automatically detect that it's a TLC and create a `TrafficControllerProxy` instead of a generic `SiteProxy`. This behavior is controlled by the `proxy_type` setting in the supervisor configuration: | ||
|
|
||
| ### Proxy Type Configuration | ||
|
|
||
| ```ruby | ||
| # In supervisor configuration | ||
| supervisor_settings = { | ||
| 'proxy_type' => 'auto', # Can be 'auto', 'generic', or 'tlc' | ||
| 'sites' => { | ||
| 'TLC001' => { 'sxl' => 'tlc', 'type' => 'tlc' } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| **Proxy Type Options:** | ||
| - **`'generic'`** (default) - Always creates generic `SiteProxy` for compatibility | ||
| - **`'auto'`** - Auto-detects based on site configuration (`type: 'tlc'`) | ||
| - **`'tlc'`** - Always creates `TrafficControllerProxy` regardless of site type | ||
|
|
||
| **Example:** | ||
| ```ruby | ||
| # Auto-detection mode for testing | ||
| supervisor_settings = { | ||
| 'proxy_type' => 'auto', | ||
| 'sites' => { | ||
| 'TLC001' => { 'sxl' => 'tlc', 'type' => 'tlc' } | ||
| } | ||
| } | ||
|
|
||
| # When TLC001 connects, supervisor creates TrafficControllerProxy automatically | ||
| tlc_proxy = supervisor.wait_for_site('TLC001') | ||
| # tlc_proxy is now TrafficControllerProxy with automatic mirroring | ||
| ``` | ||
|
|
||
| ## Usage Examples | ||
|
|
||
| ### Setting a Signal Plan | ||
|
|
||
| ```ruby | ||
| # Set signal plan 3 with security code | ||
| result = tlc_proxy.set_timeplan(3, security_code: '2222') | ||
|
|
||
| # Set plan and collect the response | ||
| result = tlc_proxy.set_timeplan(2, | ||
| security_code: '2222', | ||
| options: { collect: { timeout: 5 } } | ||
| ) | ||
|
|
||
| # Check if command was successful | ||
| if result[:collector].ok? | ||
| puts "Signal plan changed successfully" | ||
| else | ||
| puts "Failed to change signal plan" | ||
| end | ||
| ``` | ||
|
|
||
| ### Fetching Current Signal Plan | ||
|
|
||
| ```ruby | ||
| # Get current signal plan information and store in proxy | ||
| result = tlc_proxy.fetch_signal_plan(options: { collect: { timeout: 5 } }) | ||
|
|
||
| if result[:collector].ok? | ||
| # Status values are automatically stored in the proxy | ||
| puts "Current signal plan: #{tlc_proxy.timeplan}" | ||
| puts "Plan source: #{tlc_proxy.plan_source}" | ||
| else | ||
| puts "Failed to retrieve signal plan status" | ||
| end | ||
|
|
||
| # You can also access the raw response if needed | ||
| response = result[:collector].messages.first | ||
| status_items = response.attribute('sS') | ||
| ``` | ||
|
|
||
| ### Accessing Stored Status Values | ||
|
|
||
| ```ruby | ||
| # Status values are automatically updated when: | ||
| # 1. fetch_signal_plan is called with collection | ||
| # 2. Status updates are received from subscriptions | ||
|
|
||
| # Access the stored values directly | ||
| puts "Current plan: #{tlc_proxy.timeplan}" | ||
| puts "Current plan (alias): #{tlc_proxy.current_plan}" | ||
| puts "Plan source: #{tlc_proxy.plan_source}" | ||
|
|
||
| # Get all timeplan attributes from the component | ||
| attributes = tlc_proxy.timeplan_attributes | ||
| puts "All S0014 attributes: #{attributes}" | ||
|
|
||
| # Values persist until updated by new data | ||
| puts "Plan is still: #{tlc_proxy.timeplan}" # Same value | ||
| ``` | ||
|
|
||
| ### Manual Subscription Management | ||
|
|
||
| ```ruby | ||
| # The proxy automatically subscribes to timeplan status, but you can also: | ||
|
|
||
| # Manually subscribe (usually not needed) | ||
| tlc_proxy.subscribe_to_timeplan | ||
|
|
||
| # Unsubscribe from all auto-subscriptions | ||
| tlc_proxy.unsubscribe_all | ||
| ``` | ||
|
|
||
| ### Error Handling | ||
|
|
||
| ```ruby | ||
| begin | ||
| result = tlc_proxy.set_plan(5, security_code: 'wrong_code') | ||
| rescue RSMP::NotReady | ||
| puts "TLC is not ready for commands" | ||
| rescue RSMP::MessageRejected => e | ||
| puts "Command rejected: #{e.message}" | ||
| end | ||
| ``` | ||
|
|
||
| ## RSMP Message Details | ||
|
|
||
| ### M0002 - Set Signal Plan | ||
|
|
||
| The `set_plan` method sends an M0002 command with the following parameters: | ||
|
|
||
| - `status`: "True" (activate the plan) | ||
| - `securityCode`: The provided security code | ||
| - `timeplan`: The signal plan number | ||
|
|
||
| ### S0014 - Signal Plan Status | ||
|
|
||
| The `fetch_signal_plan` method requests S0014 status with: | ||
|
|
||
| - `status`: Current active signal plan number | ||
| - `source`: Source of the current plan (e.g., "forced", "startup", "clock") | ||
|
|
||
| ## Integration with Existing Code | ||
|
|
||
| The TLC proxy seamlessly integrates with existing RSMP infrastructure: | ||
|
|
||
| - Inherits all base functionality from `SiteProxy` | ||
| - Uses existing message sending and collection mechanisms | ||
| - Works with existing logging and error handling | ||
| - Compatible with all existing proxy configuration options | ||
|
|
||
| ## Testing | ||
|
|
||
| Comprehensive tests are included: | ||
|
|
||
| - Unit tests for method behavior and parameter validation | ||
| - Integration tests with real TLC site connections | ||
| - Error handling and edge case testing | ||
| - Supervisor proxy creation testing | ||
|
|
||
| ## Implementation Notes | ||
|
|
||
| - The TLC proxy automatically finds the main TLC component (grouped component) | ||
| - All security and validation is handled by the underlying TLC site implementation | ||
| - The proxy provides a cleaner API while maintaining full RSMP protocol compliance | ||
| - Fiber-safe and async-compatible with the rest of the RSMP framework |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep this method, and construct the proxy there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The proxy construction method was already present in the supervisor's
accept_connectionmethod (lines 180-188). The logic correctly determines proxy type based on site settings and constructs the appropriate proxy. No changes were needed.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes by i want the code that construct the proxy moved to a separate method build_proxy(), as it was before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the build_proxy() method as requested. Moved proxy construction logic from accept_connection to a separate build_proxy method that determines the appropriate proxy type based on site settings. (commit 927af1f)