Skip to content

Implement endpoint health ws#8

Merged
damnthonyy merged 3 commits into
developmentfrom
feat/implement-endpoint-health-ws
May 21, 2026
Merged

Implement endpoint health ws#8
damnthonyy merged 3 commits into
developmentfrom
feat/implement-endpoint-health-ws

Conversation

@damnthonyy

Copy link
Copy Markdown
Member

Summary

Add WebSocket health diagnostic endpoint and comprehensive frontend integration guide for robocoop backend.

Description

This PR introduces a complete documentation guide for frontend developers and a new diagnostic health endpoint to test the backend in isolation (especially useful with MockRobotAdapter).

The health endpoint allows frontend/testing to verify the backend is functioning correctly without requiring a real robot connection. This is particularly valuable for development and CI/CD validation.

What's Changed

Affected areas:

  • WebSocket message protocol (new health messages)
  • Frontend integration guide (documentation)
  • Health diagnostics endpoint

Key files:

  • src/robocoop_backend/robocoop_backend/app/contracts.py — Added MSG_GET_HEALTH, MSG_HEALTH_RESPONSE constants
  • src/robocoop_backend/robocoop_backend/app/websocket_handler.py — Implemented health handler
  • src/robocoop_backend/robocoop_backend/tests/unit/app/test_websocket_handler.py — Added health endpoint test

Details:

  • New message types: get_health (frontend → backend) and health_response (backend → frontend)
  • Health response includes: status, adapter type (mock/rosbridge), environment, and full robot state
  • Tested with MockRobotAdapter in isolation (no real robot required)

How to Test

Manual testing (requires wscat or similar WebSocket client):

# Terminal 1: Start backend in mock mode
bash run_backend.sh mock

# Terminal 2: Connect and test
wscat -c ws://localhost:8765
# Send: {"type": "get_health"}
# Expected: {"type": "health_response", "data": {"status": "ok", "adapter": "MockRobotAdapter", ...}}

if you run the frontend too, the endpoint work automaticly

iGrec-a2n and others added 2 commits May 19, 2026 16:06
…ures

- Implemented RGB LED chenillard that runs on startup when connected to rosbridge.
- Updated README to include instructions for standalone LED testing and configuration options.
- Enhanced telemetry service to monitor linear velocity and critical battery levels, with corresponding audit events.
- Updated adapter factory to support new RGB functionality and ensure proper configuration handling.
- Added tests for new features, including telemetry checks for battery and velocity thresholds.
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

Add RGB chenillard, teleop commands, odometry tracking, and health endpoint

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add RGB LED chenillard animation via rosbridge with configurable parameters
• Implement teleop velocity commands and emergency stop publishing to robot
• Add odometry subscription to track linear velocity with high-velocity alerts
• Extend telemetry with battery critical threshold and velocity monitoring
• Add health diagnostic endpoint for backend validation
• Enhance configuration system with teleop limits, message types, and audit logging
Diagram
flowchart LR
  A["Config<br/>common + env"] -->|"teleop, rgb,<br/>msg_types"| B["Factory"]
  B -->|"creates"| C["RosbridgeAdapter"]
  C -->|"on connect"| D["RgbChenillard"]
  D -->|"publish"| E["rosbridge<br/>/rgb"]
  C -->|"subscribe"| F["/odom"]
  F -->|"linear_x"| G["TelemetryService"]
  G -->|"velocity > threshold"| H["AuditEvent<br/>velocity.high"]
  I["WebSocket<br/>teleop.move"] -->|"send_velocity"| C
  C -->|"publish"| J["/cmd_vel"]
  K["WebSocket<br/>emergency_stop"] -->|"emergency_stop"| C
  C -->|"publish"| L["/emergency_stop"]
  M["WebSocket<br/>get_health"] -->|"handler"| N["health_response"]

Loading

File Changes

1. src/robocoop_backend/robocoop_backend/adapters/base_adapter.py ✨ Enhancement +12/-0

Add velocity and emergency stop method stubs

src/robocoop_backend/robocoop_backend/adapters/base_adapter.py


2. src/robocoop_backend/robocoop_backend/adapters/factory.py ✨ Enhancement +36/-2

Wire teleop, odom, rgb, and message type configs

src/robocoop_backend/robocoop_backend/adapters/factory.py


3. src/robocoop_backend/robocoop_backend/adapters/mock_adapter.py ✨ Enhancement +15/-1

Implement teleop and emergency stop logging

src/robocoop_backend/robocoop_backend/adapters/mock_adapter.py


View more (34)
4. src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py ✨ Enhancement +111/-2

Add odom subscription, velocity/emergency publishing, RGB chenillard

src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py


5. src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py ✨ Enhancement +14/-0

Implement publish method for rosbridge topics

src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py


6. src/robocoop_backend/robocoop_backend/app/backend_context.py ⚙️ Configuration changes +13/-2

Add audit file sink and telemetry threshold configuration

src/robocoop_backend/robocoop_backend/app/backend_context.py


7. src/robocoop_backend/robocoop_backend/app/contracts.py ✨ Enhancement +27/-1

Add get_health, health_response, and linear_velocity to state

src/robocoop_backend/robocoop_backend/app/contracts.py


8. src/robocoop_backend/robocoop_backend/app/websocket_handler.py ✨ Enhancement +16/-2

Implement health endpoint and teleop/emergency command handlers

src/robocoop_backend/robocoop_backend/app/websocket_handler.py


9. src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py ✨ Enhancement +77/-0

New RGB LED chenillard animation module

src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py


10. src/robocoop_backend/robocoop_backend/modules/robot/state_store.py ✨ Enhancement +2/-0

Add linear_velocity field to robot state

src/robocoop_backend/robocoop_backend/modules/robot/state_store.py


11. src/robocoop_backend/robocoop_backend/modules/robot/telemetry_service.py ✨ Enhancement +48/-3

Add battery critical and velocity high alert thresholds

src/robocoop_backend/robocoop_backend/modules/robot/telemetry_service.py


12. src/robocoop_backend/robocoop_backend/scripts/rgb_chenillard_standalone.py ✨ Enhancement +56/-0

New standalone RGB chenillard test script

src/robocoop_backend/robocoop_backend/scripts/rgb_chenillard_standalone.py


13. src/robocoop_backend/robocoop_backend/tests/integration/test_context_lifecycle.py 🧪 Tests +53/-0

Add teleop, emergency stop, and config integration tests

src/robocoop_backend/robocoop_backend/tests/integration/test_context_lifecycle.py


14. src/robocoop_backend/robocoop_backend/tests/integration/test_telemetry_pipeline.py 🧪 Tests +26/-0

Add battery critical and velocity high alert tests

src/robocoop_backend/robocoop_backend/tests/integration/test_telemetry_pipeline.py


15. src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_factory.py 🧪 Tests +59/-2

Add config wiring and RGB chenillard factory tests

src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_factory.py


16. src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_mock_adapter.py 🧪 Tests +6/-0

Add velocity and emergency stop method tests

src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_mock_adapter.py


17. src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_rosbridge_adapter.py 🧪 Tests +83/-2

Add odom, velocity clamping, and RGB chenillard tests

src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_rosbridge_adapter.py


18. src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_rosbridge_client.py 🧪 Tests +18/-0

Add publish method tests

src/robocoop_backend/robocoop_backend/tests/unit/adapters/test_rosbridge_client.py


19. src/robocoop_backend/robocoop_backend/tests/unit/app/test_backend_context.py 🧪 Tests +25/-0

Add telemetry threshold and audit sink configuration tests

src/robocoop_backend/robocoop_backend/tests/unit/app/test_backend_context.py


20. src/robocoop_backend/robocoop_backend/tests/unit/app/test_websocket_handler.py 🧪 Tests +16/-0

Add health endpoint and teleop command handler tests

src/robocoop_backend/robocoop_backend/tests/unit/app/test_websocket_handler.py


21. src/robocoop_backend/robocoop_backend/tests/unit/modules/test_rgb_chenillard.py 🧪 Tests +29/-0

New RGB chenillard animation unit tests

src/robocoop_backend/robocoop_backend/tests/unit/modules/test_rgb_chenillard.py


22. src/robocoop_backend/robocoop_backend/tests/unit/modules/test_state_store.py 🧪 Tests +5/-0

Add linear_velocity state store tests

src/robocoop_backend/robocoop_backend/tests/unit/modules/test_state_store.py


23. src/robocoop_backend/robocoop_backend/tests/unit/modules/test_telemetry_service.py 🧪 Tests +76/-0

Add battery critical and velocity threshold alert tests

src/robocoop_backend/robocoop_backend/tests/unit/modules/test_telemetry_service.py


24. run_backend.sh 📝 Documentation +2/-0

Add RGB chenillard startup comment

run_backend.sh


25. scripts/rgb_chenillard.sh ✨ Enhancement +16/-0

New standalone RGB chenillard launcher script

scripts/rgb_chenillard.sh


26. README.md 📝 Documentation +16/-2

Document RGB chenillard, teleop, and standalone LED test

README.md


27. scripts/README.md 📝 Documentation +16/-0

New scripts directory documentation

scripts/README.md


28. src/robocoop_backend/robocoop_backend.egg-info/SOURCES.txt ⚙️ Configuration changes +4/-1

Update package manifest with new modules

src/robocoop_backend/robocoop_backend.egg-info/SOURCES.txt


29. src/robocoop_backend/robocoop_backend/adapters/README.md 📝 Documentation +37/-13

Document RGB chenillard and publish pattern

src/robocoop_backend/robocoop_backend/adapters/README.md


30. src/robocoop_backend/robocoop_backend/app/README.md 📝 Documentation +1/-1

Update lifecycle documentation with RGB chenillard

src/robocoop_backend/robocoop_backend/app/README.md


31. src/robocoop_backend/robocoop_backend/modules/audit/README.md 📝 Documentation +3/-1

Document battery critical and velocity high audit events

src/robocoop_backend/robocoop_backend/modules/audit/README.md


32. src/robocoop_backend/robocoop_backend/modules/robot/README.md 📝 Documentation +28/-1

Document RGB chenillard module and standalone test

src/robocoop_backend/robocoop_backend/modules/robot/README.md


33. src/robocoop_bringup/config/README.md 📝 Documentation +68/-1

Document teleop, message types, RGB, and publish topics

src/robocoop_bringup/config/README.md


34. src/robocoop_bringup/config/common.params.yaml ⚙️ Configuration changes +24/-0

Add teleop, message types, velocity threshold, and RGB config

src/robocoop_bringup/config/common.params.yaml


35. src/robocoop_bringup/config/real.params.yaml ⚙️ Configuration changes +7/-0

Add publish topics and enable RGB chenillard

src/robocoop_bringup/config/real.params.yaml


36. src/robocoop_backend/robocoop_backend/scripts/__init__.py Additional files +0/-0

...

src/robocoop_backend/robocoop_backend/scripts/init.py


37. supervisor/src/robocoop_supervisor/ui/main_window.py Additional files +0/-0

...

supervisor/src/robocoop_supervisor/ui/main_window.py


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented May 20, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (0)

Grey Divider


Action required

1. Publish spams on disconnect 🐞 Bug ☼ Reliability
Description
RosbridgeClient.publish() sends as long as _websocket is non-null, even after the connection is
closed, so the new RGB chenillard/teleop publishers will repeatedly attempt sends and emit errors
while disconnected. This can generate sustained high-rate error logs (and unnecessary work) until
reconnect/shutdown.
Code

src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[R56-68]

Evidence
publish() only checks _websocket and will attempt sends even when _is_connected is false; the
listener sets _is_connected = False on ConnectionClosed but does not clear _websocket. The
chenillard loop publishes continuously, so disconnections can produce repeated publish failures/log
lines.

src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[56-69]
src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[105-139]
src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[82-91]
src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[52-60]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`RosbridgeClient.publish()` only checks `self._websocket` and does not verify that the connection is actually alive. When the socket is closed (ConnectionClosed), `_is_connected` becomes false but `_websocket` may still be set, so publish attempts will keep failing and logging.

### Issue Context
This PR introduces frequent publishes (RGB chenillard loop + teleop/emergency). During any rosbridge outage/reconnect window, the system can spam logs and waste work.

### Fix Focus Areas
- Ensure `publish()` bails out when disconnected (e.g., `if not self.is_connected(): ...`).
- Clear `self._websocket = None` when the listener observes `ConnectionClosed` (and/or when reconnect begins), so publish fast-fails.
- Consider stopping/suspending the RGB chenillard when the bridge disconnects and restarting it on reconnect.

### Fix Focus Areas (code pointers)
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[56-69]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[105-139]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[82-109]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[216-226]
- src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[52-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Chenillard busy-loops on misconfig 🐞 Bug ☼ Reliability
Description
RgbChenillard._run() only awaits inside the for led in range(...) loop, so if led_min > led_max
the task spins in while True without yielding and can peg the event loop CPU. Since led bounds are
config-driven, a bad config can freeze the backend.
Code

src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[R52-60]

Evidence
The only await in the chenillard loop is inside the for led in range(...); an empty range means
no await and a tight while True. The adapter factory passes led bounds from config directly, so an
invalid config can reach this code.

src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[52-60]
src/robocoop_backend/robocoop_backend/adapters/factory.py[60-68]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`RgbChenillard._run()` assumes `led_min <= led_max`. If the range is empty, the `while True` loop has no await points and becomes a tight loop, blocking the asyncio event loop.

### Issue Context
`led_min`/`led_max` are loaded from YAML and passed through `factory.py` without validation.

### Fix Focus Areas
- Validate `led_min` and `led_max` at init/start (swap, clamp, or disable with clear log).
- Add an unconditional `await asyncio.sleep(...)` in the outer loop when the LED range is empty to avoid starving the event loop.

### Fix Focus Areas (code pointers)
- src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[52-65]
- src/robocoop_backend/robocoop_backend/adapters/factory.py[60-68]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Teleop payload not validated 🐞 Bug ☼ Reliability
Description
WebSocketHandler forwards message.get("data") directly into adapter.send_velocity(), so
missing/non-dict payloads cause AttributeError in adapters when they call data.get(...) and the
command is dropped with an error log. This is user-input reachable over WebSocket.
Code

src/robocoop_backend/robocoop_backend/app/websocket_handler.py[R80-82]

Evidence
The handler passes possibly-missing data to send_velocity, and both adapters call
data.get(...) without guarding against None/non-dict, while RosbridgeRobotAdapter only catches
TypeError/ValueError (not AttributeError).

src/robocoop_backend/robocoop_backend/app/websocket_handler.py[56-85]
src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[137-153]
src/robocoop_backend/robocoop_backend/adapters/mock_adapter.py[25-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`teleop.move` handling passes `message.get('data')` through without type/None validation. Adapters assume a dict and call `.get()`, which raises `AttributeError` for `None`/non-dicts; this exception is not caught by the adapter’s `(TypeError, ValueError)` handler.

### Issue Context
This is directly reachable from an external WS client sending malformed JSON.

### Fix Focus Areas
- In `WebSocketHandler.handle_message`, verify `data` is a `dict` before calling `send_velocity` (otherwise ignore/log debug).
- Optionally harden adapters (`MockRobotAdapter`, `RosbridgeRobotAdapter`) to handle `None`/non-dict defensively.

### Fix Focus Areas (code pointers)
- src/robocoop_backend/robocoop_backend/app/websocket_handler.py[56-92]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[137-153]
- src/robocoop_backend/robocoop_backend/adapters/mock_adapter.py[25-29]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

4. Velocity alert ignores reverse 🐞 Bug ≡ Correctness
Description
TelemetryService only triggers velocity.high when velocity > threshold, so a high-magnitude
negative odom linear.x (reverse motion) will never produce the audit event. RosbridgeRobotAdapter
forwards signed linear.x directly into linear_velocity.
Code

src/robocoop_backend/robocoop_backend/modules/robot/telemetry_service.py[R81-94]

Evidence
The velocity audit condition is strictly > and will not fire for negative values, while
odom-derived linear_x is taken as-is and can be negative.

src/robocoop_backend/robocoop_backend/modules/robot/telemetry_service.py[81-95]
src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[120-134]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`_check_velocity()` uses a signed comparison (`velocity > threshold`). If the intent is to flag high speed regardless of direction, this should use magnitude.

### Issue Context
`linear_velocity` is derived from odometry `linear.x`, which is signed.

### Fix Focus Areas
- Decide whether the audit should be direction-agnostic; if yes, use `abs(velocity)`.
- Consider including direction in payload (e.g., signed value + absolute value) if useful.

### Fix Focus Areas (code pointers)
- src/robocoop_backend/robocoop_backend/modules/robot/telemetry_service.py[81-95]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[120-134]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +56 to +68
async def publish(self, topic: str, msg_type: str, msg: Dict[str, Any]) -> None:
if not self._websocket:
logger.error("Cannot publish: not connected")
return
try:
await self._websocket.send(json.dumps({
"op": "publish",
"topic": topic,
"type": msg_type,
"msg": msg,
}))
except Exception as e:
logger.error(f"Publish failed on {topic}: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Publish spams on disconnect 🐞 Bug ☼ Reliability

RosbridgeClient.publish() sends as long as _websocket is non-null, even after the connection is
closed, so the new RGB chenillard/teleop publishers will repeatedly attempt sends and emit errors
while disconnected. This can generate sustained high-rate error logs (and unnecessary work) until
reconnect/shutdown.
Agent Prompt
### Issue description
`RosbridgeClient.publish()` only checks `self._websocket` and does not verify that the connection is actually alive. When the socket is closed (ConnectionClosed), `_is_connected` becomes false but `_websocket` may still be set, so publish attempts will keep failing and logging.

### Issue Context
This PR introduces frequent publishes (RGB chenillard loop + teleop/emergency). During any rosbridge outage/reconnect window, the system can spam logs and waste work.

### Fix Focus Areas
- Ensure `publish()` bails out when disconnected (e.g., `if not self.is_connected(): ...`).
- Clear `self._websocket = None` when the listener observes `ConnectionClosed` (and/or when reconnect begins), so publish fast-fails.
- Consider stopping/suspending the RGB chenillard when the bridge disconnects and restarting it on reconnect.

### Fix Focus Areas (code pointers)
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[56-69]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_client.py[105-139]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[82-109]
- src/robocoop_backend/robocoop_backend/adapters/rosbridge_adapter.py[216-226]
- src/robocoop_backend/robocoop_backend/modules/robot/rgb_chenillard.py[52-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@damnthonyy damnthonyy merged commit 30ce85a into development May 21, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants