Repository navigation
Connect demos to the selfpatch platform through the agent #80
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
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
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 |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # Connecting the demos to the selfpatch platform | ||
|
|
||
| Any demo in this repository can show up in the selfpatch platform as a robot. The connection goes through the selfpatch agent: a small container next to the demo that opens an outbound connection to the platform and lets the platform read the demo's ros2_medkit gateway. Nothing on the demo side listens for the platform, so the same steps work when the platform is in the cloud and the demo is behind NAT. | ||
|
|
||
| This page is also written for AI coding assistants. Paste it into the assistant's context before asking it to run a demo against the platform or to build platform UI on top of a demo. | ||
|
|
||
| ## What you need | ||
|
|
||
| - A running demo (`./run-demo.sh` in its directory). | ||
| - An account on the platform you want to use. | ||
| - Docker. The scripts pull the public agent image `ghcr.io/selfpatch/agent:0.1` (amd64 and arm64). `SELFPATCH_AGENT_IMAGE` picks another one. | ||
|
|
||
| ## Connect a demo | ||
|
|
||
| 1. In the platform: Devices > Add device > "Through the selfpatch agent". Copy the pairing code. It is valid for 10 minutes. | ||
| 2. In the demo directory: | ||
|
|
||
| ```bash | ||
| ./connect-platform.sh | ||
| ``` | ||
|
|
||
| Paste the code when asked, or pass it as `PAIRING_CODE=XXXX-XXXX-XXXX-XXXX`. | ||
|
|
||
| 3. The device shows as online in the platform within a few seconds. | ||
|
|
||
| The agent runs as the container `selfpatch-agent-<gateway container>` and keeps its credential in a volume of the same name. It restarts with Docker and reconnects on its own. `./connect-platform.sh --disconnect` removes it. Remove the device in the platform as well. | ||
|
|
||
| Available in `sensor_diagnostics`, `ota_nav2_sensor_fix` and `turtlebot3_integration`. For any other demo run `lib/connect-platform.sh <gateway container>`. | ||
|
|
||
| | Variable | Default | Use | | ||
| |---|---|---| | ||
| | `PLATFORM_URL` | `https://platform.selfpatch.ai` | The platform to pair with, for example a staging deployment | | ||
| | `PAIRING_CODE` | asked for | The code from the platform | | ||
| | `SELFPATCH_AGENT_IMAGE` | `ghcr.io/selfpatch/agent:0.1` | Agent image | | ||
| | `PLATFORM_INSECURE_HTTP` | `0` | `1` allows a plain http platform, for a local dev platform | | ||
| | `GATEWAY_CONTAINER` | the demo's gateway container | Which demo instance to connect | | ||
|
|
||
| ## A platform running on your machine | ||
|
|
||
| The agent runs in a container, so `localhost` is the container itself. Point it at the host: | ||
|
|
||
| ```bash | ||
| PLATFORM_URL=http://host.docker.internal:<platform port> PLATFORM_INSECURE_HTTP=1 ./connect-platform.sh | ||
| ``` | ||
|
|
||
| On Linux, `host.docker.internal` needs `--add-host=host.docker.internal:host-gateway` or the host's LAN address instead. | ||
|
|
||
| ## Several robots | ||
|
|
||
| Every demo instance is its own device in the platform, with its own agent. The sensor demo can run several times side by side: | ||
|
|
||
| ```bash | ||
| cd demos/sensor_diagnostics | ||
| COMPOSE_PROJECT_NAME=robot2 DEMO_CONTAINER=robot2 GATEWAY_PORT=8082 \ | ||
| WEB_UI_CONTAINER=robot2_web_ui WEB_UI_PORT=3002 ROS_DOMAIN_ID=41 \ | ||
| docker compose up -d --build | ||
| GATEWAY_CONTAINER=robot2 ./connect-platform.sh | ||
| ``` | ||
|
|
||
| To stop it, disconnect the agent first. While it is attached, compose cannot remove the network: | ||
|
|
||
| ```bash | ||
| GATEWAY_CONTAINER=robot2 ./connect-platform.sh --disconnect | ||
| COMPOSE_PROJECT_NAME=robot2 ./stop-demo.sh | ||
| ``` | ||
|
|
||
| Give each instance its own `ROS_DOMAIN_ID` so the robots do not see each other's ROS graph. The fault scripts take `GATEWAY_URL`, for example `GATEWAY_URL=http://localhost:8082 ./inject-noise.sh`. | ||
|
|
||
| ## Making something happen | ||
|
|
||
| | Demo | Faults | Back to normal | | ||
| |---|---|---| | ||
| | `sensor_diagnostics` | `./inject-noise.sh`, `./inject-drift.sh`, `./inject-nan.sh`, `./inject-failure.sh`, `./inject-fault-scenario.sh` (all sensors at once) | `./restore-normal.sh` | | ||
| | `ota_nav2_sensor_fix` | `./send-goal.sh`: the robot drives into the phantom obstacle of the broken lidar, Nav2 aborts | `./publish-fix.sh`, `./apply-fix.sh`, `./clear-fault.sh`, `./send-goal.sh` again | | ||
| | `turtlebot3_integration` | `./inject-nav-failure.sh`, `./inject-localization-failure.sh` | `./restore-normal.sh` | | ||
|
|
||
| ## What the gateway exposes | ||
|
|
||
| The platform shows what the demo's gateway returns. The full list of routes is in the gateway's own OpenAPI document: `curl http://localhost:8080/api/v1/docs`. The parts a platform view usually needs: | ||
|
|
||
| - Entity tree: `/areas`, `/components`, `/apps`, `/functions`, each with `/{id}` and relations such as `/components/{id}/hosts`. | ||
| - Faults: `/faults` (all), `/faults/stream` (server-sent events), `/{entity}/faults`, `/{entity}/faults/{fault_code}` with freeze frames and the recording reference. | ||
| - Recordings: `/{entity}/bulk-data` and `/{entity}/bulk-data/rosbags/{id}` (MCAP). | ||
| - Live values: `/{entity}/data` and `/{entity}/data/{data_id}`. | ||
| - Logs: `/{entity}/logs`. | ||
| - Health and version: `/health`, `/version-info`. | ||
|
|
||
| Through the platform the agent forwards read requests (GET) only. Operations, scripts, configuration writes and fault clearing work on the gateway directly (`http://localhost:8080`) but not through the platform. | ||
|
|
||
| ## Building platform UI on a demo | ||
|
|
||
| Build against what the gateway actually returns, not against mocked data. Before adding a view, call the endpoint on a running demo and use that response. If a view needs data the gateway does not expose, that is a finding, not something to mock: open an issue in [ros2_medkit](https://github.com/selfpatch/ros2_medkit/issues) with the view you want, the endpoint you tried and its response. Some gaps are by design and some are missing features, and the issue is where that gets decided. | ||
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,9 @@ | ||
| #!/bin/bash | ||
| # Connect this demo to the selfpatch platform through the selfpatch agent. | ||
| # See lib/connect-platform.sh for the environment variables. | ||
| # | ||
| # ./connect-platform.sh pair and start the agent | ||
| # ./connect-platform.sh --disconnect stop and remove the agent | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| exec "${SCRIPT_DIR}/../../lib/connect-platform.sh" "${GATEWAY_CONTAINER:-ota_demo_gateway}" "$@" |
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,9 @@ | ||
| #!/bin/bash | ||
| # Connect this demo to the selfpatch platform through the selfpatch agent. | ||
| # See lib/connect-platform.sh for the environment variables. | ||
| # | ||
| # ./connect-platform.sh pair and start the agent | ||
| # ./connect-platform.sh --disconnect stop and remove the agent | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| exec "${SCRIPT_DIR}/../../lib/connect-platform.sh" "${GATEWAY_CONTAINER:-sensor_diagnostics_demo}" "$@" |
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,16 @@ | ||
| #!/bin/bash | ||
| # Connect this demo to the selfpatch platform through the selfpatch agent. | ||
| # See lib/connect-platform.sh for the environment variables. | ||
| # | ||
| # ./connect-platform.sh pair and start the agent | ||
| # ./connect-platform.sh --disconnect stop and remove the agent | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| # run-demo.sh --nvidia starts the gateway under a different container name. | ||
| if [[ -z "${GATEWAY_CONTAINER:-}" ]]; then | ||
| GATEWAY_CONTAINER=turtlebot3_medkit_demo | ||
| if [[ "$(docker inspect -f '{{.State.Running}}' turtlebot3_medkit_demo_nvidia 2>/dev/null)" == "true" ]]; then | ||
| GATEWAY_CONTAINER=turtlebot3_medkit_demo_nvidia | ||
| fi | ||
| fi | ||
| exec "${SCRIPT_DIR}/../../lib/connect-platform.sh" "$GATEWAY_CONTAINER" "$@" |
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,89 @@ | ||
| #!/bin/bash | ||
| # Connect a running demo to the selfpatch platform through the selfpatch agent. | ||
| # Source-free: each demo's connect-platform.sh calls this with its gateway | ||
| # container name. | ||
| # | ||
| # lib/connect-platform.sh <gateway-container> pair and start the agent | ||
| # lib/connect-platform.sh <gateway-container> --disconnect stop and remove the agent | ||
| # | ||
| # The agent runs as its own container on the demo's Docker network, opens an | ||
| # outbound connection to the platform and lets it read the demo's gateway. It | ||
| # keeps its credential in a volume, so it survives restarts and reconnects on | ||
| # its own. Each demo instance gets its own agent and shows up in the platform | ||
| # as its own device. | ||
| # | ||
| # Environment variables: | ||
| # PLATFORM_URL - platform to pair with (default: https://platform.selfpatch.ai) | ||
| # PAIRING_CODE - pairing code from the platform (asked for when unset) | ||
| # SELFPATCH_AGENT_IMAGE - agent image (default: ghcr.io/selfpatch/agent:0.1) | ||
| # PLATFORM_INSECURE_HTTP=1 - allow a plain http platform, e.g. a local dev | ||
| # platform at http://host.docker.internal:<port> | ||
|
|
||
| set -eu | ||
|
|
||
| usage() { | ||
| echo "Usage: $0 <gateway-container> [--disconnect]" | ||
| } | ||
|
|
||
| if [[ $# -lt 1 ]]; then | ||
| usage | ||
| exit 1 | ||
| fi | ||
|
|
||
| GATEWAY_CONTAINER="$1" | ||
| ACTION="${2:-connect}" | ||
| PLATFORM_URL="${PLATFORM_URL:-https://platform.selfpatch.ai}" | ||
| AGENT_IMAGE="${SELFPATCH_AGENT_IMAGE:-ghcr.io/selfpatch/agent:0.1}" | ||
| AGENT_NAME="selfpatch-agent-${GATEWAY_CONTAINER}" | ||
|
|
||
| if [[ "$ACTION" == "--disconnect" ]]; then | ||
| docker rm -f "$AGENT_NAME" >/dev/null 2>&1 || true | ||
| docker volume rm "$AGENT_NAME" >/dev/null 2>&1 || true | ||
| echo "Agent ${AGENT_NAME} removed. Remove the device in the platform too." | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [[ "$(docker inspect -f '{{.State.Running}}' "$GATEWAY_CONTAINER" 2>/dev/null)" != "true" ]]; then | ||
| echo "Container ${GATEWAY_CONTAINER} is not running. Start the demo first: ./run-demo.sh" | ||
| exit 1 | ||
| fi | ||
|
|
||
| NETWORK="$(docker inspect -f '{{range $name, $_ := .NetworkSettings.Networks}}{{$name}} {{end}}' "$GATEWAY_CONTAINER" | awk '{print $1}')" | ||
| if [[ -z "$NETWORK" || "$NETWORK" == "host" ]]; then | ||
| MEDKIT_URL="http://127.0.0.1:8080" | ||
| NETWORK="host" | ||
| else | ||
| MEDKIT_URL="http://${GATEWAY_CONTAINER}:8080" | ||
| fi | ||
|
|
||
| if ! docker image inspect "$AGENT_IMAGE" >/dev/null 2>&1 && ! docker pull -q "$AGENT_IMAGE" >/dev/null; then | ||
| echo "Cannot pull ${AGENT_IMAGE}. Set SELFPATCH_AGENT_IMAGE to an agent image you can reach." | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ -z "${PAIRING_CODE:-}" ]]; then | ||
| echo "In the platform: Devices > Add device > 'Through the selfpatch agent', then copy the pairing code." | ||
| read -r -p "Pairing code: " PAIRING_CODE | ||
| fi | ||
|
|
||
| PAIR_ARGS=(pair --platform-url "$PLATFORM_URL" --medkit-url "$MEDKIT_URL") | ||
| RUN_ARGS=(run) | ||
| if [[ "${PLATFORM_INSECURE_HTTP:-0}" == "1" ]]; then | ||
| PAIR_ARGS+=(--insecure-platform-http) | ||
| RUN_ARGS+=(--insecure-platform-http) | ||
| fi | ||
|
|
||
| docker volume create "$AGENT_NAME" >/dev/null | ||
| echo "$PAIRING_CODE" | docker run --rm -i --network "$NETWORK" \ | ||
| -e SELFPATCH_AGENT_STATE=/data -v "${AGENT_NAME}:/data" \ | ||
| "$AGENT_IMAGE" "${PAIR_ARGS[@]}" | ||
|
|
||
| docker rm -f "$AGENT_NAME" >/dev/null 2>&1 || true | ||
| docker run -d --name "$AGENT_NAME" --restart unless-stopped --network "$NETWORK" \ | ||
| -e SELFPATCH_AGENT_STATE=/data -v "${AGENT_NAME}:/data" \ | ||
| "$AGENT_IMAGE" "${RUN_ARGS[@]}" >/dev/null | ||
|
|
||
| echo "" | ||
| echo "Agent ${AGENT_NAME} is running. The demo appears in the platform within a few seconds." | ||
| echo "Logs: docker logs -f ${AGENT_NAME}" | ||
| echo "Disconnect: GATEWAY_CONTAINER=${GATEWAY_CONTAINER} ./connect-platform.sh --disconnect (in the demo directory)" |
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.
Uh oh!
There was an error while loading. Please reload this page.